From 87abefdb8c2ba1f5cb0004b89d4165fc3f99033b Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 11 Jan 2023 17:48:29 +0100 Subject: [PATCH 01/18] feat: start ECDSA on secp256k1 --- ecc/secp256k1/ecdsa.go | 246 ++++++++++++++++++++++++++++++++++++ ecc/secp256k1/ecdsa_test.go | 41 ++++++ 2 files changed, 287 insertions(+) create mode 100644 ecc/secp256k1/ecdsa.go create mode 100644 ecc/secp256k1/ecdsa_test.go diff --git a/ecc/secp256k1/ecdsa.go b/ecc/secp256k1/ecdsa.go new file mode 100644 index 000000000..c4e06fedd --- /dev/null +++ b/ecc/secp256k1/ecdsa.go @@ -0,0 +1,246 @@ +// adapted from "crypto/ecdsa" + +package secp256k1 + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "errors" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" +) + +// PublicKey represents an ECDSA public key. +type PublicKey struct { + A G1Affine +} + +// PrivateKey represents an ECDSA private key. +type PrivateKey struct { + PublicKey + D *big.Int +} + +const ( + aesIV = "IV for ECDSA CTR" +) + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bytes+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) + return + +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + + priv := new(PrivateKey) + priv.D = k + priv.PublicKey.A.ScalarMultiplication(&g1GenAff, k) + return priv, nil + +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) *big.Int { + orderBits := fr.Bits + orderBytes := (orderBits + 7) / 8 + if len(hash) > orderBytes { + hash = hash[:orderBytes] + + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - orderBits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + + } + return ret + +} + +var errZeroParam = errors.New("zero parameter") + +// Sign signs a hash (which should be the result of hashing a larger message) +// using the private key, priv. If the hash is longer than the bit-length of the +// private key's curve order, the hash will be truncated to that length. It +// returns the signature as a pair of integers. Most applications should use +// SignASN1 instead of dealing directly with r, s. +func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(priv.D || entropy || hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(priv.D.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, err := aes.NewCipher(key) + if err != nil { + return nil, nil, err + + } + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng := &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return sign(priv, csprng, hash) + +} + +func sign(priv *PrivateKey, csprng *cipher.StreamReader, hash []byte) (r, s *big.Int, err error) { + // SEC 1, Version 2.0, Section 4.1.3 + N := fr.Modulus() + if N.Sign() == 0 { + return nil, nil, errZeroParam + + } + var k, kInv *big.Int + for { + for { + k, err = randFieldElement(*csprng) + if err != nil { + r = nil + return + + } + + var _kInv fr.Element + _kInv.SetBigInt(k). + Inverse(&_kInv). + BigInt(kInv) + + var R G1Affine + R.ScalarMultiplication(&g1GenAff, k) + R.X.BigInt(r) + + r.Mod(r, N) + if r.Sign() != 0 { + break + + } + + } + + e := hashToInt(hash) + s = new(big.Int).Mul(priv.D, r) + s.Add(s, e) + s.Mul(s, kInv) + s.Mod(s, N) // N != 0 + if s.Sign() != 0 { + break + + } + + } + + return + +} + +// Verify verifies the signature in r, s of hash using the public key, pub. Its +// return value records whether the signature is valid. +func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { + + N := fr.Modulus() + + if r.Sign() <= 0 || s.Sign() <= 0 { + return false + + } + if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 { + return false + + } + return verify(pub, hash, r, s) + +} + +func verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { + // SEC 1, Version 2.0, Section 4.1.4 + e := hashToInt(hash) + var w *big.Int + N := fr.Modulus() + + var _sInv fr.Element + _sInv.SetBigInt(s). + Inverse(&_sInv). + BigInt(w) + + u1 := e.Mul(e, w) + u1.Mod(u1, N) + u2 := w.Mul(r, w) + u2.Mod(u2, N) + + var P1, P2 G1Affine + P1.ScalarMultiplication(&g1GenAff, u1) + P2.ScalarMultiplication(&pub.A, u2). + Add(&P2, &P1) + + return P2.X.BigInt(w).Cmp(r) == 0 + +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + + } + return len(dst), nil + +} + +var zeroReader = zr{} diff --git a/ecc/secp256k1/ecdsa_test.go b/ecc/secp256k1/ecdsa_test.go new file mode 100644 index 000000000..f0d7255a5 --- /dev/null +++ b/ecc/secp256k1/ecdsa_test.go @@ -0,0 +1,41 @@ +package secp256k1 + +import ( + "crypto/rand" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[SECP256K1] check that the generated keys are valid", prop.ForAll( + func() bool { + priv, _ := GenerateKey(rand.Reader) + + return priv.PublicKey.A.IsInSubGroup() + }, + )) + + properties.Property("[SECP256K1] test the sign and verify protocol", prop.ForAll( + func() bool { + priv, _ := GenerateKey(rand.Reader) + + hashed := []byte("testing") + r, s, err := Sign(rand.Reader, priv, hashed) + if err != nil { + t.Errorf("error signing: %s", err) + return false + } + + return Verify(&priv.PublicKey, hashed, r, s) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} From bca4322afe6378a340b57ffd6ce29231670b08ee Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 12 Jan 2023 17:56:35 +0100 Subject: [PATCH 02/18] fix: ecdsa on secp256k1 working --- ecc/secp256k1/ecdsa.go | 246 ------------------------------ ecc/secp256k1/ecdsa/ecdsa.go | 113 ++++++++++++++ ecc/secp256k1/ecdsa/ecdsa_test.go | 34 +++++ ecc/secp256k1/ecdsa_test.go | 41 ----- 4 files changed, 147 insertions(+), 287 deletions(-) delete mode 100644 ecc/secp256k1/ecdsa.go create mode 100644 ecc/secp256k1/ecdsa/ecdsa.go create mode 100644 ecc/secp256k1/ecdsa/ecdsa_test.go delete mode 100644 ecc/secp256k1/ecdsa_test.go diff --git a/ecc/secp256k1/ecdsa.go b/ecc/secp256k1/ecdsa.go deleted file mode 100644 index c4e06fedd..000000000 --- a/ecc/secp256k1/ecdsa.go +++ /dev/null @@ -1,246 +0,0 @@ -// adapted from "crypto/ecdsa" - -package secp256k1 - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/sha512" - "errors" - "io" - "math/big" - - "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" -) - -// PublicKey represents an ECDSA public key. -type PublicKey struct { - A G1Affine -} - -// PrivateKey represents an ECDSA private key. -type PrivateKey struct { - PublicKey - D *big.Int -} - -const ( - aesIV = "IV for ECDSA CTR" -) - -var one = new(big.Int).SetInt64(1) - -// randFieldElement returns a random element of the order of the given -// curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func randFieldElement(rand io.Reader) (k *big.Int, err error) { - b := make([]byte, fr.Bytes+8) - _, err = io.ReadFull(rand, b) - if err != nil { - return - - } - - k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) - k.Mod(k, n) - k.Add(k, one) - return - -} - -// GenerateKey generates a public and private key pair. -func GenerateKey(rand io.Reader) (*PrivateKey, error) { - - k, err := randFieldElement(rand) - if err != nil { - return nil, err - - } - - priv := new(PrivateKey) - priv.D = k - priv.PublicKey.A.ScalarMultiplication(&g1GenAff, k) - return priv, nil - -} - -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, -// we use the left-most bits of the hash to match the bit-length of the order of -// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { - orderBits := fr.Bits - orderBytes := (orderBits + 7) / 8 - if len(hash) > orderBytes { - hash = hash[:orderBytes] - - } - - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - orderBits - if excess > 0 { - ret.Rsh(ret, uint(excess)) - - } - return ret - -} - -var errZeroParam = errors.New("zero parameter") - -// Sign signs a hash (which should be the result of hashing a larger message) -// using the private key, priv. If the hash is longer than the bit-length of the -// private key's curve order, the hash will be truncated to that length. It -// returns the signature as a pair of integers. Most applications should use -// SignASN1 instead of dealing directly with r, s. -func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { - // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: - // - // SHA2-512(priv.D || entropy || hash)[:32] - // - // The CSPRNG key is indifferentiable from a random oracle as shown in - // [Coron], the AES-CTR stream is indifferentiable from a random oracle - // under standard cryptographic assumptions (see [Larsson] for examples). - // - // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf - // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf - - // Get 256 bits of entropy from rand. - entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) - if err != nil { - return - - } - - // Initialize an SHA-512 hash context; digest... - md := sha512.New() - md.Write(priv.D.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), - // which is an indifferentiable MAC. - - // Create an AES-CTR instance to use as a CSPRNG. - block, err := aes.NewCipher(key) - if err != nil { - return nil, nil, err - - } - - // Create a CSPRNG that xors a stream of zeros with - // the output of the AES-CTR instance. - csprng := &cipher.StreamReader{ - R: zeroReader, - S: cipher.NewCTR(block, []byte(aesIV)), - } - - return sign(priv, csprng, hash) - -} - -func sign(priv *PrivateKey, csprng *cipher.StreamReader, hash []byte) (r, s *big.Int, err error) { - // SEC 1, Version 2.0, Section 4.1.3 - N := fr.Modulus() - if N.Sign() == 0 { - return nil, nil, errZeroParam - - } - var k, kInv *big.Int - for { - for { - k, err = randFieldElement(*csprng) - if err != nil { - r = nil - return - - } - - var _kInv fr.Element - _kInv.SetBigInt(k). - Inverse(&_kInv). - BigInt(kInv) - - var R G1Affine - R.ScalarMultiplication(&g1GenAff, k) - R.X.BigInt(r) - - r.Mod(r, N) - if r.Sign() != 0 { - break - - } - - } - - e := hashToInt(hash) - s = new(big.Int).Mul(priv.D, r) - s.Add(s, e) - s.Mul(s, kInv) - s.Mod(s, N) // N != 0 - if s.Sign() != 0 { - break - - } - - } - - return - -} - -// Verify verifies the signature in r, s of hash using the public key, pub. Its -// return value records whether the signature is valid. -func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { - - N := fr.Modulus() - - if r.Sign() <= 0 || s.Sign() <= 0 { - return false - - } - if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 { - return false - - } - return verify(pub, hash, r, s) - -} - -func verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { - // SEC 1, Version 2.0, Section 4.1.4 - e := hashToInt(hash) - var w *big.Int - N := fr.Modulus() - - var _sInv fr.Element - _sInv.SetBigInt(s). - Inverse(&_sInv). - BigInt(w) - - u1 := e.Mul(e, w) - u1.Mod(u1, N) - u2 := w.Mul(r, w) - u2.Mod(u2, N) - - var P1, P2 G1Affine - P1.ScalarMultiplication(&g1GenAff, u1) - P2.ScalarMultiplication(&pub.A, u2). - Add(&P2, &P1) - - return P2.X.BigInt(w).Cmp(r) == 0 - -} - -type zr struct{} - -// Read replaces the contents of dst with zeros. It is safe for concurrent use. -func (zr) Read(dst []byte) (n int, err error) { - for i := range dst { - dst[i] = 0 - - } - return len(dst), nil - -} - -var zeroReader = zr{} diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go new file mode 100644 index 000000000..7ae17e378 --- /dev/null +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -0,0 +1,113 @@ +package ecdsa + +import ( + "bytes" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/secp256k1" + "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" +) + +// PublicKey represents an ECDSA public key. +type PublicKey struct { + A secp256k1.G1Affine +} + +// PrivateKey represents an ECDSA private key. +type PrivateKey struct { + PublicKey + D big.Int +} + +// params is the ECDSA data structure +type params struct { + G secp256k1.G1Affine + N *big.Int +} + +// NewParams defines a new params data structure +func NewParams(g secp256k1.G1Affine) params { + var pp params + pp.G = g + pp.N = fr.Modulus() + return pp +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + + priv := new(PrivateKey) + priv.D = k + priv.PublicKey.A.ScalarMultiplication(&pp.G, &k) + return priv, nil +} + +// Sign performs the ECDSA signature +func (pp params) Sign(hashed *big.Int, privateKey *big.Int, rand io.Reader) ([2]*big.Int, error) { + k, err := randFieldElement(rand) + if err != nil { + return [2]*big.Int{}, err + } + + kCopy := new(big.Int).SetBytes(k.Bytes()) + var p secp256k1.G1Affine + p.ScalarMultiplication(&pp.G, kCopy) + inv := new(big.Int).ModInverse(&k, pp.N) + + privateKeyCopy := new(big.Int).SetBytes(privateKey.Bytes()) + var _x big.Int + xPrivateKey := new(big.Int).Mul(p.X.BigInt(&_x), privateKeyCopy) + + sum := new(big.Int).Add(hashed, xPrivateKey) + + a := new(big.Int).Mul(inv, sum) + r2 := new(big.Int).Mod(a, pp.N) + return [2]*big.Int{&_x, r2}, nil +} + +// Verify validates the ECDSA signature +func (pp params) Verify(hashed *big.Int, sig [2]*big.Int, publicKey secp256k1.G1Affine) bool { + w := new(big.Int).ModInverse(sig[1], pp.N) + wCopy := new(big.Int).SetBytes(w.Bytes()) + u1raw := new(big.Int).Mul(hashed, wCopy) + u1 := new(big.Int).Mod(u1raw, pp.N) + wCopy = new(big.Int).SetBytes(w.Bytes()) + u2raw := new(big.Int).Mul(sig[0], wCopy) + u2 := new(big.Int).Mod(u2raw, pp.N) + + var gU1, publicKeyU2, p secp256k1.G1Affine + gU1.ScalarMultiplication(&pp.G, u1) + publicKeyU2.ScalarMultiplication(&publicKey, u2) + + p.Add(&gU1, &publicKeyU2) + + var _x big.Int + pXmodN := new(big.Int).Mod(p.X.BigInt(&_x), pp.N) + return bytes.Equal(pXmodN.Bytes(), sig[0].Bytes()) +} diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..cb550d5cb --- /dev/null +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -0,0 +1,34 @@ +package ecdsa + +import ( + "crypto/rand" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/secp256k1" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[SECP256K1] test the signing and verification", prop.ForAll( + func() bool { + + _, g := secp256k1.Generators() + dsa := NewParams(g) + privKey, _ := dsa.GenerateKey(rand.Reader) + + hashval := big.NewInt(int64(40)) + sig, _ := dsa.Sign(hashval, &privKey.D, rand.Reader) + + return dsa.Verify(hashval, sig, privKey.PublicKey.A) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/secp256k1/ecdsa_test.go b/ecc/secp256k1/ecdsa_test.go deleted file mode 100644 index f0d7255a5..000000000 --- a/ecc/secp256k1/ecdsa_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package secp256k1 - -import ( - "crypto/rand" - "testing" - - "github.com/leanovate/gopter" - "github.com/leanovate/gopter/prop" -) - -func TestECDSA(t *testing.T) { - - t.Parallel() - parameters := gopter.DefaultTestParameters() - properties := gopter.NewProperties(parameters) - - properties.Property("[SECP256K1] check that the generated keys are valid", prop.ForAll( - func() bool { - priv, _ := GenerateKey(rand.Reader) - - return priv.PublicKey.A.IsInSubGroup() - }, - )) - - properties.Property("[SECP256K1] test the sign and verify protocol", prop.ForAll( - func() bool { - priv, _ := GenerateKey(rand.Reader) - - hashed := []byte("testing") - r, s, err := Sign(rand.Reader, priv, hashed) - if err != nil { - t.Errorf("error signing: %s", err) - return false - } - - return Verify(&priv.PublicKey, hashed, r, s) - }, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} From 6948d85b725ee8bd925a709f55b62d361223e210 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 16 Jan 2023 16:18:53 +0100 Subject: [PATCH 03/18] feat(ecdsa): use aes-ctr in signing randomness --- ecc/secp256k1/ecdsa/ecdsa.go | 138 +++++++++++++++++++++++------- ecc/secp256k1/ecdsa/ecdsa_test.go | 15 ++-- 2 files changed, 117 insertions(+), 36 deletions(-) diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index 7ae17e378..f2d7f39f6 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -2,6 +2,9 @@ package ecdsa import ( "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/sha512" "io" "math/big" @@ -9,29 +12,21 @@ import ( "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" ) -// PublicKey represents an ECDSA public key. +// PublicKey represents an ECDSA public key type PublicKey struct { A secp256k1.G1Affine } -// PrivateKey represents an ECDSA private key. +// PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - D big.Int + Secret big.Int } -// params is the ECDSA data structure +// params are the ECDSA public parameters type params struct { - G secp256k1.G1Affine - N *big.Int -} - -// NewParams defines a new params data structure -func NewParams(g secp256k1.G1Affine) params { - var pp params - pp.G = g - pp.N = fr.Modulus() - return pp + Base secp256k1.G1Affine + Order *big.Int } var one = new(big.Int).SetInt64(1) @@ -63,51 +58,134 @@ func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { } priv := new(PrivateKey) - priv.D = k - priv.PublicKey.A.ScalarMultiplication(&pp.G, &k) + priv.Secret = k + priv.PublicKey.A.ScalarMultiplication(&pp.Base, &k) return priv, nil } +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + + } + return len(dst), nil + +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, priv *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(priv.D || entropy || hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(priv.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + // Sign performs the ECDSA signature -func (pp params) Sign(hashed *big.Int, privateKey *big.Int, rand io.Reader) ([2]*big.Int, error) { - k, err := randFieldElement(rand) +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) ([2]*big.Int, error) { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return [2]*big.Int{}, err + } + k, err := randFieldElement(csprng) if err != nil { return [2]*big.Int{}, err } kCopy := new(big.Int).SetBytes(k.Bytes()) var p secp256k1.G1Affine - p.ScalarMultiplication(&pp.G, kCopy) - inv := new(big.Int).ModInverse(&k, pp.N) + p.ScalarMultiplication(&pp.Base, kCopy) + inv := new(big.Int).ModInverse(&k, pp.Order) - privateKeyCopy := new(big.Int).SetBytes(privateKey.Bytes()) + privateKeyCopy := new(big.Int).SetBytes(privateKey.Secret.Bytes()) var _x big.Int xPrivateKey := new(big.Int).Mul(p.X.BigInt(&_x), privateKeyCopy) - sum := new(big.Int).Add(hashed, xPrivateKey) + e := hashToInt(hash) + sum := new(big.Int).Add(&e, xPrivateKey) a := new(big.Int).Mul(inv, sum) - r2 := new(big.Int).Mod(a, pp.N) + r2 := new(big.Int).Mod(a, pp.Order) return [2]*big.Int{&_x, r2}, nil } // Verify validates the ECDSA signature -func (pp params) Verify(hashed *big.Int, sig [2]*big.Int, publicKey secp256k1.G1Affine) bool { - w := new(big.Int).ModInverse(sig[1], pp.N) +func (pp params) Verify(hash []byte, sig [2]*big.Int, publicKey secp256k1.G1Affine) bool { + w := new(big.Int).ModInverse(sig[1], pp.Order) wCopy := new(big.Int).SetBytes(w.Bytes()) - u1raw := new(big.Int).Mul(hashed, wCopy) - u1 := new(big.Int).Mod(u1raw, pp.N) + e := hashToInt(hash) + u1raw := new(big.Int).Mul(&e, wCopy) + u1 := new(big.Int).Mod(u1raw, pp.Order) wCopy = new(big.Int).SetBytes(w.Bytes()) u2raw := new(big.Int).Mul(sig[0], wCopy) - u2 := new(big.Int).Mod(u2raw, pp.N) + u2 := new(big.Int).Mod(u2raw, pp.Order) var gU1, publicKeyU2, p secp256k1.G1Affine - gU1.ScalarMultiplication(&pp.G, u1) + gU1.ScalarMultiplication(&pp.Base, u1) publicKeyU2.ScalarMultiplication(&publicKey, u2) p.Add(&gU1, &publicKeyU2) var _x big.Int - pXmodN := new(big.Int).Mod(p.X.BigInt(&_x), pp.N) + pXmodN := new(big.Int).Mod(p.X.BigInt(&_x), pp.Order) return bytes.Equal(pXmodN.Bytes(), sig[0].Bytes()) } diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go index cb550d5cb..bd5713f72 100644 --- a/ecc/secp256k1/ecdsa/ecdsa_test.go +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -2,10 +2,10 @@ package ecdsa import ( "crypto/rand" - "math/big" "testing" "github.com/consensys/gnark-crypto/ecc/secp256k1" + "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -19,14 +19,17 @@ func TestECDSA(t *testing.T) { properties.Property("[SECP256K1] test the signing and verification", prop.ForAll( func() bool { + var pp params _, g := secp256k1.Generators() - dsa := NewParams(g) - privKey, _ := dsa.GenerateKey(rand.Reader) + pp.Base.Set(&g) + pp.Order = fr.Modulus() - hashval := big.NewInt(int64(40)) - sig, _ := dsa.Sign(hashval, &privKey.D, rand.Reader) + privKey, _ := pp.GenerateKey(rand.Reader) - return dsa.Verify(hashval, sig, privKey.PublicKey.A) + hash := []byte("testing ECDSA") + sig, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, sig, privKey.PublicKey.A) }, )) From c8ecac90091967e8020b664dad575f810bbc3f99 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 17 Jan 2023 13:22:06 +0100 Subject: [PATCH 04/18] refactor(ecdsa): follows SEC 1 v-2 --- ecc/secp256k1/ecdsa/ecdsa.go | 151 ++++++++++++++++++------------ ecc/secp256k1/ecdsa/ecdsa_test.go | 4 +- 2 files changed, 95 insertions(+), 60 deletions(-) diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index f2d7f39f6..f09d8afd7 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -1,7 +1,14 @@ +/* +ecdsa package implements the Elliptic Curve Digital Signature (ECDSA) scheme. +The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +Documentation: +- Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +- FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +- SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +*/ package ecdsa import ( - "bytes" "crypto/aes" "crypto/cipher" "crypto/sha512" @@ -14,7 +21,7 @@ import ( // PublicKey represents an ECDSA public key type PublicKey struct { - A secp256k1.G1Affine + Q secp256k1.G1Affine } // PrivateKey represents an ECDSA private key @@ -23,6 +30,12 @@ type PrivateKey struct { Secret big.Int } +// Signature represents an ECDSA signature +type Signature struct { + r big.Int + s big.Int +} + // params are the ECDSA public parameters type params struct { Base secp256k1.G1Affine @@ -33,16 +46,15 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return - } k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(pp.Order, one) k.Mod(&k, n) k.Add(&k, one) return @@ -51,16 +63,16 @@ func randFieldElement(rand io.Reader) (k big.Int, err error) { // GenerateKey generates a public and private key pair. func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := randFieldElement(rand) + k, err := pp.randFieldElement(rand) if err != nil { return nil, err } - priv := new(PrivateKey) - priv.Secret = k - priv.PublicKey.A.ScalarMultiplication(&pp.Base, &k) - return priv, nil + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, @@ -69,14 +81,12 @@ func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { func hashToInt(hash []byte) big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] - } ret := new(big.Int).SetBytes(hash) excess := len(hash)*8 - fr.Bits if excess > 0 { ret.Rsh(ret, uint(excess)) - } return *ret } @@ -87,10 +97,8 @@ type zr struct{} func (zr) Read(dst []byte) (n int, err error) { for i := range dst { dst[i] = 0 - } return len(dst), nil - } var zeroReader = zr{} @@ -99,10 +107,10 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, priv *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(priv.D || entropy || hash)[:32] + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -121,10 +129,10 @@ func nonce(rand io.Reader, priv *PrivateKey, hash []byte) (csprng *cipher.Stream // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(priv.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -141,51 +149,78 @@ func nonce(rand io.Reader, priv *PrivateKey, hash []byte) (csprng *cipher.Stream } // Sign performs the ECDSA signature -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) ([2]*big.Int, error) { - csprng, err := nonce(rand, &privateKey, hash) - if err != nil { - return [2]*big.Int{}, err +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R secp256k1.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } } - k, err := randFieldElement(csprng) - if err != nil { - return [2]*big.Int{}, err - } - - kCopy := new(big.Int).SetBytes(k.Bytes()) - var p secp256k1.G1Affine - p.ScalarMultiplication(&pp.Base, kCopy) - inv := new(big.Int).ModInverse(&k, pp.Order) - - privateKeyCopy := new(big.Int).SetBytes(privateKey.Secret.Bytes()) - var _x big.Int - xPrivateKey := new(big.Int).Mul(p.X.BigInt(&_x), privateKeyCopy) - - e := hashToInt(hash) - sum := new(big.Int).Add(&e, xPrivateKey) - a := new(big.Int).Mul(inv, sum) - r2 := new(big.Int).Mod(a, pp.Order) - return [2]*big.Int{&_x, r2}, nil + return signature, err } // Verify validates the ECDSA signature -func (pp params) Verify(hash []byte, sig [2]*big.Int, publicKey secp256k1.G1Affine) bool { - w := new(big.Int).ModInverse(sig[1], pp.Order) - wCopy := new(big.Int).SetBytes(w.Bytes()) +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) e := hashToInt(hash) - u1raw := new(big.Int).Mul(&e, wCopy) - u1 := new(big.Int).Mod(u1raw, pp.Order) - wCopy = new(big.Int).SetBytes(w.Bytes()) - u2raw := new(big.Int).Mul(sig[0], wCopy) - u2 := new(big.Int).Mod(u2raw, pp.Order) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) - var gU1, publicKeyU2, p secp256k1.G1Affine - gU1.ScalarMultiplication(&pp.Base, u1) - publicKeyU2.ScalarMultiplication(&publicKey, u2) + var U1, U2 secp256k1.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) - p.Add(&gU1, &publicKeyU2) + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) - var _x big.Int - pXmodN := new(big.Int).Mod(p.X.BigInt(&_x), pp.Order) - return bytes.Equal(pXmodN.Bytes(), sig[0].Bytes()) + return x.Cmp(&signature.r) == 0 } diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go index bd5713f72..a2396602a 100644 --- a/ecc/secp256k1/ecdsa/ecdsa_test.go +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -27,9 +27,9 @@ func TestECDSA(t *testing.T) { privKey, _ := pp.GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - sig, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := pp.Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, sig, privKey.PublicKey.A) + return pp.Verify(hash, signature, privKey.PublicKey.Q) }, )) From 50fab2e1629cdcfb07d9fb1d04319dd1896b97b6 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 18 Jan 2023 11:33:39 +0100 Subject: [PATCH 05/18] feat(templates): ecdsa package for all curves --- ecc/bls12-377/ecdsa/doc.go | 28 +++ ecc/bls12-377/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bls12-377/ecdsa/ecdsa_test.go | 53 ++++ ecc/bls12-378/ecdsa/doc.go | 28 +++ ecc/bls12-378/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bls12-378/ecdsa/ecdsa_test.go | 53 ++++ ecc/bls12-381/ecdsa/doc.go | 28 +++ ecc/bls12-381/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bls12-381/ecdsa/ecdsa_test.go | 53 ++++ ecc/bls24-315/ecdsa/doc.go | 28 +++ ecc/bls24-315/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bls24-315/ecdsa/ecdsa_test.go | 53 ++++ ecc/bls24-317/ecdsa/doc.go | 28 +++ ecc/bls24-317/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bls24-317/ecdsa/ecdsa_test.go | 53 ++++ ecc/bn254/ecdsa/doc.go | 28 +++ ecc/bn254/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bn254/ecdsa/ecdsa_test.go | 53 ++++ ecc/bw6-633/ecdsa/doc.go | 28 +++ ecc/bw6-633/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bw6-633/ecdsa/ecdsa_test.go | 53 ++++ ecc/bw6-756/ecdsa/doc.go | 28 +++ ecc/bw6-756/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bw6-756/ecdsa/ecdsa_test.go | 53 ++++ ecc/bw6-761/ecdsa/doc.go | 28 +++ ecc/bw6-761/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/bw6-761/ecdsa/ecdsa_test.go | 53 ++++ ecc/secp256k1/ecdsa/doc.go | 28 +++ ecc/secp256k1/ecdsa/ecdsa.go | 28 ++- ecc/secp256k1/ecdsa/ecdsa_test.go | 16 ++ ecc/stark-curve/ecdsa/doc.go | 28 +++ ecc/stark-curve/ecdsa/ecdsa.go | 234 ++++++++++++++++++ ecc/stark-curve/ecdsa/ecdsa_test.go | 53 ++++ internal/generator/config/stark-curve.go | 2 +- internal/generator/ecdsa/generate.go | 22 ++ internal/generator/ecdsa/template/doc.go.tmpl | 13 + .../generator/ecdsa/template/ecdsa.go.tmpl | 216 ++++++++++++++++ .../ecdsa/template/ecdsa.test.go.tmpl | 39 +++ internal/generator/main.go | 4 + 39 files changed, 3507 insertions(+), 11 deletions(-) create mode 100644 ecc/bls12-377/ecdsa/doc.go create mode 100644 ecc/bls12-377/ecdsa/ecdsa.go create mode 100644 ecc/bls12-377/ecdsa/ecdsa_test.go create mode 100644 ecc/bls12-378/ecdsa/doc.go create mode 100644 ecc/bls12-378/ecdsa/ecdsa.go create mode 100644 ecc/bls12-378/ecdsa/ecdsa_test.go create mode 100644 ecc/bls12-381/ecdsa/doc.go create mode 100644 ecc/bls12-381/ecdsa/ecdsa.go create mode 100644 ecc/bls12-381/ecdsa/ecdsa_test.go create mode 100644 ecc/bls24-315/ecdsa/doc.go create mode 100644 ecc/bls24-315/ecdsa/ecdsa.go create mode 100644 ecc/bls24-315/ecdsa/ecdsa_test.go create mode 100644 ecc/bls24-317/ecdsa/doc.go create mode 100644 ecc/bls24-317/ecdsa/ecdsa.go create mode 100644 ecc/bls24-317/ecdsa/ecdsa_test.go create mode 100644 ecc/bn254/ecdsa/doc.go create mode 100644 ecc/bn254/ecdsa/ecdsa.go create mode 100644 ecc/bn254/ecdsa/ecdsa_test.go create mode 100644 ecc/bw6-633/ecdsa/doc.go create mode 100644 ecc/bw6-633/ecdsa/ecdsa.go create mode 100644 ecc/bw6-633/ecdsa/ecdsa_test.go create mode 100644 ecc/bw6-756/ecdsa/doc.go create mode 100644 ecc/bw6-756/ecdsa/ecdsa.go create mode 100644 ecc/bw6-756/ecdsa/ecdsa_test.go create mode 100644 ecc/bw6-761/ecdsa/doc.go create mode 100644 ecc/bw6-761/ecdsa/ecdsa.go create mode 100644 ecc/bw6-761/ecdsa/ecdsa_test.go create mode 100644 ecc/secp256k1/ecdsa/doc.go create mode 100644 ecc/stark-curve/ecdsa/doc.go create mode 100644 ecc/stark-curve/ecdsa/ecdsa.go create mode 100644 ecc/stark-curve/ecdsa/ecdsa_test.go create mode 100644 internal/generator/ecdsa/generate.go create mode 100644 internal/generator/ecdsa/template/doc.go.tmpl create mode 100644 internal/generator/ecdsa/template/ecdsa.go.tmpl create mode 100644 internal/generator/ecdsa/template/ecdsa.test.go.tmpl diff --git a/ecc/bls12-377/ecdsa/doc.go b/ecc/bls12-377/ecdsa/doc.go new file mode 100644 index 000000000..6fdb39d25 --- /dev/null +++ b/ecc/bls12-377/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bls12-377 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go new file mode 100644 index 000000000..a1326c831 --- /dev/null +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bls12377.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bls12377.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bls12377.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bls12377.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bls12377.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bls12-377/ecdsa/ecdsa_test.go b/ecc/bls12-377/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..5c0f275d9 --- /dev/null +++ b/ecc/bls12-377/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-377] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bls12377.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls12-378/ecdsa/doc.go b/ecc/bls12-378/ecdsa/doc.go new file mode 100644 index 000000000..7172ada5c --- /dev/null +++ b/ecc/bls12-378/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bls12-378 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go new file mode 100644 index 000000000..0f3c488b4 --- /dev/null +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-378" + "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bls12378.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bls12378.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bls12378.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bls12378.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bls12378.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bls12-378/ecdsa/ecdsa_test.go b/ecc/bls12-378/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..ae4c96ca7 --- /dev/null +++ b/ecc/bls12-378/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-378" + "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-378] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bls12378.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls12-381/ecdsa/doc.go b/ecc/bls12-381/ecdsa/doc.go new file mode 100644 index 000000000..860389a54 --- /dev/null +++ b/ecc/bls12-381/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bls12-381 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go new file mode 100644 index 000000000..61b2c5bc3 --- /dev/null +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bls12381.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bls12381.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bls12381.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bls12381.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bls12381.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bls12-381/ecdsa/ecdsa_test.go b/ecc/bls12-381/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..52c11e037 --- /dev/null +++ b/ecc/bls12-381/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-381] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bls12381.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls24-315/ecdsa/doc.go b/ecc/bls24-315/ecdsa/doc.go new file mode 100644 index 000000000..f06ac91fc --- /dev/null +++ b/ecc/bls24-315/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bls24-315 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go new file mode 100644 index 000000000..5194c0528 --- /dev/null +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bls24315.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bls24315.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bls24315.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bls24315.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bls24315.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bls24-315/ecdsa/ecdsa_test.go b/ecc/bls24-315/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..443952228 --- /dev/null +++ b/ecc/bls24-315/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS24-315] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bls24315.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls24-317/ecdsa/doc.go b/ecc/bls24-317/ecdsa/doc.go new file mode 100644 index 000000000..52471c4cb --- /dev/null +++ b/ecc/bls24-317/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bls24-317 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go new file mode 100644 index 000000000..e99ece800 --- /dev/null +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bls24317.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bls24317.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bls24317.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bls24317.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bls24317.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bls24-317/ecdsa/ecdsa_test.go b/ecc/bls24-317/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..de198127b --- /dev/null +++ b/ecc/bls24-317/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS24-317] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bls24317.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bn254/ecdsa/doc.go b/ecc/bn254/ecdsa/doc.go new file mode 100644 index 000000000..69dbd4c98 --- /dev/null +++ b/ecc/bn254/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bn254 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go new file mode 100644 index 000000000..bad4c4e3f --- /dev/null +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bn254.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bn254.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bn254.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bn254.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bn254/ecdsa/ecdsa_test.go b/ecc/bn254/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..ce39f4d31 --- /dev/null +++ b/ecc/bn254/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BN254] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bn254.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-633/ecdsa/doc.go b/ecc/bw6-633/ecdsa/doc.go new file mode 100644 index 000000000..8be83117e --- /dev/null +++ b/ecc/bw6-633/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bw6-633 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go new file mode 100644 index 000000000..9965f0b2f --- /dev/null +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bw6633.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bw6633.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bw6633.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bw6633.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bw6-633/ecdsa/ecdsa_test.go b/ecc/bw6-633/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..e31fce873 --- /dev/null +++ b/ecc/bw6-633/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-633] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bw6633.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-756/ecdsa/doc.go b/ecc/bw6-756/ecdsa/doc.go new file mode 100644 index 000000000..29c1b18ef --- /dev/null +++ b/ecc/bw6-756/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bw6-756 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go new file mode 100644 index 000000000..a046e26e7 --- /dev/null +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-756" + "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bw6756.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bw6756.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bw6756.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bw6756.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bw6-756/ecdsa/ecdsa_test.go b/ecc/bw6-756/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..5f18f6114 --- /dev/null +++ b/ecc/bw6-756/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bw6-756" + "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-756] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bw6756.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-761/ecdsa/doc.go b/ecc/bw6-761/ecdsa/doc.go new file mode 100644 index 000000000..ea1c78355 --- /dev/null +++ b/ecc/bw6-761/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the bw6-761 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go new file mode 100644 index 000000000..3faad26e4 --- /dev/null +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q bw6761.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base bw6761.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R bw6761.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 bw6761.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/bw6-761/ecdsa/ecdsa_test.go b/ecc/bw6-761/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..5877bfe62 --- /dev/null +++ b/ecc/bw6-761/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-761] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, _, g, _ := bw6761.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/secp256k1/ecdsa/doc.go b/ecc/secp256k1/ecdsa/doc.go new file mode 100644 index 000000000..ac59fef6f --- /dev/null +++ b/ecc/secp256k1/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the secp256k1 curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index f09d8afd7..5b73f992f 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -1,11 +1,19 @@ -/* -ecdsa package implements the Elliptic Curve Digital Signature (ECDSA) scheme. -The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. -Documentation: -- Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm -- FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf -- SEC 1, v-2: https://www.secg.org/sec1-v2.pdf -*/ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + package ecdsa import ( @@ -32,8 +40,7 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r big.Int - s big.Int + r, s big.Int } // params are the ECDSA public parameters @@ -175,6 +182,7 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa kInv.ModInverse(&k, pp.Order) R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) if signature.r.Sign() != 0 { break } diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go index a2396602a..916585d75 100644 --- a/ecc/secp256k1/ecdsa/ecdsa_test.go +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -1,3 +1,19 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + package ecdsa import ( diff --git a/ecc/stark-curve/ecdsa/doc.go b/ecc/stark-curve/ecdsa/doc.go new file mode 100644 index 000000000..f704026f7 --- /dev/null +++ b/ecc/stark-curve/ecdsa/doc.go @@ -0,0 +1,28 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package ecdsa provides ECDSA signature scheme on the stark-curve curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +package ecdsa diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go new file mode 100644 index 000000000..3ce176365 --- /dev/null +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -0,0 +1,234 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/stark-curve" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q starkcurve.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base starkcurve.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R starkcurve.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey starkcurve.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 starkcurve.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/ecc/stark-curve/ecdsa/ecdsa_test.go b/ecc/stark-curve/ecdsa/ecdsa_test.go new file mode 100644 index 000000000..4334a483f --- /dev/null +++ b/ecc/stark-curve/ecdsa/ecdsa_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/stark-curve" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[STARK-CURVE] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + _, g := starkcurve.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/internal/generator/config/stark-curve.go b/internal/generator/config/stark-curve.go index 8af4ef48c..34c267d8b 100644 --- a/internal/generator/config/stark-curve.go +++ b/internal/generator/config/stark-curve.go @@ -2,7 +2,7 @@ package config var STARK_CURVE = Curve{ Name: "stark-curve", - CurvePackage: "stark-curve", + CurvePackage: "starkcurve", EnumID: "STARK_CURVE", FrModulus: "3618502788666131213697322783095070105526743751716087489154079457884512865583", FpModulus: "3618502788666131213697322783095070105623107215331596699973092056135872020481", diff --git a/internal/generator/ecdsa/generate.go b/internal/generator/ecdsa/generate.go new file mode 100644 index 000000000..5af469b50 --- /dev/null +++ b/internal/generator/ecdsa/generate.go @@ -0,0 +1,22 @@ +package ecdsa + +import ( + "path/filepath" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/internal/generator/config" +) + +func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) error { + // ecdsa + conf.Package = "ecdsa" + baseDir = filepath.Join(baseDir, conf.Package) + + entries := []bavard.Entry{ + {File: filepath.Join(baseDir, "doc.go"), Templates: []string{"doc.go.tmpl"}}, + {File: filepath.Join(baseDir, "ecdsa.go"), Templates: []string{"ecdsa.go.tmpl"}}, + {File: filepath.Join(baseDir, "ecdsa_test.go"), Templates: []string{"ecdsa.test.go.tmpl"}}, + } + return bgen.Generate(conf, conf.Package, "./ecdsa/template", entries...) + +} diff --git a/internal/generator/ecdsa/template/doc.go.tmpl b/internal/generator/ecdsa/template/doc.go.tmpl new file mode 100644 index 000000000..19acc324b --- /dev/null +++ b/internal/generator/ecdsa/template/doc.go.tmpl @@ -0,0 +1,13 @@ +// Package {{.Package}} provides ECDSA signature scheme on the {{.Name}} curve. +// +// The implementation is adapted from https://pkg.go.dev/crypto/ecdsa. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +// - FIPS 186-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +// - SEC 1, v-2: https://www.secg.org/sec1-v2.pdf +// +package {{.Package}} diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl new file mode 100644 index 000000000..b2a0c4be6 --- /dev/null +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -0,0 +1,216 @@ +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha512" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}" + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" +) + +// PublicKey represents an ECDSA public key +type PublicKey struct { + Q {{ .CurvePackage }}.G1Affine +} + +// PrivateKey represents an ECDSA private key +type PrivateKey struct { + PublicKey + Secret big.Int +} + +// Signature represents an ECDSA signature +type Signature struct { + r, s big.Int +} + +// params are the ECDSA public parameters +type params struct { + Base {{ .CurvePackage }}.G1Affine + Order *big.Int +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = *new(big.Int).SetBytes(b) + n := new(big.Int).Sub(pp.Order, one) + k.Mod(&k, n) + k.Add(&k, one) + return +} + +// GenerateKey generates a public and private key pair. +func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := pp.randFieldElement(rand) + if err != nil { + return nil, err + + } + + privateKey := new(PrivateKey) + privateKey.Secret = k + privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + return privateKey, nil +} + +// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func hashToInt(hash []byte) big.Int { + if len(hash) > fr.Bytes { + hash = hash[:fr.Bytes] + } + + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - fr.Bits + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return *ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Sign performs the ECDSA signature +// +// k ← 𝔽r (random) +// R = k ⋅ Base +// r = x_R (mod Order) +// s = k⁻¹ . (m + sk ⋅ r) +// signature = {s, r} +// +// SEC 1, Version 2.0, Section 4.1.3 +func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + var kInv big.Int + for { + for { + csprng, err := nonce(rand, &privateKey, hash) + if err != nil { + return Signature{}, err + } + k, err := pp.randFieldElement(csprng) + if err != nil { + return Signature{}, err + } + + var R {{ .CurvePackage }}.G1Affine + R.ScalarMultiplication(&pp.Base, &k) + kInv.ModInverse(&k, pp.Order) + + R.X.BigInt(&signature.r) + signature.r.Mod(&signature.r, pp.Order) + if signature.r.Sign() != 0 { + break + } + } + signature.s.Mul(&signature.r, &privateKey.Secret) + m := hashToInt(hash) + signature.s.Add(&m, &signature.s). + Mul(&kInv, &signature.s). + Mod(&signature.s, pp.Order) // pp.Order != 0 + if signature.s.Sign() != 0 { + break + } + } + + return signature, err +} + +// Verify validates the ECDSA signature +// +// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// +// SEC 1, Version 2.0, Section 4.1.4 +func (pp params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePackage }}.G1Affine) bool { + + if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + return false + } + if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + return false + } + + sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + e := hashToInt(hash) + u1 := new(big.Int).Mul(&e, sInv) + u1.Mod(u1, pp.Order) + u2 := new(big.Int).Mul(&signature.r, sInv) + u2.Mod(u2, pp.Order) + + var U1, U2 {{ .CurvePackage }}.G1Affine + U1.ScalarMultiplication(&pp.Base, u1) + U2.ScalarMultiplication(&publicKey, u2). + Add(&U2, &U1) + + var xU2 big.Int + U2.X.BigInt(&xU2) + x := new(big.Int).Mod(&xU2, pp.Order) + + return x.Cmp(&signature.r) == 0 +} diff --git a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl new file mode 100644 index 000000000..fb887585c --- /dev/null +++ b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl @@ -0,0 +1,39 @@ +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}" + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestECDSA(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[{{ toUpper .Name }}] test the signing and verification", prop.ForAll( + func() bool { + + var pp params + {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} + _, g := {{ .CurvePackage }}.Generators() + {{- else}} + _, _, g, _ := {{ .CurvePackage }}.Generators() + {{- end}} + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("testing ECDSA") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + + return pp.Verify(hash, signature, privKey.PublicKey.Q) + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/internal/generator/main.go b/internal/generator/main.go index eeaff729d..810893658 100644 --- a/internal/generator/main.go +++ b/internal/generator/main.go @@ -13,6 +13,7 @@ import ( "github.com/consensys/gnark-crypto/internal/generator/config" "github.com/consensys/gnark-crypto/internal/generator/crypto/hash/mimc" "github.com/consensys/gnark-crypto/internal/generator/ecc" + "github.com/consensys/gnark-crypto/internal/generator/ecdsa" "github.com/consensys/gnark-crypto/internal/generator/edwards" "github.com/consensys/gnark-crypto/internal/generator/edwards/eddsa" "github.com/consensys/gnark-crypto/internal/generator/fft" @@ -61,6 +62,9 @@ func main() { assertNoError(generator.GenerateFF(conf.Fr, filepath.Join(curveDir, "fr"))) assertNoError(generator.GenerateFF(conf.Fp, filepath.Join(curveDir, "fp"))) + // generate ecdsa + assertNoError(ecdsa.Generate(conf, curveDir, bgen)) + if conf.Equal(config.STARK_CURVE) { return // TODO @yelhousni } From dbd95c7d4fc20b27c051b81d16002ce3b985bf12 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 18 Jan 2023 11:43:51 +0100 Subject: [PATCH 06/18] test: add ecdsa benchmarks --- ecc/bls12-377/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/bls12-378/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/bls12-381/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/bls24-315/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/bls24-317/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/bn254/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/bw6-633/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/bw6-756/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/bw6-761/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/secp256k1/ecdsa/ecdsa_test.go | 34 +++++++++++++++ ecc/stark-curve/ecdsa/ecdsa_test.go | 34 +++++++++++++++ .../ecdsa/template/ecdsa.test.go.tmpl | 42 +++++++++++++++++++ 12 files changed, 416 insertions(+) diff --git a/ecc/bls12-377/ecdsa/ecdsa_test.go b/ecc/bls12-377/ecdsa/ecdsa_test.go index 5c0f275d9..74598e17f 100644 --- a/ecc/bls12-377/ecdsa/ecdsa_test.go +++ b/ecc/bls12-377/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls12377.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls12377.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/bls12-378/ecdsa/ecdsa_test.go b/ecc/bls12-378/ecdsa/ecdsa_test.go index ae4c96ca7..46dedd9e3 100644 --- a/ecc/bls12-378/ecdsa/ecdsa_test.go +++ b/ecc/bls12-378/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls12378.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls12378.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/bls12-381/ecdsa/ecdsa_test.go b/ecc/bls12-381/ecdsa/ecdsa_test.go index 52c11e037..454599ea3 100644 --- a/ecc/bls12-381/ecdsa/ecdsa_test.go +++ b/ecc/bls12-381/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls12381.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls12381.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/bls24-315/ecdsa/ecdsa_test.go b/ecc/bls24-315/ecdsa/ecdsa_test.go index 443952228..c60a54ed4 100644 --- a/ecc/bls24-315/ecdsa/ecdsa_test.go +++ b/ecc/bls24-315/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls24315.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls24315.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/bls24-317/ecdsa/ecdsa_test.go b/ecc/bls24-317/ecdsa/ecdsa_test.go index de198127b..9f7a7613d 100644 --- a/ecc/bls24-317/ecdsa/ecdsa_test.go +++ b/ecc/bls24-317/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls24317.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bls24317.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/bn254/ecdsa/ecdsa_test.go b/ecc/bn254/ecdsa/ecdsa_test.go index ce39f4d31..aebf4efd0 100644 --- a/ecc/bn254/ecdsa/ecdsa_test.go +++ b/ecc/bn254/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bn254.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bn254.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/bw6-633/ecdsa/ecdsa_test.go b/ecc/bw6-633/ecdsa/ecdsa_test.go index e31fce873..49815c96a 100644 --- a/ecc/bw6-633/ecdsa/ecdsa_test.go +++ b/ecc/bw6-633/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bw6633.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bw6633.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/bw6-756/ecdsa/ecdsa_test.go b/ecc/bw6-756/ecdsa/ecdsa_test.go index 5f18f6114..7b9823b4c 100644 --- a/ecc/bw6-756/ecdsa/ecdsa_test.go +++ b/ecc/bw6-756/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bw6756.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bw6756.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/bw6-761/ecdsa/ecdsa_test.go b/ecc/bw6-761/ecdsa/ecdsa_test.go index 5877bfe62..8d59eef60 100644 --- a/ecc/bw6-761/ecdsa/ecdsa_test.go +++ b/ecc/bw6-761/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, _, g, _ := bw6761.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, _, g, _ := bw6761.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go index 916585d75..f9ed870f6 100644 --- a/ecc/secp256k1/ecdsa/ecdsa_test.go +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, g := secp256k1.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, g := secp256k1.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/ecc/stark-curve/ecdsa/ecdsa_test.go b/ecc/stark-curve/ecdsa/ecdsa_test.go index 4334a483f..631181eff 100644 --- a/ecc/stark-curve/ecdsa/ecdsa_test.go +++ b/ecc/stark-curve/ecdsa/ecdsa_test.go @@ -51,3 +51,37 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + _, g := starkcurve.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + _, g := starkcurve.Generators() + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} diff --git a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl index fb887585c..46c51a2d1 100644 --- a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl @@ -37,3 +37,45 @@ func TestECDSA(t *testing.T) { properties.TestingRun(t, gopter.ConsoleReporter(false)) } + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignECDSA(b *testing.B) { + var pp params + {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} + _, g := {{ .CurvePackage }}.Generators() + {{- else}} + _, _, g, _ := {{ .CurvePackage }}.Generators() + {{- end}} + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Sign(hash, *privKey, rand.Reader) + } +} + +func BenchmarkVerifyECDSA(b *testing.B) { + var pp params + {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} + _, g := {{ .CurvePackage }}.Generators() + {{- else}} + _, _, g, _ := {{ .CurvePackage }}.Generators() + {{- end}} + pp.Base.Set(&g) + pp.Order = fr.Modulus() + + privKey, _ := pp.GenerateKey(rand.Reader) + + hash := []byte("benchmarking ECDSA sign()") + signature, _ := pp.Sign(hash, *privKey, rand.Reader) + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp.Verify(hash, signature, privKey.PublicKey.Q) + } +} From 863d067af79991debecaa66c494bc9a267040da1 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 18 Jan 2023 17:43:40 +0100 Subject: [PATCH 07/18] perf(ecdsa): avoid 2 inverses in verify (affine scalarMul) --- ecc/bls12-377/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/bls12-378/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/bls12-381/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/bls24-315/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/bls24-317/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/bn254/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/bw6-633/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/bw6-756/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/bw6-761/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/secp256k1/ecdsa/ecdsa.go | 19 +++++++++++++------ ecc/stark-curve/ecdsa/ecdsa.go | 19 +++++++++++++------ .../generator/ecdsa/template/ecdsa.go.tmpl | 19 +++++++++++++------ 12 files changed, 156 insertions(+), 72 deletions(-) diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go index a1326c831..09ab230c7 100644 --- a/ecc/bls12-377/ecdsa/ecdsa.go +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12377.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls12377.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bls12377.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go index 0f3c488b4..964b24687 100644 --- a/ecc/bls12-378/ecdsa/ecdsa.go +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12378.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls12378.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bls12378.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go index 61b2c5bc3..810b3eebb 100644 --- a/ecc/bls12-381/ecdsa/ecdsa.go +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12381.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls12381.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bls12381.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go index 5194c0528..e3d9fc513 100644 --- a/ecc/bls24-315/ecdsa/ecdsa.go +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls24315.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls24315.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bls24315.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go index e99ece800..c669e75ea 100644 --- a/ecc/bls24-317/ecdsa/ecdsa.go +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls24317.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls24317.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bls24317.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go index bad4c4e3f..935e0f71a 100644 --- a/ecc/bn254/ecdsa/ecdsa.go +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affi u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bn254.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bn254.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go index 9965f0b2f..22c1f87c7 100644 --- a/ecc/bw6-633/ecdsa/ecdsa.go +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Aff u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bw6633.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bw6633.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go index a046e26e7..d5820b035 100644 --- a/ecc/bw6-756/ecdsa/ecdsa.go +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Aff u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bw6756.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bw6756.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go index 3faad26e4..e848220a3 100644 --- a/ecc/bw6-761/ecdsa/ecdsa.go +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Aff u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bw6761.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 bw6761.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index 5b73f992f..ffa28f7b8 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1 u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 secp256k1.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 secp256k1.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index 3ce176365..8fd8fdd5d 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -221,14 +221,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey starkcurve.G u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 starkcurve.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 starkcurve.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index b2a0c4be6..f9943951d 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -203,14 +203,21 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePac u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 {{ .CurvePackage }}.G1Affine - U1.ScalarMultiplication(&pp.Base, u1) - U2.ScalarMultiplication(&publicKey, u2). - Add(&U2, &U1) + var U1, U2 {{ .CurvePackage }}.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) - var xU2 big.Int + // signature.r * Z^2 + U2.Z.Square(&U2.Z). + Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + + var xU2, rzz big.Int U2.X.BigInt(&xU2) + U2.Z.BigInt(&rzz) x := new(big.Int).Mod(&xU2, pp.Order) + r := new(big.Int).Mod(&rzz, pp.Order) + + return x.Cmp(r) == 0 - return x.Cmp(&signature.r) == 0 } From 1dd6e2e16eea6ce81c12d1bb0b8a90da654af350 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 18 Jan 2023 18:14:36 +0100 Subject: [PATCH 08/18] fix(ecdsa): avoid only 1 inverse in verify --- ecc/bls12-377/ecdsa/ecdsa.go | 14 ++++++-------- ecc/bls12-378/ecdsa/ecdsa.go | 14 ++++++-------- ecc/bls12-381/ecdsa/ecdsa.go | 14 ++++++-------- ecc/bls24-315/ecdsa/ecdsa.go | 14 ++++++-------- ecc/bls24-317/ecdsa/ecdsa.go | 14 ++++++-------- ecc/bn254/ecdsa/ecdsa.go | 14 ++++++-------- ecc/bw6-633/ecdsa/ecdsa.go | 14 ++++++-------- ecc/bw6-756/ecdsa/ecdsa.go | 14 ++++++-------- ecc/bw6-761/ecdsa/ecdsa.go | 14 ++++++-------- ecc/secp256k1/ecdsa/ecdsa.go | 14 ++++++-------- ecc/stark-curve/ecdsa/ecdsa.go | 14 ++++++-------- internal/generator/ecdsa/template/ecdsa.go.tmpl | 16 +++++++--------- 12 files changed, 73 insertions(+), 97 deletions(-) diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go index 09ab230c7..34e917f08 100644 --- a/ecc/bls12-377/ecdsa/ecdsa.go +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12377.G1A U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go index 964b24687..e91dd84de 100644 --- a/ecc/bls12-378/ecdsa/ecdsa.go +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12378.G1A U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go index 810b3eebb..b8e2982b2 100644 --- a/ecc/bls12-381/ecdsa/ecdsa.go +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12381.G1A U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go index e3d9fc513..5aa9664b6 100644 --- a/ecc/bls24-315/ecdsa/ecdsa.go +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls24315.G1A U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go index c669e75ea..ad161ea79 100644 --- a/ecc/bls24-317/ecdsa/ecdsa.go +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls24317.G1A U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go index 935e0f71a..583dfa26b 100644 --- a/ecc/bn254/ecdsa/ecdsa.go +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affi U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go index 22c1f87c7..cfb16cf90 100644 --- a/ecc/bw6-633/ecdsa/ecdsa.go +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Aff U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go index d5820b035..7e1a05976 100644 --- a/ecc/bw6-756/ecdsa/ecdsa.go +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Aff U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go index e848220a3..dd685e29f 100644 --- a/ecc/bw6-761/ecdsa/ecdsa.go +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Aff U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index ffa28f7b8..6c5e096d1 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1 U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index 8fd8fdd5d..4ad094f85 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -226,16 +226,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey starkcurve.G U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 + var z big.Int U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index f9943951d..1f1c30596 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -208,16 +208,14 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePac U2.ScalarMultiplicationAffine(&publicKey, u2). AddAssign(&U1) - // signature.r * Z^2 - U2.Z.Square(&U2.Z). - Mul(&U2.Z, U2.Y.SetBigInt(&signature.r)) + var z big.Int + U2.Z.Square(&U2.Z). + Inverse(&U2.Z). + Mul(&U2.Z, &U2.X). + BigInt(&z) - var xU2, rzz big.Int - U2.X.BigInt(&xU2) - U2.Z.BigInt(&rzz) - x := new(big.Int).Mod(&xU2, pp.Order) - r := new(big.Int).Mod(&rzz, pp.Order) + z.Mod(&z, pp.Order) - return x.Cmp(r) == 0 + return z.Cmp(&signature.r) == 0 } From c07f70d037673d4d0e2adb0fc3ec43ca081934f3 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 19 Jan 2023 10:48:21 +0100 Subject: [PATCH 09/18] perf(stark-curve/ecdsa): faster verification with JointScalarMul --- ecc/stark-curve/ecdsa/ecdsa.go | 6 +- ecc/stark-curve/g1.go | 67 +++++++++++++++++++ ecc/stark-curve/g1_test.go | 25 +++++++ .../generator/ecdsa/template/ecdsa.go.tmpl | 13 ++-- 4 files changed, 103 insertions(+), 8 deletions(-) diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index 4ad094f85..42ae07f0c 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -221,10 +221,8 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey starkcurve.G u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 starkcurve.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U2 starkcurve.G1Jac + U2.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int U2.Z.Square(&U2.Z). diff --git a/ecc/stark-curve/g1.go b/ecc/stark-curve/g1.go index a2c7d97b1..79424ceb5 100644 --- a/ecc/stark-curve/g1.go +++ b/ecc/stark-curve/g1.go @@ -422,6 +422,73 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/stark-curve/g1_test.go b/ecc/stark-curve/g1_test.go index 5f0d40275..065aacebf 100644 --- a/ecc/stark-curve/g1_test.go +++ b/ecc/stark-curve/g1_test.go @@ -361,6 +361,31 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) + properties.Property("[STARK-CURVE] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index 1f1c30596..cd1f05960 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -203,10 +203,15 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePac u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 {{ .CurvePackage }}.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + {{if eq .Name "stark-curve"}} + var U2 {{ .CurvePackage }}.G1Jac + U2.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + {{- else}} + var U1, U2 {{ .CurvePackage }}.G1Jac + U1.ScalarMultiplicationAffine(&pp.Base, u1) + U2.ScalarMultiplicationAffine(&publicKey, u2). + AddAssign(&U1) + {{- end}} var z big.Int U2.Z.Square(&U2.Z). From c826abb5c78dfcf3dd818e40b5f955c70b4bce1c Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 19 Jan 2023 11:05:54 +0100 Subject: [PATCH 10/18] perf(all curves/ecdsa): faster verification with JointScalarMul --- ecc/bls12-377/ecdsa/ecdsa.go | 12 ++-- ecc/bls12-377/g1.go | 67 ++++++++++++++++++ ecc/bls12-377/g1_test.go | 24 +++++++ ecc/bls12-378/ecdsa/ecdsa.go | 12 ++-- ecc/bls12-378/g1.go | 67 ++++++++++++++++++ ecc/bls12-378/g1_test.go | 24 +++++++ ecc/bls12-381/ecdsa/ecdsa.go | 12 ++-- ecc/bls12-381/g1.go | 67 ++++++++++++++++++ ecc/bls12-381/g1_test.go | 24 +++++++ ecc/bls24-315/ecdsa/ecdsa.go | 12 ++-- ecc/bls24-315/g1.go | 67 ++++++++++++++++++ ecc/bls24-315/g1_test.go | 24 +++++++ ecc/bls24-317/ecdsa/ecdsa.go | 12 ++-- ecc/bls24-317/g1.go | 67 ++++++++++++++++++ ecc/bls24-317/g1_test.go | 24 +++++++ ecc/bn254/ecdsa/ecdsa.go | 12 ++-- ecc/bn254/g1.go | 67 ++++++++++++++++++ ecc/bn254/g1_test.go | 24 +++++++ ecc/bw6-633/ecdsa/ecdsa.go | 12 ++-- ecc/bw6-633/g1.go | 67 ++++++++++++++++++ ecc/bw6-633/g1_test.go | 24 +++++++ ecc/bw6-756/ecdsa/ecdsa.go | 12 ++-- ecc/bw6-756/g1.go | 67 ++++++++++++++++++ ecc/bw6-756/g1_test.go | 24 +++++++ ecc/bw6-761/ecdsa/ecdsa.go | 12 ++-- ecc/bw6-761/g1.go | 67 ++++++++++++++++++ ecc/bw6-761/g1_test.go | 24 +++++++ ecc/secp256k1/ecdsa/ecdsa.go | 12 ++-- ecc/secp256k1/g1.go | 67 ++++++++++++++++++ ecc/stark-curve/ecdsa/ecdsa.go | 10 +-- internal/generator/ecc/template/point.go.tmpl | 69 ++++++++++++++++++- .../ecc/template/tests/point.go.tmpl | 29 ++++++++ .../generator/ecdsa/template/ecdsa.go.tmpl | 17 ++--- 33 files changed, 1043 insertions(+), 88 deletions(-) diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go index 34e917f08..55b703c03 100644 --- a/ecc/bls12-377/ecdsa/ecdsa.go +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12377.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls12377.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bls12377.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index 3e44f69cf..0429fe896 100644 --- a/ecc/bls12-377/g1.go +++ b/ecc/bls12-377/g1.go @@ -527,6 +527,73 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bls12-377/g1_test.go b/ecc/bls12-377/g1_test.go index 94f0c32de..856e07440 100644 --- a/ecc/bls12-377/g1_test.go +++ b/ecc/bls12-377/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BLS12-377] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go index e91dd84de..160fe8e49 100644 --- a/ecc/bls12-378/ecdsa/ecdsa.go +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12378.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls12378.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bls12378.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bls12-378/g1.go b/ecc/bls12-378/g1.go index cd9155b76..7ffd369d6 100644 --- a/ecc/bls12-378/g1.go +++ b/ecc/bls12-378/g1.go @@ -527,6 +527,73 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bls12-378/g1_test.go b/ecc/bls12-378/g1_test.go index 93f106197..0685a36e6 100644 --- a/ecc/bls12-378/g1_test.go +++ b/ecc/bls12-378/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BLS12-378] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go index b8e2982b2..15b7ee969 100644 --- a/ecc/bls12-381/ecdsa/ecdsa.go +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12381.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls12381.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bls12381.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bls12-381/g1.go b/ecc/bls12-381/g1.go index a6e2f174c..734823472 100644 --- a/ecc/bls12-381/g1.go +++ b/ecc/bls12-381/g1.go @@ -527,6 +527,73 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bls12-381/g1_test.go b/ecc/bls12-381/g1_test.go index 7e25d4d4e..0efe897fe 100644 --- a/ecc/bls12-381/g1_test.go +++ b/ecc/bls12-381/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BLS12-381] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go index 5aa9664b6..254622695 100644 --- a/ecc/bls24-315/ecdsa/ecdsa.go +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls24315.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls24315.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bls24315.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bls24-315/g1.go b/ecc/bls24-315/g1.go index d9c125045..3dd222641 100644 --- a/ecc/bls24-315/g1.go +++ b/ecc/bls24-315/g1.go @@ -529,6 +529,73 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bls24-315/g1_test.go b/ecc/bls24-315/g1_test.go index 6f553b866..c9a9e6136 100644 --- a/ecc/bls24-315/g1_test.go +++ b/ecc/bls24-315/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BLS24-315] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go index ad161ea79..477d9fac0 100644 --- a/ecc/bls24-317/ecdsa/ecdsa.go +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls24317.G1A u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bls24317.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bls24317.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bls24-317/g1.go b/ecc/bls24-317/g1.go index 9a4d35cf7..698296c18 100644 --- a/ecc/bls24-317/g1.go +++ b/ecc/bls24-317/g1.go @@ -529,6 +529,73 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bls24-317/g1_test.go b/ecc/bls24-317/g1_test.go index dc50ffb49..d50afe46c 100644 --- a/ecc/bls24-317/g1_test.go +++ b/ecc/bls24-317/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BLS24-317] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go index 583dfa26b..35a7ca195 100644 --- a/ecc/bn254/ecdsa/ecdsa.go +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affi u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bn254.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bn254.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bn254/g1.go b/ecc/bn254/g1.go index 62d1937ae..4080af86b 100644 --- a/ecc/bn254/g1.go +++ b/ecc/bn254/g1.go @@ -498,6 +498,73 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { return p } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bn254/g1_test.go b/ecc/bn254/g1_test.go index ec7ce9eed..637636bc1 100644 --- a/ecc/bn254/g1_test.go +++ b/ecc/bn254/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BN254] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go index cfb16cf90..33b2d04c9 100644 --- a/ecc/bw6-633/ecdsa/ecdsa.go +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Aff u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bw6633.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bw6633.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bw6-633/g1.go b/ecc/bw6-633/g1.go index 95e71fb1d..4c0f41844 100644 --- a/ecc/bw6-633/g1.go +++ b/ecc/bw6-633/g1.go @@ -557,6 +557,73 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bw6-633/g1_test.go b/ecc/bw6-633/g1_test.go index bf3e45975..23f7f901e 100644 --- a/ecc/bw6-633/g1_test.go +++ b/ecc/bw6-633/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BW6-633] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go index 7e1a05976..6275124eb 100644 --- a/ecc/bw6-756/ecdsa/ecdsa.go +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Aff u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bw6756.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bw6756.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bw6-756/g1.go b/ecc/bw6-756/g1.go index 9ad403028..0a355de53 100644 --- a/ecc/bw6-756/g1.go +++ b/ecc/bw6-756/g1.go @@ -557,6 +557,73 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { return p } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bw6-756/g1_test.go b/ecc/bw6-756/g1_test.go index 4ab6a4cee..2a315fa2e 100644 --- a/ecc/bw6-756/g1_test.go +++ b/ecc/bw6-756/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BW6-756] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go index dd685e29f..13d24bf1f 100644 --- a/ecc/bw6-761/ecdsa/ecdsa.go +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Aff u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 bw6761.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U bw6761.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/bw6-761/g1.go b/ecc/bw6-761/g1.go index 7457b4fdb..80a375019 100644 --- a/ecc/bw6-761/g1.go +++ b/ecc/bw6-761/g1.go @@ -568,6 +568,73 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/bw6-761/g1_test.go b/ecc/bw6-761/g1_test.go index 5a3edef3d..786f2d52d 100644 --- a/ecc/bw6-761/g1_test.go +++ b/ecc/bw6-761/g1_test.go @@ -393,6 +393,30 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) + properties.Property("[BW6-761] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 G1Affine + g1.Set(&g1GenAff) + g2.Set(&g1GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&g1Gen, &_s1) + p2.ScalarMultiplication(&g1Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index 6c5e096d1..1ded213de 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -221,15 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1 u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U1, U2 secp256k1.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) + var U secp256k1.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/ecc/secp256k1/g1.go b/ecc/secp256k1/g1.go index 4b34b63fc..e9820f4f2 100644 --- a/ecc/secp256k1/g1.go +++ b/ecc/secp256k1/g1.go @@ -498,6 +498,73 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { return p } +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]G1Jac + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index 42ae07f0c..bb0f806f0 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -221,13 +221,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey starkcurve.G u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - var U2 starkcurve.G1Jac - U2.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + var U starkcurve.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) diff --git a/internal/generator/ecc/template/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl index 5efbfeeef..c8b9a920c 100644 --- a/internal/generator/ecc/template/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -1123,7 +1123,74 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{ end }} +{{ if eq .PointName "g1" }} +// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique +func (p *{{$TJacobian}}) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *{{$TJacobian}} { + + var res, p1, p2 {{$TJacobian}} + res.Set(&{{ toLower .PointName }}Infinity) + p1.FromAffine(a1) + p2.FromAffine(a2) + + var table [15]{{$TJacobian}} + + if s1.Sign() == -1 { + s1.Neg(s1) + table[0].Neg(&p1) + } else { + table[0].Set(&p1) + } + if s2.Sign() == -1 { + s2.Neg(s2) + table[3].Neg(&p2) + } else { + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(s1).Bits() + s[1] = s[1].SetBigInt(s2).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} +{{ end }} // ------------------------------------------------------------------------------------------------- @@ -1526,7 +1593,7 @@ func BatchScalarMultiplication{{ toUpper .PointName }}(base *{{ $TAffine }}, sca for c := 2; c <= 16; c++ { cost := uint64(1 << (c-1)) // pre compute the table nbChunks := computeNbChunks(uint64(c)) - cost += nbPoints * (uint64(c) + 1) * nbChunks // doublings + point add + cost += nbPoints * (uint64(c) + 1) * nbChunks // doublings + point add if cost < min { min = cost bestC = c diff --git a/internal/generator/ecc/template/tests/point.go.tmpl b/internal/generator/ecc/template/tests/point.go.tmpl index 161177d0f..bd9da4b50 100644 --- a/internal/generator/ecc/template/tests/point.go.tmpl +++ b/internal/generator/ecc/template/tests/point.go.tmpl @@ -436,6 +436,35 @@ func Test{{ $TAffine }}Ops(t *testing.T) { }, genScalar, )) + + {{- if eq .PointName "g1"}} + properties.Property("[{{ toUpper .Name }}] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var g1, g2 {{ $TAffine }} + g1.Set(&{{.PointName}}GenAff) + g2.Set(&{{.PointName}}GenAff) + + var _s1, _s2 big.Int + s1.BigInt(&_s1) + s2.BigInt(&_s2) + + var p1, p2 G1Jac + p1.ScalarMultiplication(&{{.PointName}}Gen, &_s1) + p2.ScalarMultiplication(&{{.PointName}}Gen, &_s2). + AddAssign(&p1) + + p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + + return p1.Equal(&p2) + + }, + genScalar, + genScalar, + )) + {{end}} + + {{end}} diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index cd1f05960..99d0123f6 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -203,20 +203,13 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePac u2 := new(big.Int).Mul(&signature.r, sInv) u2.Mod(u2, pp.Order) - {{if eq .Name "stark-curve"}} - var U2 {{ .CurvePackage }}.G1Jac - U2.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) - {{- else}} - var U1, U2 {{ .CurvePackage }}.G1Jac - U1.ScalarMultiplicationAffine(&pp.Base, u1) - U2.ScalarMultiplicationAffine(&publicKey, u2). - AddAssign(&U1) - {{- end}} + var U {{ .CurvePackage }}.G1Jac + U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) var z big.Int - U2.Z.Square(&U2.Z). - Inverse(&U2.Z). - Mul(&U2.Z, &U2.X). + U.Z.Square(&U.Z). + Inverse(&U.Z). + Mul(&U.Z, &U.X). BigInt(&z) z.Mod(&z, pp.Order) From 92008e9e83c529abb1a6beba5bf2465e0ffa11c2 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 20 Jan 2023 12:21:45 +0100 Subject: [PATCH 11/18] refactor(ecdsa): make public params exportable to gnark --- ecc/bls12-377/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bls12-377/ecdsa/ecdsa_test.go | 6 +-- ecc/bls12-378/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bls12-378/ecdsa/ecdsa_test.go | 6 +-- ecc/bls12-381/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bls12-381/ecdsa/ecdsa_test.go | 6 +-- ecc/bls24-315/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bls24-315/ecdsa/ecdsa_test.go | 6 +-- ecc/bls24-317/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bls24-317/ecdsa/ecdsa_test.go | 6 +-- ecc/bn254/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bn254/ecdsa/ecdsa_test.go | 6 +-- ecc/bw6-633/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bw6-633/ecdsa/ecdsa_test.go | 6 +-- ecc/bw6-756/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bw6-756/ecdsa/ecdsa_test.go | 6 +-- ecc/bw6-761/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/bw6-761/ecdsa/ecdsa_test.go | 6 +-- ecc/secp256k1/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/secp256k1/ecdsa/ecdsa_test.go | 6 +-- ecc/stark-curve/ecdsa/ecdsa.go | 40 +++++++++---------- ecc/stark-curve/ecdsa/ecdsa_test.go | 6 +-- .../generator/ecdsa/template/ecdsa.go.tmpl | 40 +++++++++---------- .../ecdsa/template/ecdsa.test.go.tmpl | 6 +-- 24 files changed, 276 insertions(+), 276 deletions(-) diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go index 55b703c03..7c69ae903 100644 --- a/ecc/bls12-377/ecdsa/ecdsa.go +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bls12377.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bls12377.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12377.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bls12377.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12377.G1A z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bls12-377/ecdsa/ecdsa_test.go b/ecc/bls12-377/ecdsa/ecdsa_test.go index 74598e17f..5a0f67afc 100644 --- a/ecc/bls12-377/ecdsa/ecdsa_test.go +++ b/ecc/bls12-377/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS12-377] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bls12377.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls12377.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls12377.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go index 160fe8e49..f6149027a 100644 --- a/ecc/bls12-378/ecdsa/ecdsa.go +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bls12378.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bls12378.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12378.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bls12378.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12378.G1A z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bls12-378/ecdsa/ecdsa_test.go b/ecc/bls12-378/ecdsa/ecdsa_test.go index 46dedd9e3..7bda7f28f 100644 --- a/ecc/bls12-378/ecdsa/ecdsa_test.go +++ b/ecc/bls12-378/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS12-378] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bls12378.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls12378.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls12378.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go index 15b7ee969..e0d2fff3f 100644 --- a/ecc/bls12-381/ecdsa/ecdsa.go +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bls12381.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bls12381.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12381.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bls12381.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls12381.G1A z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bls12-381/ecdsa/ecdsa_test.go b/ecc/bls12-381/ecdsa/ecdsa_test.go index 454599ea3..c911d1de5 100644 --- a/ecc/bls12-381/ecdsa/ecdsa_test.go +++ b/ecc/bls12-381/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS12-381] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bls12381.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls12381.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls12381.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go index 254622695..1be84b3f5 100644 --- a/ecc/bls24-315/ecdsa/ecdsa.go +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bls24315.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bls24315.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bls24315.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bls24315.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls24315.G1A z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bls24-315/ecdsa/ecdsa_test.go b/ecc/bls24-315/ecdsa/ecdsa_test.go index c60a54ed4..e2a14bb96 100644 --- a/ecc/bls24-315/ecdsa/ecdsa_test.go +++ b/ecc/bls24-315/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS24-315] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bls24315.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls24315.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls24315.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go index 477d9fac0..6c323bd1a 100644 --- a/ecc/bls24-317/ecdsa/ecdsa.go +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bls24317.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bls24317.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bls24317.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bls24317.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bls24317.G1A z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bls24-317/ecdsa/ecdsa_test.go b/ecc/bls24-317/ecdsa/ecdsa_test.go index 9f7a7613d..6084242e4 100644 --- a/ecc/bls24-317/ecdsa/ecdsa_test.go +++ b/ecc/bls24-317/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS24-317] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bls24317.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls24317.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bls24317.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go index 35a7ca195..863210264 100644 --- a/ecc/bn254/ecdsa/ecdsa.go +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bn254.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bn254.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affi z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bn254/ecdsa/ecdsa_test.go b/ecc/bn254/ecdsa/ecdsa_test.go index aebf4efd0..d070dd02a 100644 --- a/ecc/bn254/ecdsa/ecdsa_test.go +++ b/ecc/bn254/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BN254] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bn254.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bn254.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bn254.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go index 33b2d04c9..0f09797d3 100644 --- a/ecc/bw6-633/ecdsa/ecdsa.go +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bw6633.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bw6633.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Aff z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bw6-633/ecdsa/ecdsa_test.go b/ecc/bw6-633/ecdsa/ecdsa_test.go index 49815c96a..dcb91dfb2 100644 --- a/ecc/bw6-633/ecdsa/ecdsa_test.go +++ b/ecc/bw6-633/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BW6-633] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bw6633.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bw6633.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bw6633.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go index 6275124eb..00b9b0c43 100644 --- a/ecc/bw6-756/ecdsa/ecdsa.go +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bw6756.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bw6756.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Aff z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bw6-756/ecdsa/ecdsa_test.go b/ecc/bw6-756/ecdsa/ecdsa_test.go index 7b9823b4c..d241ed250 100644 --- a/ecc/bw6-756/ecdsa/ecdsa_test.go +++ b/ecc/bw6-756/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BW6-756] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bw6756.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bw6756.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bw6756.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go index 13d24bf1f..a14c4cd5b 100644 --- a/ecc/bw6-761/ecdsa/ecdsa.go +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base bw6761.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U bw6761.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Aff z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/bw6-761/ecdsa/ecdsa_test.go b/ecc/bw6-761/ecdsa/ecdsa_test.go index 8d59eef60..fdda4b111 100644 --- a/ecc/bw6-761/ecdsa/ecdsa_test.go +++ b/ecc/bw6-761/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[BW6-761] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, _, g, _ := bw6761.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bw6761.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, _, g, _ := bw6761.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index 1ded213de..67ab9b082 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base secp256k1.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U secp256k1.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1 z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go index f9ed870f6..2b8955ce7 100644 --- a/ecc/secp256k1/ecdsa/ecdsa_test.go +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[SECP256K1] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, g := secp256k1.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, g := secp256k1.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, g := secp256k1.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index bb0f806f0..58c0f7f15 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -40,11 +40,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base starkcurve.G1Affine Order *big.Int } @@ -53,7 +53,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -68,7 +68,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -164,7 +164,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -181,18 +181,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -205,20 +205,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey starkcurve.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey starkcurve.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U starkcurve.G1Jac @@ -232,6 +232,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey starkcurve.G z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/ecc/stark-curve/ecdsa/ecdsa_test.go b/ecc/stark-curve/ecdsa/ecdsa_test.go index 631181eff..666a2ba79 100644 --- a/ecc/stark-curve/ecdsa/ecdsa_test.go +++ b/ecc/stark-curve/ecdsa/ecdsa_test.go @@ -35,7 +35,7 @@ func TestECDSA(t *testing.T) { properties.Property("[STARK-CURVE] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params _, g := starkcurve.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -56,7 +56,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params _, g := starkcurve.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() @@ -71,7 +71,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params _, g := starkcurve.Generators() pp.Base.Set(&g) pp.Order = fr.Modulus() diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index 99d0123f6..e03aae183 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -22,11 +22,11 @@ type PrivateKey struct { // Signature represents an ECDSA signature type Signature struct { - r, s big.Int + R, S big.Int } -// params are the ECDSA public parameters -type params struct { +// Params are the ECDSA public parameters +type Params struct { Base {{ .CurvePackage }}.G1Affine Order *big.Int } @@ -35,7 +35,7 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { @@ -50,7 +50,7 @@ func (pp params) randFieldElement(rand io.Reader) (k big.Int, err error) { } // GenerateKey generates a public and private key pair. -func (pp params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { k, err := pp.randFieldElement(rand) if err != nil { @@ -146,7 +146,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { +func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { var kInv big.Int for { for { @@ -163,18 +163,18 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa R.ScalarMultiplication(&pp.Base, &k) kInv.ModInverse(&k, pp.Order) - R.X.BigInt(&signature.r) - signature.r.Mod(&signature.r, pp.Order) - if signature.r.Sign() != 0 { + R.X.BigInt(&signature.R) + signature.R.Mod(&signature.R, pp.Order) + if signature.R.Sign() != 0 { break } } - signature.s.Mul(&signature.r, &privateKey.Secret) + signature.S.Mul(&signature.R, &privateKey.Secret) m := hashToInt(hash) - signature.s.Add(&m, &signature.s). - Mul(&kInv, &signature.s). - Mod(&signature.s, pp.Order) // pp.Order != 0 - if signature.s.Sign() != 0 { + signature.S.Add(&m, &signature.S). + Mul(&kInv, &signature.S). + Mod(&signature.S, pp.Order) // pp.Order != 0 + if signature.S.Sign() != 0 { break } } @@ -187,20 +187,20 @@ func (pp params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signa // R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey // // SEC 1, Version 2.0, Section 4.1.4 -func (pp params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePackage }}.G1Affine) bool { +func (pp Params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePackage }}.G1Affine) bool { - if signature.r.Sign() <= 0 || signature.s.Sign() <= 0 { + if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.r.Cmp(pp.Order) >= 0 || signature.s.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.s, pp.Order) + sInv := new(big.Int).ModInverse(&signature.S, pp.Order) e := hashToInt(hash) u1 := new(big.Int).Mul(&e, sInv) u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.r, sInv) + u2 := new(big.Int).Mul(&signature.R, sInv) u2.Mod(u2, pp.Order) var U {{ .CurvePackage }}.G1Jac @@ -214,6 +214,6 @@ func (pp params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePac z.Mod(&z, pp.Order) - return z.Cmp(&signature.r) == 0 + return z.Cmp(&signature.R) == 0 } diff --git a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl index 46c51a2d1..6b25f25f8 100644 --- a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl @@ -17,7 +17,7 @@ func TestECDSA(t *testing.T) { properties.Property("[{{ toUpper .Name }}] test the signing and verification", prop.ForAll( func() bool { - var pp params + var pp Params {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} _, g := {{ .CurvePackage }}.Generators() {{- else}} @@ -42,7 +42,7 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp params + var pp Params {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} _, g := {{ .CurvePackage }}.Generators() {{- else}} @@ -61,7 +61,7 @@ func BenchmarkSignECDSA(b *testing.B) { } func BenchmarkVerifyECDSA(b *testing.B) { - var pp params + var pp Params {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} _, g := {{ .CurvePackage }}.Generators() {{- else}} From 96af55a6f816554b72056451b753d079ad961733 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 20 Jan 2023 13:09:34 +0100 Subject: [PATCH 12/18] fix(curves): copy scalars in JointScalarMul --- ecc/bls12-377/g1.go | 17 ++++++++++------- ecc/bls12-378/g1.go | 17 ++++++++++------- ecc/bls12-381/g1.go | 17 ++++++++++------- ecc/bls24-315/g1.go | 17 ++++++++++------- ecc/bls24-317/g1.go | 17 ++++++++++------- ecc/bn254/g1.go | 17 ++++++++++------- ecc/bw6-633/g1.go | 17 ++++++++++------- ecc/bw6-756/g1.go | 17 ++++++++++------- ecc/bw6-761/g1.go | 17 ++++++++++------- ecc/secp256k1/g1.go | 17 ++++++++++------- internal/generator/ecc/template/point.go.tmpl | 17 ++++++++++------- 11 files changed, 110 insertions(+), 77 deletions(-) diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index 0429fe896..55ae5a74b 100644 --- a/ecc/bls12-377/g1.go +++ b/ecc/bls12-377/g1.go @@ -537,16 +537,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -566,12 +569,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/bls12-378/g1.go b/ecc/bls12-378/g1.go index 7ffd369d6..1a839f014 100644 --- a/ecc/bls12-378/g1.go +++ b/ecc/bls12-378/g1.go @@ -537,16 +537,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -566,12 +569,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/bls12-381/g1.go b/ecc/bls12-381/g1.go index 734823472..47f3d18e2 100644 --- a/ecc/bls12-381/g1.go +++ b/ecc/bls12-381/g1.go @@ -537,16 +537,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -566,12 +569,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/bls24-315/g1.go b/ecc/bls24-315/g1.go index 3dd222641..6d9030cac 100644 --- a/ecc/bls24-315/g1.go +++ b/ecc/bls24-315/g1.go @@ -539,16 +539,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -568,12 +571,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/bls24-317/g1.go b/ecc/bls24-317/g1.go index 698296c18..b02050f9b 100644 --- a/ecc/bls24-317/g1.go +++ b/ecc/bls24-317/g1.go @@ -539,16 +539,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -568,12 +571,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/bn254/g1.go b/ecc/bn254/g1.go index 4080af86b..7ba84474f 100644 --- a/ecc/bn254/g1.go +++ b/ecc/bn254/g1.go @@ -508,16 +508,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -537,12 +540,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/bw6-633/g1.go b/ecc/bw6-633/g1.go index 4c0f41844..03e530830 100644 --- a/ecc/bw6-633/g1.go +++ b/ecc/bw6-633/g1.go @@ -567,16 +567,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -596,12 +599,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/bw6-756/g1.go b/ecc/bw6-756/g1.go index 0a355de53..7d7938fea 100644 --- a/ecc/bw6-756/g1.go +++ b/ecc/bw6-756/g1.go @@ -567,16 +567,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -596,12 +599,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/bw6-761/g1.go b/ecc/bw6-761/g1.go index 80a375019..6e31d3cdc 100644 --- a/ecc/bw6-761/g1.go +++ b/ecc/bw6-761/g1.go @@ -578,16 +578,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -607,12 +610,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/secp256k1/g1.go b/ecc/secp256k1/g1.go index e9820f4f2..e3a150cf0 100644 --- a/ecc/secp256k1/g1.go +++ b/ecc/secp256k1/g1.go @@ -508,16 +508,19 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -537,12 +540,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/internal/generator/ecc/template/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl index c8b9a920c..93d62b584 100644 --- a/internal/generator/ecc/template/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -1134,16 +1134,19 @@ func (p *{{$TJacobian}}) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s var table [15]{{$TJacobian}} + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -1163,12 +1166,12 @@ func (p *{{$TJacobian}}) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 From eb8bce9077e582f7ef48a5af7f616b8bc8f0e731 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 20 Jan 2023 18:15:13 +0100 Subject: [PATCH 13/18] refactor(ecdsa): remove Params struct --- ecc/bls12-377/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bls12-377/ecdsa/ecdsa_test.go | 31 ++---- ecc/bls12-377/g1.go | 17 ++- ecc/bls12-377/g1_test.go | 23 ++-- ecc/bls12-378/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bls12-378/ecdsa/ecdsa_test.go | 31 ++---- ecc/bls12-378/g1.go | 17 ++- ecc/bls12-378/g1_test.go | 23 ++-- ecc/bls12-381/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bls12-381/ecdsa/ecdsa_test.go | 31 ++---- ecc/bls12-381/g1.go | 17 ++- ecc/bls12-381/g1_test.go | 23 ++-- ecc/bls24-315/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bls24-315/ecdsa/ecdsa_test.go | 31 ++---- ecc/bls24-315/g1.go | 17 ++- ecc/bls24-315/g1_test.go | 23 ++-- ecc/bls24-317/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bls24-317/ecdsa/ecdsa_test.go | 31 ++---- ecc/bls24-317/g1.go | 17 ++- ecc/bls24-317/g1_test.go | 23 ++-- ecc/bn254/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bn254/ecdsa/ecdsa_test.go | 31 ++---- ecc/bn254/g1.go | 17 ++- ecc/bn254/g1_test.go | 23 ++-- ecc/bw6-633/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bw6-633/ecdsa/ecdsa_test.go | 31 ++---- ecc/bw6-633/g1.go | 17 ++- ecc/bw6-633/g1_test.go | 23 ++-- ecc/bw6-756/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bw6-756/ecdsa/ecdsa_test.go | 31 ++---- ecc/bw6-756/g1.go | 17 ++- ecc/bw6-756/g1_test.go | 23 ++-- ecc/bw6-761/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/bw6-761/ecdsa/ecdsa_test.go | 31 ++---- ecc/bw6-761/g1.go | 17 ++- ecc/bw6-761/g1_test.go | 23 ++-- ecc/secp256k1/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/secp256k1/ecdsa/ecdsa_test.go | 31 ++---- ecc/secp256k1/g1.go | 17 ++- ecc/secp256k1/g1_test.go | 17 +++ ecc/stark-curve/ecdsa/ecdsa.go | 91 ++++++++-------- ecc/stark-curve/ecdsa/ecdsa_test.go | 31 ++---- ecc/stark-curve/g1.go | 34 ++++-- ecc/stark-curve/g1_test.go | 22 ++-- internal/generator/ecc/template/point.go.tmpl | 18 +++- .../ecc/template/tests/point.go.tmpl | 29 ++--- .../generator/ecdsa/template/ecdsa.go.tmpl | 100 +++++++++--------- .../ecdsa/template/ecdsa.test.go.tmpl | 43 ++------ 48 files changed, 917 insertions(+), 1065 deletions(-) diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go index 7c69ae903..8edd7092a 100644 --- a/ecc/bls12-377/ecdsa/ecdsa.go +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bls12377.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bls12377.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bls12377.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bls12377.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12377.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bls12377.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bls12377.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12377.G1A Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bls12-377/ecdsa/ecdsa_test.go b/ecc/bls12-377/ecdsa/ecdsa_test.go index 5a0f67afc..0b37d238a 100644 --- a/ecc/bls12-377/ecdsa/ecdsa_test.go +++ b/ecc/bls12-377/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS12-377] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bls12377.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls12377.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls12377.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index 55ae5a74b..b5b6f65e6 100644 --- a/ecc/bls12-377/g1.go +++ b/ecc/bls12-377/g1.go @@ -73,6 +73,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -527,13 +535,14 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bls12-377/g1_test.go b/ecc/bls12-377/g1_test.go index 856e07440..a41aff06f 100644 --- a/ecc/bls12-377/g1_test.go +++ b/ecc/bls12-377/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BLS12-377] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BLS12-377] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go index f6149027a..3d9d52ded 100644 --- a/ecc/bls12-378/ecdsa/ecdsa.go +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bls12378.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bls12378.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bls12378.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bls12378.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12378.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bls12378.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bls12378.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12378.G1A Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bls12-378/ecdsa/ecdsa_test.go b/ecc/bls12-378/ecdsa/ecdsa_test.go index 7bda7f28f..7edae55ee 100644 --- a/ecc/bls12-378/ecdsa/ecdsa_test.go +++ b/ecc/bls12-378/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bls12-378" - "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS12-378] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bls12378.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls12378.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls12378.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bls12-378/g1.go b/ecc/bls12-378/g1.go index 1a839f014..85e515305 100644 --- a/ecc/bls12-378/g1.go +++ b/ecc/bls12-378/g1.go @@ -73,6 +73,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -527,13 +535,14 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bls12-378/g1_test.go b/ecc/bls12-378/g1_test.go index 0685a36e6..e16c91f2f 100644 --- a/ecc/bls12-378/g1_test.go +++ b/ecc/bls12-378/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BLS12-378] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BLS12-378] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go index e0d2fff3f..905ac0b96 100644 --- a/ecc/bls12-381/ecdsa/ecdsa.go +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bls12381.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bls12381.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bls12381.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bls12381.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12381.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bls12381.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bls12381.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bls12381.G1A Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bls12-381/ecdsa/ecdsa_test.go b/ecc/bls12-381/ecdsa/ecdsa_test.go index c911d1de5..d7561fce4 100644 --- a/ecc/bls12-381/ecdsa/ecdsa_test.go +++ b/ecc/bls12-381/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS12-381] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bls12381.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls12381.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls12381.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bls12-381/g1.go b/ecc/bls12-381/g1.go index 47f3d18e2..6f93fe409 100644 --- a/ecc/bls12-381/g1.go +++ b/ecc/bls12-381/g1.go @@ -73,6 +73,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -527,13 +535,14 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bls12-381/g1_test.go b/ecc/bls12-381/g1_test.go index 0efe897fe..cb2205a88 100644 --- a/ecc/bls12-381/g1_test.go +++ b/ecc/bls12-381/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BLS12-381] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BLS12-381] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go index 1be84b3f5..87700e4d3 100644 --- a/ecc/bls24-315/ecdsa/ecdsa.go +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bls24315.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bls24315.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bls24315.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bls24315.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bls24315.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bls24315.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bls24315.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bls24315.G1A Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bls24-315/ecdsa/ecdsa_test.go b/ecc/bls24-315/ecdsa/ecdsa_test.go index e2a14bb96..328e840a1 100644 --- a/ecc/bls24-315/ecdsa/ecdsa_test.go +++ b/ecc/bls24-315/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS24-315] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bls24315.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls24315.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls24315.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bls24-315/g1.go b/ecc/bls24-315/g1.go index 6d9030cac..762e42196 100644 --- a/ecc/bls24-315/g1.go +++ b/ecc/bls24-315/g1.go @@ -73,6 +73,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -529,13 +537,14 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bls24-315/g1_test.go b/ecc/bls24-315/g1_test.go index c9a9e6136..b88868eb3 100644 --- a/ecc/bls24-315/g1_test.go +++ b/ecc/bls24-315/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BLS24-315] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BLS24-315] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go index 6c323bd1a..0daa10c74 100644 --- a/ecc/bls24-317/ecdsa/ecdsa.go +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bls24317.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bls24317.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bls24317.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bls24317.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bls24317.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bls24317.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bls24317.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bls24317.G1A Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bls24-317/ecdsa/ecdsa_test.go b/ecc/bls24-317/ecdsa/ecdsa_test.go index 6084242e4..1c206b169 100644 --- a/ecc/bls24-317/ecdsa/ecdsa_test.go +++ b/ecc/bls24-317/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bls24-317" - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BLS24-317] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bls24317.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls24317.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bls24317.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bls24-317/g1.go b/ecc/bls24-317/g1.go index b02050f9b..ce5b72561 100644 --- a/ecc/bls24-317/g1.go +++ b/ecc/bls24-317/g1.go @@ -73,6 +73,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -529,13 +537,14 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bls24-317/g1_test.go b/ecc/bls24-317/g1_test.go index d50afe46c..87bc4b05c 100644 --- a/ecc/bls24-317/g1_test.go +++ b/ecc/bls24-317/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BLS24-317] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BLS24-317] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go index 863210264..120caaf0f 100644 --- a/ecc/bn254/ecdsa/ecdsa.go +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bn254.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bn254.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bn254.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bn254.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bn254.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bn254.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bn254.G1Affi Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bn254/ecdsa/ecdsa_test.go b/ecc/bn254/ecdsa/ecdsa_test.go index d070dd02a..31c1f6b74 100644 --- a/ecc/bn254/ecdsa/ecdsa_test.go +++ b/ecc/bn254/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BN254] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bn254.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bn254.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bn254.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bn254/g1.go b/ecc/bn254/g1.go index 7ba84474f..383acf536 100644 --- a/ecc/bn254/g1.go +++ b/ecc/bn254/g1.go @@ -73,6 +73,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -498,13 +506,14 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { return p } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bn254/g1_test.go b/ecc/bn254/g1_test.go index 637636bc1..1285562d8 100644 --- a/ecc/bn254/g1_test.go +++ b/ecc/bn254/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BN254] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BN254] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go index 0f09797d3..4167c0506 100644 --- a/ecc/bw6-633/ecdsa/ecdsa.go +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bw6633.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bw6633.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bw6633.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bw6633.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bw6633.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bw6633.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6633.G1Aff Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bw6-633/ecdsa/ecdsa_test.go b/ecc/bw6-633/ecdsa/ecdsa_test.go index dcb91dfb2..8738d8853 100644 --- a/ecc/bw6-633/ecdsa/ecdsa_test.go +++ b/ecc/bw6-633/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bw6-633" - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BW6-633] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bw6633.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bw6633.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bw6633.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bw6-633/g1.go b/ecc/bw6-633/g1.go index 03e530830..f6398338b 100644 --- a/ecc/bw6-633/g1.go +++ b/ecc/bw6-633/g1.go @@ -78,6 +78,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -557,13 +565,14 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bw6-633/g1_test.go b/ecc/bw6-633/g1_test.go index 23f7f901e..35e85d7e2 100644 --- a/ecc/bw6-633/g1_test.go +++ b/ecc/bw6-633/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BW6-633] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BW6-633] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go index 00b9b0c43..26eefd8ab 100644 --- a/ecc/bw6-756/ecdsa/ecdsa.go +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bw6756.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bw6756.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bw6756.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bw6756.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bw6756.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bw6756.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6756.G1Aff Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bw6-756/ecdsa/ecdsa_test.go b/ecc/bw6-756/ecdsa/ecdsa_test.go index d241ed250..7bef2959f 100644 --- a/ecc/bw6-756/ecdsa/ecdsa_test.go +++ b/ecc/bw6-756/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bw6-756" - "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BW6-756] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bw6756.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bw6756.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bw6756.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bw6-756/g1.go b/ecc/bw6-756/g1.go index 7d7938fea..28fd27815 100644 --- a/ecc/bw6-756/g1.go +++ b/ecc/bw6-756/g1.go @@ -78,6 +78,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -557,13 +565,14 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { return p } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bw6-756/g1_test.go b/ecc/bw6-756/g1_test.go index 2a315fa2e..b8babbd96 100644 --- a/ecc/bw6-756/g1_test.go +++ b/ecc/bw6-756/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BW6-756] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BW6-756] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go index a14c4cd5b..983ad8399 100644 --- a/ecc/bw6-761/ecdsa/ecdsa.go +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base bw6761.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, _, g, _ := bw6761.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R bw6761.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P bw6761.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey bw6761.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U bw6761.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey bw6761.G1Aff Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/bw6-761/ecdsa/ecdsa_test.go b/ecc/bw6-761/ecdsa/ecdsa_test.go index fdda4b111..b23d37a6e 100644 --- a/ecc/bw6-761/ecdsa/ecdsa_test.go +++ b/ecc/bw6-761/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bw6-761" - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[BW6-761] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, _, g, _ := bw6761.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bw6761.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, _, g, _ := bw6761.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/bw6-761/g1.go b/ecc/bw6-761/g1.go index 6e31d3cdc..ab29f2f24 100644 --- a/ecc/bw6-761/g1.go +++ b/ecc/bw6-761/g1.go @@ -78,6 +78,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -568,13 +576,14 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/bw6-761/g1_test.go b/ecc/bw6-761/g1_test.go index 786f2d52d..3de514f40 100644 --- a/ecc/bw6-761/g1_test.go +++ b/ecc/bw6-761/g1_test.go @@ -393,25 +393,18 @@ func TestG1AffineOps(t *testing.T) { }, genScalar, )) - properties.Property("[BW6-761] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + properties.Property("[BW6-761] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp G1Jac - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index 67ab9b082..f8deef8d5 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base secp256k1.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, g := secp256k1.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R secp256k1.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P secp256k1.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey secp256k1.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U secp256k1.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey secp256k1.G1 Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go index 2b8955ce7..2ddc0cdd1 100644 --- a/ecc/secp256k1/ecdsa/ecdsa_test.go +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/secp256k1" - "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[SECP256K1] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, g := secp256k1.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, g := secp256k1.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, g := secp256k1.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/secp256k1/g1.go b/ecc/secp256k1/g1.go index e3a150cf0..c65572e33 100644 --- a/ecc/secp256k1/g1.go +++ b/ecc/secp256k1/g1.go @@ -73,6 +73,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplication computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -498,13 +506,14 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { return p } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac diff --git a/ecc/secp256k1/g1_test.go b/ecc/secp256k1/g1_test.go index 0de1717a8..ff87f98da 100644 --- a/ecc/secp256k1/g1_test.go +++ b/ecc/secp256k1/g1_test.go @@ -398,6 +398,23 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) + properties.Property("[SECP256K1] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { + + var op1, op2, temp G1Jac + + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) + + return op1.Equal(&op2) + + }, + genScalar, + genScalar, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index 58c0f7f15..d8ac06c73 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -35,57 +35,52 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base starkcurve.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + _, g := starkcurve.Generators() privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -95,7 +90,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -158,71 +153,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R starkcurve.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P starkcurve.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey starkcurve.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey starkcurve.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) var U starkcurve.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -230,8 +229,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey starkcurve.G Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/ecc/stark-curve/ecdsa/ecdsa_test.go b/ecc/stark-curve/ecdsa/ecdsa_test.go index 666a2ba79..09f577476 100644 --- a/ecc/stark-curve/ecdsa/ecdsa_test.go +++ b/ecc/stark-curve/ecdsa/ecdsa_test.go @@ -20,8 +20,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/stark-curve" - "github.com/consensys/gnark-crypto/ecc/stark-curve/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -35,17 +33,12 @@ func TestECDSA(t *testing.T) { properties.Property("[STARK-CURVE] test the signing and verification", prop.ForAll( func() bool { - var pp Params - _, g := starkcurve.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -56,32 +49,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - _, g := starkcurve.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - _, g := starkcurve.Generators() - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } diff --git a/ecc/stark-curve/g1.go b/ecc/stark-curve/g1.go index 79424ceb5..cc71db005 100644 --- a/ecc/stark-curve/g1.go +++ b/ecc/stark-curve/g1.go @@ -72,6 +72,14 @@ func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { return p } +// ScalarMultiplication computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulWindowed(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. // This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { @@ -422,26 +430,30 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]G1Jac + var k1, k2 big.Int if s1.Sign() == -1 { - s1.Neg(s1) + k1.Neg(s1) table[0].Neg(&p1) } else { + k1.Set(s1) table[0].Set(&p1) } if s2.Sign() == -1 { - s2.Neg(s2) + k2.Neg(s2) table[3].Neg(&p2) } else { + k2.Set(s2) table[3].Set(&p2) } @@ -461,12 +473,12 @@ func (p *G1Jac) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.In table[14].Set(&table[11]).AddAssign(&table[2]) var s [2]fr.Element - s[0] = s[0].SetBigInt(s1).Bits() - s[1] = s[1].SetBigInt(s2).Bits() + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() } hiWordIndex := (maxBit - 1) / 64 diff --git a/ecc/stark-curve/g1_test.go b/ecc/stark-curve/g1_test.go index 065aacebf..4af91886a 100644 --- a/ecc/stark-curve/g1_test.go +++ b/ecc/stark-curve/g1_test.go @@ -361,25 +361,17 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[STARK-CURVE] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( + properties.Property("[STARK-CURVE] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( func(s1, s2 fr.Element) bool { - var g1, g2 G1Affine - g1.Set(&g1GenAff) - g2.Set(&g1GenAff) + var op1, op2, temp G1Jac - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - var p1, p2 G1Jac - p1.ScalarMultiplication(&g1Gen, &_s1) - p2.ScalarMultiplication(&g1Gen, &_s2). - AddAssign(&p1) - - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) - - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, diff --git a/internal/generator/ecc/template/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl index 93d62b584..746087ec7 100644 --- a/internal/generator/ecc/template/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -86,6 +86,15 @@ func (p *{{ $TJacobian }}) ScalarMultiplicationAffine(a *{{ $TAffine }}, s *big. {{- end }} return p } + +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *{{ $TAffine }}) ScalarMultiplicationBase(s *big.Int) *{{ $TAffine }} { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + {{- end}} // Add adds two point in affine coordinates. @@ -1124,13 +1133,14 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{ end }} {{ if eq .PointName "g1" }} -// JointScalarMultiplication computes [a]P+[b]Q using Straus-Shamir technique -func (p *{{$TJacobian}}) JointScalarMultiplicationAffine(a1, a2 *G1Affine, s1, s2 *big.Int) *{{$TJacobian}} { +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *{{$TJacobian}}) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *{{$TJacobian}} { var res, p1, p2 {{$TJacobian}} res.Set(&{{ toLower .PointName }}Infinity) - p1.FromAffine(a1) - p2.FromAffine(a2) + p1.Set(&g1Gen) + p2.FromAffine(a) var table [15]{{$TJacobian}} diff --git a/internal/generator/ecc/template/tests/point.go.tmpl b/internal/generator/ecc/template/tests/point.go.tmpl index bd9da4b50..db5cc6b88 100644 --- a/internal/generator/ecc/template/tests/point.go.tmpl +++ b/internal/generator/ecc/template/tests/point.go.tmpl @@ -437,36 +437,29 @@ func Test{{ $TAffine }}Ops(t *testing.T) { genScalar, )) - {{- if eq .PointName "g1"}} - properties.Property("[{{ toUpper .Name }}] JointScalarMultiplication and [a]P+[b]Q should output the same result", prop.ForAll( - func(s1, s2 fr.Element) bool { - var g1, g2 {{ $TAffine }} - g1.Set(&{{.PointName}}GenAff) - g2.Set(&{{.PointName}}GenAff) + {{end}} - var _s1, _s2 big.Int - s1.BigInt(&_s1) - s2.BigInt(&_s2) + {{- if eq .PointName "g1" }} + properties.Property("[{{ toUpper .Name }}] JointScalarMultiplicationBase and ScalarMultiplication should output the same results", prop.ForAll( + func(s1, s2 fr.Element) bool { - var p1, p2 G1Jac - p1.ScalarMultiplication(&{{.PointName}}Gen, &_s1) - p2.ScalarMultiplication(&{{.PointName}}Gen, &_s2). - AddAssign(&p1) + var op1, op2, temp {{ $TJacobian }} - p1.JointScalarMultiplicationAffine(&g1, &g2, &_s1, &_s2) + op1.JointScalarMultiplicationBase(&g1GenAff, s1.BigInt(new(big.Int)), s2.BigInt(new(big.Int))) + temp.ScalarMultiplication(&g1Gen, s2.BigInt(new(big.Int))) + op2.ScalarMultiplication(&g1Gen, s1.BigInt(new(big.Int))). + AddAssign(&temp) - return p1.Equal(&p2) + return op1.Equal(&op2) }, genScalar, genScalar, )) - {{end}} - - {{end}} + {{- end }} properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index e03aae183..bdb7a88f5 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -17,57 +17,57 @@ type PublicKey struct { // PrivateKey represents an ECDSA private key type PrivateKey struct { PublicKey - Secret big.Int + Secret *big.Int } // Signature represents an ECDSA signature type Signature struct { - R, S big.Int -} - -// Params are the ECDSA public parameters -type Params struct { - Base {{ .CurvePackage }}.G1Affine - Order *big.Int + R, S *big.Int } var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the order of the given // curve using the procedure given in FIPS 186-4, Appendix B.5.1. -func (pp Params) randFieldElement(rand io.Reader) (k big.Int, err error) { +func randFieldElement(rand io.Reader) (k *big.Int, err error) { b := make([]byte, fr.Bits/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } - k = *new(big.Int).SetBytes(b) - n := new(big.Int).Sub(pp.Order, one) - k.Mod(&k, n) - k.Add(&k, one) + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(fr.Modulus(), one) + k.Mod(k, n) + k.Add(k, one) return } // GenerateKey generates a public and private key pair. -func (pp Params) GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey(rand io.Reader) (*PrivateKey, error) { - k, err := pp.randFieldElement(rand) + k, err := randFieldElement(rand) if err != nil { return nil, err } + {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} + _, g := {{ .CurvePackage }}.Generators() + {{- else}} + _, _, g, _ := {{ .CurvePackage }}.Generators() + {{- end}} + privateKey := new(PrivateKey) privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&pp.Base, &k) + privateKey.PublicKey.Q.ScalarMultiplication(&g, k) return privateKey, nil } // hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) big.Int { +func hashToInt(hash []byte) *big.Int { if len(hash) > fr.Bytes { hash = hash[:fr.Bytes] } @@ -77,7 +77,7 @@ func hashToInt(hash []byte) big.Int { if excess > 0 { ret.Rsh(ret, uint(excess)) } - return *ret + return ret } type zr struct{} @@ -140,71 +140,75 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Sign performs the ECDSA signature // // k ← 𝔽r (random) -// R = k ⋅ Base -// r = x_R (mod Order) +// P = k ⋅ g1Gen +// r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func (pp Params) Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - var kInv big.Int +func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { + order := fr.Modulus() + r, s, kInv := new(big.Int), new(big.Int), new(big.Int) for { for { csprng, err := nonce(rand, &privateKey, hash) if err != nil { return Signature{}, err } - k, err := pp.randFieldElement(csprng) + k, err := randFieldElement(csprng) if err != nil { return Signature{}, err } - var R {{ .CurvePackage }}.G1Affine - R.ScalarMultiplication(&pp.Base, &k) - kInv.ModInverse(&k, pp.Order) + var P {{ .CurvePackage }}.G1Affine + P.ScalarMultiplicationBase(k) + kInv.ModInverse(k, order) - R.X.BigInt(&signature.R) - signature.R.Mod(&signature.R, pp.Order) - if signature.R.Sign() != 0 { + P.X.BigInt(r) + r.Mod(r, order) + if r.Sign() != 0 { break } } - signature.S.Mul(&signature.R, &privateKey.Secret) + s.Mul(r, privateKey.Secret) m := hashToInt(hash) - signature.S.Add(&m, &signature.S). - Mul(&kInv, &signature.S). - Mod(&signature.S, pp.Order) // pp.Order != 0 - if signature.S.Sign() != 0 { - break + s.Add(m, s). + Mul(kInv, s). + Mod(s, order) // order != 0 + if s.Sign() != 0 { + break } } + signature.R, signature.S = r, s + return signature, err } // Verify validates the ECDSA signature // -// R ?= s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ r ⋅ publiKey +// R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func (pp Params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePackage }}.G1Affine) bool { +func Verify(hash []byte, signature Signature, publicKey {{ .CurvePackage }}.G1Affine) bool { + + order := fr.Modulus() if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { return false } - if signature.R.Cmp(pp.Order) >= 0 || signature.S.Cmp(pp.Order) >= 0 { + if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { return false } - sInv := new(big.Int).ModInverse(&signature.S, pp.Order) + sInv := new(big.Int).ModInverse(signature.S, order) e := hashToInt(hash) - u1 := new(big.Int).Mul(&e, sInv) - u1.Mod(u1, pp.Order) - u2 := new(big.Int).Mul(&signature.R, sInv) - u2.Mod(u2, pp.Order) - - var U {{ .CurvePackage }}.G1Jac - U.JointScalarMultiplicationAffine(&pp.Base, &publicKey, u1, u2) + u1 := new(big.Int).Mul(e, sInv) + u1.Mod(u1, order) + u2 := new(big.Int).Mul(signature.R, sInv) + u2.Mod(u2, order) + var U {{ .CurvePackage }}.G1Jac + U.JointScalarMultiplicationBase(&publicKey, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -212,8 +216,8 @@ func (pp Params) Verify(hash []byte, signature Signature, publicKey {{ .CurvePac Mul(&U.Z, &U.X). BigInt(&z) - z.Mod(&z, pp.Order) + z.Mod(&z, order) - return z.Cmp(&signature.R) == 0 + return z.Cmp(signature.R) == 0 } diff --git a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl index 6b25f25f8..c7f4c74d3 100644 --- a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl @@ -2,8 +2,6 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/{{ .Name }}" - "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -17,21 +15,12 @@ func TestECDSA(t *testing.T) { properties.Property("[{{ toUpper .Name }}] test the signing and verification", prop.ForAll( func() bool { - var pp Params - {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} - _, g := {{ .CurvePackage }}.Generators() - {{- else}} - _, _, g, _ := {{ .CurvePackage }}.Generators() - {{- end}} - pp.Base.Set(&g) - pp.Order = fr.Modulus() - - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("testing ECDSA") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) - return pp.Verify(hash, signature, privKey.PublicKey.Q) + return Verify(hash, signature, privKey.PublicKey.Q) }, )) @@ -42,40 +31,24 @@ func TestECDSA(t *testing.T) { // benches func BenchmarkSignECDSA(b *testing.B) { - var pp Params - {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} - _, g := {{ .CurvePackage }}.Generators() - {{- else}} - _, _, g, _ := {{ .CurvePackage }}.Generators() - {{- end}} - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Sign(hash, *privKey, rand.Reader) + Sign(hash, *privKey, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { - var pp Params - {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} - _, g := {{ .CurvePackage }}.Generators() - {{- else}} - _, _, g, _ := {{ .CurvePackage }}.Generators() - {{- end}} - pp.Base.Set(&g) - pp.Order = fr.Modulus() - privKey, _ := pp.GenerateKey(rand.Reader) + privKey, _ := GenerateKey(rand.Reader) hash := []byte("benchmarking ECDSA sign()") - signature, _ := pp.Sign(hash, *privKey, rand.Reader) + signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - pp.Verify(hash, signature, privKey.PublicKey.Q) + Verify(hash, signature, privKey.PublicKey.Q) } } From 12ea0ab6d592ab654732df6bdab9fb1181665931 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 23 Jan 2023 19:05:27 +0100 Subject: [PATCH 14/18] refactor(ecdsa): marshal + follow interface --- ecc/bls12-377/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bls12-377/ecdsa/ecdsa_test.go | 22 ++-- ecc/bls12-377/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bls12-377/ecdsa/marshal_test.go | 64 ++++++++++ ecc/bls12-378/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bls12-378/ecdsa/ecdsa_test.go | 22 ++-- ecc/bls12-378/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bls12-378/ecdsa/marshal_test.go | 64 ++++++++++ ecc/bls12-381/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bls12-381/ecdsa/ecdsa_test.go | 22 ++-- ecc/bls12-381/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bls12-381/ecdsa/marshal_test.go | 64 ++++++++++ ecc/bls24-315/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bls24-315/ecdsa/ecdsa_test.go | 22 ++-- ecc/bls24-315/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bls24-315/ecdsa/marshal_test.go | 64 ++++++++++ ecc/bls24-317/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bls24-317/ecdsa/ecdsa_test.go | 22 ++-- ecc/bls24-317/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bls24-317/ecdsa/marshal_test.go | 64 ++++++++++ ecc/bn254/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bn254/ecdsa/ecdsa_test.go | 22 ++-- ecc/bn254/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bn254/ecdsa/marshal_test.go | 64 ++++++++++ ecc/bw6-633/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bw6-633/ecdsa/ecdsa_test.go | 22 ++-- ecc/bw6-633/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bw6-633/ecdsa/marshal_test.go | 64 ++++++++++ ecc/bw6-756/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bw6-756/ecdsa/ecdsa_test.go | 22 ++-- ecc/bw6-756/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bw6-756/ecdsa/marshal_test.go | 64 ++++++++++ ecc/bw6-761/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/bw6-761/ecdsa/ecdsa_test.go | 22 ++-- ecc/bw6-761/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/bw6-761/ecdsa/marshal_test.go | 64 ++++++++++ ecc/secp256k1/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/secp256k1/ecdsa/ecdsa_test.go | 22 ++-- ecc/secp256k1/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/secp256k1/ecdsa/marshal_test.go | 64 ++++++++++ ecc/secp256k1/marshal.go | 78 ++++++++++++ ecc/secp256k1/marshal_test.go | 82 +++++++++++++ ecc/stark-curve/ecdsa/ecdsa.go | 116 ++++++++++++------ ecc/stark-curve/ecdsa/ecdsa_test.go | 22 ++-- ecc/stark-curve/ecdsa/marshal.go | 108 ++++++++++++++++ ecc/stark-curve/ecdsa/marshal_test.go | 64 ++++++++++ ecc/stark-curve/marshal.go | 80 ++++++++++++ ecc/stark-curve/marshal_test.go | 82 +++++++++++++ internal/generator/ecdsa/generate.go | 2 + .../generator/ecdsa/template/ecdsa.go.tmpl | 116 ++++++++++++------ .../ecdsa/template/ecdsa.test.go.tmpl | 22 ++-- .../generator/ecdsa/template/marshal.go.tmpl | 98 +++++++++++++++ .../ecdsa/template/marshal.test.go.tmpl | 46 +++++++ signature/ecdsa/ecdsa.go | 63 ++++++++++ 54 files changed, 3517 insertions(+), 562 deletions(-) create mode 100644 ecc/bls12-377/ecdsa/marshal.go create mode 100644 ecc/bls12-377/ecdsa/marshal_test.go create mode 100644 ecc/bls12-378/ecdsa/marshal.go create mode 100644 ecc/bls12-378/ecdsa/marshal_test.go create mode 100644 ecc/bls12-381/ecdsa/marshal.go create mode 100644 ecc/bls12-381/ecdsa/marshal_test.go create mode 100644 ecc/bls24-315/ecdsa/marshal.go create mode 100644 ecc/bls24-315/ecdsa/marshal_test.go create mode 100644 ecc/bls24-317/ecdsa/marshal.go create mode 100644 ecc/bls24-317/ecdsa/marshal_test.go create mode 100644 ecc/bn254/ecdsa/marshal.go create mode 100644 ecc/bn254/ecdsa/marshal_test.go create mode 100644 ecc/bw6-633/ecdsa/marshal.go create mode 100644 ecc/bw6-633/ecdsa/marshal_test.go create mode 100644 ecc/bw6-756/ecdsa/marshal.go create mode 100644 ecc/bw6-756/ecdsa/marshal_test.go create mode 100644 ecc/bw6-761/ecdsa/marshal.go create mode 100644 ecc/bw6-761/ecdsa/marshal_test.go create mode 100644 ecc/secp256k1/ecdsa/marshal.go create mode 100644 ecc/secp256k1/ecdsa/marshal_test.go create mode 100644 ecc/secp256k1/marshal.go create mode 100644 ecc/secp256k1/marshal_test.go create mode 100644 ecc/stark-curve/ecdsa/marshal.go create mode 100644 ecc/stark-curve/ecdsa/marshal_test.go create mode 100644 ecc/stark-curve/marshal.go create mode 100644 ecc/stark-curve/marshal_test.go create mode 100644 internal/generator/ecdsa/template/marshal.go.tmpl create mode 100644 internal/generator/ecdsa/template/marshal.test.go.tmpl create mode 100644 signature/ecdsa/ecdsa.go diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go index 8edd7092a..02bd4a194 100644 --- a/ecc/bls12-377/ecdsa/ecdsa.go +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bls12377.G1Affine + A bls12377.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bls12377.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bls12377.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bls12377.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bls12377.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bls12377.G1Affine) bool z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bls12-377/ecdsa/ecdsa_test.go b/ecc/bls12-377/ecdsa/ecdsa_test.go index 0b37d238a..6573079f9 100644 --- a/ecc/bls12-377/ecdsa/ecdsa_test.go +++ b/ecc/bls12-377/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bls12-377/ecdsa/marshal.go b/ecc/bls12-377/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bls12-377/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls12-377/ecdsa/marshal_test.go b/ecc/bls12-377/ecdsa/marshal_test.go new file mode 100644 index 000000000..4cbe081d4 --- /dev/null +++ b/ecc/bls12-377/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-377] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go index 3d9d52ded..9aad11043 100644 --- a/ecc/bls12-378/ecdsa/ecdsa.go +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bls12-378" + "github.com/consensys/gnark-crypto/ecc/bls12-378/fp" "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bls12378.G1Affine + A bls12378.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bls12378.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bls12378.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bls12378.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bls12378.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bls12378.G1Affine) bool z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bls12-378/ecdsa/ecdsa_test.go b/ecc/bls12-378/ecdsa/ecdsa_test.go index 7edae55ee..8b5551fd7 100644 --- a/ecc/bls12-378/ecdsa/ecdsa_test.go +++ b/ecc/bls12-378/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bls12-378/ecdsa/marshal.go b/ecc/bls12-378/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bls12-378/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls12-378/ecdsa/marshal_test.go b/ecc/bls12-378/ecdsa/marshal_test.go new file mode 100644 index 000000000..5d41f7401 --- /dev/null +++ b/ecc/bls12-378/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-378] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go index 905ac0b96..49c60d3e9 100644 --- a/ecc/bls12-381/ecdsa/ecdsa.go +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bls12381.G1Affine + A bls12381.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bls12381.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bls12381.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bls12381.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bls12381.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bls12381.G1Affine) bool z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bls12-381/ecdsa/ecdsa_test.go b/ecc/bls12-381/ecdsa/ecdsa_test.go index d7561fce4..1c5abb240 100644 --- a/ecc/bls12-381/ecdsa/ecdsa_test.go +++ b/ecc/bls12-381/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bls12-381/ecdsa/marshal.go b/ecc/bls12-381/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bls12-381/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls12-381/ecdsa/marshal_test.go b/ecc/bls12-381/ecdsa/marshal_test.go new file mode 100644 index 000000000..1cf4318ed --- /dev/null +++ b/ecc/bls12-381/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-381] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go index 87700e4d3..c5e057d27 100644 --- a/ecc/bls24-315/ecdsa/ecdsa.go +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fp" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bls24315.G1Affine + A bls24315.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bls24315.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bls24315.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bls24315.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bls24315.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bls24315.G1Affine) bool z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bls24-315/ecdsa/ecdsa_test.go b/ecc/bls24-315/ecdsa/ecdsa_test.go index 328e840a1..9356788e8 100644 --- a/ecc/bls24-315/ecdsa/ecdsa_test.go +++ b/ecc/bls24-315/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bls24-315/ecdsa/marshal.go b/ecc/bls24-315/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bls24-315/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls24-315/ecdsa/marshal_test.go b/ecc/bls24-315/ecdsa/marshal_test.go new file mode 100644 index 000000000..c8e427470 --- /dev/null +++ b/ecc/bls24-315/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS24-315] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go index 0daa10c74..8823824fb 100644 --- a/ecc/bls24-317/ecdsa/ecdsa.go +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fp" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bls24317.G1Affine + A bls24317.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bls24317.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bls24317.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bls24317.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bls24317.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bls24317.G1Affine) bool z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bls24-317/ecdsa/ecdsa_test.go b/ecc/bls24-317/ecdsa/ecdsa_test.go index 1c206b169..65c9f3eb1 100644 --- a/ecc/bls24-317/ecdsa/ecdsa_test.go +++ b/ecc/bls24-317/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bls24-317/ecdsa/marshal.go b/ecc/bls24-317/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bls24-317/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls24-317/ecdsa/marshal_test.go b/ecc/bls24-317/ecdsa/marshal_test.go new file mode 100644 index 000000000..1d04d711d --- /dev/null +++ b/ecc/bls24-317/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS24-317] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go index 120caaf0f..543a1c104 100644 --- a/ecc/bn254/ecdsa/ecdsa.go +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bn254.G1Affine + A bn254.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bn254.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bn254.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bn254.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bn254.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bn254.G1Affine) bool { z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bn254/ecdsa/ecdsa_test.go b/ecc/bn254/ecdsa/ecdsa_test.go index 31c1f6b74..233427e5d 100644 --- a/ecc/bn254/ecdsa/ecdsa_test.go +++ b/ecc/bn254/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bn254/ecdsa/marshal.go b/ecc/bn254/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bn254/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bn254/ecdsa/marshal_test.go b/ecc/bn254/ecdsa/marshal_test.go new file mode 100644 index 000000000..5697c241d --- /dev/null +++ b/ecc/bn254/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BN254] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go index 4167c0506..ff9cfccbc 100644 --- a/ecc/bw6-633/ecdsa/ecdsa.go +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fp" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bw6633.G1Affine + A bw6633.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bw6633.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bw6633.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bw6633.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bw6633.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bw6633.G1Affine) bool { z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bw6-633/ecdsa/ecdsa_test.go b/ecc/bw6-633/ecdsa/ecdsa_test.go index 8738d8853..8c44212c5 100644 --- a/ecc/bw6-633/ecdsa/ecdsa_test.go +++ b/ecc/bw6-633/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bw6-633/ecdsa/marshal.go b/ecc/bw6-633/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bw6-633/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bw6-633/ecdsa/marshal_test.go b/ecc/bw6-633/ecdsa/marshal_test.go new file mode 100644 index 000000000..5fc8c2133 --- /dev/null +++ b/ecc/bw6-633/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-633] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go index 26eefd8ab..2a86f9c91 100644 --- a/ecc/bw6-756/ecdsa/ecdsa.go +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bw6-756" + "github.com/consensys/gnark-crypto/ecc/bw6-756/fp" "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bw6756.G1Affine + A bw6756.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bw6756.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bw6756.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bw6756.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bw6756.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bw6756.G1Affine) bool { z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bw6-756/ecdsa/ecdsa_test.go b/ecc/bw6-756/ecdsa/ecdsa_test.go index 7bef2959f..560fc4be8 100644 --- a/ecc/bw6-756/ecdsa/ecdsa_test.go +++ b/ecc/bw6-756/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bw6-756/ecdsa/marshal.go b/ecc/bw6-756/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bw6-756/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bw6-756/ecdsa/marshal_test.go b/ecc/bw6-756/ecdsa/marshal_test.go new file mode 100644 index 000000000..48fd0f03c --- /dev/null +++ b/ecc/bw6-756/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-756] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go index 983ad8399..71ad4b3b4 100644 --- a/ecc/bw6-761/ecdsa/ecdsa.go +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q bw6761.G1Affine + A bw6761.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, _, g, _ := bw6761.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P bw6761.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey bw6761.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U bw6761.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey bw6761.G1Affine) bool { z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/bw6-761/ecdsa/ecdsa_test.go b/ecc/bw6-761/ecdsa/ecdsa_test.go index b23d37a6e..c37ed7ae9 100644 --- a/ecc/bw6-761/ecdsa/ecdsa_test.go +++ b/ecc/bw6-761/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/bw6-761/ecdsa/marshal.go b/ecc/bw6-761/ecdsa/marshal.go new file mode 100644 index 000000000..72d74c5cb --- /dev/null +++ b/ecc/bw6-761/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bw6-761/ecdsa/marshal_test.go b/ecc/bw6-761/ecdsa/marshal_test.go new file mode 100644 index 000000000..3c41062a2 --- /dev/null +++ b/ecc/bw6-761/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-761] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index f8deef8d5..74aa9e651 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/secp256k1" + "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = 2 * sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q secp256k1.G1Affine + A secp256k1.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, g := secp256k1.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P secp256k1.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey secp256k1.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U secp256k1.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey secp256k1.G1Affine) bool z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go index 2ddc0cdd1..32f5da0cf 100644 --- a/ecc/secp256k1/ecdsa/ecdsa_test.go +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/secp256k1/ecdsa/marshal.go b/ecc/secp256k1/ecdsa/marshal.go new file mode 100644 index 000000000..ff04c7d94 --- /dev/null +++ b/ecc/secp256k1/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.RawBytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.RawBytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/secp256k1/ecdsa/marshal_test.go b/ecc/secp256k1/ecdsa/marshal_test.go new file mode 100644 index 000000000..b5a7f1af1 --- /dev/null +++ b/ecc/secp256k1/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[SECP256K1] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/secp256k1/marshal.go b/ecc/secp256k1/marshal.go new file mode 100644 index 000000000..de81d4006 --- /dev/null +++ b/ecc/secp256k1/marshal.go @@ -0,0 +1,78 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package secp256k1 + +import ( + "errors" + "io" + + "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" +) + +// SizeOfG1AffineCompressed represents the size in bytes that a G1Affine need in binary form, compressed +const SizeOfG1AffineCompressed = 32 + +// SizeOfG1AffineUncompressed represents the size in bytes that a G1Affine need in binary form, uncompressed +const SizeOfG1AffineUncompressed = SizeOfG1AffineCompressed * 2 + +// RawBytes returns binary representation of p (stores X and Y coordinate) +func (p *G1Affine) RawBytes() (res [SizeOfG1AffineUncompressed]byte) { + + // not compressed + // we store the Y coordinate + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[32:32+fp.Bytes]), p.Y) + + // we store the X coordinate + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) + + return +} + +// SetBytes sets p from binary representation in buf and returns number of consumed bytes +// +// bytes in buf must match RawBytes() +// +// if buf is too short io.ErrShortBuffer is returned +// +// this check if the resulting point is on the curve and in the correct subgroup +func (p *G1Affine) SetBytes(buf []byte) (int, error) { + return p.setBytes(buf, true) +} + +// we store both X and Y and there is no spare bit for flagging +func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { + if len(buf) < SizeOfG1AffineCompressed { + return 0, io.ErrShortBuffer + } + + // uncompressed point + // read X and Y coordinates + if err := p.X.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.Y.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineUncompressed, nil + +} diff --git a/ecc/secp256k1/marshal_test.go b/ecc/secp256k1/marshal_test.go new file mode 100644 index 000000000..9195ed864 --- /dev/null +++ b/ecc/secp256k1/marshal_test.go @@ -0,0 +1,82 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package secp256k1 + +import ( + "math/big" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" + + "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" +) + +func TestG1AffineSerialization(t *testing.T) { + t.Parallel() + // test round trip serialization of infinity + { + // uncompressed + { + var p1, p2 G1Affine + p2.X.SetRandom() + p2.Y.SetRandom() + buf := p1.RawBytes() + n, err := p2.SetBytes(buf[:]) + if err != nil { + t.Fatal(err) + } + if n != SizeOfG1AffineUncompressed { + t.Fatal("invalid number of bytes consumed in buffer") + } + if !(p2.X.IsZero() && p2.Y.IsZero()) { + t.Fatal("deserialization of uncompressed infinity point is not infinity") + } + } + } + + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[G1] Affine SetBytes(RawBytes) should stay the same", prop.ForAll( + func(a fp.Element) bool { + var start, end G1Affine + var ab big.Int + a.BigInt(&ab) + start.ScalarMultiplication(&g1GenAff, &ab) + + buf := start.RawBytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != SizeOfG1AffineUncompressed { + return false + } + return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) + }, + GenFp(), + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index d8ac06c73..8e9525fa4 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -20,27 +20,44 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/stark-curve" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" "github.com/consensys/gnark-crypto/ecc/stark-curve/fr" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = 2 * sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q starkcurve.G1Affine + A starkcurve.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -55,7 +72,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -72,8 +89,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { _, g := starkcurve.Generators() privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -81,12 +98,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] + if len(hash) > sizeFr { + hash = hash[:sizeFr] } - ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -112,7 +128,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -131,10 +147,10 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, - md.Write(entropy) // the entropy, - md.Write(hash) // and the input hash; - key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), // which is an indifferentiable MAC. // Create an AES-CTR instance to use as a CSPRNG. @@ -150,6 +166,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -159,18 +193,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P starkcurve.G1Affine @@ -183,8 +217,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -193,9 +227,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -203,25 +239,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey starkcurve.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() - - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err } - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) + u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U starkcurve.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -231,6 +269,6 @@ func Verify(hash []byte, signature Signature, publicKey starkcurve.G1Affine) boo z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/ecc/stark-curve/ecdsa/ecdsa_test.go b/ecc/stark-curve/ecdsa/ecdsa_test.go index 09f577476..fb6093df5 100644 --- a/ecc/stark-curve/ecdsa/ecdsa_test.go +++ b/ecc/stark-curve/ecdsa/ecdsa_test.go @@ -18,6 +18,7 @@ package ecdsa import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -34,11 +35,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -52,21 +57,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/ecc/stark-curve/ecdsa/marshal.go b/ecc/stark-curve/ecdsa/marshal.go new file mode 100644 index 000000000..ff04c7d94 --- /dev/null +++ b/ecc/stark-curve/ecdsa/marshal.go @@ -0,0 +1,108 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.RawBytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.RawBytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/stark-curve/ecdsa/marshal_test.go b/ecc/stark-curve/ecdsa/marshal_test.go new file mode 100644 index 000000000..da2130c6d --- /dev/null +++ b/ecc/stark-curve/ecdsa/marshal_test.go @@ -0,0 +1,64 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package ecdsa + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[STARK-CURVE] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/stark-curve/marshal.go b/ecc/stark-curve/marshal.go new file mode 100644 index 000000000..64465a6f6 --- /dev/null +++ b/ecc/stark-curve/marshal.go @@ -0,0 +1,80 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package starkcurve + +import ( + "errors" + "io" + + "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" +) + +// TODO (@yelhousni): compressed coordinates + complete marshal + +// SizeOfG1AffineCompressed represents the size in bytes that a G1Affine need in binary form, compressed +const SizeOfG1AffineCompressed = 32 + +// SizeOfG1AffineUncompressed represents the size in bytes that a G1Affine need in binary form, uncompressed +const SizeOfG1AffineUncompressed = SizeOfG1AffineCompressed * 2 + +// RawBytes returns binary representation of p (stores X and Y coordinate) +func (p *G1Affine) RawBytes() (res [SizeOfG1AffineUncompressed]byte) { + + // not compressed + // we store the Y coordinate + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[32:32+fp.Bytes]), p.Y) + + // we store the X coordinate + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) + + return +} + +// SetBytes sets p from binary representation in buf and returns number of consumed bytes +// +// bytes in buf must match RawBytes() +// +// if buf is too short io.ErrShortBuffer is returned +// +// this check if the resulting point is on the curve and in the correct subgroup +func (p *G1Affine) SetBytes(buf []byte) (int, error) { + return p.setBytes(buf, true) +} + +// we store both X and Y and there is no spare bit for flagging +func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { + if len(buf) < SizeOfG1AffineCompressed { + return 0, io.ErrShortBuffer + } + + // uncompressed point + // read X and Y coordinates + if err := p.X.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.Y.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineUncompressed, nil + +} diff --git a/ecc/stark-curve/marshal_test.go b/ecc/stark-curve/marshal_test.go new file mode 100644 index 000000000..15c0af7b1 --- /dev/null +++ b/ecc/stark-curve/marshal_test.go @@ -0,0 +1,82 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package starkcurve + +import ( + "math/big" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" + + "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" +) + +func TestG1AffineSerialization(t *testing.T) { + t.Parallel() + // test round trip serialization of infinity + { + // uncompressed + { + var p1, p2 G1Affine + p2.X.SetRandom() + p2.Y.SetRandom() + buf := p1.RawBytes() + n, err := p2.SetBytes(buf[:]) + if err != nil { + t.Fatal(err) + } + if n != SizeOfG1AffineUncompressed { + t.Fatal("invalid number of bytes consumed in buffer") + } + if !(p2.X.IsZero() && p2.Y.IsZero()) { + t.Fatal("deserialization of uncompressed infinity point is not infinity") + } + } + } + + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[G1] Affine SetBytes(RawBytes) should stay the same", prop.ForAll( + func(a fp.Element) bool { + var start, end G1Affine + var ab big.Int + a.BigInt(&ab) + start.ScalarMultiplication(&g1GenAff, &ab) + + buf := start.RawBytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != SizeOfG1AffineUncompressed { + return false + } + return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) + }, + GenFp(), + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/internal/generator/ecdsa/generate.go b/internal/generator/ecdsa/generate.go index 5af469b50..00076625e 100644 --- a/internal/generator/ecdsa/generate.go +++ b/internal/generator/ecdsa/generate.go @@ -16,6 +16,8 @@ func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) er {File: filepath.Join(baseDir, "doc.go"), Templates: []string{"doc.go.tmpl"}}, {File: filepath.Join(baseDir, "ecdsa.go"), Templates: []string{"ecdsa.go.tmpl"}}, {File: filepath.Join(baseDir, "ecdsa_test.go"), Templates: []string{"ecdsa.test.go.tmpl"}}, + {File: filepath.Join(baseDir, "marshal.go"), Templates: []string{"marshal.go.tmpl"}}, + {File: filepath.Join(baseDir, "marshal_test.go"), Templates: []string{"marshal.test.go.tmpl"}}, } return bgen.Generate(conf, conf.Package, "./ecdsa/template", entries...) diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index bdb7a88f5..08ed4c7f5 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -2,27 +2,48 @@ import ( "crypto/aes" "crypto/cipher" "crypto/sha512" + "crypto/subtle" + "errors" + "hash" "io" "math/big" "github.com/consensys/gnark-crypto/ecc/{{ .Name }}" "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fp" + "github.com/consensys/gnark-crypto/signature" ) +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes +{{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} + sizePublicKey = 2 * sizeFp +{{- else}} + sizePublicKey = sizeFp +{{- end}} + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + // PublicKey represents an ECDSA public key type PublicKey struct { - Q {{ .CurvePackage }}.G1Affine + A {{ .CurvePackage }}.G1Affine } // PrivateKey represents an ECDSA private key type PrivateKey struct { - PublicKey - Secret *big.Int + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian } // Signature represents an ECDSA signature type Signature struct { - R, S *big.Int + R, S [sizeFr]byte } var one = new(big.Int).SetInt64(1) @@ -37,7 +58,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(fr.Modulus(), one) + n := new(big.Int).Sub(order, one) k.Mod(k, n) k.Add(k, one) return @@ -59,8 +80,8 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { {{- end}} privateKey := new(PrivateKey) - privateKey.Secret = k - privateKey.PublicKey.Q.ScalarMultiplication(&g, k) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) return privateKey, nil } @@ -68,12 +89,11 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. func hashToInt(hash []byte) *big.Int { - if len(hash) > fr.Bytes { - hash = hash[:fr.Bytes] - } - + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } ret := new(big.Int).SetBytes(hash) - excess := len(hash)*8 - fr.Bits + excess := len(hash)*8 - sizeFr if excess > 0 { ret.Rsh(ret, uint(excess)) } @@ -99,7 +119,7 @@ const ( func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // - // SHA2-512(privateKey.Secret ∥ entropy ∥ hash)[:32] + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] // // The CSPRNG key is indifferentiable from a random oracle as shown in // [Coron], the AES-CTR stream is indifferentiable from a random oracle @@ -118,7 +138,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Initialize an SHA-512 hash context; digest... md := sha512.New() - md.Write(privateKey.Secret.Bytes()) // the private key, + md.Write(privateKey.scalar[:sizeFr]) // the private key, md.Write(entropy) // the entropy, md.Write(hash) // and the input hash; key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), @@ -137,6 +157,24 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. return csprng, err } +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + // Sign performs the ECDSA signature // // k ← 𝔽r (random) @@ -146,18 +184,18 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // signature = {s, r} // // SEC 1, Version 2.0, Section 4.1.3 -func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signature, err error) { - order := fr.Modulus() - r, s, kInv := new(big.Int), new(big.Int), new(big.Int) +func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { + scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, &privateKey, hash) + csprng, err := nonce(rand, privKey, message) if err != nil { - return Signature{}, err + return nil, err } k, err := randFieldElement(csprng) if err != nil { - return Signature{}, err + return nil, err } var P {{ .CurvePackage }}.G1Affine @@ -170,8 +208,8 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu break } } - s.Mul(r, privateKey.Secret) - m := hashToInt(hash) + s.Mul(r, scalar) + m := hashToInt(message) s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -180,9 +218,11 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu } } - signature.R, signature.S = r, s + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) - return signature, err + return sig.Bytes(), nil } // Verify validates the ECDSA signature @@ -190,25 +230,27 @@ func Sign(hash []byte, privateKey PrivateKey, rand io.Reader) (signature Signatu // R ?= (s⁻¹ ⋅ m ⋅ Base + s⁻¹ ⋅ R ⋅ publiKey)_x // // SEC 1, Version 2.0, Section 4.1.4 -func Verify(hash []byte, signature Signature, publicKey {{ .CurvePackage }}.G1Affine) bool { +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { - order := fr.Modulus() + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } - if signature.R.Sign() <= 0 || signature.S.Sign() <= 0 { - return false - } - if signature.R.Cmp(order) >= 0 || signature.S.Cmp(order) >= 0 { - return false - } + r, s := new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + sInv := new(big.Int).ModInverse(s, order) + e := hashToInt(message) - sInv := new(big.Int).ModInverse(signature.S, order) - e := hashToInt(hash) u1 := new(big.Int).Mul(e, sInv) u1.Mod(u1, order) - u2 := new(big.Int).Mul(signature.R, sInv) + u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) var U {{ .CurvePackage }}.G1Jac - U.JointScalarMultiplicationBase(&publicKey, u1, u2) + U.JointScalarMultiplicationBase(&publicKey.A, u1, u2) var z big.Int U.Z.Square(&U.Z). @@ -218,6 +260,6 @@ func Verify(hash []byte, signature Signature, publicKey {{ .CurvePackage }}.G1Af z.Mod(&z, order) - return z.Cmp(signature.R) == 0 + return z.Cmp(r) == 0, nil } diff --git a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl index c7f4c74d3..9b89ea820 100644 --- a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl @@ -1,5 +1,6 @@ import ( "crypto/rand" + "crypto/sha512" "testing" "github.com/leanovate/gopter" @@ -16,11 +17,15 @@ func TestECDSA(t *testing.T) { func() bool { privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey - hash := []byte("testing ECDSA") - signature, _ := Sign(hash, *privKey, rand.Reader) + msg := []byte("testing ECDSA") + sig, _ := privKey.Sign(msg, rand.Reader) - return Verify(hash, signature, privKey.PublicKey.Q) + md := sha512.New() + flag, _ := publicKey.Verify(sig, msg, md) + + return flag }, )) @@ -34,21 +39,22 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) - hash := []byte("benchmarking ECDSA sign()") + msg := []byte("benchmarking ECDSA sign()") b.ResetTimer() for i := 0; i < b.N; i++ { - Sign(hash, *privKey, rand.Reader) + privKey.Sign(msg, rand.Reader) } } func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking ECDSA sign()") + sig, _ := privKey.Sign(msg, rand.Reader) + md := sha512.New() - hash := []byte("benchmarking ECDSA sign()") - signature, _ := Sign(hash, *privKey, rand.Reader) b.ResetTimer() for i := 0; i < b.N; i++ { - Verify(hash, signature, privKey.PublicKey.Q) + privKey.PublicKey.Verify(sig, msg, md) } } diff --git a/internal/generator/ecdsa/template/marshal.go.tmpl b/internal/generator/ecdsa/template/marshal.go.tmpl new file mode 100644 index 000000000..d8c360633 --- /dev/null +++ b/internal/generator/ecdsa/template/marshal.go.tmpl @@ -0,0 +1,98 @@ +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte +{{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} + pkBin := pk.A.RawBytes() +{{- else}} + pkBin := pk.A.Bytes() +{{- end}} + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte +{{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} + pubkBin := privKey.PublicKey.A.RawBytes() +{{- else}} + pubkBin := privKey.PublicKey.A.Bytes() +{{- end}} + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/internal/generator/ecdsa/template/marshal.test.go.tmpl b/internal/generator/ecdsa/template/marshal.test.go.tmpl new file mode 100644 index 000000000..5fc66a474 --- /dev/null +++ b/internal/generator/ecdsa/template/marshal.test.go.tmpl @@ -0,0 +1,46 @@ +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[{{ toUpper .Name }}] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/signature/ecdsa/ecdsa.go b/signature/ecdsa/ecdsa.go new file mode 100644 index 000000000..9fde6810c --- /dev/null +++ b/signature/ecdsa/ecdsa.go @@ -0,0 +1,63 @@ +/* +Copyright © 2020 ConsenSys + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ecdsa + +import ( + "io" + + "github.com/consensys/gnark-crypto/ecc" + ecdsa_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/ecdsa" + ecdsa_bls12378 "github.com/consensys/gnark-crypto/ecc/bls12-378/ecdsa" + ecdsa_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/ecdsa" + ecdsa_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/ecdsa" + ecdsa_bls24317 "github.com/consensys/gnark-crypto/ecc/bls24-317/ecdsa" + ecdsa_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/ecdsa" + ecdsa_bw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/ecdsa" + ecdsa_bw6756 "github.com/consensys/gnark-crypto/ecc/bw6-756/ecdsa" + ecdsa_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/ecdsa" + "github.com/consensys/gnark-crypto/signature" +) + +// New takes a source of randomness and returns a new key pair +func New(ss ecc.ID, r io.Reader) (signature.Signer, error) { + switch ss { + case ecc.BN254: + return ecdsa_bn254.GenerateKey(r) + case ecc.BLS12_381: + return ecdsa_bls12381.GenerateKey(r) + case ecc.BLS12_377: + return ecdsa_bls12377.GenerateKey(r) + case ecc.BLS12_378: + return ecdsa_bls12378.GenerateKey(r) + case ecc.BW6_761: + return ecdsa_bw6761.GenerateKey(r) + case ecc.BW6_756: + return ecdsa_bw6756.GenerateKey(r) + case ecc.BLS24_315: + return ecdsa_bls24315.GenerateKey(r) + case ecc.BLS24_317: + return ecdsa_bls24317.GenerateKey(r) + case ecc.BW6_633: + return ecdsa_bw6633.GenerateKey(r) + case ecc.SECP256K1: + return ecdsa_secp256k1.GenerateKey(r) + case ecc.STARK_CURVE: + return ecdsa_starkcurve.GenerateKey(r) + default: + panic("not implemented") + } +} From a08e8193886f0d96ee424b8e2f8f11dd4a53e6fb Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 24 Jan 2023 12:33:25 +0100 Subject: [PATCH 15/18] refactor: concile ecdsa and eddsa on signature interface --- ecc/bls12-377/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bls12-377/ecdsa/ecdsa_test.go | 8 ++-- ecc/bls12-378/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bls12-378/ecdsa/ecdsa_test.go | 8 ++-- ecc/bls12-381/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bls12-381/ecdsa/ecdsa_test.go | 8 ++-- ecc/bls24-315/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bls24-315/ecdsa/ecdsa_test.go | 8 ++-- ecc/bls24-317/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bls24-317/ecdsa/ecdsa_test.go | 8 ++-- ecc/bn254/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bn254/ecdsa/ecdsa_test.go | 8 ++-- ecc/bw6-633/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bw6-633/ecdsa/ecdsa_test.go | 8 ++-- ecc/bw6-756/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bw6-756/ecdsa/ecdsa_test.go | 8 ++-- ecc/bw6-761/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/bw6-761/ecdsa/ecdsa_test.go | 8 ++-- ecc/secp256k1/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/secp256k1/ecdsa/ecdsa_test.go | 8 ++-- ecc/stark-curve/ecdsa/ecdsa.go | 38 +++++++++++++++---- ecc/stark-curve/ecdsa/ecdsa_test.go | 8 ++-- .../generator/ecdsa/template/ecdsa.go.tmpl | 38 +++++++++++++++---- .../ecdsa/template/ecdsa.test.go.tmpl | 8 ++-- signature/ecdsa/ecdsa.go | 2 + 25 files changed, 410 insertions(+), 144 deletions(-) diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go index 02bd4a194..132bf1e59 100644 --- a/ecc/bls12-377/ecdsa/ecdsa.go +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bls12-377/ecdsa/ecdsa_test.go b/ecc/bls12-377/ecdsa/ecdsa_test.go index 6573079f9..d2f8c0fd0 100644 --- a/ecc/bls12-377/ecdsa/ecdsa_test.go +++ b/ecc/bls12-377/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go index 9aad11043..752b9beb2 100644 --- a/ecc/bls12-378/ecdsa/ecdsa.go +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bls12-378/ecdsa/ecdsa_test.go b/ecc/bls12-378/ecdsa/ecdsa_test.go index 8b5551fd7..7183e591c 100644 --- a/ecc/bls12-378/ecdsa/ecdsa_test.go +++ b/ecc/bls12-378/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go index 49c60d3e9..48238031c 100644 --- a/ecc/bls12-381/ecdsa/ecdsa.go +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bls12-381/ecdsa/ecdsa_test.go b/ecc/bls12-381/ecdsa/ecdsa_test.go index 1c5abb240..6f0fb9b83 100644 --- a/ecc/bls12-381/ecdsa/ecdsa_test.go +++ b/ecc/bls12-381/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go index c5e057d27..f0ee355c1 100644 --- a/ecc/bls24-315/ecdsa/ecdsa.go +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bls24-315/ecdsa/ecdsa_test.go b/ecc/bls24-315/ecdsa/ecdsa_test.go index 9356788e8..563f5c354 100644 --- a/ecc/bls24-315/ecdsa/ecdsa_test.go +++ b/ecc/bls24-315/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go index 8823824fb..eea0aba8f 100644 --- a/ecc/bls24-317/ecdsa/ecdsa.go +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bls24-317/ecdsa/ecdsa_test.go b/ecc/bls24-317/ecdsa/ecdsa_test.go index 65c9f3eb1..c189e6666 100644 --- a/ecc/bls24-317/ecdsa/ecdsa_test.go +++ b/ecc/bls24-317/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go index 543a1c104..3c49e196c 100644 --- a/ecc/bn254/ecdsa/ecdsa.go +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bn254/ecdsa/ecdsa_test.go b/ecc/bn254/ecdsa/ecdsa_test.go index 233427e5d..7eb67274b 100644 --- a/ecc/bn254/ecdsa/ecdsa_test.go +++ b/ecc/bn254/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go index ff9cfccbc..192912bd5 100644 --- a/ecc/bw6-633/ecdsa/ecdsa.go +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bw6-633/ecdsa/ecdsa_test.go b/ecc/bw6-633/ecdsa/ecdsa_test.go index 8c44212c5..d060ccef1 100644 --- a/ecc/bw6-633/ecdsa/ecdsa_test.go +++ b/ecc/bw6-633/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go index 2a86f9c91..0a781696e 100644 --- a/ecc/bw6-756/ecdsa/ecdsa.go +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bw6-756/ecdsa/ecdsa_test.go b/ecc/bw6-756/ecdsa/ecdsa_test.go index 560fc4be8..25ec14e85 100644 --- a/ecc/bw6-756/ecdsa/ecdsa_test.go +++ b/ecc/bw6-756/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go index 71ad4b3b4..b800005b9 100644 --- a/ecc/bw6-761/ecdsa/ecdsa.go +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/bw6-761/ecdsa/ecdsa_test.go b/ecc/bw6-761/ecdsa/ecdsa_test.go index c37ed7ae9..f088d4e84 100644 --- a/ecc/bw6-761/ecdsa/ecdsa_test.go +++ b/ecc/bw6-761/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index 74aa9e651..5fd399625 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/ecdsa/ecdsa_test.go index 32f5da0cf..b4746cc39 100644 --- a/ecc/secp256k1/ecdsa/ecdsa_test.go +++ b/ecc/secp256k1/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index 8e9525fa4..827f89b1d 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -19,6 +19,7 @@ package ecdsa import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -125,7 +126,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -139,7 +140,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -190,15 +191,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -218,7 +219,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -252,9 +264,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/ecc/stark-curve/ecdsa/ecdsa_test.go b/ecc/stark-curve/ecdsa/ecdsa_test.go index fb6093df5..ca3d2269c 100644 --- a/ecc/stark-curve/ecdsa/ecdsa_test.go +++ b/ecc/stark-curve/ecdsa/ecdsa_test.go @@ -38,9 +38,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -58,9 +57,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -68,8 +68,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index 08ed4c7f5..d74a9388b 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -1,6 +1,7 @@ import ( "crypto/aes" "crypto/cipher" + "crypto/rand" "crypto/sha512" "crypto/subtle" "errors" @@ -116,7 +117,7 @@ const ( aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) ) -func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: // // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] @@ -130,7 +131,7 @@ func nonce(rand io.Reader, privateKey *PrivateKey, hash []byte) (csprng *cipher. // Get 256 bits of entropy from rand. entropy := make([]byte, 32) - _, err = io.ReadFull(rand, entropy) + _, err = io.ReadFull(rand.Reader, entropy) if err != nil { return @@ -181,15 +182,15 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // P = k ⋅ g1Gen // r = x_P (mod order) // s = k⁻¹ . (m + sk ⋅ r) -// signature = {s, r} +// signature = {r, s} // // SEC 1, Version 2.0, Section 4.1.3 -func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) { +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { scalar, r, s, kInv := new(big.Int), new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) for { for { - csprng, err := nonce(rand, privKey, message) + csprng, err := nonce(privKey, message) if err != nil { return nil, err } @@ -209,7 +210,18 @@ func (privKey *PrivateKey) Sign(message []byte, rand io.Reader) ([]byte, error) } } s.Mul(r, scalar) - m := hashToInt(message) + + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + s.Add(m, s). Mul(kInv, s). Mod(s, order) // order != 0 @@ -243,9 +255,19 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo s.SetBytes(sig.S[:sizeFr]) sInv := new(big.Int).ModInverse(s, order) - e := hashToInt(message) - u1 := new(big.Int).Mul(e, sInv) + // compute the hash of the message as an integer + dataToHash := make([]byte, len(message)) + copy(dataToHash[:], message[:]) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + hramBin := hFunc.Sum(nil) + m := hashToInt(hramBin) + + u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) u2 := new(big.Int).Mul(r, sInv) u2.Mod(u2, order) diff --git a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl index 9b89ea820..bc91596d1 100644 --- a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.test.go.tmpl @@ -20,9 +20,8 @@ func TestECDSA(t *testing.T) { publicKey := privKey.PublicKey msg := []byte("testing ECDSA") - sig, _ := privKey.Sign(msg, rand.Reader) - md := sha512.New() + sig, _ := privKey.Sign(msg, md) flag, _ := publicKey.Verify(sig, msg, md) return flag @@ -40,9 +39,10 @@ func BenchmarkSignECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") + md := sha512.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, rand.Reader) + privKey.Sign(msg, md) } } @@ -50,8 +50,8 @@ func BenchmarkVerifyECDSA(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking ECDSA sign()") - sig, _ := privKey.Sign(msg, rand.Reader) md := sha512.New() + sig, _ := privKey.Sign(msg, md) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/signature/ecdsa/ecdsa.go b/signature/ecdsa/ecdsa.go index 9fde6810c..68daac09d 100644 --- a/signature/ecdsa/ecdsa.go +++ b/signature/ecdsa/ecdsa.go @@ -29,6 +29,8 @@ import ( ecdsa_bw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/ecdsa" ecdsa_bw6756 "github.com/consensys/gnark-crypto/ecc/bw6-756/ecdsa" ecdsa_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/ecdsa" + ecdsa_secp256k1 "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" + ecdsa_starkcurve "github.com/consensys/gnark-crypto/ecc/stark-curve/ecdsa" "github.com/consensys/gnark-crypto/signature" ) From 7fddebf43c9fc846238e672f926469b59050fb5e Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 24 Jan 2023 13:14:35 +0100 Subject: [PATCH 16/18] fix: serialization of stark-curve points --- ecc/stark-curve/ecdsa/ecdsa.go | 2 +- ecc/stark-curve/ecdsa/marshal.go | 4 +- ecc/stark-curve/marshal.go | 669 +++++++++++++++++- ecc/stark-curve/marshal_test.go | 172 +++++ .../generator/ecdsa/template/ecdsa.go.tmpl | 2 +- .../generator/ecdsa/template/marshal.go.tmpl | 4 +- 6 files changed, 838 insertions(+), 15 deletions(-) diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index 827f89b1d..912900bbd 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -38,7 +38,7 @@ var errInvalidSig = errors.New("invalid signature") const ( sizeFr = fr.Bytes sizeFp = fp.Bytes - sizePublicKey = 2 * sizeFp + sizePublicKey = sizeFp sizePrivateKey = sizeFr + sizePublicKey sizeSignature = 2 * sizeFr ) diff --git a/ecc/stark-curve/ecdsa/marshal.go b/ecc/stark-curve/ecdsa/marshal.go index ff04c7d94..72d74c5cb 100644 --- a/ecc/stark-curve/ecdsa/marshal.go +++ b/ecc/stark-curve/ecdsa/marshal.go @@ -30,7 +30,7 @@ import ( // compressed representation store x with a parity bit to recompute y func (pk *PublicKey) Bytes() []byte { var res [sizePublicKey]byte - pkBin := pk.A.RawBytes() + pkBin := pk.A.Bytes() subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) return res[:] } @@ -58,7 +58,7 @@ func (pk *PublicKey) SetBytes(buf []byte) (int, error) { // scalar is in big endian, of size sizeFr. func (privKey *PrivateKey) Bytes() []byte { var res [sizePrivateKey]byte - pubkBin := privKey.PublicKey.A.RawBytes() + pubkBin := privKey.PublicKey.A.Bytes() subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) return res[:] diff --git a/ecc/stark-curve/marshal.go b/ecc/stark-curve/marshal.go index 64465a6f6..04cff5609 100644 --- a/ecc/stark-curve/marshal.go +++ b/ecc/stark-curve/marshal.go @@ -17,13 +17,471 @@ package starkcurve import ( + "encoding/binary" "errors" "io" + "reflect" + "sync/atomic" "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fr" + "github.com/consensys/gnark-crypto/internal/parallel" ) -// TODO (@yelhousni): compressed coordinates + complete marshal +// To encode G1Affine points, we mask the most significant bits with these bits to specify without ambiguity +// metadata needed for point (de)compression +// we have less than 3 bits available on the msw, so we can't follow BLS12-381 style encoding. +// the difference is the case where a point is infinity and uncompressed is not flagged +const ( + mMask byte = 0b11 << 6 + mUncompressed byte = 0b00 << 6 + mCompressedSmallest byte = 0b10 << 6 + mCompressedLargest byte = 0b11 << 6 + mCompressedInfinity byte = 0b01 << 6 +) + +// Encoder writes stark-curve object values to an output stream +type Encoder struct { + w io.Writer + n int64 // written bytes + raw bool // raw vs compressed encoding +} + +// Decoder reads stark-curve object values from an inbound stream +type Decoder struct { + r io.Reader + n int64 // read bytes + subGroupCheck bool // default to true +} + +// NewDecoder returns a binary decoder supporting curve stark-curve objects in both +// compressed and uncompressed (raw) forms +func NewDecoder(r io.Reader, options ...func(*Decoder)) *Decoder { + d := &Decoder{r: r, subGroupCheck: true} + + for _, o := range options { + o(d) + } + + return d +} + +// Decode reads the binary encoding of v from the stream +// type must be *uint64, *fr.Element, *fp.Element, *G1Affine or *[]G1Affine +func (dec *Decoder) Decode(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { + return errors.New("stark-curve decoder: unsupported type, need pointer") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + // in particular, careful attention must be given to usage of Bytes() method on Elements and Points + // that return an array (not a slice) of bytes. Using this is beneficial to minimize memallocs + // in very large (de)serialization upstream in gnark. + // (but detrimental to code lisibility here) + + var buf [SizeOfG1AffineUncompressed]byte + var read int + + switch t := v.(type) { + case *fr.Element: + read, err = io.ReadFull(dec.r, buf[:fr.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + err = t.SetBytesCanonical(buf[:fr.Bytes]) + return + case *fp.Element: + read, err = io.ReadFull(dec.r, buf[:fp.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + err = t.SetBytesCanonical(buf[:fp.Bytes]) + return + case *[]fr.Element: + var sliceLen uint32 + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]fr.Element, sliceLen) + } + + for i := 0; i < len(*t); i++ { + read, err = io.ReadFull(dec.r, buf[:fr.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + if err = (*t)[i].SetBytesCanonical(buf[:fr.Bytes]); err != nil { + return + } + } + return + case *[]fp.Element: + var sliceLen uint32 + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]fp.Element, sliceLen) + } + + for i := 0; i < len(*t); i++ { + read, err = io.ReadFull(dec.r, buf[:fp.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + if err = (*t)[i].SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return + } + } + return + case *G1Affine: + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG1AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG1AffineCompressed + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG1AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG1AffineCompressed:SizeOfG1AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + } + _, err = t.setBytes(buf[:nbBytes], dec.subGroupCheck) + return + case *[]G1Affine: + var sliceLen uint32 + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]G1Affine, sliceLen) + } + compressed := make([]bool, sliceLen) + for i := 0; i < len(*t); i++ { + + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG1AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG1AffineCompressed + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG1AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG1AffineCompressed:SizeOfG1AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + _, err = (*t)[i].setBytes(buf[:nbBytes], false) + if err != nil { + return + } + } else { + var r bool + if r, err = ((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])); err != nil { + return + } + compressed[i] = !r + } + } + var nbErrs uint64 + parallel.Execute(len(compressed), func(start, end int) { + for i := start; i < end; i++ { + if compressed[i] { + if err := (*t)[i].unsafeComputeY(dec.subGroupCheck); err != nil { + atomic.AddUint64(&nbErrs, 1) + } + } else if dec.subGroupCheck { + if !(*t)[i].IsInSubGroup() { + atomic.AddUint64(&nbErrs, 1) + } + } + } + }) + if nbErrs != 0 { + return errors.New("point decompression failed") + } + + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New("stark-curve encoder: unsupported type") + } + err = binary.Read(dec.r, binary.BigEndian, t) + if err == nil { + dec.n += int64(n) + } + return + } +} + +// BytesRead return total bytes read from reader +func (dec *Decoder) BytesRead() int64 { + return dec.n +} + +func (dec *Decoder) readUint32() (r uint32, err error) { + var read int + var buf [4]byte + read, err = io.ReadFull(dec.r, buf[:4]) + dec.n += int64(read) + if err != nil { + return + } + r = binary.BigEndian.Uint32(buf[:4]) + return +} + +func isCompressed(msb byte) bool { + mData := msb & mMask + return !(mData == mUncompressed) +} + +// NewEncoder returns a binary encoder supporting curve stark-curve objects +func NewEncoder(w io.Writer, options ...func(*Encoder)) *Encoder { + // default settings + enc := &Encoder{ + w: w, + n: 0, + raw: false, + } + + // handle options + for _, option := range options { + option(enc) + } + + return enc +} + +// Encode writes the binary encoding of v to the stream +// type must be uint64, *fr.Element, *fp.Element, *G1Affine, *G2Affine, []G1Affine or []G2Affine +func (enc *Encoder) Encode(v interface{}) (err error) { + if enc.raw { + return enc.encodeRaw(v) + } + return enc.encode(v) +} + +// BytesWritten return total bytes written on writer +func (enc *Encoder) BytesWritten() int64 { + return enc.n +} + +// RawEncoding returns an option to use in NewEncoder(...) which sets raw encoding mode to true +// points will not be compressed using this option +func RawEncoding() func(*Encoder) { + return func(enc *Encoder) { + enc.raw = true + } +} + +// NoSubgroupChecks returns an option to use in NewDecoder(...) which disable subgroup checks on the points +// the decoder will read. Use with caution, as crafted points from an untrusted source can lead to crypto-attacks. +func NoSubgroupChecks() func(*Decoder) { + return func(dec *Decoder) { + dec.subGroupCheck = false + } +} + +func (enc *Encoder) encode(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { + return errors.New(" encoder: can't encode ") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + + var written int + switch t := v.(type) { + case *fr.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *fp.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G1Affine: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case []fr.Element: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + var buf [fr.Bytes]byte + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []fp.Element: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + var buf [fp.Bytes]byte + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + + case []G1Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG1AffineCompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New(" encoder: unsupported type") + } + err = binary.Write(enc.w, binary.BigEndian, t) + enc.n += int64(n) + return + } +} + +func (enc *Encoder) encodeRaw(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { + return errors.New(" encoder: can't encode ") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + + var written int + switch t := v.(type) { + case *fr.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *fp.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G1Affine: + buf := t.RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case []fr.Element: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + var buf [fr.Bytes]byte + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []fp.Element: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + var buf [fp.Bytes]byte + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + + case []G1Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG1AffineUncompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New(" encoder: unsupported type") + } + err = binary.Write(enc.w, binary.BigEndian, t) + enc.n += int64(n) + return + } +} // SizeOfG1AffineCompressed represents the size in bytes that a G1Affine need in binary form, compressed const SizeOfG1AffineCompressed = 32 @@ -31,50 +489,243 @@ const SizeOfG1AffineCompressed = 32 // SizeOfG1AffineUncompressed represents the size in bytes that a G1Affine need in binary form, uncompressed const SizeOfG1AffineUncompressed = SizeOfG1AffineCompressed * 2 +// Marshal converts p to a byte slice (without point compression) +func (p *G1Affine) Marshal() []byte { + b := p.RawBytes() + return b[:] +} + +// Unmarshal is an allias to SetBytes() +func (p *G1Affine) Unmarshal(buf []byte) error { + _, err := p.SetBytes(buf) + return err +} + +// Bytes returns binary representation of p +// will store X coordinate in regular form and a parity bit +// as we have less than 3 bits available in our coordinate, we can't follow BLS12-381 style encoding (ZCash/IETF) +// +// we use the 2 most significant bits instead +// +// 00 -> uncompressed +// 10 -> compressed, use smallest lexicographically square root of Y^2 +// 11 -> compressed, use largest lexicographically square root of Y^2 +// 01 -> compressed infinity point +// the "uncompressed infinity point" will just have 00 (uncompressed) followed by zeroes (infinity = 0,0 in affine coordinates) +func (p *G1Affine) Bytes() (res [SizeOfG1AffineCompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + res[0] = mCompressedInfinity + return + } + + msbMask := mCompressedSmallest + // compressed, we need to know if Y is lexicographically bigger than -Y + // if p.Y ">" -p.Y + if p.Y.LexicographicallyLargest() { + msbMask = mCompressedLargest + } + + // we store X and mask the most significant word with our metadata mask + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) + + res[0] |= msbMask + + return +} + // RawBytes returns binary representation of p (stores X and Y coordinate) +// see Bytes() for a compressed representation func (p *G1Affine) RawBytes() (res [SizeOfG1AffineUncompressed]byte) { + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + + res[0] = mUncompressed + + return + } + // not compressed // we store the Y coordinate fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[32:32+fp.Bytes]), p.Y) - // we store the X coordinate + // we store X and mask the most significant word with our metadata mask fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) + res[0] |= mUncompressed + return } // SetBytes sets p from binary representation in buf and returns number of consumed bytes // -// bytes in buf must match RawBytes() +// bytes in buf must match either RawBytes() or Bytes() output // // if buf is too short io.ErrShortBuffer is returned // +// if buf contains compressed representation (output from Bytes()) and we're unable to compute +// the Y coordinate (i.e the square root doesn't exist) this function returns an error +// // this check if the resulting point is on the curve and in the correct subgroup func (p *G1Affine) SetBytes(buf []byte) (int, error) { return p.setBytes(buf, true) } -// we store both X and Y and there is no spare bit for flagging func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { if len(buf) < SizeOfG1AffineCompressed { return 0, io.ErrShortBuffer } + // most significant byte + mData := buf[0] & mMask + + // check buffer size + if mData == mUncompressed { + if len(buf) < SizeOfG1AffineUncompressed { + return 0, io.ErrShortBuffer + } + } + + // if infinity is encoded in the metadata, we don't need to read the buffer + if mData == mCompressedInfinity { + p.X.SetZero() + p.Y.SetZero() + return SizeOfG1AffineCompressed, nil + } + // uncompressed point - // read X and Y coordinates - if err := p.X.SetBytesCanonical(buf[:fp.Bytes]); err != nil { - return 0, err + if mData == mUncompressed { + // read X and Y coordinates + if err := p.X.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.Y.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineUncompressed, nil } - if err := p.Y.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + + // we have a compressed coordinate + // we need to + // 1. copy the buffer (to keep this method thread safe) + // 2. we need to solve the curve equation to compute Y + + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + if err := p.X.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { return 0, err } + var YSquared, Y fp.Element + + // y^2=x^3+x+b + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &p.X). + Add(&YSquared, &bCurveCoeff) + + if Y.Sqrt(&YSquared) == nil { + return 0, errors.New("invalid compressed coordinate: square root doesn't exist") + } + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + // subgroup check if subGroupCheck && !p.IsInSubGroup() { return 0, errors.New("invalid point: subgroup check failed") } - return SizeOfG1AffineUncompressed, nil + return SizeOfG1AffineCompressed, nil +} + +// unsafeComputeY called by Decoder when processing slices of compressed point in parallel (step 2) +// it computes the Y coordinate from the already set X coordinate and is compute intensive +func (p *G1Affine) unsafeComputeY(subGroupCheck bool) error { + // stored in unsafeSetCompressedBytes + + mData := byte(p.Y[0]) + + // we have a compressed coordinate, we need to solve the curve equation to compute Y + var YSquared, Y fp.Element + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bCurveCoeff) + if Y.Sqrt(&YSquared) == nil { + return errors.New("invalid compressed coordinate: square root doesn't exist") + } + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return errors.New("invalid point: subgroup check failed") + } + + return nil +} + +// unsafeSetCompressedBytes is called by Decoder when processing slices of compressed point in parallel (step 1) +// assumes buf[:8] mask is set to compressed +// returns true if point is infinity and need no further processing +// it sets X coordinate and uses Y for scratch space to store decompression metadata +func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err error) { + + // read the most significant byte + mData := buf[0] & mMask + + if mData == mCompressedInfinity { + p.X.SetZero() + p.Y.SetZero() + isInfinity = true + return isInfinity, nil + } + + // we need to copy the input buffer (to keep this method thread safe) + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + if err := p.X.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return false, err + } + // store mData in p.Y[0] + p.Y[0] = uint64(mData) + // recomputing Y will be done asynchronously + return isInfinity, nil } diff --git a/ecc/stark-curve/marshal_test.go b/ecc/stark-curve/marshal_test.go index 15c0af7b1..470f6fc0f 100644 --- a/ecc/stark-curve/marshal_test.go +++ b/ecc/stark-curve/marshal_test.go @@ -17,19 +17,171 @@ package starkcurve import ( + "bytes" + "io" "math/big" + "math/rand" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fr" ) +func TestEncoder(t *testing.T) { + t.Parallel() + // TODO need proper fuzz testing here + + var inA uint64 + var inB fr.Element + var inC fp.Element + var inD G1Affine + var inE G1Affine + var inG []G1Affine + var inI []fp.Element + var inJ []fr.Element + + // set values of inputs + inA = rand.Uint64() + inB.SetRandom() + inC.SetRandom() + inD.ScalarMultiplication(&g1GenAff, new(big.Int).SetUint64(rand.Uint64())) + // inE --> infinity + inG = make([]G1Affine, 2) + inG[1] = inD + inI = make([]fp.Element, 3) + inI[2] = inD.X + inJ = make([]fr.Element, 0) + + // encode them, compressed and raw + var buf, bufRaw bytes.Buffer + enc := NewEncoder(&buf) + encRaw := NewEncoder(&bufRaw, RawEncoding()) + toEncode := []interface{}{inA, &inB, &inC, &inD, &inE, inG, inI, inJ} + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + t.Fatal(err) + } + if err := encRaw.Encode(v); err != nil { + t.Fatal(err) + } + } + + testDecode := func(t *testing.T, r io.Reader, n int64) { + dec := NewDecoder(r) + var outA uint64 + var outB fr.Element + var outC fp.Element + var outD G1Affine + var outE G1Affine + outE.X.SetOne() + outE.Y.SetUint64(42) + var outG []G1Affine + var outI []fp.Element + var outJ []fr.Element + + toDecode := []interface{}{&outA, &outB, &outC, &outD, &outE, &outG, &outI, &outJ} + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + t.Fatal(err) + } + } + + // compare values + if inA != outA { + t.Fatal("didn't encode/decode uint64 value properly") + } + + if !inB.Equal(&outB) || !inC.Equal(&outC) { + t.Fatal("decode(encode(Element) failed") + } + if !inD.Equal(&outD) || !inE.Equal(&outE) { + t.Fatal("decode(encode(G1Affine) failed") + } + for i := 0; i < len(inG); i++ { + if !inG[i].Equal(&outG[i]) { + t.Fatal("decode(encode(slice(points))) failed") + } + } + if (len(inI) != len(outI)) || (len(inJ) != len(outJ)) { + t.Fatal("decode(encode(slice(elements))) failed") + } + for i := 0; i < len(inI); i++ { + if !inI[i].Equal(&outI[i]) { + t.Fatal("decode(encode(slice(elements))) failed") + } + } + if n != dec.BytesRead() { + t.Fatal("bytes read don't match bytes written") + } + } + + // decode them + testDecode(t, &buf, enc.BytesWritten()) + testDecode(t, &bufRaw, encRaw.BytesWritten()) + +} + +func TestIsCompressed(t *testing.T) { + t.Parallel() + var g1Inf, g1 G1Affine + + g1 = g1GenAff + + { + b := g1Inf.Bytes() + if !isCompressed(b[0]) { + t.Fatal("g1Inf.Bytes() should be compressed") + } + } + + { + b := g1Inf.RawBytes() + if isCompressed(b[0]) { + t.Fatal("g1Inf.RawBytes() should be uncompressed") + } + } + + { + b := g1.Bytes() + if !isCompressed(b[0]) { + t.Fatal("g1.Bytes() should be compressed") + } + } + + { + b := g1.RawBytes() + if isCompressed(b[0]) { + t.Fatal("g1.RawBytes() should be uncompressed") + } + } + +} + func TestG1AffineSerialization(t *testing.T) { t.Parallel() // test round trip serialization of infinity { + // compressed + { + var p1, p2 G1Affine + p2.X.SetRandom() + p2.Y.SetRandom() + buf := p1.Bytes() + n, err := p2.SetBytes(buf[:]) + if err != nil { + t.Fatal(err) + } + if n != SizeOfG1AffineCompressed { + t.Fatal("invalid number of bytes consumed in buffer") + } + if !(p2.X.IsZero() && p2.Y.IsZero()) { + t.Fatal("deserialization of uncompressed infinity point is not infinity") + } + } + // uncompressed { var p1, p2 G1Affine @@ -78,5 +230,25 @@ func TestG1AffineSerialization(t *testing.T) { GenFp(), )) + properties.Property("[G1] Affine SetBytes(Bytes()) should stay the same", prop.ForAll( + func(a fp.Element) bool { + var start, end G1Affine + var ab big.Int + a.BigInt(&ab) + start.ScalarMultiplication(&g1GenAff, &ab) + + buf := start.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != SizeOfG1AffineCompressed { + return false + } + return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) + }, + GenFp(), + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index d74a9388b..747631c00 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -20,7 +20,7 @@ var errInvalidSig = errors.New("invalid signature") const ( sizeFr = fr.Bytes sizeFp = fp.Bytes -{{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} +{{- if eq .Name "secp256k1"}} sizePublicKey = 2 * sizeFp {{- else}} sizePublicKey = sizeFp diff --git a/internal/generator/ecdsa/template/marshal.go.tmpl b/internal/generator/ecdsa/template/marshal.go.tmpl index d8c360633..2e76fe21e 100644 --- a/internal/generator/ecdsa/template/marshal.go.tmpl +++ b/internal/generator/ecdsa/template/marshal.go.tmpl @@ -12,7 +12,7 @@ import ( // compressed representation store x with a parity bit to recompute y func (pk *PublicKey) Bytes() []byte { var res [sizePublicKey]byte -{{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} +{{- if eq .Name "secp256k1"}} pkBin := pk.A.RawBytes() {{- else}} pkBin := pk.A.Bytes() @@ -44,7 +44,7 @@ func (pk *PublicKey) SetBytes(buf []byte) (int, error) { // scalar is in big endian, of size sizeFr. func (privKey *PrivateKey) Bytes() []byte { var res [sizePrivateKey]byte -{{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} +{{- if eq .Name "secp256k1"}} pubkBin := privKey.PublicKey.A.RawBytes() {{- else}} pubkBin := privKey.PublicKey.A.Bytes() From 0b2c0d5d2fd177c9dc55c19efa3f57f3eac0a65a Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 24 Jan 2023 14:05:41 +0100 Subject: [PATCH 17/18] fix(stark-curve): point encoder (a!=0) --- ecc/stark-curve/marshal.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ecc/stark-curve/marshal.go b/ecc/stark-curve/marshal.go index 04cff5609..755ad3a15 100644 --- a/ecc/stark-curve/marshal.go +++ b/ecc/stark-curve/marshal.go @@ -670,8 +670,11 @@ func (p *G1Affine) unsafeComputeY(subGroupCheck bool) error { // we have a compressed coordinate, we need to solve the curve equation to compute Y var YSquared, Y fp.Element + // y^2=x^3+x+b YSquared.Square(&p.X).Mul(&YSquared, &p.X) - YSquared.Add(&YSquared, &bCurveCoeff) + YSquared.Add(&YSquared, &p.X). + Add(&YSquared, &bCurveCoeff) + if Y.Sqrt(&YSquared) == nil { return errors.New("invalid compressed coordinate: square root doesn't exist") } From ef3b0d72b7ae32723f057622ecad0b9be5c8d858 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 24 Jan 2023 15:03:22 +0100 Subject: [PATCH 18/18] refactor(ecdsa): make hashToInt accessible for gnark --- ecc/bls12-377/ecdsa/ecdsa.go | 8 ++++---- ecc/bls12-378/ecdsa/ecdsa.go | 8 ++++---- ecc/bls12-381/ecdsa/ecdsa.go | 8 ++++---- ecc/bls24-315/ecdsa/ecdsa.go | 8 ++++---- ecc/bls24-317/ecdsa/ecdsa.go | 8 ++++---- ecc/bn254/ecdsa/ecdsa.go | 8 ++++---- ecc/bw6-633/ecdsa/ecdsa.go | 8 ++++---- ecc/bw6-756/ecdsa/ecdsa.go | 8 ++++---- ecc/bw6-761/ecdsa/ecdsa.go | 8 ++++---- ecc/secp256k1/ecdsa/ecdsa.go | 8 ++++---- ecc/stark-curve/ecdsa/ecdsa.go | 8 ++++---- internal/generator/ecdsa/template/ecdsa.go.tmpl | 8 ++++---- 12 files changed, 48 insertions(+), 48 deletions(-) diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/ecdsa/ecdsa.go index 132bf1e59..739b46f80 100644 --- a/ecc/bls12-377/ecdsa/ecdsa.go +++ b/ecc/bls12-377/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/ecdsa/ecdsa.go index 752b9beb2..b40630124 100644 --- a/ecc/bls12-378/ecdsa/ecdsa.go +++ b/ecc/bls12-378/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/ecdsa/ecdsa.go index 48238031c..bc31f1db7 100644 --- a/ecc/bls12-381/ecdsa/ecdsa.go +++ b/ecc/bls12-381/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/ecdsa/ecdsa.go index f0ee355c1..503bae858 100644 --- a/ecc/bls24-315/ecdsa/ecdsa.go +++ b/ecc/bls24-315/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/ecdsa/ecdsa.go index eea0aba8f..a7bfe566c 100644 --- a/ecc/bls24-317/ecdsa/ecdsa.go +++ b/ecc/bls24-317/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/ecdsa/ecdsa.go index 3c49e196c..ffc709a4d 100644 --- a/ecc/bn254/ecdsa/ecdsa.go +++ b/ecc/bn254/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/ecdsa/ecdsa.go index 192912bd5..811ef33b4 100644 --- a/ecc/bw6-633/ecdsa/ecdsa.go +++ b/ecc/bw6-633/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/ecdsa/ecdsa.go index 0a781696e..bbf25a9bd 100644 --- a/ecc/bw6-756/ecdsa/ecdsa.go +++ b/ecc/bw6-756/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/ecdsa/ecdsa.go index b800005b9..ee7411090 100644 --- a/ecc/bw6-761/ecdsa/ecdsa.go +++ b/ecc/bw6-761/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/ecdsa/ecdsa.go index 5fd399625..0fdc3882b 100644 --- a/ecc/secp256k1/ecdsa/ecdsa.go +++ b/ecc/secp256k1/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/ecdsa/ecdsa.go index 912900bbd..d378fef06 100644 --- a/ecc/stark-curve/ecdsa/ecdsa.go +++ b/ecc/stark-curve/ecdsa/ecdsa.go @@ -95,10 +95,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -229,7 +229,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -274,7 +274,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order) diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/ecdsa/template/ecdsa.go.tmpl index 747631c00..724715eb8 100644 --- a/internal/generator/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/ecdsa/template/ecdsa.go.tmpl @@ -86,10 +86,10 @@ func GenerateKey(rand io.Reader) (*PrivateKey, error) { return privateKey, nil } -// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, // we use the left-most bits of the hash to match the bit-length of the order of // the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. -func hashToInt(hash []byte) *big.Int { +func HashToInt(hash []byte) *big.Int { if len(hash) > sizeFr { hash = hash[:sizeFr] } @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) return nil, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) s.Add(m, s). Mul(kInv, s). @@ -265,7 +265,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo return false, err } hramBin := hFunc.Sum(nil) - m := hashToInt(hramBin) + m := HashToInt(hramBin) u1 := new(big.Int).Mul(m, sInv) u1.Mod(u1, order)