github.com/mavryk-network/mvgo@v1.19.9/mavryk/sig.go (about)

     1  // Copyright (c) 2020-2021 Blockwatch Data Inc.
     2  // Author: alex@blockwatch.cc
     3  
     4  package mavryk
     5  
     6  import (
     7  	"bytes"
     8  	"errors"
     9  	"fmt"
    10  	"strings"
    11  
    12  	"github.com/mavryk-network/mvgo/base58"
    13  )
    14  
    15  var (
    16  	// ErrUnknownSignatureType describes an error where a type for a
    17  	// signature is undefined.
    18  	ErrUnknownSignatureType = errors.New("unknown signature type")
    19  
    20  	// ErrSignature is returned when signature verification fails
    21  	ErrSignature = errors.New("signature mismatch")
    22  
    23  	// InvalidSignature represents an empty invalid signature
    24  	InvalidSignature = Signature{Type: SignatureTypeInvalid, Data: nil}
    25  
    26  	// ZeroSignature represents a valid signature derived from null bytes
    27  	ZeroSignature = MustParseSignature("sigMzJ4GVAvXEd2RjsKGfG2H9QvqTSKCZsuB2KiHbZRGFz72XgF6KaKADznh674fQgBatxw3xdHqTtMHUZAGRprxy64wg1aq")
    28  )
    29  
    30  // SignatureType represents the type of a Tezos signature.
    31  type SignatureType byte
    32  
    33  const (
    34  	SignatureTypeEd25519 SignatureType = iota
    35  	SignatureTypeSecp256k1
    36  	SignatureTypeP256
    37  	SignatureTypeBls12_381
    38  	SignatureTypeGeneric
    39  	SignatureTypeGenericAggregate
    40  	SignatureTypeInvalid
    41  )
    42  
    43  func (t SignatureType) IsValid() bool {
    44  	return t < SignatureTypeInvalid
    45  }
    46  
    47  func (t SignatureType) HashType() HashType {
    48  	switch t {
    49  	case SignatureTypeEd25519:
    50  		return HashTypeSigEd25519
    51  	case SignatureTypeSecp256k1:
    52  		return HashTypeSigSecp256k1
    53  	case SignatureTypeP256:
    54  		return HashTypeSigP256
    55  	case SignatureTypeBls12_381:
    56  		return HashTypeSigBls12_381
    57  	case SignatureTypeGeneric:
    58  		return HashTypeSigGeneric
    59  	case SignatureTypeGenericAggregate:
    60  		return HashTypeSigGenericAggregate
    61  	default:
    62  		return HashTypeInvalid
    63  	}
    64  }
    65  
    66  func (t SignatureType) PrefixBytes() []byte {
    67  	switch t {
    68  	case SignatureTypeEd25519:
    69  		return ED25519_SIGNATURE_ID
    70  	case SignatureTypeSecp256k1:
    71  		return SECP256K1_SIGNATURE_ID
    72  	case SignatureTypeP256:
    73  		return P256_SIGNATURE_ID
    74  	case SignatureTypeBls12_381:
    75  		return BLS12_381_SIGNATURE_ID
    76  	case SignatureTypeGeneric:
    77  		return GENERIC_SIGNATURE_ID
    78  	case SignatureTypeGenericAggregate:
    79  		return GENERIC_AGGREGATE_SIGNATURE_ID
    80  	default:
    81  		return nil
    82  	}
    83  }
    84  
    85  func (t SignatureType) Prefix() string {
    86  	switch t {
    87  	case SignatureTypeEd25519:
    88  		return ED25519_SIGNATURE_PREFIX
    89  	case SignatureTypeSecp256k1:
    90  		return SECP256K1_SIGNATURE_PREFIX
    91  	case SignatureTypeP256:
    92  		return P256_SIGNATURE_PREFIX
    93  	case SignatureTypeBls12_381:
    94  		return BLS12_381_SIGNATURE_PREFIX
    95  	case SignatureTypeGeneric:
    96  		return GENERIC_SIGNATURE_PREFIX
    97  	case SignatureTypeGenericAggregate:
    98  		return GENERIC_AGGREGATE_SIGNATURE_PREFIX
    99  	default:
   100  		return ""
   101  	}
   102  }
   103  
   104  func (t SignatureType) String() string {
   105  	return t.Prefix()
   106  }
   107  
   108  func (t SignatureType) Tag() byte {
   109  	switch t {
   110  	case SignatureTypeEd25519:
   111  		return 0
   112  	case SignatureTypeSecp256k1:
   113  		return 1
   114  	case SignatureTypeP256:
   115  		return 2
   116  	case SignatureTypeBls12_381:
   117  		return 3
   118  	default:
   119  		return 255
   120  	}
   121  }
   122  
   123  func ParseSignatureTag(b byte) SignatureType {
   124  	switch b {
   125  	case 0:
   126  		return SignatureTypeEd25519
   127  	case 1:
   128  		return SignatureTypeSecp256k1
   129  	case 2:
   130  		return SignatureTypeP256
   131  	case 3:
   132  		return SignatureTypeBls12_381
   133  	default:
   134  		return SignatureTypeGeneric
   135  	}
   136  }
   137  
   138  func HasSignaturePrefix(s string) bool {
   139  	for _, prefix := range []string{
   140  		ED25519_SIGNATURE_PREFIX,
   141  		SECP256K1_SIGNATURE_PREFIX,
   142  		P256_SIGNATURE_PREFIX,
   143  		BLS12_381_SIGNATURE_PREFIX,
   144  		GENERIC_SIGNATURE_PREFIX,
   145  		GENERIC_AGGREGATE_SIGNATURE_PREFIX,
   146  	} {
   147  		if strings.HasPrefix(s, prefix) {
   148  			return true
   149  		}
   150  	}
   151  	return false
   152  }
   153  
   154  func (t SignatureType) Len() int {
   155  	switch t {
   156  	case SignatureTypeBls12_381, SignatureTypeGenericAggregate:
   157  		return 96
   158  	case SignatureTypeInvalid:
   159  		return 0
   160  	default:
   161  		return 64
   162  	}
   163  }
   164  
   165  func IsSignature(s string) bool {
   166  	for _, prefix := range []string{
   167  		ED25519_SIGNATURE_PREFIX,
   168  		SECP256K1_SIGNATURE_PREFIX,
   169  		P256_SIGNATURE_PREFIX,
   170  		BLS12_381_SIGNATURE_PREFIX,
   171  		GENERIC_SIGNATURE_PREFIX,
   172  		GENERIC_AGGREGATE_SIGNATURE_PREFIX,
   173  	} {
   174  		if strings.HasPrefix(s, prefix) {
   175  			return true
   176  		}
   177  	}
   178  	return false
   179  }
   180  
   181  // Signature represents a typed Tezos signature.
   182  type Signature struct {
   183  	Type SignatureType
   184  	Data []byte
   185  }
   186  
   187  func NewSignature(typ SignatureType, data []byte) Signature {
   188  	return Signature{
   189  		Type: typ,
   190  		Data: data,
   191  	}
   192  }
   193  
   194  func (s Signature) IsValid() bool {
   195  	return s.Type.IsValid() && s.Type.Len() == len(s.Data)
   196  }
   197  
   198  func (s Signature) Equal(s2 Signature) bool {
   199  	return s.Type == s2.Type && bytes.Equal(s.Data, s2.Data)
   200  }
   201  
   202  func (s Signature) Clone() Signature {
   203  	buf := make([]byte, len(s.Data))
   204  	copy(buf, s.Data)
   205  	return Signature{
   206  		Type: s.Type,
   207  		Data: buf,
   208  	}
   209  }
   210  
   211  // Signature converts a typed Tezos signature into a generic signature string.
   212  func (s Signature) Generic() string {
   213  	if !s.IsValid() {
   214  		return ""
   215  	}
   216  	return base58.CheckEncode(s.Data, GENERIC_SIGNATURE_ID)
   217  }
   218  
   219  func (s Signature) String() string {
   220  	if !s.IsValid() {
   221  		return ""
   222  	}
   223  	return base58.CheckEncode(s.Data, s.Type.PrefixBytes())
   224  }
   225  
   226  func (s Signature) MarshalText() ([]byte, error) {
   227  	return []byte(s.String()), nil
   228  }
   229  
   230  func (s *Signature) UnmarshalText(data []byte) error {
   231  	sig, err := ParseSignature(string(data))
   232  	if err != nil {
   233  		return err
   234  	}
   235  	*s = sig
   236  	return nil
   237  }
   238  
   239  func (s Signature) Bytes() []byte {
   240  	tag := s.Type.Tag()
   241  	if tag == 255 {
   242  		return s.Data
   243  	}
   244  	return append([]byte{tag}, s.Data...)
   245  }
   246  
   247  func (s *Signature) DecodeBuffer(buf *bytes.Buffer) error {
   248  	l := buf.Len()
   249  	if l < 64 {
   250  		return fmt.Errorf("tezos: invalid binary signature length %d", l)
   251  	}
   252  	// default to generic without tag
   253  	s.Type = SignatureTypeGeneric
   254  	// tagged signatures are either 65 byte or 97 byte (BLS)
   255  	if l == 65 || l == 97 {
   256  		tag := buf.Next(1)[0]
   257  		if typ := ParseSignatureTag(tag); !typ.IsValid() {
   258  			return fmt.Errorf("tezos: invalid binary signature type %x", tag)
   259  		} else {
   260  			s.Type = typ
   261  		}
   262  	}
   263  	l = s.Type.Len()
   264  	s.Data = make([]byte, l)
   265  	copy(s.Data, buf.Next(l))
   266  	if !s.IsValid() {
   267  		return fmt.Errorf("tezos: invalid %s signature length %d", s.Type, l)
   268  	}
   269  	return nil
   270  }
   271  
   272  func (s Signature) MarshalBinary() ([]byte, error) {
   273  	if !s.Type.IsValid() {
   274  		return nil, ErrUnknownSignatureType
   275  	}
   276  	return s.Bytes(), nil
   277  }
   278  
   279  func (s *Signature) UnmarshalBinary(b []byte) error {
   280  	switch len(b) {
   281  	case 64:
   282  		s.Type = SignatureTypeGeneric
   283  	case 96:
   284  		s.Type = SignatureTypeGenericAggregate
   285  	case 65, 97:
   286  		if typ := ParseSignatureTag(b[0]); !typ.IsValid() {
   287  			return fmt.Errorf("tezos: invalid binary signature type %x", b[0])
   288  		} else {
   289  			s.Type = typ
   290  		}
   291  		b = b[1:]
   292  	default:
   293  		return fmt.Errorf("tezos: invalid binary signature length %d", len(b))
   294  	}
   295  	if cap(s.Data) < s.Type.Len() {
   296  		s.Data = make([]byte, s.Type.Len())
   297  	} else {
   298  		s.Data = s.Data[:s.Type.Len()]
   299  	}
   300  	copy(s.Data, b)
   301  	return nil
   302  }
   303  
   304  func ParseSignature(s string) (sig Signature, err error) {
   305  	var (
   306  		dec, ver []byte
   307  		typ      SignatureType
   308  	)
   309  	switch {
   310  	case strings.HasPrefix(s, ED25519_SIGNATURE_PREFIX):
   311  		dec, ver, err = base58.CheckDecode(s, 5, nil)
   312  		typ = SignatureTypeEd25519
   313  
   314  	case strings.HasPrefix(s, SECP256K1_SIGNATURE_PREFIX):
   315  		dec, ver, err = base58.CheckDecode(s, 5, nil)
   316  		typ = SignatureTypeSecp256k1
   317  
   318  	case strings.HasPrefix(s, P256_SIGNATURE_PREFIX):
   319  		dec, ver, err = base58.CheckDecode(s, 4, nil)
   320  		typ = SignatureTypeP256
   321  
   322  	case strings.HasPrefix(s, BLS12_381_SIGNATURE_PREFIX):
   323  		dec, ver, err = base58.CheckDecode(s, 4, nil)
   324  		typ = SignatureTypeBls12_381
   325  
   326  	case strings.HasPrefix(s, GENERIC_SIGNATURE_PREFIX):
   327  		dec, ver, err = base58.CheckDecode(s, 3, nil)
   328  		typ = SignatureTypeGeneric
   329  
   330  	case strings.HasPrefix(s, GENERIC_AGGREGATE_SIGNATURE_PREFIX):
   331  		dec, ver, err = base58.CheckDecode(s, 4, nil)
   332  		typ = SignatureTypeGenericAggregate
   333  
   334  	default:
   335  		err = fmt.Errorf("tezos: unknown signature prefix %s", s)
   336  		return
   337  	}
   338  
   339  	if err != nil {
   340  		if err == base58.ErrChecksum {
   341  			err = ErrChecksumMismatch
   342  			return
   343  		}
   344  		err = fmt.Errorf("tezos: unknown signature format: %w", err)
   345  		return
   346  	}
   347  
   348  	if !bytes.Equal(ver, typ.PrefixBytes()) {
   349  		err = fmt.Errorf("tezos: invalid signature type %x for %s", ver, typ.Prefix())
   350  		return
   351  	}
   352  
   353  	if l := len(dec); l < typ.Len() {
   354  		err = fmt.Errorf("tezos: invalid length %d for %s signature data", l, typ.Prefix())
   355  		return
   356  	}
   357  
   358  	sig.Type = typ
   359  	sig.Data = dec[:typ.Len()]
   360  	return
   361  }
   362  
   363  func MustParseSignature(s string) Signature {
   364  	sig, err := ParseSignature(s)
   365  	if err != nil {
   366  		panic(err)
   367  	}
   368  	return sig
   369  }
   370  
   371  // Set implements the flags.Value interface for use in command line
   372  // argument parsing.
   373  func (s *Signature) Set(sig string) (err error) {
   374  	*s, err = ParseSignature(sig)
   375  	return
   376  }