dione/types/signature.go
2020-12-02 17:03:39 +03:00

133 lines
2.6 KiB
Go

package types
import (
"bytes"
"fmt"
"io"
"math"
cbg "github.com/whyrusleeping/cbor-gen"
)
type SigType byte
const (
SigTypeUnknown = SigType(math.MaxUint8)
SigTypeSecp256k1 = SigType(iota)
SigTypeBLS
SigTypeEd25519
)
func (t SigType) Name() (string, error) {
switch t {
case SigTypeUnknown:
return "unknown", nil
case SigTypeEd25519:
return "ed25519", nil
case SigTypeSecp256k1:
return "secp256k1", nil
case SigTypeBLS:
return "bls", nil
default:
return "", fmt.Errorf("invalid signature type: %d", t)
}
}
const SignatureMaxLength = 200
type Signature struct {
Type SigType
Data []byte
}
func (s *Signature) Equals(o *Signature) bool {
if s == nil || o == nil {
return s == o
}
return s.Type == o.Type && bytes.Equal(s.Data, o.Data)
}
func (s *Signature) MarshalCBOR(w io.Writer) error {
if s == nil {
_, err := w.Write(cbg.CborNull)
return err
}
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.Type)}); 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("not a byte string")
}
if l > SignatureMaxLength {
return fmt.Errorf("string too long")
}
if l == 0 {
return fmt.Errorf("string empty")
}
buf := make([]byte, l)
if _, err = io.ReadFull(br, buf); err != nil {
return err
}
switch SigType(buf[0]) {
default:
return fmt.Errorf("invalid signature type in cbor input: %d", buf[0])
case SigTypeEd25519:
s.Type = SigTypeEd25519
case SigTypeSecp256k1:
s.Type = SigTypeSecp256k1
case SigTypeBLS:
s.Type = SigTypeBLS
}
s.Data = buf[1:]
return nil
}
func (s *Signature) MarshalBinary() ([]byte, error) {
bs := make([]byte, len(s.Data)+1)
bs[0] = byte(s.Type)
copy(bs[1:], s.Data)
return bs, nil
}
func (s *Signature) UnmarshalBinary(bs []byte) error {
if len(bs) > SignatureMaxLength {
return fmt.Errorf("invalid signature bytes, too long (%d)", len(bs))
}
if len(bs) == 0 {
return fmt.Errorf("invalid signature bytes of length 0")
}
switch SigType(bs[0]) {
default:
// Do not error during unmarshal but leave a standard value.
// unmarshal(marshal(zero valued sig)) is valuable for test
// and type needs to be checked by caller anyway.
s.Type = SigTypeUnknown
case SigTypeEd25519:
s.Type = SigTypeEd25519
case SigTypeSecp256k1:
s.Type = SigTypeSecp256k1
case SigTypeBLS:
s.Type = SigTypeBLS
}
s.Data = bs[1:]
return nil
}