1 // Package chainkd This is an extension to ed25519.Sign that is compatible with NaCl `crypto_sign`
2 // function taking 64-byte expanded private key (where the left part is a pre-multiplied
3 // scalar and the right part is "prefix" used for generating a nonce).
6 // 1) Expanded(PrivateKey).Sign() == PrivateKey.Sign()
7 // 2) InnerSign(Expanded(PrivateKey)) == Sign(PrivateKey)
17 "github.com/bytom/crypto/ed25519"
18 "github.com/bytom/crypto/ed25519/internal/edwards25519"
22 // ExpandedPrivateKeySize is the size, in bytes, of a "secret key" as defined in NaCl.
23 ExpandedPrivateKeySize = 64
26 // ExpandedPrivateKey is the type of NaCl secret keys. It implements crypto.Signer.
27 type ExpandedPrivateKey []byte
29 // Public returns the PublicKey corresponding to secret key.
30 func (priv ExpandedPrivateKey) Public() crypto.PublicKey {
31 var A edwards25519.ExtendedGroupElement
33 copy(scalar[:], priv[:32])
34 edwards25519.GeScalarMultBase(&A, &scalar)
35 var publicKeyBytes [32]byte
36 A.ToBytes(&publicKeyBytes)
37 return ed25519.PublicKey(publicKeyBytes[:])
40 func expandEd25519PrivateKey(priv ed25519.PrivateKey) ExpandedPrivateKey {
41 digest := sha512.Sum512(priv[:32])
45 return ExpandedPrivateKey(digest[:])
48 // Sign signs the given message with expanded private key.
49 // Ed25519 performs two passes over messages to be signed and therefore cannot
50 // handle pre-hashed messages. Thus opts.HashFunc() must return zero to
51 // indicate the message hasn't been hashed. This can be achieved by passing
52 // crypto.Hash(0) as the value for opts.
53 func (priv ExpandedPrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
54 if opts.HashFunc() != crypto.Hash(0) {
55 return nil, errors.New("ed25519: cannot sign hashed message")
58 return Ed25519InnerSign(priv, message), nil
61 // Ed25519InnerSign signs the message with expanded private key and returns a signature.
62 // It will panic if len(privateKey) is not ExpandedPrivateKeySize.
63 func Ed25519InnerSign(privateKey ExpandedPrivateKey, message []byte) []byte {
64 if l := len(privateKey); l != ExpandedPrivateKeySize {
65 panic("ed25519: bad private key length: " + strconv.Itoa(l))
68 var messageDigest, hramDigest [64]byte
71 h.Write(privateKey[32:])
73 h.Sum(messageDigest[:0])
75 var messageDigestReduced [32]byte
76 edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
77 var R edwards25519.ExtendedGroupElement
78 edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
83 publicKey := privateKey.Public().(ed25519.PublicKey)
89 var hramDigestReduced [32]byte
90 edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
93 copy(sk[:], privateKey[:32])
95 edwards25519.ScMulAdd(&s, &hramDigestReduced, &sk, &messageDigestReduced)
97 signature := make([]byte, ed25519.SignatureSize)
98 copy(signature[:], encodedR[:])
99 copy(signature[32:], s[:])