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

     1  package ecdsa
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/sha256"
     7  	"fmt"
     8  	"math/big"
     9  
    10  	tmcrypto "github.com/Finschia/ostracon/crypto"
    11  
    12  	"github.com/Finschia/finschia-sdk/types/address"
    13  	"github.com/Finschia/finschia-sdk/types/errors"
    14  )
    15  
    16  // signatureFromBytes function roughly copied from secp256k1_nocgo.go
    17  // Read Signature struct from R || S. Caller needs to ensure that
    18  // len(sigStr) == 64.
    19  func signatureFromBytes(sigStr []byte) *signature {
    20  	return &signature{
    21  		R: new(big.Int).SetBytes(sigStr[:32]),
    22  		S: new(big.Int).SetBytes(sigStr[32:64]),
    23  	}
    24  }
    25  
    26  // signature holds the r and s values of an ECDSA signature.
    27  type signature struct {
    28  	R, S *big.Int
    29  }
    30  
    31  type PubKey struct {
    32  	ecdsa.PublicKey
    33  
    34  	// cache
    35  	address tmcrypto.Address
    36  }
    37  
    38  // Address gets the address associated with a pubkey. If no address exists, it returns a newly created ADR-28 address
    39  // for ECDSA keys.
    40  // protoName is a concrete proto structure id.
    41  func (pk *PubKey) Address(protoName string) tmcrypto.Address {
    42  	if pk.address == nil {
    43  		pk.address = address.Hash(protoName, pk.Bytes())
    44  	}
    45  	return pk.address
    46  }
    47  
    48  // Bytes returns the byte representation of the public key using a compressed form
    49  // specified in section 4.3.6 of ANSI X9.62 with first byte being the curve type.
    50  func (pk *PubKey) Bytes() []byte {
    51  	if pk == nil {
    52  		return nil
    53  	}
    54  	return elliptic.MarshalCompressed(pk.Curve, pk.X, pk.Y)
    55  }
    56  
    57  // VerifySignature checks if sig is a valid ECDSA signature for msg.
    58  // This includes checking for low-s normalized signatures
    59  // where the s integer component of the signature is in the
    60  // lower half of the curve order
    61  // 7/21/21 - expects raw encoded signature (fixed-width 64-bytes, R || S)
    62  func (pk *PubKey) VerifySignature(msg []byte, sig []byte) bool {
    63  	// check length for raw signature
    64  	// which is two 32-byte padded big.Ints
    65  	// concatenated
    66  	// NOT DER!
    67  
    68  	if len(sig) != 64 {
    69  		return false
    70  	}
    71  
    72  	s := signatureFromBytes(sig)
    73  	if !IsSNormalized(s.S) {
    74  		return false
    75  	}
    76  
    77  	h := sha256.Sum256(msg)
    78  	return ecdsa.Verify(&pk.PublicKey, h[:], s.R, s.S)
    79  }
    80  
    81  // String returns a string representation of the public key based on the curveName.
    82  func (pk *PubKey) String(curveName string) string {
    83  	return fmt.Sprintf("%s{%X}", curveName, pk.Bytes())
    84  }
    85  
    86  // **** Proto Marshaler ****
    87  
    88  // MarshalTo implements proto.Marshaler interface.
    89  func (pk *PubKey) MarshalTo(dAtA []byte) (int, error) {
    90  	bz := pk.Bytes()
    91  	copy(dAtA, bz)
    92  	return len(bz), nil
    93  }
    94  
    95  // Unmarshal implements proto.Marshaler interface.
    96  func (pk *PubKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error {
    97  	if len(bz) != expectedSize {
    98  		return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, expecting %d bytes, got %d", expectedSize, len(bz))
    99  	}
   100  	cpk := ecdsa.PublicKey{Curve: curve}
   101  	cpk.X, cpk.Y = elliptic.UnmarshalCompressed(curve, bz)
   102  	if cpk.X == nil || cpk.Y == nil {
   103  		return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, unknown curve type: %d", bz[0])
   104  	}
   105  	pk.PublicKey = cpk
   106  	return nil
   107  }