github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/crypto/ed25519/chainkd/expanded_key.go (about) 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). 4 // 5 // Invariants: 6 // 1) Expanded(PrivateKey).Sign() == PrivateKey.Sign() 7 // 2) InnerSign(Expanded(PrivateKey)) == Sign(PrivateKey) 8 package chainkd 9 10 import ( 11 "crypto" 12 "crypto/sha512" 13 "errors" 14 "io" 15 "strconv" 16 17 "github.com/bytom/bytom/crypto/ed25519" 18 "github.com/bytom/bytom/crypto/ed25519/internal/edwards25519" 19 ) 20 21 const ( 22 // ExpandedPrivateKeySize is the size, in bytes, of a "secret key" as defined in NaCl. 23 ExpandedPrivateKeySize = 64 24 ) 25 26 // ExpandedPrivateKey is the type of NaCl secret keys. It implements crypto.Signer. 27 type ExpandedPrivateKey []byte 28 29 // Public returns the PublicKey corresponding to secret key. 30 func (priv ExpandedPrivateKey) Public() crypto.PublicKey { 31 var A edwards25519.ExtendedGroupElement 32 var scalar [32]byte 33 copy(scalar[:], priv[:32]) 34 edwards25519.GeScalarMultBase(&A, &scalar) 35 var publicKeyBytes [32]byte 36 A.ToBytes(&publicKeyBytes) 37 return ed25519.PublicKey(publicKeyBytes[:]) 38 } 39 40 func expandEd25519PrivateKey(priv ed25519.PrivateKey) ExpandedPrivateKey { 41 digest := sha512.Sum512(priv[:32]) 42 digest[0] &= 248 43 digest[31] &= 127 44 digest[31] |= 64 45 return ExpandedPrivateKey(digest[:]) 46 } 47 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") 56 } 57 58 return Ed25519InnerSign(priv, message), nil 59 } 60 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)) 66 } 67 68 var messageDigest, hramDigest [64]byte 69 70 h := sha512.New() 71 h.Write(privateKey[32:]) 72 h.Write(message) 73 h.Sum(messageDigest[:0]) 74 75 var messageDigestReduced [32]byte 76 edwards25519.ScReduce(&messageDigestReduced, &messageDigest) 77 var R edwards25519.ExtendedGroupElement 78 edwards25519.GeScalarMultBase(&R, &messageDigestReduced) 79 80 var encodedR [32]byte 81 R.ToBytes(&encodedR) 82 83 publicKey := privateKey.Public().(ed25519.PublicKey) 84 h.Reset() 85 h.Write(encodedR[:]) 86 h.Write(publicKey[:]) 87 h.Write(message) 88 h.Sum(hramDigest[:0]) 89 var hramDigestReduced [32]byte 90 edwards25519.ScReduce(&hramDigestReduced, &hramDigest) 91 92 var sk [32]byte 93 copy(sk[:], privateKey[:32]) 94 var s [32]byte 95 edwards25519.ScMulAdd(&s, &hramDigestReduced, &sk, &messageDigestReduced) 96 97 signature := make([]byte, ed25519.SignatureSize) 98 copy(signature[:], encodedR[:]) 99 copy(signature[32:], s[:]) 100 101 return signature 102 }