// Verify returns true iff sig is a valid signature of message by publicKey. func Verify(publicKey *[PublicKeySize]byte, message []byte, sig *[SignatureSize]byte) bool { if sig[63]&224 != 0 { return false } var A edwards25519.ExtendedGroupElement if !A.FromBytes(publicKey) { return false } edwards25519.FeNeg(&A.X, &A.X) edwards25519.FeNeg(&A.T, &A.T) h := sha512.New() h.Write(sig[:32]) h.Write(publicKey[:]) h.Write(message) var digest [64]byte h.Sum(digest[:0]) var hReduced [32]byte edwards25519.ScReduce(&hReduced, &digest) var R edwards25519.ProjectiveGroupElement var b [32]byte copy(b[:], sig[32:]) edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b) var checkR [32]byte R.ToBytes(&checkR) return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1 }
// EncodedBytesToBigIntPoint converts a 32 byte representation of a point // on the elliptical curve into a big integer point. It returns an error // if the point does not fall on the curve. func (curve *TwistedEdwardsCurve) EncodedBytesToBigIntPoint(s *[32]byte) (*big.Int, *big.Int, error) { sCopy := new([32]byte) for i := 0; i < fieldIntSize; i++ { sCopy[i] = s[i] } xIsNegBytes := sCopy[31]>>7 == 1 p := new(edwards25519.ExtendedGroupElement) if p.FromBytes(sCopy) == false { return nil, nil, fmt.Errorf("point not on curve") } // Normalize the X and Y coordinates in affine space. x, y, isNegative := curve.extendedToBigAffine(&p.X, &p.Y, &p.Z) // We got the wrong sign; flip the bit and recalculate. if xIsNegBytes != isNegative { x.Sub(curve.P, x) } // This should hopefully never happen, since the // library itself should never let us create a bad // point. if !curve.IsOnCurve(x, y) { return nil, nil, fmt.Errorf("point not on curve") } return x, y, nil }
// PublicKeyToCurve25519 converts an Ed25519 public key into the curve25519 // public key that would be generated from the same private key. func PublicKeyToCurve25519(curve25519Public *[32]byte, publicKey *[32]byte) bool { var A edwards25519.ExtendedGroupElement if !A.FromBytes(publicKey) { return false } // A.Z = 1 as a postcondition of FromBytes. var x edwards25519.FieldElement edwardsToMontgomeryX(&x, &A.Y) edwards25519.FeToBytes(curve25519Public, &x) return true }
// 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 }
// 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 }