Skip to content

Commit

Permalink
Merge pull request #386 from dedis/ed25519_new_key_351
Browse files Browse the repository at this point in the history
Fix ed25519 secret key generation w.r.t multiple of 8
  • Loading branch information
kc1212 authored Jul 2, 2019
2 parents 1a3d86c + 505cf34 commit ed53097
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 27 deletions.
32 changes: 24 additions & 8 deletions group/edwards25519/curve.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,32 @@ func (c *Curve) Point() kyber.Point {
return P
}

// 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 {
// 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] &= 0x7f
digest[31] |= 0x40

secret := c.Scalar().(*scalar)
copy(secret.v[:], digest[:])
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)
scalar := sha512.Sum512(buffer[:])
scalar[0] &= 0xf8
scalar[31] &= 0x7f
scalar[31] |= 0x40
return c.NewKeyAndSeedWithInput(buffer[:])
}

secret := c.Scalar().SetBytes(scalar[:32])
// 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
}
15 changes: 15 additions & 0 deletions group/edwards25519/curve_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package edwards25519

import (
"math"
"testing"

"github.com/stretchr/testify/assert"
"go.dedis.ch/kyber/v3/util/test"
)

Expand All @@ -11,6 +13,19 @@ var groupBench = test.NewGroupBench(tSuite)

func TestSuite(t *testing.T) { test.SuiteTest(t, tSuite) }

// Test that NewKey generates correct secret keys
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
assert.Equal(t, uint8(0), s.v[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) }
Expand Down
26 changes: 7 additions & 19 deletions sign/eddsa/eddsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/group/edwards25519"
"go.dedis.ch/kyber/v3/util/random"
)

var group = new(edwards25519.Curve)
Expand All @@ -33,17 +32,13 @@ func NewEdDSA(stream cipher.Stream) *EdDSA {
if stream == nil {
panic("stream is required")
}
var buffer [32]byte
random.Bytes(buffer[:], stream)

scalar := hashSeed(buffer[:])

secret := group.Scalar().SetBytes(scalar[:32])
secret, buffer, prefix := group.NewKeyAndSeed(stream)
public := group.Point().Mul(secret, nil)

return &EdDSA{
seed: buffer[:],
prefix: scalar[32:],
seed: buffer,
prefix: prefix,
Secret: secret,
Public: public,
}
Expand All @@ -69,10 +64,11 @@ func (e *EdDSA) UnmarshalBinary(buff []byte) error {
return errors.New("wrong length for decoding EdDSA private")
}

secret, _, prefix := group.NewKeyAndSeedWithInput(buff[:32])

e.seed = buff[:32]
scalar := hashSeed(e.seed)
e.prefix = scalar[32:]
e.Secret = group.Scalar().SetBytes(scalar[:32])
e.prefix = prefix
e.Secret = secret
e.Public = group.Point().Mul(e.Secret, nil)
return nil
}
Expand Down Expand Up @@ -161,11 +157,3 @@ func Verify(public kyber.Point, msg, sig []byte) error {
}
return nil
}

func hashSeed(seed []byte) (hash [64]byte) {
hash = sha512.Sum512(seed)
hash[0] &= 0xf8
hash[31] &= 0x3f
hash[31] |= 0x40
return
}
25 changes: 25 additions & 0 deletions sign/eddsa/eddsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import (
"compress/gzip"
"crypto/cipher"
"encoding/hex"
"math/rand"
"os"
"strings"
"testing"

"go.dedis.ch/kyber/v3/group/edwards25519"

"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -51,6 +54,9 @@ func TestEdDSAMarshalling(t *testing.T) {

stream := ConstantStream(seed)
edDSA := NewEdDSA(stream)

assert.Equal(t, edDSA.Public.String(), vec.public)

marshalled, err := edDSA.MarshalBinary()
assert.Nil(t, err)
assert.NotNil(t, marshalled)
Expand Down Expand Up @@ -95,6 +101,25 @@ func TestEdDSASigning(t *testing.T) {
}
}

// Test the property of a EdDSA signature
func TestEdDSASigningRandom(t *testing.T) {
suite := edwards25519.NewBlakeSHA256Ed25519()

for i := 0.0; i < 10000; i++ {
ed := NewEdDSA(suite.RandomStream())

msg := make([]byte, 32)
_, err := rand.Read(msg)
assert.NoError(t, err)

sig, err := ed.Sign(msg)
assert.Nil(t, err)
// see https://tools.ietf.org/html/rfc8032#section-5.1.6 (item 6.)
assert.Equal(t, uint8(0), sig[63]&0xe0)
assert.Nil(t, Verify(ed.Public, msg, sig))
}
}

type constantStream struct {
seed []byte
}
Expand Down

0 comments on commit ed53097

Please sign in to comment.