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 }