// RepresentativeToPublicKey converts a uniform representative value for a // curve25519 public key, as produced by ScalarBaseMult, to a curve25519 public // key. func RepresentativeToPublicKey(publicKey, representative *[32]byte) { var rr2, v, e edwards25519.FieldElement edwards25519.FeFromBytes(&rr2, representative) edwards25519.FeSquare2(&rr2, &rr2) rr2[0]++ edwards25519.FeInvert(&rr2, &rr2) edwards25519.FeMul(&v, &edwards25519.A, &rr2) edwards25519.FeNeg(&v, &v) var v2, v3 edwards25519.FieldElement edwards25519.FeSquare(&v2, &v) edwards25519.FeMul(&v3, &v, &v2) edwards25519.FeAdd(&e, &v3, &v) edwards25519.FeMul(&v2, &v2, &edwards25519.A) edwards25519.FeAdd(&e, &v2, &e) chi(&e, &e) var eBytes [32]byte edwards25519.FeToBytes(&eBytes, &e) // eBytes[1] is either 0 (for e = 1) or 0xff (for e = -1) eIsMinus1 := int32(eBytes[1]) & 1 var negV edwards25519.FieldElement edwards25519.FeNeg(&negV, &v) edwards25519.FeCMove(&v, &negV, eIsMinus1) edwards25519.FeZero(&v2) edwards25519.FeCMove(&v2, &edwards25519.A, eIsMinus1) edwards25519.FeSub(&v, &v, &v2) edwards25519.FeToBytes(publicKey, &v) }
// 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 }
// RecoverXFieldElement recovers the X value for some Y value, for a coordinate // on the Ed25519 curve given as a field element. Y value. Probably the fastest // way to get your respective X from Y. func (curve *TwistedEdwardsCurve) RecoverXFieldElement(xIsNeg bool, y *edwards25519.FieldElement) *edwards25519.FieldElement { // (y^2 - 1) l := new(edwards25519.FieldElement) edwards25519.FeSquare(l, y) edwards25519.FeSub(l, l, &feOne) // inv(d*y^2+1) r := new(edwards25519.FieldElement) edwards25519.FeSquare(r, y) edwards25519.FeMul(r, r, &fed) edwards25519.FeAdd(r, r, &feOne) edwards25519.FeInvert(r, r) x2 := new(edwards25519.FieldElement) edwards25519.FeMul(x2, r, l) // Get a big int so we can do the exponentiation. x2Big := FieldElementToBigInt(x2) // x = exp(x^2,(P+3)/8, P) qp3 := new(big.Int).Add(curve.P, three) qp3.Div(qp3, eight) // /= curve.H xBig := new(big.Int).Exp(x2Big, qp3, curve.P) // Convert back to a field element and do // the rest. x := BigIntToFieldElement(xBig) // check (x^2 - x2) % q != 0 x22 := new(edwards25519.FieldElement) edwards25519.FeSquare(x22, x) xsub := new(edwards25519.FieldElement) edwards25519.FeSub(xsub, x22, x2) xsubBig := FieldElementToBigInt(xsub) xsubBig.Mod(xsubBig, curve.P) if xsubBig.Cmp(zero) != 0 { xi := new(edwards25519.FieldElement) edwards25519.FeMul(xi, x, &feI) xiModBig := FieldElementToBigInt(xi) xiModBig.Mod(xiModBig, curve.P) xiMod := BigIntToFieldElement(xiModBig) x = xiMod } xBig = FieldElementToBigInt(x) xmod2 := new(big.Int).Mod(xBig, two) if xmod2.Cmp(zero) != 0 { // TODO replace this with FeSub xBig.Sub(curve.P, xBig) x = BigIntToFieldElement(xBig) } // We got the wrong x, negate it to get the right one. isNegative := edwards25519.FeIsNegative(x) == 1 if xIsNeg != isNegative { edwards25519.FeNeg(x, x) } return x }
// ScalarBaseMult computes a curve25519 public key from a private key and also // a uniform representative for that public key. Note that this function will // fail and return false for about half of private keys. // See http://elligator.cr.yp.to/elligator-20130828.pdf. func ScalarBaseMult(publicKey, representative, privateKey *[32]byte) bool { var maskedPrivateKey [32]byte copy(maskedPrivateKey[:], privateKey[:]) maskedPrivateKey[0] &= 248 maskedPrivateKey[31] &= 127 maskedPrivateKey[31] |= 64 var A edwards25519.ExtendedGroupElement edwards25519.GeScalarMultBase(&A, &maskedPrivateKey) var inv1 edwards25519.FieldElement edwards25519.FeSub(&inv1, &A.Z, &A.Y) edwards25519.FeMul(&inv1, &inv1, &A.X) edwards25519.FeInvert(&inv1, &inv1) var t0, u edwards25519.FieldElement edwards25519.FeMul(&u, &inv1, &A.X) edwards25519.FeAdd(&t0, &A.Y, &A.Z) edwards25519.FeMul(&u, &u, &t0) var v edwards25519.FieldElement edwards25519.FeMul(&v, &t0, &inv1) edwards25519.FeMul(&v, &v, &A.Z) edwards25519.FeMul(&v, &v, &sqrtMinusA) var b edwards25519.FieldElement edwards25519.FeAdd(&b, &u, &edwards25519.A) var c, b3, b8 edwards25519.FieldElement edwards25519.FeSquare(&b3, &b) // 2 edwards25519.FeMul(&b3, &b3, &b) // 3 edwards25519.FeSquare(&c, &b3) // 6 edwards25519.FeMul(&c, &c, &b) // 7 edwards25519.FeMul(&b8, &c, &b) // 8 edwards25519.FeMul(&c, &c, &u) q58(&c, &c) var chi edwards25519.FieldElement edwards25519.FeSquare(&chi, &c) edwards25519.FeSquare(&chi, &chi) edwards25519.FeSquare(&t0, &u) edwards25519.FeMul(&chi, &chi, &t0) edwards25519.FeSquare(&t0, &b) // 2 edwards25519.FeMul(&t0, &t0, &b) // 3 edwards25519.FeSquare(&t0, &t0) // 6 edwards25519.FeMul(&t0, &t0, &b) // 7 edwards25519.FeSquare(&t0, &t0) // 14 edwards25519.FeMul(&chi, &chi, &t0) edwards25519.FeNeg(&chi, &chi) var chiBytes [32]byte edwards25519.FeToBytes(&chiBytes, &chi) // chi[1] is either 0 or 0xff if chiBytes[1] == 0xff { return false } // Calculate r1 = sqrt(-u/(2*(u+A))) var r1 edwards25519.FieldElement edwards25519.FeMul(&r1, &c, &u) edwards25519.FeMul(&r1, &r1, &b3) edwards25519.FeMul(&r1, &r1, &sqrtMinusHalf) var maybeSqrtM1 edwards25519.FieldElement edwards25519.FeSquare(&t0, &r1) edwards25519.FeMul(&t0, &t0, &b) edwards25519.FeAdd(&t0, &t0, &t0) edwards25519.FeAdd(&t0, &t0, &u) edwards25519.FeOne(&maybeSqrtM1) edwards25519.FeCMove(&maybeSqrtM1, &edwards25519.SqrtM1, edwards25519.FeIsNonZero(&t0)) edwards25519.FeMul(&r1, &r1, &maybeSqrtM1) // Calculate r = sqrt(-(u+A)/(2u)) var r edwards25519.FieldElement edwards25519.FeSquare(&t0, &c) // 2 edwards25519.FeMul(&t0, &t0, &c) // 3 edwards25519.FeSquare(&t0, &t0) // 6 edwards25519.FeMul(&r, &t0, &c) // 7 edwards25519.FeSquare(&t0, &u) // 2 edwards25519.FeMul(&t0, &t0, &u) // 3 edwards25519.FeMul(&r, &r, &t0) edwards25519.FeSquare(&t0, &b8) // 16 edwards25519.FeMul(&t0, &t0, &b8) // 24 edwards25519.FeMul(&t0, &t0, &b) // 25 edwards25519.FeMul(&r, &r, &t0) edwards25519.FeMul(&r, &r, &sqrtMinusHalf) edwards25519.FeSquare(&t0, &r) edwards25519.FeMul(&t0, &t0, &u) edwards25519.FeAdd(&t0, &t0, &t0) edwards25519.FeAdd(&t0, &t0, &b) edwards25519.FeOne(&maybeSqrtM1) edwards25519.FeCMove(&maybeSqrtM1, &edwards25519.SqrtM1, edwards25519.FeIsNonZero(&t0)) edwards25519.FeMul(&r, &r, &maybeSqrtM1) var vBytes [32]byte edwards25519.FeToBytes(&vBytes, &v) vInSquareRootImage := feBytesLE(&vBytes, &halfQMinus1Bytes) edwards25519.FeCMove(&r, &r1, vInSquareRootImage) edwards25519.FeToBytes(publicKey, &u) edwards25519.FeToBytes(representative, &r) return true }