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