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