83 lines
1.3 KiB
Go
83 lines
1.3 KiB
Go
|
package types
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
|
||
|
"github.com/ethereum/go-ethereum/crypto"
|
||
|
"github.com/status-im/keycard-go/apdu"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
TagSignatureTemplate = uint8(0xA0)
|
||
|
)
|
||
|
|
||
|
type Signature struct {
|
||
|
pubKey []byte
|
||
|
r []byte
|
||
|
s []byte
|
||
|
v byte
|
||
|
}
|
||
|
|
||
|
func ParseSignature(message, resp []byte) (*Signature, error) {
|
||
|
pubKey, err := apdu.FindTag(resp, TagSignatureTemplate, uint8(0x80))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
r, err := apdu.FindTagN(resp, 0, TagSignatureTemplate, uint8(0x30), uint8(0x02))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if len(r) > 32 {
|
||
|
r = r[len(r)-32:]
|
||
|
}
|
||
|
|
||
|
s, err := apdu.FindTagN(resp, 1, TagSignatureTemplate, uint8(0x30), uint8(0x02))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
v, err := calculateV(message, pubKey, r, s)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &Signature{
|
||
|
pubKey: pubKey,
|
||
|
r: r,
|
||
|
s: s,
|
||
|
v: v,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (s *Signature) R() []byte {
|
||
|
return s.r
|
||
|
}
|
||
|
|
||
|
func (s *Signature) S() []byte {
|
||
|
return s.s
|
||
|
}
|
||
|
|
||
|
func (s *Signature) V() byte {
|
||
|
return s.v
|
||
|
}
|
||
|
|
||
|
func calculateV(message, pubKey, r, s []byte) (v byte, err error) {
|
||
|
rs := append(r, s...)
|
||
|
for i := 0; i < 2; i++ {
|
||
|
v = byte(i)
|
||
|
sig := append(rs, v)
|
||
|
rec, err := crypto.Ecrecover(message, sig)
|
||
|
if err != nil {
|
||
|
return v, err
|
||
|
}
|
||
|
|
||
|
if bytes.Equal(pubKey, rec) {
|
||
|
return v, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return v, err
|
||
|
}
|