// MakePublicKey makes a publicKey from the first half of privateKey. func MakePublicKey(privateKey *[PrivateKeySize]byte) (publicKey *[PublicKeySize]byte) { publicKey = new([32]byte) 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 }
// 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 }
// 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 }