5400547a5f
I had to move Verify function into separate file to tag it as `cgo` only build. go-fuzz doesn't work with cgo. License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
135 lines
2.5 KiB
Go
135 lines
2.5 KiB
Go
package types
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
|
|
cbor "github.com/ipfs/go-ipld-cbor"
|
|
"github.com/polydawn/refmt/obj/atlas"
|
|
cbg "github.com/whyrusleeping/cbor-gen"
|
|
)
|
|
|
|
const SignatureMaxLength = 200
|
|
|
|
const (
|
|
KTSecp256k1 = "secp256k1"
|
|
KTBLS = "bls"
|
|
)
|
|
|
|
const (
|
|
IKTUnknown = -1
|
|
|
|
IKTSecp256k1 = iota
|
|
IKTBLS
|
|
)
|
|
|
|
func init() {
|
|
cbor.RegisterCborType(atlas.BuildEntry(Signature{}).Transform().
|
|
TransformMarshal(atlas.MakeMarshalTransformFunc(
|
|
func(s Signature) ([]byte, error) {
|
|
buf := make([]byte, 4)
|
|
n := binary.PutUvarint(buf, uint64(s.TypeCode()))
|
|
return append(buf[:n], s.Data...), nil
|
|
})).
|
|
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
|
|
func(x []byte) (Signature, error) {
|
|
return SignatureFromBytes(x)
|
|
})).
|
|
Complete())
|
|
}
|
|
|
|
type Signature struct {
|
|
Type string
|
|
Data []byte
|
|
}
|
|
|
|
func SignatureFromBytes(x []byte) (Signature, error) {
|
|
val, nr := binary.Uvarint(x)
|
|
if nr != 1 {
|
|
return Signature{}, fmt.Errorf("signatures with type field longer than one byte are invalid")
|
|
}
|
|
var ts string
|
|
switch val {
|
|
case IKTSecp256k1:
|
|
ts = KTSecp256k1
|
|
case IKTBLS:
|
|
ts = KTBLS
|
|
default:
|
|
return Signature{}, fmt.Errorf("unsupported signature type: %d", val)
|
|
}
|
|
|
|
return Signature{
|
|
Type: ts,
|
|
Data: x[1:],
|
|
}, nil
|
|
}
|
|
|
|
func (s *Signature) TypeCode() int {
|
|
switch s.Type {
|
|
case KTSecp256k1:
|
|
return IKTSecp256k1
|
|
case KTBLS:
|
|
return IKTBLS
|
|
case "":
|
|
return IKTUnknown
|
|
default:
|
|
panic("unsupported signature type")
|
|
}
|
|
}
|
|
|
|
func (s *Signature) MarshalCBOR(w io.Writer) error {
|
|
header := cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(s.Data)+1))
|
|
|
|
if _, err := w.Write(header); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := w.Write([]byte{byte(s.TypeCode())}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := w.Write(s.Data); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Signature) UnmarshalCBOR(br io.Reader) error {
|
|
maj, l, err := cbg.CborReadHeader(br)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if maj != cbg.MajByteString {
|
|
return fmt.Errorf("cbor input for signature was not a byte string")
|
|
}
|
|
|
|
if l > SignatureMaxLength {
|
|
return fmt.Errorf("cbor byte array for signature was too long")
|
|
}
|
|
|
|
buf := make([]byte, l)
|
|
if _, err := io.ReadFull(br, buf); err != nil {
|
|
return err
|
|
}
|
|
|
|
switch buf[0] {
|
|
default:
|
|
return fmt.Errorf("invalid signature type in cbor input: %d", buf[0])
|
|
case IKTSecp256k1:
|
|
s.Type = KTSecp256k1
|
|
case IKTBLS:
|
|
s.Type = KTBLS
|
|
}
|
|
s.Data = buf[1:]
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Signature) Equals(o *Signature) bool {
|
|
return s.Type == o.Type && bytes.Equal(s.Data, o.Data)
|
|
}
|