// GenerateKey generates a public/private key pair using randomness from rand. func GenerateKey(rand io.Reader) (publicKey *[PublicKeySize]byte, privateKey *[PrivateKeySize]byte, err error) { privateKey = new([64]byte) publicKey = new([32]byte) _, err = io.ReadFull(rand, privateKey[:32]) if err != nil { return nil, nil, err } h := sha512.New() h.Write(privateKey[:32]) digest := h.Sum(nil) digest[0] &= 248 digest[31] &= 127 digest[31] |= 64 var A edwards25519.ExtendedGroupElement var hBytes [32]byte copy(hBytes[:], digest) edwards25519.GeScalarMultBase(&A, &hBytes) A.ToBytes(publicKey) copy(privateKey[32:], publicKey[:]) return }
// ScalarMult returns k*(Bx,By) where k is a number in big-endian form. This // uses the repeated doubling method, which is variable time. // TODO use a constant time method to prevent side channel attacks. func (curve *TwistedEdwardsCurve) ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int) { // Convert the scalar to a big int. s := new(big.Int).SetBytes(k) // Get a new group element to do cached doubling // calculations in. dEGE := new(edwards25519.ExtendedGroupElement) dEGE.Zero() // Use the doubling method for the multiplication. // p := given point // q := point(zero) // for each bit in the scalar, descending: // double(q) // if bit == 1: // add(q, p) // return q // // Note that the addition is skipped for zero bits, // making this variable time and thus vulnerable to // side channel attack vectors. for i := s.BitLen() - 1; i >= 0; i-- { dCGE := new(edwards25519.CompletedGroupElement) dEGE.Double(dCGE) dCGE.ToExtended(dEGE) if s.Bit(i) == 1 { ss := new([32]byte) dEGE.ToBytes(ss) var err error xi, yi, err := curve.EncodedBytesToBigIntPoint(ss) if err != nil { return nil, nil } xAdd, yAdd := curve.Add(xi, yi, x1, y1) dTempBytes := BigIntPointToEncodedBytes(xAdd, yAdd) dEGE.FromBytes(dTempBytes) } } finalBytes := new([32]byte) dEGE.ToBytes(finalBytes) var err error x, y, err = curve.EncodedBytesToBigIntPoint(finalBytes) if err != nil { return nil, nil } return }
func TestUnmarshalMarshal(t *testing.T) { pub, _, _ := GenerateKey(rand.Reader) var A edwards25519.ExtendedGroupElement if !A.FromBytes(pub) { t.Fatalf("ExtendedGroupElement.FromBytes failed") } var pub2 [32]byte A.ToBytes(&pub2) if *pub != pub2 { t.Errorf("FromBytes(%v)->ToBytes does not round-trip, got %x\n", *pub, pub2) } }
// Double adds the same pair of big integer coordinates to itself on the // elliptical curve. func (curve *TwistedEdwardsCurve) Double(x1, y1 *big.Int) (x, y *big.Int) { // Convert to extended projective coordinates. a := BigIntPointToEncodedBytes(x1, y1) aEGE := new(edwards25519.ExtendedGroupElement) aEGE.FromBytes(a) r := new(edwards25519.CompletedGroupElement) aEGE.Double(r) rEGE := new(edwards25519.ExtendedGroupElement) r.ToExtended(rEGE) s := new([32]byte) rEGE.ToBytes(s) x, y, _ = curve.EncodedBytesToBigIntPoint(s) return }
// SignFromScalar signs a message 'hash' using the given private scalar priv. // It uses RFC6979 to generate a deterministic nonce. Considered experimental. // r = kG, where k is the RFC6979 nonce // s = r + hash512(k || A || M) * a func SignFromScalar(curve *TwistedEdwardsCurve, priv *PrivateKey, nonce []byte, hash []byte) (r, s *big.Int, err error) { publicKey := new([PubKeyBytesLen]byte) var A edwards25519.ExtendedGroupElement privateScalar := copyBytes(priv.Serialize()) reverse(privateScalar) // BE --> LE edwards25519.GeScalarMultBase(&A, privateScalar) A.ToBytes(publicKey) // For signing from a scalar, r = nonce. nonceLE := copyBytes(nonce) reverse(nonceLE) var R edwards25519.ExtendedGroupElement edwards25519.GeScalarMultBase(&R, nonceLE) var encodedR [32]byte R.ToBytes(&encodedR) // h = hash512(k || A || M) h := sha512.New() h.Reset() h.Write(encodedR[:]) h.Write(publicKey[:]) h.Write(hash) // s = r + h * a var hramDigest [64]byte h.Sum(hramDigest[:0]) var hramDigestReduced [32]byte edwards25519.ScReduce(&hramDigestReduced, &hramDigest) var localS [32]byte edwards25519.ScMulAdd(&localS, &hramDigestReduced, privateScalar, nonceLE) signature := new([64]byte) copy(signature[:], encodedR[:]) copy(signature[32:], localS[:]) sigEd, err := ParseSignature(curve, signature[:]) if err != nil { return nil, nil, err } return sigEd.GetR(), sigEd.GetS(), nil }
// Add adds two points represented by pairs of big integers on the elliptical // curve. func (curve *TwistedEdwardsCurve) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) { // Convert to extended from affine. a := BigIntPointToEncodedBytes(x1, y1) aEGE := new(edwards25519.ExtendedGroupElement) aEGE.FromBytes(a) b := BigIntPointToEncodedBytes(x2, y2) bEGE := new(edwards25519.ExtendedGroupElement) bEGE.FromBytes(b) // Cache b for use in group element addition. bCached := new(cachedGroupElement) toCached(bCached, bEGE) p := aEGE q := bCached // geAdd(r*CompletedGroupElement, p*ExtendedGroupElement, // q*CachedGroupElement) // r is the result. r := new(edwards25519.CompletedGroupElement) var t0 edwards25519.FieldElement edwards25519.FeAdd(&r.X, &p.Y, &p.X) edwards25519.FeSub(&r.Y, &p.Y, &p.X) edwards25519.FeMul(&r.Z, &r.X, &q.yPlusX) edwards25519.FeMul(&r.Y, &r.Y, &q.yMinusX) edwards25519.FeMul(&r.T, &q.T2d, &p.T) edwards25519.FeMul(&r.X, &p.Z, &q.Z) edwards25519.FeAdd(&t0, &r.X, &r.X) edwards25519.FeSub(&r.X, &r.Z, &r.Y) edwards25519.FeAdd(&r.Y, &r.Z, &r.Y) edwards25519.FeAdd(&r.Z, &t0, &r.T) edwards25519.FeSub(&r.T, &t0, &r.T) rEGE := new(edwards25519.ExtendedGroupElement) r.ToExtended(rEGE) s := new([32]byte) rEGE.ToBytes(s) x, y, _ = curve.EncodedBytesToBigIntPoint(s) return }
// Sign signs the message with privateKey and returns a signature. func Sign(privateKey *[PrivateKeySize]byte, message []byte) *[SignatureSize]byte { h := sha512.New() h.Write(privateKey[:32]) var digest1, messageDigest, hramDigest [64]byte var expandedSecretKey [32]byte h.Sum(digest1[:0]) copy(expandedSecretKey[:], digest1[:]) expandedSecretKey[0] &= 248 expandedSecretKey[31] &= 63 expandedSecretKey[31] |= 64 h.Reset() h.Write(digest1[32:]) h.Write(message) h.Sum(messageDigest[:0]) var messageDigestReduced [32]byte edwards25519.ScReduce(&messageDigestReduced, &messageDigest) var R edwards25519.ExtendedGroupElement edwards25519.GeScalarMultBase(&R, &messageDigestReduced) var encodedR [32]byte R.ToBytes(&encodedR) h.Reset() h.Write(encodedR[:]) h.Write(privateKey[32:]) h.Write(message) h.Sum(hramDigest[:0]) var hramDigestReduced [32]byte edwards25519.ScReduce(&hramDigestReduced, &hramDigest) var s [32]byte edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) signature := new([64]byte) copy(signature[:], encodedR[:]) copy(signature[32:], s[:]) return signature }