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