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 }