github.com/project-88388/tendermint-v0.34.14-terra.2@v1.0.0/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 //------------------------------------- 126 127 var _ crypto.PubKey = PubKey{} 128 129 // PubKeySize is comprised of 32 bytes for one field element 130 // (the x-coordinate), plus one byte for the parity of the y-coordinate. 131 const PubKeySize = 33 132 133 // PubKey implements crypto.PubKey. 134 // It is the compressed form of the pubkey. The first byte depends is a 0x02 byte 135 // if the y-coordinate is the lexicographically largest of the two associated with 136 // the x-coordinate. Otherwise the first byte is a 0x03. 137 // This prefix is followed with the x-coordinate. 138 type PubKey []byte 139 140 // Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey)) 141 func (pubKey PubKey) Address() crypto.Address { 142 if len(pubKey) != PubKeySize { 143 panic("length of pubkey is incorrect") 144 } 145 hasherSHA256 := sha256.New() 146 _, _ = hasherSHA256.Write(pubKey) // does not error 147 sha := hasherSHA256.Sum(nil) 148 149 hasherRIPEMD160 := ripemd160.New() 150 _, _ = hasherRIPEMD160.Write(sha) // does not error 151 152 return crypto.Address(hasherRIPEMD160.Sum(nil)) 153 } 154 155 // Bytes returns the pubkey marshalled with amino encoding. 156 func (pubKey PubKey) Bytes() []byte { 157 return []byte(pubKey) 158 } 159 160 func (pubKey PubKey) String() string { 161 return fmt.Sprintf("PubKeySecp256k1{%X}", []byte(pubKey)) 162 } 163 164 func (pubKey PubKey) Equals(other crypto.PubKey) bool { 165 if otherSecp, ok := other.(PubKey); ok { 166 return bytes.Equal(pubKey[:], otherSecp[:]) 167 } 168 return false 169 } 170 171 func (pubKey PubKey) Type() string { 172 return KeyType 173 }