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  }