github.com/onflow/flow-go@v0.33.17/fvm/fvm_signature_test.go (about) 1 package fvm_test 2 3 import ( 4 "crypto/rand" 5 "fmt" 6 "testing" 7 8 "github.com/onflow/cadence" 9 jsoncdc "github.com/onflow/cadence/encoding/json" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 "github.com/onflow/flow-go/crypto" 14 "github.com/onflow/flow-go/crypto/hash" 15 16 "github.com/onflow/flow-go/engine/execution/testutil" 17 "github.com/onflow/flow-go/fvm" 18 fvmCrypto "github.com/onflow/flow-go/fvm/crypto" 19 "github.com/onflow/flow-go/fvm/storage/snapshot" 20 "github.com/onflow/flow-go/model/flow" 21 msig "github.com/onflow/flow-go/module/signature" 22 ) 23 24 var createMessage = func(m string) (signableMessage []byte, message cadence.Array) { 25 signableMessage = []byte(m) 26 message = testutil.BytesToCadenceArray(signableMessage) 27 return signableMessage, message 28 } 29 30 func TestKeyListSignature(t *testing.T) { 31 32 t.Parallel() 33 34 type signatureAlgorithm struct { 35 name string 36 seedLength int 37 algorithm crypto.SigningAlgorithm 38 } 39 40 signatureAlgorithms := []signatureAlgorithm{ 41 {"ECDSA_P256", crypto.KeyGenSeedMinLen, crypto.ECDSAP256}, 42 {"ECDSA_secp256k1", crypto.KeyGenSeedMinLen, crypto.ECDSASecp256k1}, 43 } 44 45 type hashAlgorithm struct { 46 name string 47 hasher func(string) hash.Hasher 48 } 49 50 // Hardcoded tag as required by the crypto.keyList Cadence contract 51 // TODO: update to a random tag once the Cadence contract is updated 52 // to accept custom tags 53 tag := "FLOW-V0.0-user" 54 55 hashAlgorithms := []hashAlgorithm{ 56 { 57 "SHA3_256", 58 func(tag string) hash.Hasher { 59 hasher, err := fvmCrypto.NewPrefixedHashing(hash.SHA3_256, tag) 60 require.Nil(t, err) 61 return hasher 62 }, 63 }, 64 { 65 "SHA2_256", 66 func(tag string) hash.Hasher { 67 hasher, err := fvmCrypto.NewPrefixedHashing(hash.SHA2_256, tag) 68 require.Nil(t, err) 69 return hasher 70 }, 71 }, 72 { 73 "KECCAK_256", 74 func(tag string) hash.Hasher { 75 hasher, err := fvmCrypto.NewPrefixedHashing(hash.Keccak_256, tag) 76 require.Nil(t, err) 77 return hasher 78 }, 79 }, 80 } 81 82 testForHash := func(signatureAlgorithm signatureAlgorithm, hashAlgorithm hashAlgorithm) { 83 84 code := []byte( 85 fmt.Sprintf( 86 ` 87 import Crypto 88 89 pub fun main( 90 rawPublicKeys: [[UInt8]], 91 message: [UInt8], 92 signatures: [[UInt8]], 93 weight: UFix64, 94 ): Bool { 95 let keyList = Crypto.KeyList() 96 97 for rawPublicKey in rawPublicKeys { 98 keyList.add( 99 PublicKey( 100 publicKey: rawPublicKey, 101 signatureAlgorithm: SignatureAlgorithm.%s 102 ), 103 hashAlgorithm: HashAlgorithm.%s, 104 weight: weight, 105 ) 106 } 107 108 let signatureSet: [Crypto.KeyListSignature] = [] 109 110 var i = 0 111 for signature in signatures { 112 signatureSet.append( 113 Crypto.KeyListSignature( 114 keyIndex: i, 115 signature: signature 116 ) 117 ) 118 i = i + 1 119 } 120 121 return keyList.verify( 122 signatureSet: signatureSet, 123 signedData: message, 124 ) 125 } 126 `, 127 signatureAlgorithm.name, 128 hashAlgorithm.name, 129 ), 130 ) 131 132 t.Run(fmt.Sprintf("%s %s", signatureAlgorithm.name, hashAlgorithm.name), func(t *testing.T) { 133 134 createKey := func() (privateKey crypto.PrivateKey, publicKey cadence.Array) { 135 seed := make([]byte, signatureAlgorithm.seedLength) 136 137 var err error 138 139 _, err = rand.Read(seed) 140 require.NoError(t, err) 141 142 privateKey, err = crypto.GeneratePrivateKey(signatureAlgorithm.algorithm, seed) 143 require.NoError(t, err) 144 145 publicKey = testutil.BytesToCadenceArray( 146 privateKey.PublicKey().Encode(), 147 ) 148 149 return privateKey, publicKey 150 } 151 152 signMessage := func(privateKey crypto.PrivateKey, message []byte) cadence.Array { 153 signature, err := privateKey.Sign(message, hashAlgorithm.hasher(tag)) 154 require.NoError(t, err) 155 156 return testutil.BytesToCadenceArray(signature) 157 } 158 159 t.Run("Single key", newVMTest().run( 160 func( 161 t *testing.T, 162 vm fvm.VM, 163 chain flow.Chain, 164 ctx fvm.Context, 165 snapshotTree snapshot.SnapshotTree, 166 ) { 167 privateKey, publicKey := createKey() 168 signableMessage, message := createMessage("foo") 169 signature := signMessage(privateKey, signableMessage) 170 weight, _ := cadence.NewUFix64("1.0") 171 172 publicKeys := cadence.NewArray([]cadence.Value{ 173 publicKey, 174 }) 175 176 signatures := cadence.NewArray([]cadence.Value{ 177 signature, 178 }) 179 180 t.Run("Valid", func(t *testing.T) { 181 script := fvm.Script(code).WithArguments( 182 jsoncdc.MustEncode(publicKeys), 183 jsoncdc.MustEncode(message), 184 jsoncdc.MustEncode(signatures), 185 jsoncdc.MustEncode(weight), 186 ) 187 188 _, output, err := vm.Run(ctx, script, snapshotTree) 189 assert.NoError(t, err) 190 assert.NoError(t, output.Err) 191 192 assert.Equal(t, cadence.NewBool(true), output.Value) 193 }) 194 195 t.Run("Invalid message", func(t *testing.T) { 196 _, invalidRawMessage := createMessage("bar") 197 198 script := fvm.Script(code).WithArguments( 199 jsoncdc.MustEncode(publicKeys), 200 jsoncdc.MustEncode(invalidRawMessage), 201 jsoncdc.MustEncode(signatures), 202 jsoncdc.MustEncode(weight), 203 ) 204 205 _, output, err := vm.Run(ctx, script, snapshotTree) 206 assert.NoError(t, err) 207 assert.NoError(t, output.Err) 208 209 assert.Equal(t, cadence.NewBool(false), output.Value) 210 }) 211 212 t.Run("Invalid signature", func(t *testing.T) { 213 invalidPrivateKey, _ := createKey() 214 invalidRawSignature := signMessage(invalidPrivateKey, signableMessage) 215 216 invalidRawSignatures := cadence.NewArray([]cadence.Value{ 217 invalidRawSignature, 218 }) 219 220 script := fvm.Script(code).WithArguments( 221 jsoncdc.MustEncode(publicKeys), 222 jsoncdc.MustEncode(message), 223 jsoncdc.MustEncode(invalidRawSignatures), 224 jsoncdc.MustEncode(weight), 225 ) 226 227 _, output, err := vm.Run(ctx, script, snapshotTree) 228 assert.NoError(t, err) 229 assert.NoError(t, output.Err) 230 231 assert.Equal(t, cadence.NewBool(false), output.Value) 232 }) 233 234 t.Run("Malformed public key", func(t *testing.T) { 235 invalidPublicKey := testutil.BytesToCadenceArray([]byte{1, 2, 3}) 236 237 invalidPublicKeys := cadence.NewArray([]cadence.Value{ 238 invalidPublicKey, 239 }) 240 241 script := fvm.Script(code).WithArguments( 242 jsoncdc.MustEncode(invalidPublicKeys), 243 jsoncdc.MustEncode(message), 244 jsoncdc.MustEncode(signatures), 245 jsoncdc.MustEncode(weight), 246 ) 247 248 _, output, err := vm.Run(ctx, script, snapshotTree) 249 require.NoError(t, err) 250 require.Error(t, output.Err) 251 }) 252 }, 253 )) 254 255 t.Run("Multiple keys", newVMTest().run( 256 func( 257 t *testing.T, 258 vm fvm.VM, 259 chain flow.Chain, 260 ctx fvm.Context, 261 snapshotTree snapshot.SnapshotTree, 262 ) { 263 privateKeyA, publicKeyA := createKey() 264 privateKeyB, publicKeyB := createKey() 265 privateKeyC, publicKeyC := createKey() 266 267 publicKeys := cadence.NewArray([]cadence.Value{ 268 publicKeyA, 269 publicKeyB, 270 publicKeyC, 271 }) 272 273 signableMessage, message := createMessage("foo") 274 275 signatureA := signMessage(privateKeyA, signableMessage) 276 signatureB := signMessage(privateKeyB, signableMessage) 277 signatureC := signMessage(privateKeyC, signableMessage) 278 279 weight, _ := cadence.NewUFix64("0.5") 280 281 t.Run("3 of 3", func(t *testing.T) { 282 signatures := cadence.NewArray([]cadence.Value{ 283 signatureA, 284 signatureB, 285 signatureC, 286 }) 287 288 script := fvm.Script(code).WithArguments( 289 jsoncdc.MustEncode(publicKeys), 290 jsoncdc.MustEncode(message), 291 jsoncdc.MustEncode(signatures), 292 jsoncdc.MustEncode(weight), 293 ) 294 295 _, output, err := vm.Run(ctx, script, snapshotTree) 296 assert.NoError(t, err) 297 assert.NoError(t, output.Err) 298 299 assert.Equal(t, cadence.NewBool(true), output.Value) 300 }) 301 302 t.Run("2 of 3", func(t *testing.T) { 303 signatures := cadence.NewArray([]cadence.Value{ 304 signatureA, 305 signatureB, 306 }) 307 308 script := fvm.Script(code).WithArguments( 309 jsoncdc.MustEncode(publicKeys), 310 jsoncdc.MustEncode(message), 311 jsoncdc.MustEncode(signatures), 312 jsoncdc.MustEncode(weight), 313 ) 314 315 _, output, err := vm.Run(ctx, script, snapshotTree) 316 assert.NoError(t, err) 317 assert.NoError(t, output.Err) 318 319 assert.Equal(t, cadence.NewBool(true), output.Value) 320 }) 321 322 t.Run("1 of 3", func(t *testing.T) { 323 signatures := cadence.NewArray([]cadence.Value{ 324 signatureA, 325 }) 326 327 script := fvm.Script(code).WithArguments( 328 jsoncdc.MustEncode(publicKeys), 329 jsoncdc.MustEncode(message), 330 jsoncdc.MustEncode(signatures), 331 jsoncdc.MustEncode(weight), 332 ) 333 334 _, output, err := vm.Run(ctx, script, snapshotTree) 335 assert.NoError(t, err) 336 assert.NoError(t, output.Err) 337 338 assert.Equal(t, cadence.NewBool(false), output.Value) 339 }) 340 }, 341 )) 342 }) 343 } 344 345 for _, signatureAlgorithm := range signatureAlgorithms { 346 for _, hashAlgorithm := range hashAlgorithms { 347 testForHash(signatureAlgorithm, hashAlgorithm) 348 } 349 } 350 351 testForHash(signatureAlgorithm{ 352 "BLS_BLS12_381", 353 crypto.KeyGenSeedMinLen, 354 crypto.BLSBLS12381, 355 }, hashAlgorithm{ 356 "KMAC128_BLS_BLS12_381", 357 func(tag string) hash.Hasher { 358 return msig.NewBLSHasher(tag) 359 }, 360 }) 361 } 362 363 func TestBLSMultiSignature(t *testing.T) { 364 365 t.Parallel() 366 367 type signatureAlgorithm struct { 368 name string 369 seedLength int 370 algorithm crypto.SigningAlgorithm 371 } 372 373 signatureAlgorithms := []signatureAlgorithm{ 374 {"BLS_BLS12_381", crypto.KeyGenSeedMinLen, crypto.BLSBLS12381}, 375 {"ECDSA_P256", crypto.KeyGenSeedMinLen, crypto.ECDSAP256}, 376 {"ECDSA_secp256k1", crypto.KeyGenSeedMinLen, crypto.ECDSASecp256k1}, 377 } 378 BLSSignatureAlgorithm := signatureAlgorithms[0] 379 380 randomSK := func(t *testing.T, signatureAlgorithm signatureAlgorithm) crypto.PrivateKey { 381 seed := make([]byte, signatureAlgorithm.seedLength) 382 n, err := rand.Read(seed) 383 require.Equal(t, n, signatureAlgorithm.seedLength) 384 require.NoError(t, err) 385 sk, err := crypto.GeneratePrivateKey(signatureAlgorithm.algorithm, seed) 386 require.NoError(t, err) 387 return sk 388 } 389 390 testVerifyPoP := func() { 391 t.Run("verifyBLSPoP", newVMTest().run( 392 func( 393 t *testing.T, 394 vm fvm.VM, 395 chain flow.Chain, 396 ctx fvm.Context, 397 snapshotTree snapshot.SnapshotTree, 398 ) { 399 400 code := func(signatureAlgorithm signatureAlgorithm) []byte { 401 return []byte( 402 fmt.Sprintf( 403 ` 404 import Crypto 405 406 pub fun main( 407 publicKey: [UInt8], 408 proof: [UInt8] 409 ): Bool { 410 let p = PublicKey( 411 publicKey: publicKey, 412 signatureAlgorithm: SignatureAlgorithm.%s 413 ) 414 return p.verifyPoP(proof) 415 } 416 `, 417 signatureAlgorithm.name, 418 ), 419 ) 420 } 421 422 t.Run("valid and correct BLS key", func(t *testing.T) { 423 424 sk := randomSK(t, BLSSignatureAlgorithm) 425 publicKey := testutil.BytesToCadenceArray( 426 sk.PublicKey().Encode(), 427 ) 428 429 proof, err := crypto.BLSGeneratePOP(sk) 430 require.NoError(t, err) 431 pop := testutil.BytesToCadenceArray( 432 proof, 433 ) 434 435 script := fvm.Script(code(BLSSignatureAlgorithm)).WithArguments( 436 jsoncdc.MustEncode(publicKey), 437 jsoncdc.MustEncode(pop), 438 ) 439 440 _, output, err := vm.Run(ctx, script, snapshotTree) 441 assert.NoError(t, err) 442 assert.NoError(t, output.Err) 443 assert.Equal(t, cadence.NewBool(true), output.Value) 444 445 }) 446 447 t.Run("valid but incorrect BLS key", func(t *testing.T) { 448 449 sk := randomSK(t, BLSSignatureAlgorithm) 450 publicKey := testutil.BytesToCadenceArray( 451 sk.PublicKey().Encode(), 452 ) 453 454 otherSk := randomSK(t, BLSSignatureAlgorithm) 455 proof, err := crypto.BLSGeneratePOP(otherSk) 456 require.NoError(t, err) 457 458 pop := testutil.BytesToCadenceArray( 459 proof, 460 ) 461 script := fvm.Script(code(BLSSignatureAlgorithm)).WithArguments( 462 jsoncdc.MustEncode(publicKey), 463 jsoncdc.MustEncode(pop), 464 ) 465 466 _, output, err := vm.Run(ctx, script, snapshotTree) 467 assert.NoError(t, err) 468 assert.NoError(t, output.Err) 469 assert.Equal(t, cadence.NewBool(false), output.Value) 470 471 }) 472 473 for _, signatureAlgorithm := range signatureAlgorithms[1:] { 474 t.Run("valid non BLS key/"+signatureAlgorithm.name, func(t *testing.T) { 475 sk := randomSK(t, signatureAlgorithm) 476 publicKey := testutil.BytesToCadenceArray( 477 sk.PublicKey().Encode(), 478 ) 479 480 random := make([]byte, crypto.SignatureLenBLSBLS12381) 481 _, err := rand.Read(random) 482 require.NoError(t, err) 483 pop := testutil.BytesToCadenceArray( 484 random, 485 ) 486 487 script := fvm.Script(code(signatureAlgorithm)).WithArguments( 488 jsoncdc.MustEncode(publicKey), 489 jsoncdc.MustEncode(pop), 490 ) 491 492 _, output, err := vm.Run(ctx, script, snapshotTree) 493 assert.NoError(t, err) 494 assert.Error(t, output.Err) 495 }) 496 } 497 }, 498 )) 499 } 500 501 testBLSSignatureAggregation := func() { 502 t.Run("aggregateBLSSignatures", newVMTest().run( 503 func( 504 t *testing.T, 505 vm fvm.VM, 506 chain flow.Chain, 507 ctx fvm.Context, 508 snapshotTree snapshot.SnapshotTree, 509 ) { 510 511 code := []byte( 512 ` 513 import Crypto 514 515 pub fun main( 516 signatures: [[UInt8]], 517 ): [UInt8]? { 518 return BLS.aggregateSignatures(signatures)! 519 } 520 `, 521 ) 522 523 // random message 524 input := make([]byte, 100) 525 _, err := rand.Read(input) 526 require.NoError(t, err) 527 528 // generate keys and signatures 529 numSigs := 50 530 sigs := make([]crypto.Signature, 0, numSigs) 531 532 kmac := msig.NewBLSHasher("test tag") 533 for i := 0; i < numSigs; i++ { 534 sk := randomSK(t, BLSSignatureAlgorithm) 535 // a valid BLS signature 536 s, err := sk.Sign(input, kmac) 537 require.NoError(t, err) 538 sigs = append(sigs, s) 539 } 540 541 t.Run("valid BLS signatures", func(t *testing.T) { 542 543 signatures := make([]cadence.Value, 0, numSigs) 544 for _, sig := range sigs { 545 s := testutil.BytesToCadenceArray(sig) 546 signatures = append(signatures, s) 547 } 548 549 script := fvm.Script(code).WithArguments( 550 jsoncdc.MustEncode(cadence.Array{ 551 Values: signatures, 552 ArrayType: &cadence.VariableSizedArrayType{ 553 ElementType: &cadence.VariableSizedArrayType{ 554 ElementType: cadence.UInt8Type{}, 555 }, 556 }, 557 }), 558 ) 559 560 _, output, err := vm.Run(ctx, script, snapshotTree) 561 assert.NoError(t, err) 562 assert.NoError(t, output.Err) 563 564 expectedSig, err := crypto.AggregateBLSSignatures(sigs) 565 require.NoError(t, err) 566 assert.Equal(t, cadence.Optional{Value: testutil.BytesToCadenceArray(expectedSig)}, output.Value) 567 }) 568 569 t.Run("at least one invalid BLS signature", func(t *testing.T) { 570 571 signatures := make([]cadence.Value, 0, numSigs) 572 // alter one random signature 573 tmp := sigs[numSigs/2] 574 sigs[numSigs/2] = crypto.BLSInvalidSignature() 575 576 for _, sig := range sigs { 577 s := testutil.BytesToCadenceArray(sig) 578 signatures = append(signatures, s) 579 } 580 581 script := fvm.Script(code).WithArguments( 582 jsoncdc.MustEncode(cadence.Array{ 583 Values: signatures, 584 ArrayType: &cadence.VariableSizedArrayType{ 585 ElementType: &cadence.VariableSizedArrayType{ 586 ElementType: cadence.UInt8Type{}, 587 }, 588 }, 589 }), 590 ) 591 592 // revert the change 593 sigs[numSigs/2] = tmp 594 595 _, output, err := vm.Run(ctx, script, snapshotTree) 596 assert.NoError(t, err) 597 assert.Error(t, output.Err) 598 assert.Equal(t, nil, output.Value) 599 }) 600 601 t.Run("empty signature list", func(t *testing.T) { 602 603 signatures := []cadence.Value{} 604 script := fvm.Script(code).WithArguments( 605 jsoncdc.MustEncode(cadence.Array{ 606 Values: signatures, 607 ArrayType: &cadence.VariableSizedArrayType{ 608 ElementType: &cadence.VariableSizedArrayType{ 609 ElementType: cadence.UInt8Type{}, 610 }, 611 }, 612 }), 613 ) 614 615 _, output, err := vm.Run(ctx, script, snapshotTree) 616 assert.NoError(t, err) 617 assert.Error(t, output.Err) 618 assert.Equal(t, nil, output.Value) 619 }) 620 }, 621 )) 622 } 623 624 testKeyAggregation := func() { 625 t.Run("aggregateBLSPublicKeys", newVMTest().run( 626 func( 627 t *testing.T, 628 vm fvm.VM, 629 chain flow.Chain, 630 ctx fvm.Context, 631 snapshotTree snapshot.SnapshotTree, 632 ) { 633 634 code := func(signatureAlgorithm signatureAlgorithm) []byte { 635 return []byte( 636 fmt.Sprintf( 637 ` 638 import Crypto 639 640 pub fun main( 641 publicKeys: [[UInt8]] 642 ): [UInt8]? { 643 let pks: [PublicKey] = [] 644 for pk in publicKeys { 645 pks.append(PublicKey( 646 publicKey: pk, 647 signatureAlgorithm: SignatureAlgorithm.%s 648 )) 649 } 650 return BLS.aggregatePublicKeys(pks)!.publicKey 651 } 652 `, 653 signatureAlgorithm.name, 654 ), 655 ) 656 } 657 658 pkNum := 100 659 pks := make([]crypto.PublicKey, 0, pkNum) 660 661 t.Run("valid BLS keys", func(t *testing.T) { 662 663 publicKeys := make([]cadence.Value, 0, pkNum) 664 for i := 0; i < pkNum; i++ { 665 sk := randomSK(t, BLSSignatureAlgorithm) 666 pk := sk.PublicKey() 667 pks = append(pks, pk) 668 publicKeys = append( 669 publicKeys, 670 testutil.BytesToCadenceArray(pk.Encode()), 671 ) 672 } 673 674 script := fvm.Script(code(BLSSignatureAlgorithm)).WithArguments( 675 jsoncdc.MustEncode(cadence.Array{ 676 Values: publicKeys, 677 ArrayType: &cadence.VariableSizedArrayType{ 678 ElementType: &cadence.VariableSizedArrayType{ 679 ElementType: cadence.UInt8Type{}, 680 }, 681 }, 682 }), 683 ) 684 685 _, output, err := vm.Run(ctx, script, snapshotTree) 686 assert.NoError(t, err) 687 assert.NoError(t, output.Err) 688 expectedPk, err := crypto.AggregateBLSPublicKeys(pks) 689 require.NoError(t, err) 690 691 assert.Equal(t, cadence.Optional{Value: testutil.BytesToCadenceArray(expectedPk.Encode())}, output.Value) 692 }) 693 694 for _, signatureAlgorithm := range signatureAlgorithms[1:] { 695 t.Run("non BLS keys/"+signatureAlgorithm.name, func(t *testing.T) { 696 697 publicKeys := make([]cadence.Value, 0, pkNum) 698 for i := 0; i < pkNum; i++ { 699 sk := randomSK(t, signatureAlgorithm) 700 pk := sk.PublicKey() 701 pks = append(pks, pk) 702 publicKeys = append( 703 publicKeys, 704 testutil.BytesToCadenceArray(sk.PublicKey().Encode()), 705 ) 706 } 707 708 script := fvm.Script(code(signatureAlgorithm)).WithArguments( 709 jsoncdc.MustEncode(cadence.Array{ 710 Values: publicKeys, 711 ArrayType: &cadence.VariableSizedArrayType{ 712 ElementType: &cadence.VariableSizedArrayType{ 713 ElementType: cadence.UInt8Type{}, 714 }, 715 }, 716 }), 717 ) 718 719 _, output, err := vm.Run(ctx, script, snapshotTree) 720 assert.NoError(t, err) 721 assert.Error(t, output.Err) 722 }) 723 } 724 725 t.Run("empty list", func(t *testing.T) { 726 727 var publicKeys []cadence.Value 728 script := fvm.Script(code(BLSSignatureAlgorithm)).WithArguments( 729 jsoncdc.MustEncode(cadence.Array{ 730 Values: publicKeys, 731 ArrayType: &cadence.VariableSizedArrayType{ 732 ElementType: &cadence.VariableSizedArrayType{ 733 ElementType: cadence.UInt8Type{}, 734 }, 735 }, 736 }), 737 ) 738 739 _, output, err := vm.Run(ctx, script, snapshotTree) 740 assert.NoError(t, err) 741 assert.Error(t, output.Err) 742 assert.Equal(t, nil, output.Value) 743 }) 744 }, 745 )) 746 } 747 748 testBLSCombinedAggregations := func() { 749 t.Run("Combined Aggregations", newVMTest().run( 750 func( 751 t *testing.T, 752 vm fvm.VM, 753 chain flow.Chain, 754 ctx fvm.Context, 755 snapshotTree snapshot.SnapshotTree, 756 ) { 757 758 message, cadenceMessage := createMessage("random_message") 759 tag := "random_tag" 760 761 code := []byte(` 762 import Crypto 763 764 pub fun main( 765 publicKeys: [[UInt8]], 766 signatures: [[UInt8]], 767 message: [UInt8], 768 tag: String, 769 ): Bool { 770 let pks: [PublicKey] = [] 771 for pk in publicKeys { 772 pks.append(PublicKey( 773 publicKey: pk, 774 signatureAlgorithm: SignatureAlgorithm.BLS_BLS12_381 775 )) 776 } 777 let aggPk = BLS.aggregatePublicKeys(pks)! 778 let aggSignature = BLS.aggregateSignatures(signatures)! 779 let boo = aggPk.verify( 780 signature: aggSignature, 781 signedData: message, 782 domainSeparationTag: tag, 783 hashAlgorithm: HashAlgorithm.KMAC128_BLS_BLS12_381) 784 return boo 785 } 786 `) 787 788 num := 50 789 publicKeys := make([]cadence.Value, 0, num) 790 signatures := make([]cadence.Value, 0, num) 791 792 kmac := msig.NewBLSHasher(string(tag)) 793 for i := 0; i < num; i++ { 794 sk := randomSK(t, BLSSignatureAlgorithm) 795 pk := sk.PublicKey() 796 publicKeys = append( 797 publicKeys, 798 testutil.BytesToCadenceArray(pk.Encode()), 799 ) 800 sig, err := sk.Sign(message, kmac) 801 require.NoError(t, err) 802 signatures = append( 803 signatures, 804 testutil.BytesToCadenceArray(sig), 805 ) 806 } 807 808 script := fvm.Script(code).WithArguments( 809 jsoncdc.MustEncode(cadence.Array{ // keys 810 Values: publicKeys, 811 ArrayType: &cadence.VariableSizedArrayType{ 812 ElementType: &cadence.VariableSizedArrayType{ 813 ElementType: cadence.UInt8Type{}, 814 }, 815 }, 816 }), 817 jsoncdc.MustEncode(cadence.Array{ // signatures 818 Values: signatures, 819 ArrayType: &cadence.VariableSizedArrayType{ 820 ElementType: &cadence.VariableSizedArrayType{ 821 ElementType: cadence.UInt8Type{}, 822 }, 823 }, 824 }), 825 jsoncdc.MustEncode(cadenceMessage), 826 jsoncdc.MustEncode(cadence.String(tag)), 827 ) 828 829 _, output, err := vm.Run(ctx, script, snapshotTree) 830 assert.NoError(t, err) 831 assert.NoError(t, output.Err) 832 assert.Equal(t, cadence.NewBool(true), output.Value) 833 }, 834 )) 835 } 836 837 testVerifyPoP() 838 testKeyAggregation() 839 testBLSSignatureAggregation() 840 testBLSCombinedAggregations() 841 }