-
Notifications
You must be signed in to change notification settings - Fork 168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Filippo version of Ed25519 #462
Open
parinayc20
wants to merge
20
commits into
master
Choose a base branch
from
filippo
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
25448ab
Docs added and filippo integration initiated
parinayc20 6fe4f1e
Filippo based point and scalar methods added
parinayc20 da9fb34
Filippo integration completed
parinayc20 451c68d
Tests and benchmarks updated
parinayc20 9cc00ea
Docs updated
parinayc20 28dd3b4
Changes added to docs
parinayc20 14e7da3
Suite documentation added
parinayc20 b41db2d
Docs updated
parinayc20 c1fe1cd
Applies `gofmt` and `go mod tidy`
nkcr b0f9796
Adds Github actions
nkcr f746f8b
Removes old .travis.yml
nkcr c7e292c
Fixes Sonar complaints
nkcr c7253db
security fix: any participant could disable DKG
vibs29 211afe7
Docs added and filippo integration initiated
parinayc20 b9c3f4d
Filippo integration completed
parinayc20 bb9eac2
Tests fixed applied to filippo
parinayc20 0d1c3cd
Merge conflicts resolved
parinayc20 bd72d1d
Merge branch 'master' into filippo
parinayc20 251bafc
small change
parinayc20 0c93a23
Reviews addressed
parinayc20 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
*~ | ||
moc_* | ||
ext/ | ||
.idea/ | ||
dissent | ||
docs/html | ||
test.log | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
|
||
To manually browse the doc start from [sidebar.md](sidebar.md). Otherwise visit [https://dedis.github.io/kyber/](https://dedis.github.io/kyber/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,4 @@ | |
- [Point](point.md) | ||
- [Scalar](scalar.md) | ||
- [Marshaling](marshalling.md) | ||
- [XOF](xof.md) | ||
- [XOF](xof.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package filippo_ed25519 | ||
|
||
import ( | ||
filippo_ed25519 "filippo.io/edwards25519" | ||
"math/big" | ||
) | ||
|
||
var primeOrder, _ = new(big.Int).SetString("7237005577332262213973186563042994240857116359379907606001950938285454250989", 10) | ||
var cofactor = new(big.Int).SetInt64(8) | ||
var fullOrder = new(big.Int).Mul(primeOrder, cofactor) | ||
|
||
var filippoPrimeOrderScalar = setBigInt(primeOrder) | ||
var filippoCofactorScalar = setBigInt(cofactor) | ||
var filippoNullPoint = Point{filippo_ed25519.NewIdentityPoint()} | ||
|
||
var marshalPointID = [16]byte{'f', 'i', 'l', 'i', 'p', 'p', 'o', '_', 'e', 'd', '.', 'p', 'o', 'i', 'n', 't'} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package filippo_ed25519 | ||
|
||
import ( | ||
"crypto/cipher" | ||
"crypto/sha512" | ||
filippo_ed25519 "filippo.io/edwards25519" | ||
"go.dedis.ch/kyber/v3" | ||
"go.dedis.ch/kyber/v3/util/random" | ||
) | ||
|
||
// Curve represents the Ed25519 group. | ||
// There are no parameters and no initialization is required | ||
// because it supports only this one specific curve. | ||
type Curve struct { | ||
} | ||
|
||
// Return the name of the curve, "Ed25519". | ||
func (c *Curve) String() string { | ||
return "Ed25519" | ||
} | ||
|
||
// ScalarLen returns 32, the size in bytes of an encoded Scalar | ||
// for the Ed25519 curve. | ||
func (c *Curve) ScalarLen() int { | ||
return 32 | ||
} | ||
|
||
// Scalar creates a new Scalar for the prime-order subgroup of the Ed25519 curve. | ||
// The scalars in this package implement kyber.Scalar's SetBytes | ||
// method, interpreting the bytes as a little-endian integer, in order to remain | ||
// compatible with other Ed25519 implementations, and with the standard implementation | ||
// of the EdDSA signature. | ||
func (c *Curve) Scalar() kyber.Scalar { | ||
return &Scalar{new(filippo_ed25519.Scalar)} | ||
} | ||
|
||
// PointLen returns 32, the size in bytes of an encoded Point on the Ed25519 curve. | ||
func (c *Curve) PointLen() int { | ||
return 32 | ||
} | ||
|
||
// Point creates a new Point on the Ed25519 curve. | ||
func (c *Curve) Point() kyber.Point { | ||
P := Point{new(filippo_ed25519.Point)} | ||
return &P | ||
} | ||
|
||
// NewKeyAndSeedWithInput returns a formatted Ed25519 key (avoid subgroup attack by | ||
// requiring it to be a multiple of 8). It also returns the input and the digest used | ||
// to generate the key. | ||
func (c *Curve) NewKeyAndSeedWithInput(buffer []byte) (kyber.Scalar, []byte, []byte) { | ||
digest := sha512.Sum512(buffer[:]) | ||
digest[0] &= 0xf8 | ||
digest[31] &= 0xf | ||
|
||
// In here the 31st byte has been done AND 16 just to bring the secret key chosen below the group order i.e. l | ||
// in which the highest priority byte is 16. Doing the normal procedure of unsetting the highest priority bit and | ||
// setting the highest priority bit leads to errors when the secret is passed to the filippo library which expects | ||
// all the scalars to be below l. | ||
|
||
secret := c.Scalar().(*Scalar) | ||
secret.SetBytes(digest[:32]) | ||
return secret, buffer, digest[32:] | ||
} | ||
|
||
// NewKeyAndSeed returns a formatted Ed25519 key (avoid subgroup attack by requiring | ||
// it to be a multiple of 8). It also returns the seed and the input used to generate | ||
// the key. | ||
func (c *Curve) NewKeyAndSeed(stream cipher.Stream) (kyber.Scalar, []byte, []byte) { | ||
var buffer [32]byte | ||
random.Bytes(buffer[:], stream) | ||
return c.NewKeyAndSeedWithInput(buffer[:]) | ||
} | ||
|
||
// NewKey returns a formatted Ed25519 key (avoiding subgroup attack by requiring | ||
// it to be a multiple of 8). NewKey implements the kyber/util/key.Generator interface. | ||
func (c *Curve) NewKey(stream cipher.Stream) kyber.Scalar { | ||
secret, _, _ := c.NewKeyAndSeed(stream) | ||
return secret | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package filippo_ed25519 | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"go.dedis.ch/kyber/v3/util/test" | ||
"math" | ||
"testing" | ||
) | ||
|
||
var tSuite = NewBlakeSHA256FilippoEd25519() | ||
var groupBench = test.NewGroupBench(tSuite) | ||
|
||
func TestSuite(t *testing.T) { test.SuiteTest(t, tSuite) } | ||
|
||
func TestCurve_NewKey(t *testing.T) { | ||
group := Curve{} | ||
stream := tSuite.RandomStream() | ||
|
||
for i := 0.0; i < math.Pow(10, 6); i++ { | ||
s := group.NewKey(stream).(*Scalar) | ||
|
||
// little-endian check of a multiple of 8 | ||
b, _ := s.MarshalBinary() | ||
assert.Equal(t, uint8(0), b[0]&7) | ||
} | ||
} | ||
|
||
func BenchmarkScalarAdd(b *testing.B) { groupBench.ScalarAdd(b.N) } | ||
func BenchmarkScalarSub(b *testing.B) { groupBench.ScalarSub(b.N) } | ||
func BenchmarkScalarNeg(b *testing.B) { groupBench.ScalarNeg(b.N) } | ||
func BenchmarkScalarMul(b *testing.B) { groupBench.ScalarMul(b.N) } | ||
func BenchmarkScalarDiv(b *testing.B) { groupBench.ScalarDiv(b.N) } | ||
func BenchmarkScalarInv(b *testing.B) { groupBench.ScalarInv(b.N) } | ||
func BenchmarkScalarPick(b *testing.B) { groupBench.ScalarPick(b.N) } | ||
func BenchmarkScalarEncode(b *testing.B) { groupBench.ScalarEncode(b.N) } | ||
func BenchmarkScalarDecode(b *testing.B) { groupBench.ScalarDecode(b.N) } | ||
|
||
func BenchmarkPointAdd(b *testing.B) { groupBench.PointAdd(b.N) } | ||
func BenchmarkPointSub(b *testing.B) { groupBench.PointSub(b.N) } | ||
func BenchmarkPointNeg(b *testing.B) { groupBench.PointNeg(b.N) } | ||
func BenchmarkPointMul(b *testing.B) { groupBench.PointMul(b.N) } | ||
func BenchmarkPointBaseMul(b *testing.B) { groupBench.PointBaseMul(b.N) } | ||
func BenchmarkPointPick(b *testing.B) { groupBench.PointPick(b.N) } | ||
func BenchmarkPointEncode(b *testing.B) { groupBench.PointEncode(b.N) } | ||
func BenchmarkPointDecode(b *testing.B) { groupBench.PointDecode(b.N) } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
package filippo_ed25519 | ||
|
||
import ( | ||
"crypto/cipher" | ||
"encoding/hex" | ||
"errors" | ||
filippo_ed25519 "filippo.io/edwards25519" | ||
"go.dedis.ch/kyber/v3" | ||
"go.dedis.ch/kyber/v3/group/internal/marshalling" | ||
"io" | ||
) | ||
|
||
type Point struct { | ||
point *filippo_ed25519.Point | ||
} | ||
|
||
func (p *Point) Equal(s2 kyber.Point) bool { | ||
return p.point.Equal(s2.(*Point).point) == 1 | ||
} | ||
|
||
func (p *Point) Null() kyber.Point { | ||
p.point = filippo_ed25519.NewIdentityPoint() | ||
return p | ||
} | ||
|
||
func (p *Point) Base() kyber.Point { | ||
p.point = filippo_ed25519.NewGeneratorPoint() | ||
return p | ||
} | ||
|
||
func (p *Point) Pick(rand cipher.Stream) kyber.Point { | ||
return p.Embed(nil, rand) | ||
} | ||
|
||
func (p *Point) Set(a kyber.Point) kyber.Point { | ||
if p.point == nil { | ||
p.point = new(filippo_ed25519.Point) | ||
} | ||
p.point.Set(a.(*Point).point) | ||
return p | ||
} | ||
|
||
func (p *Point) Clone() kyber.Point { | ||
p2 := new(Point) | ||
p2.point = new(filippo_ed25519.Point) | ||
p2.point.Set(p.point) | ||
return p2 | ||
} | ||
|
||
func (p *Point) Add(a, b kyber.Point) kyber.Point { | ||
if p.point == nil { | ||
p.point = new(filippo_ed25519.Point) | ||
} | ||
p.point.Add(a.(*Point).point, b.(*Point).point) | ||
return p | ||
} | ||
|
||
func (p *Point) Sub(a, b kyber.Point) kyber.Point { | ||
if p.point == nil { | ||
p.point = new(filippo_ed25519.Point) | ||
} | ||
p.point.Subtract(a.(*Point).point, b.(*Point).point) | ||
return p | ||
} | ||
|
||
func (p *Point) Neg(a kyber.Point) kyber.Point { | ||
if p.point == nil { | ||
p.point = new(filippo_ed25519.Point) | ||
} | ||
p.point.Negate(a.(*Point).point) | ||
return p | ||
} | ||
|
||
func (p *Point) Mul(a kyber.Scalar, b kyber.Point) kyber.Point { | ||
if p == nil || p.point == nil { | ||
p.point = new(filippo_ed25519.Point) | ||
} | ||
if b == nil || b.(*Point).point == nil { | ||
p.point = p.point.ScalarBaseMult(a.(*Scalar).scalar) | ||
} else { | ||
p.point.ScalarMult(a.(*Scalar).scalar, b.(*Point).point) | ||
} | ||
return p | ||
} | ||
|
||
func (p *Point) EmbedLen() int { | ||
// Reserve the most-significant 8 bits for pseudo-randomness. | ||
// Reserve the least-significant 8 bits for embedded data length. | ||
// (Hopefully it's unlikely we'll need >=2048-bit curves soon.) | ||
return (255 - 8 - 8) / 8 | ||
} | ||
|
||
func (p *Point) Embed(data []byte, rand cipher.Stream) kyber.Point { | ||
|
||
// How many bytes to embed? | ||
dl := p.EmbedLen() | ||
if dl > len(data) { | ||
dl = len(data) | ||
} | ||
|
||
p.point = new(filippo_ed25519.Point) | ||
|
||
// Github issue raised for the problem of the infinite loop | ||
|
||
for { | ||
// Pick a random point, with optional embedded data | ||
var b [32]byte | ||
rand.XORKeyStream(b[:], b[:]) | ||
if data != nil { | ||
b[0] = byte(dl) // Encode length in low 8 bits | ||
copy(b[1:1+dl], data) // Copy in data to embed | ||
} | ||
|
||
_, err := p.point.SetBytes(b[:]) | ||
if err != nil { | ||
continue | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems this would produce an infinite loop with a maliciously crafted
|
||
} | ||
|
||
// If we're using the full group, | ||
// we just need any point on the curve, so we're done. | ||
// if c.full { | ||
// return P,data[dl:] | ||
// } | ||
Comment on lines
+119
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. commented out code |
||
|
||
// We're using the prime-order subgroup, | ||
// so we need to make sure the point is in that subencoding. | ||
// If we're not trying to embed data, | ||
// we can convert our point into one in the subgroup | ||
// simply by multiplying it by the cofactor. | ||
|
||
if data == nil { | ||
p.Mul(filippoCofactorScalar, p) // multiply by cofactor | ||
if p.Equal(&filippoNullPoint) { | ||
continue // unlucky; try again | ||
} | ||
return p // success | ||
} | ||
|
||
// Since we need the point's y-coordinate to hold our data, | ||
// we must simply check if the point is in the subgroup | ||
// and retry point generation until it is. | ||
var Q Point | ||
Q.Mul(filippoPrimeOrderScalar, p) | ||
if Q.Equal(&filippoNullPoint) { | ||
return p // success | ||
} | ||
// Keep trying... | ||
} | ||
} | ||
|
||
func (p *Point) Data() ([]byte, error) { | ||
if p.point == nil { | ||
return nil, errors.New("point not initialized") | ||
} | ||
|
||
b := p.point.Bytes() | ||
dl := int(b[0]) | ||
if dl > p.EmbedLen() { | ||
return nil, errors.New("invalid embedded data length") | ||
} | ||
return b[1 : 1+dl], nil | ||
} | ||
|
||
func (p *Point) MarshalSize() int { | ||
return 32 | ||
} | ||
|
||
func (p *Point) String() string { | ||
b := p.point.Bytes() | ||
return hex.EncodeToString(b) | ||
} | ||
|
||
func (p *Point) MarshalBinary() ([]byte, error) { | ||
if p.point == nil { | ||
return nil, errors.New("point not initialized") | ||
} | ||
return p.point.Bytes(), nil | ||
} | ||
|
||
func (p *Point) MarshalID() []byte { | ||
return marshalPointID[:] | ||
} | ||
|
||
func (p *Point) UnmarshalBinary(b []byte) error { | ||
if p.point == nil { | ||
p.point = new(filippo_ed25519.Point) | ||
} | ||
_, err := p.point.SetBytes(b) | ||
return err | ||
} | ||
|
||
func (p *Point) MarshalTo(w io.Writer) (int, error) { | ||
return marshalling.PointMarshalTo(p, w) | ||
} | ||
|
||
func (p *Point) UnmarshalFrom(r io.Reader) (int, error) { | ||
return marshalling.PointUnmarshalFrom(p, r) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requiring it to be a multiple of 8
where is this check being done ?If I understand correctly, lines 53-54 do not seem to guarantee a multiple of 8, counter example: 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I am correct then zero would also be a valid output for what we are trying to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@si-co do you agree ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function seems to have different problems:
sha512
when only 32 bytes are needed;.digest[:32]
to initialize the scalar, but returnsdigest[32:]
, which is not the digest used to generate the key.IMHO the best way to implement this function would be to use
SetBytesWithClamping
withsha256
to hash thebuffer
, assuming that's what the function is trying to do. If @parinayc20 adds the appropriate documentation we can continue the discussion.