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 }