// SignThreshold signs a message 'hash' using the given private scalar priv in // a threshold group signature. It uses RFC6979 to generate a deterministic nonce. // Considered experimental. // As opposed to the threshold signing function for secp256k1, this function // takes the entirety of the public nonce point (all points added) instead of // the public nonce point with n-1 keys added. // r = K_Sum // s = r + hash512(k || A || M) * a func SignThreshold(curve *TwistedEdwardsCurve, priv *PrivateKey, groupPub *PublicKey, hash []byte, privNonce *PrivateKey, pubNonceSum *PublicKey) (r, s *big.Int, err error) { if priv == nil || hash == nil || privNonce == nil || pubNonceSum == nil { return nil, nil, fmt.Errorf("nil input") } privateScalar := copyBytes(priv.Serialize()) reverse(privateScalar) // BE --> LE // Threshold variant scheme: // R = K_Sum // Where K_Sum is the sum of the public keys corresponding to // the private nonce scalars of each group signature member. // That is, R = k1G + ... + knG. encodedGroupR := BigIntPointToEncodedBytes(pubNonceSum.GetX(), pubNonceSum.GetY()) // h = hash512(k || A || M) var hramDigest [64]byte h := sha512.New() h.Reset() h.Write(encodedGroupR[:]) h.Write(groupPub.Serialize()[:]) h.Write(hash) h.Sum(hramDigest[:0]) var hramDigestReduced [32]byte edwards25519.ScReduce(&hramDigestReduced, &hramDigest) // s = r + h * a var localS [32]byte privNonceLE := copyBytes(privNonce.Serialize()) reverse(privNonceLE) // BE --> LE edwards25519.ScMulAdd(&localS, &hramDigestReduced, privateScalar, privNonceLE) signature := new([64]byte) copy(signature[:], encodedGroupR[:]) copy(signature[32:], localS[:]) sigEd, err := ParseSignature(curve, signature[:]) if err != nil { return nil, nil, err } return sigEd.GetR(), sigEd.GetS(), nil }
// 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 }
// 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 }