1package types 2 3import ( 4 "bytes" 5 6 "github.com/ethereum/go-ethereum/crypto" 7 "github.com/status-im/keycard-go/apdu" 8) 9 10var ( 11 TagSignatureTemplate = uint8(0xA0) 12) 13 14type Signature struct { 15 pubKey []byte 16 r []byte 17 s []byte 18 v byte 19} 20 21func ParseSignature(message, resp []byte) (*Signature, error) { 22 pubKey, err := apdu.FindTag(resp, TagSignatureTemplate, uint8(0x80)) 23 if err != nil { 24 return nil, err 25 } 26 27 r, err := apdu.FindTagN(resp, 0, TagSignatureTemplate, uint8(0x30), uint8(0x02)) 28 if err != nil { 29 return nil, err 30 } 31 32 if len(r) > 32 { 33 r = r[len(r)-32:] 34 } 35 36 s, err := apdu.FindTagN(resp, 1, TagSignatureTemplate, uint8(0x30), uint8(0x02)) 37 if err != nil { 38 return nil, err 39 } 40 41 v, err := calculateV(message, pubKey, r, s) 42 if err != nil { 43 return nil, err 44 } 45 46 return &Signature{ 47 pubKey: pubKey, 48 r: r, 49 s: s, 50 v: v, 51 }, nil 52} 53 54func (s *Signature) R() []byte { 55 return s.r 56} 57 58func (s *Signature) S() []byte { 59 return s.s 60} 61 62func (s *Signature) V() byte { 63 return s.v 64} 65 66func calculateV(message, pubKey, r, s []byte) (v byte, err error) { 67 rs := append(r, s...) 68 for i := 0; i < 2; i++ { 69 v = byte(i) 70 sig := append(rs, v) 71 rec, err := crypto.Ecrecover(message, sig) 72 if err != nil { 73 return v, err 74 } 75 76 if bytes.Equal(pubKey, rec) { 77 return v, nil 78 } 79 } 80 81 return v, err 82} 83