github.com/Finschia/finschia-sdk@v0.48.1/crypto/keys/internal/ecdsa/privkey.go (about)

     1  package ecdsa
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"crypto/sha256"
     8  	"fmt"
     9  	"math/big"
    10  )
    11  
    12  // p256Order returns the curve order for the secp256r1 curve
    13  // NOTE: this is specific to the secp256r1/P256 curve,
    14  // and not taken from the domain params for the key itself
    15  // (which would be a more generic approach for all EC).
    16  var p256Order = elliptic.P256().Params().N
    17  
    18  // p256HalfOrder returns half the curve order
    19  // a bit shift of 1 to the right (Rsh) is equivalent
    20  // to division by 2, only faster.
    21  var p256HalfOrder = new(big.Int).Rsh(p256Order, 1)
    22  
    23  // IsSNormalized returns true for the integer sigS if sigS falls in
    24  // lower half of the curve order
    25  func IsSNormalized(sigS *big.Int) bool {
    26  	return sigS.Cmp(p256HalfOrder) != 1
    27  }
    28  
    29  // NormalizeS will invert the s value if not already in the lower half
    30  // of curve order value
    31  func NormalizeS(sigS *big.Int) *big.Int {
    32  	if IsSNormalized(sigS) {
    33  		return sigS
    34  	}
    35  
    36  	return new(big.Int).Sub(p256Order, sigS)
    37  }
    38  
    39  // signatureRaw will serialize signature to R || S.
    40  // R, S are padded to 32 bytes respectively.
    41  // code roughly copied from secp256k1_nocgo.go
    42  func signatureRaw(r *big.Int, s *big.Int) []byte {
    43  	rBytes := r.Bytes()
    44  	sBytes := s.Bytes()
    45  	sigBytes := make([]byte, 64)
    46  	// 0 pad the byte arrays from the left if they aren't big enough.
    47  	copy(sigBytes[32-len(rBytes):32], rBytes)
    48  	copy(sigBytes[64-len(sBytes):64], sBytes)
    49  	return sigBytes
    50  }
    51  
    52  // GenPrivKey generates a new secp256r1 private key. It uses operating
    53  // system randomness.
    54  func GenPrivKey(curve elliptic.Curve) (PrivKey, error) {
    55  	key, err := ecdsa.GenerateKey(curve, rand.Reader)
    56  	if err != nil {
    57  		return PrivKey{}, err
    58  	}
    59  	return PrivKey{*key}, nil
    60  }
    61  
    62  type PrivKey struct {
    63  	ecdsa.PrivateKey
    64  }
    65  
    66  // PubKey returns ECDSA public key associated with this private key.
    67  func (sk *PrivKey) PubKey() PubKey {
    68  	return PubKey{sk.PublicKey, nil}
    69  }
    70  
    71  // Bytes serialize the private key using big-endian.
    72  func (sk *PrivKey) Bytes() []byte {
    73  	if sk == nil {
    74  		return nil
    75  	}
    76  	fieldSize := (sk.Curve.Params().BitSize + 7) / 8
    77  	bz := make([]byte, fieldSize)
    78  	sk.D.FillBytes(bz)
    79  	return bz
    80  }
    81  
    82  // Sign hashes and signs the message using ECDSA. Implements SDK
    83  // PrivKey interface.
    84  // NOTE: this now calls the ecdsa Sign function
    85  // (not method!) directly as the s value of the signature is needed to
    86  // low-s normalize the signature value
    87  // See issue: https://github.com/cosmos/cosmos-sdk/issues/9723
    88  // It then raw encodes the signature as two fixed width 32-byte values
    89  // concatenated, reusing the code copied from secp256k1_nocgo.go
    90  func (sk *PrivKey) Sign(msg []byte) ([]byte, error) {
    91  	digest := sha256.Sum256(msg)
    92  	r, s, err := ecdsa.Sign(rand.Reader, &sk.PrivateKey, digest[:])
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	normS := NormalizeS(s)
    98  	return signatureRaw(r, normS), nil
    99  }
   100  
   101  // String returns a string representation of the public key based on the curveName.
   102  func (sk *PrivKey) String(name string) string {
   103  	return name + "{-}"
   104  }
   105  
   106  // MarshalTo implements proto.Marshaler interface.
   107  func (sk *PrivKey) MarshalTo(dAtA []byte) (int, error) {
   108  	bz := sk.Bytes()
   109  	copy(dAtA, bz)
   110  	return len(bz), nil
   111  }
   112  
   113  // Unmarshal implements proto.Marshaler interface.
   114  func (sk *PrivKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error {
   115  	if len(bz) != expectedSize {
   116  		return fmt.Errorf("wrong ECDSA SK bytes, expecting %d bytes", expectedSize)
   117  	}
   118  
   119  	sk.Curve = curve
   120  	sk.D = new(big.Int).SetBytes(bz)
   121  	sk.X, sk.Y = curve.ScalarBaseMult(bz)
   122  	return nil
   123  }