github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/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 ) 16 17 var _ crypto.PrivKey = PrivKey{} 18 19 const ( 20 PrivKeySize = 32 21 keyType = "secp256k1" 22 ) 23 24 // PrivKey implements PrivKey. 25 type PrivKey []byte 26 27 // Bytes returns the byte representation of the Private Key. 28 func (privKey PrivKey) Bytes() []byte { 29 return []byte(privKey) 30 } 31 32 // PubKey performs the point-scalar multiplication from the privKey on the 33 // generator point to get the pubkey. 34 func (privKey PrivKey) PubKey() crypto.PubKey { 35 _, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey) 36 return PubKey(pubkeyObject.SerializeCompressed()) 37 } 38 39 // Equals - you probably don't need to use this. 40 // Runs in constant time based on length of the keys. 41 func (privKey PrivKey) Equals(other crypto.PrivKey) bool { 42 if otherSecp, ok := other.(PrivKey); ok { 43 return subtle.ConstantTimeCompare(privKey[:], otherSecp[:]) == 1 44 } 45 return false 46 } 47 48 func (privKey PrivKey) Type() string { 49 return keyType 50 } 51 52 // GenPrivKey generates a new ECDSA private key on curve secp256k1 private key. 53 // It uses OS randomness to generate the private key. 54 func GenPrivKey() PrivKey { 55 return genPrivKey(crypto.CReader()) 56 } 57 58 // genPrivKey generates a new secp256k1 private key using the provided reader. 59 func genPrivKey(rand io.Reader) PrivKey { 60 var privKeyBytes [PrivKeySize]byte 61 d := new(big.Int) 62 for { 63 privKeyBytes = [PrivKeySize]byte{} 64 _, err := io.ReadFull(rand, privKeyBytes[:]) 65 if err != nil { 66 panic(err) 67 } 68 69 d.SetBytes(privKeyBytes[:]) 70 // break if we found a valid point (i.e. > 0 and < N == curverOrder) 71 isValidFieldElement := 0 < d.Sign() && d.Cmp(secp256k1.S256().N) < 0 72 if isValidFieldElement { 73 break 74 } 75 } 76 77 return PrivKey(privKeyBytes[:]) 78 } 79 80 var one = new(big.Int).SetInt64(1) 81 82 // GenPrivKeySecp256k1 hashes the secret with SHA2, and uses 83 // that 32 byte output to create the private key. 84 // 85 // It makes sure the private key is a valid field element by setting: 86 // 87 // c = sha256(secret) 88 // k = (c mod (n − 1)) + 1, where n = curve order. 89 // 90 // NOTE: secret should be the output of a KDF like bcrypt, 91 // if it's derived from user input. 92 func GenPrivKeySecp256k1(secret []byte) PrivKey { 93 secHash := sha256.Sum256(secret) 94 // to guarantee that we have a valid field element, we use the approach of: 95 // "Suite B Implementer’s Guide to FIPS 186-3", A.2.1 96 // https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm 97 // see also https://github.com/golang/go/blob/0380c9ad38843d523d9c9804fe300cb7edd7cd3c/src/crypto/ecdsa/ecdsa.go#L89-L101 98 fe := new(big.Int).SetBytes(secHash[:]) 99 n := new(big.Int).Sub(secp256k1.S256().N, one) 100 fe.Mod(fe, n) 101 fe.Add(fe, one) 102 103 feB := fe.Bytes() 104 privKey32 := make([]byte, PrivKeySize) 105 // copy feB over to fixed 32 byte privKey32 and pad (if necessary) 106 copy(privKey32[32-len(feB):32], feB) 107 108 return PrivKey(privKey32) 109 } 110 111 //------------------------------------- 112 113 var _ crypto.PubKey = PubKey{} 114 115 // PubKeySize is comprised of 32 bytes for one field element 116 // (the x-coordinate), plus one byte for the parity of the y-coordinate. 117 const PubKeySize = 33 118 119 // PubKey implements crypto.PubKey. 120 // It is the compressed form of the pubkey. The first byte depends is a 0x02 byte 121 // if the y-coordinate is the lexicographically largest of the two associated with 122 // the x-coordinate. Otherwise the first byte is a 0x03. 123 // This prefix is followed with the x-coordinate. 124 type PubKey []byte 125 126 // Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey)) 127 func (pubKey PubKey) Address() crypto.Address { 128 if len(pubKey) != PubKeySize { 129 panic("length of pubkey is incorrect") 130 } 131 132 hasherSHA256 := sha256.New() 133 hasherSHA256.Write(pubKey) // does not error 134 sha := hasherSHA256.Sum(nil) 135 136 hasherRIPEMD160 := ripemd160.New() 137 hasherRIPEMD160.Write(sha) // does not error 138 return crypto.Address(hasherRIPEMD160.Sum(nil)) 139 } 140 141 // Bytes returns the pubkey byte format. 142 func (pubKey PubKey) Bytes() []byte { 143 return []byte(pubKey) 144 } 145 146 func (pubKey PubKey) String() string { 147 return fmt.Sprintf("PubKeySecp256k1{%X}", []byte(pubKey)) 148 } 149 150 func (pubKey PubKey) Type() string { 151 return keyType 152 } 153 154 func (pubKey PubKey) Equals(other crypto.PubKey) bool { 155 if otherSecp, ok := other.(PubKey); ok { 156 return bytes.Equal(pubKey[:], otherSecp[:]) 157 } 158 return false 159 }