Skip to content
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
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
*.o
*.pyc
*.swp
*.deb
parinayc20 marked this conversation as resolved.
Show resolved Hide resolved
*~
moc_*
ext/
.idea/
dissent
docs/html
test.log
Expand Down
1 change: 0 additions & 1 deletion docs/README.md
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/)
2 changes: 1 addition & 1 deletion docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

The kyber go library posses several functions for cryptographic operations on
different cureves like ed25519 and the functions can be used to perform various
operations on points, scalars and groups in linear or varaible time and can be
operations on points, scalars and groups in linear or variable time and can be
used to implement the same.
2 changes: 1 addition & 1 deletion docs/point.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ group. It returns a `true/false` indicating wether the Points are equal or not.
| Output | - `Point` : Caller Point with value equal to the neutral identity element |

This function sets the receiver object to a neutral identity element, depending
upon the suite taken into consideration.
upon the suite taken into consideration.

### Base()

Expand Down
2 changes: 1 addition & 1 deletion docs/sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
- [Point](point.md)
- [Scalar](scalar.md)
- [Marshaling](marshalling.md)
- [XOF](xof.md)
- [XOF](xof.md)
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module go.dedis.ch/kyber/v3

require (
filippo.io/edwards25519 v1.0.0-rc.1
parinayc20 marked this conversation as resolved.
Show resolved Hide resolved
github.com/stretchr/testify v1.3.0
go.dedis.ch/fixbuf v1.0.3
go.dedis.ch/protobuf v1.0.11
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
21 changes: 21 additions & 0 deletions group/edwards25519/curve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,24 @@ 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) }

//func TestScalarMulAdd(t *testing.T) {
parinayc20 marked this conversation as resolved.
Show resolved Hide resolved
// p1 := new(scalar)
// err1 := p1.UnmarshalBinary([]byte{238, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16})
// if err1 != nil {
// fmt.Println(err1)
// t.Fail()
// }
// p2 := new(scalar)
// err2 := p2.UnmarshalBinary([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
// if err2 != nil {
// fmt.Println(err2)
// t.Fail()
// }
// p3 := new(point).Mul(p1, nil)
// p4 := new(point).Mul(p2, nil)
// if p3.Equal(p4) {
// fmt.Println("Two different private keys give the same public key")
// t.Fail()
// }
//}
parinayc20 marked this conversation as resolved.
Show resolved Hide resolved
16 changes: 16 additions & 0 deletions group/filippo_ed25519/const.go
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 = [8]byte{'e', 'd', '.', 'p', 'o', 'i', 'n', 't'}
parinayc20 marked this conversation as resolved.
Show resolved Hide resolved
75 changes: 75 additions & 0 deletions group/filippo_ed25519/curve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
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
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

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 ?

Copy link

@si-co si-co Mar 13, 2023

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:

  • It is not documented.
  • I don't understand why it uses sha512 when only 32 bytes are needed;.
  • I seems to try to implement clamping, but it is wrong.
  • It uses digest[:32] to initialize the scalar, but returns digest[32:], which is not the digest used to generate the key.

IMHO the best way to implement this function would be to use SetBytesWithClamping with sha256 to hash the buffer, assuming that's what the function is trying to do. If @parinayc20 adds the appropriate documentation we can continue the discussion.

// to generate the key.
func (c *Curve) NewKeyAndSeedWithInput(buffer []byte) (kyber.Scalar, []byte, []byte) {
digest := sha512.Sum512(buffer[:])
digest[0] &= 0xf8
digest[31] &= 0xf

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
}
45 changes: 45 additions & 0 deletions group/filippo_ed25519/curve_test.go
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) }
Loading