gitlab.com/gpdionisio/tendermint@v0.34.19-dev2/crypto/secp256k1/secp256k1.go (about) 1 package secp256k1 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "crypto/subtle" 7 "fmt" 8 "io" 9 "math/big" 10 11 secp256k1 "github.com/btcsuite/btcd/btcec" 12 "golang.org/x/crypto/ripemd160" // nolint: staticcheck // necessary for Bitcoin address format 13 14 "github.com/tendermint/tendermint/crypto" 15 tmjson "github.com/tendermint/tendermint/libs/json" 16 ) 17 18 //------------------------------------- 19 const ( 20 PrivKeyName = "tendermint/PrivKeySecp256k1" 21 PubKeyName = "tendermint/PubKeySecp256k1" 22 23 KeyType = "secp256k1" 24 PrivKeySize = 32 25 ) 26 27 func init() { 28 tmjson.RegisterType(PubKey{}, PubKeyName) 29 tmjson.RegisterType(PrivKey{}, PrivKeyName) 30 } 31 32 var _ crypto.PrivKey = PrivKey{} 33 34 // PrivKey implements PrivKey. 35 type PrivKey []byte 36 37 // Bytes marshalls the private key using amino encoding. 38 func (privKey PrivKey) Bytes() []byte { 39 return []byte(privKey) 40 } 41 42 // PubKey performs the point-scalar multiplication from the privKey on the 43 // generator point to get the pubkey. 44 func (privKey PrivKey) PubKey() crypto.PubKey { 45 _, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey) 46 47 pk := pubkeyObject.SerializeCompressed() 48 49 return PubKey(pk) 50 } 51 52 // Equals - you probably don't need to use this. 53 // Runs in constant time based on length of the keys. 54 func (privKey PrivKey) Equals(other crypto.PrivKey) bool { 55 if otherSecp, ok := other.(PrivKey); ok { 56 return subtle.ConstantTimeCompare(privKey[:], otherSecp[:]) == 1 57 } 58 return false 59 } 60 61 func (privKey PrivKey) Type() string { 62 return KeyType 63 } 64 65 // GenPrivKey generates a new ECDSA private key on curve secp256k1 private key. 66 // It uses OS randomness to generate the private key. 67 func GenPrivKey() PrivKey { 68 return genPrivKey(crypto.CReader()) 69 } 70 71 // genPrivKey generates a new secp256k1 private key using the provided reader. 72 func genPrivKey(rand io.Reader) PrivKey { 73 var privKeyBytes [PrivKeySize]byte 74 d := new(big.Int) 75 76 for { 77 privKeyBytes = [PrivKeySize]byte{} 78 _, err := io.ReadFull(rand, privKeyBytes[:]) 79 if err != nil { 80 panic(err) 81 } 82 83 d.SetBytes(privKeyBytes[:]) 84 // break if we found a valid point (i.e. > 0 and < N == curverOrder) 85 isValidFieldElement := 0 < d.Sign() && d.Cmp(secp256k1.S256().N) < 0 86 if isValidFieldElement { 87 break 88 } 89 } 90 91 return PrivKey(privKeyBytes[:]) 92 } 93 94 var one = new(big.Int).SetInt64(1) 95 96 // GenPrivKeySecp256k1 hashes the secret with SHA2, and uses 97 // that 32 byte output to create the private key. 98 // 99 // It makes sure the private key is a valid field element by setting: 100 // 101 // c = sha256(secret) 102 // k = (c mod (n − 1)) + 1, where n = curve order. 103 // 104 // NOTE: secret should be the output of a KDF like bcrypt, 105 // if it's derived from user input. 106 func GenPrivKeySecp256k1(secret []byte) PrivKey { 107 secHash := sha256.Sum256(secret) 108 // to guarantee that we have a valid field element, we use the approach of: 109 // "Suite B Implementer’s Guide to FIPS 186-3", A.2.1 110 // https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm 111 // see also https://github.com/golang/go/blob/0380c9ad38843d523d9c9804fe300cb7edd7cd3c/src/crypto/ecdsa/ecdsa.go#L89-L101 112 fe := new(big.Int).SetBytes(secHash[:]) 113 n := new(big.Int).Sub(secp256k1.S256().N, one) 114 fe.Mod(fe, n) 115 fe.Add(fe, one) 116 117 feB := fe.Bytes() 118 privKey32 := make([]byte, PrivKeySize) 119 // copy feB over to fixed 32 byte privKey32 and pad (if necessary) 120 copy(privKey32[32-len(feB):32], feB) 121 122 return PrivKey(privKey32) 123 } 124 125 // used to reject malleable signatures 126 // see: 127 // - https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/signature_nocgo.go#L90-L93 128 // - https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/crypto.go#L39 129 var secp256k1halfN = new(big.Int).Rsh(secp256k1.S256().N, 1) 130 131 // Sign creates an ECDSA signature on curve Secp256k1, using SHA256 on the msg. 132 // The returned signature will be of the form R || S (in lower-S form). 133 func (privKey PrivKey) Sign(msg []byte) ([]byte, error) { 134 priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey) 135 136 sig, err := priv.Sign(crypto.Sha256(msg)) 137 if err != nil { 138 return nil, err 139 } 140 141 sigBytes := serializeSig(sig) 142 return sigBytes, nil 143 } 144 145 //------------------------------------- 146 147 var _ crypto.PubKey = PubKey{} 148 149 // PubKeySize is comprised of 32 bytes for one field element 150 // (the x-coordinate), plus one byte for the parity of the y-coordinate. 151 const PubKeySize = 33 152 153 // PubKey implements crypto.PubKey. 154 // It is the compressed form of the pubkey. The first byte depends is a 0x02 byte 155 // if the y-coordinate is the lexicographically largest of the two associated with 156 // the x-coordinate. Otherwise the first byte is a 0x03. 157 // This prefix is followed with the x-coordinate. 158 type PubKey []byte 159 160 // Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey)) 161 func (pubKey PubKey) Address() crypto.Address { 162 if len(pubKey) != PubKeySize { 163 panic("length of pubkey is incorrect") 164 } 165 hasherSHA256 := sha256.New() 166 _, _ = hasherSHA256.Write(pubKey) // does not error 167 sha := hasherSHA256.Sum(nil) 168 169 hasherRIPEMD160 := ripemd160.New() 170 _, _ = hasherRIPEMD160.Write(sha) // does not error 171 172 return crypto.Address(hasherRIPEMD160.Sum(nil)) 173 } 174 175 // Bytes returns the pubkey marshaled with amino encoding. 176 func (pubKey PubKey) Bytes() []byte { 177 return []byte(pubKey) 178 } 179 180 func (pubKey PubKey) String() string { 181 return fmt.Sprintf("PubKeySecp256k1{%X}", []byte(pubKey)) 182 } 183 184 func (pubKey PubKey) Equals(other crypto.PubKey) bool { 185 if otherSecp, ok := other.(PubKey); ok { 186 return bytes.Equal(pubKey[:], otherSecp[:]) 187 } 188 return false 189 } 190 191 func (pubKey PubKey) Type() string { 192 return KeyType 193 } 194 195 // VerifySignature verifies a signature of the form R || S. 196 // It rejects signatures which are not in lower-S form. 197 func (pubKey PubKey) VerifySignature(msg []byte, sigStr []byte) bool { 198 if len(sigStr) != 64 { 199 return false 200 } 201 202 pub, err := secp256k1.ParsePubKey(pubKey, secp256k1.S256()) 203 if err != nil { 204 return false 205 } 206 207 // parse the signature: 208 signature := signatureFromBytes(sigStr) 209 // Reject malleable signatures. libsecp256k1 does this check but btcec doesn't. 210 // see: https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/signature_nocgo.go#L90-L93 211 if signature.S.Cmp(secp256k1halfN) > 0 { 212 return false 213 } 214 215 return signature.Verify(crypto.Sha256(msg), pub) 216 } 217 218 // Read Signature struct from R || S. Caller needs to ensure 219 // that len(sigStr) == 64. 220 func signatureFromBytes(sigStr []byte) *secp256k1.Signature { 221 return &secp256k1.Signature{ 222 R: new(big.Int).SetBytes(sigStr[:32]), 223 S: new(big.Int).SetBytes(sigStr[32:64]), 224 } 225 } 226 227 // Serialize signature to R || S. 228 // R, S are padded to 32 bytes respectively. 229 func serializeSig(sig *secp256k1.Signature) []byte { 230 rBytes := sig.R.Bytes() 231 sBytes := sig.S.Bytes() 232 sigBytes := make([]byte, 64) 233 // 0 pad the byte arrays from the left if they aren't big enough. 234 copy(sigBytes[32-len(rBytes):32], rBytes) 235 copy(sigBytes[64-len(sBytes):64], sBytes) 236 return sigBytes 237 }