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