github.com/cosmos/cosmos-sdk@v0.50.1/crypto/keys/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 "github.com/cometbft/cometbft/crypto" 12 secp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4" 13 "golang.org/x/crypto/ripemd160" //nolint: staticcheck // keep around for backwards compatibility 14 15 errorsmod "cosmossdk.io/errors" 16 17 "github.com/cosmos/cosmos-sdk/codec" 18 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 19 "github.com/cosmos/cosmos-sdk/types/errors" 20 ) 21 22 var ( 23 _ cryptotypes.PrivKey = &PrivKey{} 24 _ codec.AminoMarshaler = &PrivKey{} 25 ) 26 27 const ( 28 PrivKeySize = 32 29 keyType = "secp256k1" 30 PrivKeyName = "tendermint/PrivKeySecp256k1" 31 PubKeyName = "tendermint/PubKeySecp256k1" 32 ) 33 34 // Bytes returns the byte representation of the Private Key. 35 func (privKey *PrivKey) Bytes() []byte { 36 return privKey.Key 37 } 38 39 // PubKey performs the point-scalar multiplication from the privKey on the 40 // generator point to get the pubkey. 41 func (privKey *PrivKey) PubKey() cryptotypes.PubKey { 42 pubkeyObject := secp256k1.PrivKeyFromBytes(privKey.Key).PubKey() 43 pk := pubkeyObject.SerializeCompressed() 44 return &PubKey{Key: pk} 45 } 46 47 // Equals - you probably don't need to use this. 48 // Runs in constant time based on length of the 49 func (privKey *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { 50 return privKey.Type() == other.Type() && subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1 51 } 52 53 func (privKey *PrivKey) Type() string { 54 return keyType 55 } 56 57 // MarshalAmino overrides Amino binary marshaling. 58 func (privKey PrivKey) MarshalAmino() ([]byte, error) { 59 return privKey.Key, nil 60 } 61 62 // UnmarshalAmino overrides Amino binary marshaling. 63 func (privKey *PrivKey) UnmarshalAmino(bz []byte) error { 64 if len(bz) != PrivKeySize { 65 return fmt.Errorf("invalid privkey size") 66 } 67 privKey.Key = bz 68 69 return nil 70 } 71 72 // MarshalAminoJSON overrides Amino JSON marshaling. 73 func (privKey PrivKey) MarshalAminoJSON() ([]byte, error) { 74 // When we marshal to Amino JSON, we don't marshal the "key" field itself, 75 // just its contents (i.e. the key bytes). 76 return privKey.MarshalAmino() 77 } 78 79 // UnmarshalAminoJSON overrides Amino JSON marshaling. 80 func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error { 81 return privKey.UnmarshalAmino(bz) 82 } 83 84 // GenPrivKey generates a new ECDSA private key on curve secp256k1 private key. 85 // It uses OS randomness to generate the private key. 86 func GenPrivKey() *PrivKey { 87 return &PrivKey{Key: genPrivKey(crypto.CReader())} 88 } 89 90 // genPrivKey generates a new secp256k1 private key using the provided reader. 91 func genPrivKey(rand io.Reader) []byte { 92 var privKeyBytes [PrivKeySize]byte 93 d := new(big.Int) 94 for { 95 privKeyBytes = [PrivKeySize]byte{} 96 _, err := io.ReadFull(rand, privKeyBytes[:]) 97 if err != nil { 98 panic(err) 99 } 100 101 d.SetBytes(privKeyBytes[:]) 102 // break if we found a valid point (i.e. > 0 and < N == curverOrder) 103 isValidFieldElement := 0 < d.Sign() && d.Cmp(secp256k1.S256().N) < 0 104 if isValidFieldElement { 105 break 106 } 107 } 108 109 return privKeyBytes[:] 110 } 111 112 var one = new(big.Int).SetInt64(1) 113 114 // GenPrivKeyFromSecret hashes the secret with SHA2, and uses 115 // that 32 byte output to create the private key. 116 // 117 // It makes sure the private key is a valid field element by setting: 118 // 119 // c = sha256(secret) 120 // k = (c mod (n − 1)) + 1, where n = curve order. 121 // 122 // NOTE: secret should be the output of a KDF like bcrypt, 123 // if it's derived from user input. 124 func GenPrivKeyFromSecret(secret []byte) *PrivKey { 125 secHash := sha256.Sum256(secret) 126 // to guarantee that we have a valid field element, we use the approach of: 127 // "Suite B Implementer’s Guide to FIPS 186-3", A.2.1 128 // https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm 129 // see also https://github.com/golang/go/blob/0380c9ad38843d523d9c9804fe300cb7edd7cd3c/src/crypto/ecdsa/ecdsa.go#L89-L101 130 fe := new(big.Int).SetBytes(secHash[:]) 131 n := new(big.Int).Sub(secp256k1.S256().N, one) 132 fe.Mod(fe, n) 133 fe.Add(fe, one) 134 135 feB := fe.Bytes() 136 privKey32 := make([]byte, PrivKeySize) 137 // copy feB over to fixed 32 byte privKey32 and pad (if necessary) 138 copy(privKey32[32-len(feB):32], feB) 139 140 return &PrivKey{Key: privKey32} 141 } 142 143 //------------------------------------- 144 145 var ( 146 _ cryptotypes.PubKey = &PubKey{} 147 _ codec.AminoMarshaler = &PubKey{} 148 ) 149 150 // PubKeySize is comprised of 32 bytes for one field element 151 // (the x-coordinate), plus one byte for the parity of the y-coordinate. 152 const PubKeySize = 33 153 154 // Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey)) 155 func (pubKey *PubKey) Address() crypto.Address { 156 if len(pubKey.Key) != PubKeySize { 157 panic("length of pubkey is incorrect") 158 } 159 160 sha := sha256.Sum256(pubKey.Key) 161 hasherRIPEMD160 := ripemd160.New() 162 hasherRIPEMD160.Write(sha[:]) // does not error 163 return crypto.Address(hasherRIPEMD160.Sum(nil)) 164 } 165 166 // Bytes returns the pubkey byte format. 167 func (pubKey *PubKey) Bytes() []byte { 168 return pubKey.Key 169 } 170 171 func (pubKey *PubKey) String() string { 172 return fmt.Sprintf("PubKeySecp256k1{%X}", pubKey.Key) 173 } 174 175 func (pubKey *PubKey) Type() string { 176 return keyType 177 } 178 179 func (pubKey *PubKey) Equals(other cryptotypes.PubKey) bool { 180 return pubKey.Type() == other.Type() && bytes.Equal(pubKey.Bytes(), other.Bytes()) 181 } 182 183 // MarshalAmino overrides Amino binary marshaling. 184 func (pubKey PubKey) MarshalAmino() ([]byte, error) { 185 return pubKey.Key, nil 186 } 187 188 // UnmarshalAmino overrides Amino binary marshaling. 189 func (pubKey *PubKey) UnmarshalAmino(bz []byte) error { 190 if len(bz) != PubKeySize { 191 return errorsmod.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size") 192 } 193 pubKey.Key = bz 194 195 return nil 196 } 197 198 // MarshalAminoJSON overrides Amino JSON marshaling. 199 func (pubKey PubKey) MarshalAminoJSON() ([]byte, error) { 200 // When we marshal to Amino JSON, we don't marshal the "key" field itself, 201 // just its contents (i.e. the key bytes). 202 return pubKey.MarshalAmino() 203 } 204 205 // UnmarshalAminoJSON overrides Amino JSON marshaling. 206 func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error { 207 return pubKey.UnmarshalAmino(bz) 208 }