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