github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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/crypto" 14 "github.com/onflow/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 access(all) 90 fun main( 91 rawPublicKeys: [[UInt8]], 92 message: [UInt8], 93 signatures: [[UInt8]], 94 weight: UFix64, 95 ): Bool { 96 let keyList = Crypto.KeyList() 97 98 for rawPublicKey in rawPublicKeys { 99 keyList.add( 100 PublicKey( 101 publicKey: rawPublicKey, 102 signatureAlgorithm: SignatureAlgorithm.%s 103 ), 104 hashAlgorithm: HashAlgorithm.%s, 105 weight: weight, 106 ) 107 } 108 109 let signatureSet: [Crypto.KeyListSignature] = [] 110 111 var i = 0 112 for signature in signatures { 113 signatureSet.append( 114 Crypto.KeyListSignature( 115 keyIndex: i, 116 signature: signature 117 ) 118 ) 119 i = i + 1 120 } 121 122 return keyList.verify( 123 signatureSet: signatureSet, 124 signedData: message, 125 domainSeparationTag: "%s" 126 ) 127 } 128 `, 129 signatureAlgorithm.name, 130 hashAlgorithm.name, 131 tag, 132 ), 133 ) 134 135 t.Run(fmt.Sprintf("%s %s", signatureAlgorithm.name, hashAlgorithm.name), func(t *testing.T) { 136 137 createKey := func() (privateKey crypto.PrivateKey, publicKey cadence.Array) { 138 seed := make([]byte, signatureAlgorithm.seedLength) 139 140 var err error 141 142 _, err = rand.Read(seed) 143 require.NoError(t, err) 144 145 privateKey, err = crypto.GeneratePrivateKey(signatureAlgorithm.algorithm, seed) 146 require.NoError(t, err) 147 148 publicKey = testutil.BytesToCadenceArray( 149 privateKey.PublicKey().Encode(), 150 ) 151 152 return privateKey, publicKey 153 } 154 155 signMessage := func(privateKey crypto.PrivateKey, message []byte) cadence.Array { 156 signature, err := privateKey.Sign(message, hashAlgorithm.hasher(tag)) 157 require.NoError(t, err) 158 159 return testutil.BytesToCadenceArray(signature) 160 } 161 162 t.Run("Single key", newVMTest().run( 163 func( 164 t *testing.T, 165 vm fvm.VM, 166 chain flow.Chain, 167 ctx fvm.Context, 168 snapshotTree snapshot.SnapshotTree, 169 ) { 170 privateKey, publicKey := createKey() 171 signableMessage, message := createMessage("foo") 172 signature := signMessage(privateKey, signableMessage) 173 weight, _ := cadence.NewUFix64("1.0") 174 175 publicKeys := cadence.NewArray([]cadence.Value{ 176 publicKey, 177 }) 178 179 signatures := cadence.NewArray([]cadence.Value{ 180 signature, 181 }) 182 183 t.Run("Valid", func(t *testing.T) { 184 script := fvm.Script(code).WithArguments( 185 jsoncdc.MustEncode(publicKeys), 186 jsoncdc.MustEncode(message), 187 jsoncdc.MustEncode(signatures), 188 jsoncdc.MustEncode(weight), 189 ) 190 191 _, output, err := vm.Run(ctx, script, snapshotTree) 192 assert.NoError(t, err) 193 assert.NoError(t, output.Err) 194 195 assert.Equal(t, cadence.NewBool(true), output.Value) 196 }) 197 198 t.Run("Invalid message", func(t *testing.T) { 199 _, invalidRawMessage := createMessage("bar") 200 201 script := fvm.Script(code).WithArguments( 202 jsoncdc.MustEncode(publicKeys), 203 jsoncdc.MustEncode(invalidRawMessage), 204 jsoncdc.MustEncode(signatures), 205 jsoncdc.MustEncode(weight), 206 ) 207 208 _, output, err := vm.Run(ctx, script, snapshotTree) 209 assert.NoError(t, err) 210 assert.NoError(t, output.Err) 211 212 assert.Equal(t, cadence.NewBool(false), output.Value) 213 }) 214 215 t.Run("Invalid signature", func(t *testing.T) { 216 invalidPrivateKey, _ := createKey() 217 invalidRawSignature := signMessage(invalidPrivateKey, signableMessage) 218 219 invalidRawSignatures := cadence.NewArray([]cadence.Value{ 220 invalidRawSignature, 221 }) 222 223 script := fvm.Script(code).WithArguments( 224 jsoncdc.MustEncode(publicKeys), 225 jsoncdc.MustEncode(message), 226 jsoncdc.MustEncode(invalidRawSignatures), 227 jsoncdc.MustEncode(weight), 228 ) 229 230 _, output, err := vm.Run(ctx, script, snapshotTree) 231 assert.NoError(t, err) 232 assert.NoError(t, output.Err) 233 234 assert.Equal(t, cadence.NewBool(false), output.Value) 235 }) 236 237 t.Run("Malformed public key", func(t *testing.T) { 238 invalidPublicKey := testutil.BytesToCadenceArray([]byte{1, 2, 3}) 239 240 invalidPublicKeys := cadence.NewArray([]cadence.Value{ 241 invalidPublicKey, 242 }) 243 244 script := fvm.Script(code).WithArguments( 245 jsoncdc.MustEncode(invalidPublicKeys), 246 jsoncdc.MustEncode(message), 247 jsoncdc.MustEncode(signatures), 248 jsoncdc.MustEncode(weight), 249 ) 250 251 _, output, err := vm.Run(ctx, script, snapshotTree) 252 require.NoError(t, err) 253 require.Error(t, output.Err) 254 }) 255 }, 256 )) 257 258 t.Run("Multiple keys", newVMTest().run( 259 func( 260 t *testing.T, 261 vm fvm.VM, 262 chain flow.Chain, 263 ctx fvm.Context, 264 snapshotTree snapshot.SnapshotTree, 265 ) { 266 privateKeyA, publicKeyA := createKey() 267 privateKeyB, publicKeyB := createKey() 268 privateKeyC, publicKeyC := createKey() 269 270 publicKeys := cadence.NewArray([]cadence.Value{ 271 publicKeyA, 272 publicKeyB, 273 publicKeyC, 274 }) 275 276 signableMessage, message := createMessage("foo") 277 278 signatureA := signMessage(privateKeyA, signableMessage) 279 signatureB := signMessage(privateKeyB, signableMessage) 280 signatureC := signMessage(privateKeyC, signableMessage) 281 282 weight, _ := cadence.NewUFix64("0.5") 283 284 t.Run("3 of 3", func(t *testing.T) { 285 signatures := cadence.NewArray([]cadence.Value{ 286 signatureA, 287 signatureB, 288 signatureC, 289 }) 290 291 script := fvm.Script(code).WithArguments( 292 jsoncdc.MustEncode(publicKeys), 293 jsoncdc.MustEncode(message), 294 jsoncdc.MustEncode(signatures), 295 jsoncdc.MustEncode(weight), 296 ) 297 298 _, output, err := vm.Run(ctx, script, snapshotTree) 299 assert.NoError(t, err) 300 assert.NoError(t, output.Err) 301 302 assert.Equal(t, cadence.NewBool(true), output.Value) 303 }) 304 305 t.Run("2 of 3", func(t *testing.T) { 306 signatures := cadence.NewArray([]cadence.Value{ 307 signatureA, 308 signatureB, 309 }) 310 311 script := fvm.Script(code).WithArguments( 312 jsoncdc.MustEncode(publicKeys), 313 jsoncdc.MustEncode(message), 314 jsoncdc.MustEncode(signatures), 315 jsoncdc.MustEncode(weight), 316 ) 317 318 _, output, err := vm.Run(ctx, script, snapshotTree) 319 assert.NoError(t, err) 320 assert.NoError(t, output.Err) 321 322 assert.Equal(t, cadence.NewBool(true), output.Value) 323 }) 324 325 t.Run("1 of 3", func(t *testing.T) { 326 signatures := cadence.NewArray([]cadence.Value{ 327 signatureA, 328 }) 329 330 script := fvm.Script(code).WithArguments( 331 jsoncdc.MustEncode(publicKeys), 332 jsoncdc.MustEncode(message), 333 jsoncdc.MustEncode(signatures), 334 jsoncdc.MustEncode(weight), 335 ) 336 337 _, output, err := vm.Run(ctx, script, snapshotTree) 338 assert.NoError(t, err) 339 assert.NoError(t, output.Err) 340 341 assert.Equal(t, cadence.NewBool(false), output.Value) 342 }) 343 }, 344 )) 345 }) 346 } 347 348 for _, signatureAlgorithm := range signatureAlgorithms { 349 for _, hashAlgorithm := range hashAlgorithms { 350 testForHash(signatureAlgorithm, hashAlgorithm) 351 } 352 } 353 354 testForHash(signatureAlgorithm{ 355 "BLS_BLS12_381", 356 crypto.KeyGenSeedMinLen, 357 crypto.BLSBLS12381, 358 }, hashAlgorithm{ 359 "KMAC128_BLS_BLS12_381", 360 func(tag string) hash.Hasher { 361 return msig.NewBLSHasher(tag) 362 }, 363 }) 364 } 365 366 func TestBLSMultiSignature(t *testing.T) { 367 368 t.Parallel() 369 370 type signatureAlgorithm struct { 371 name string 372 seedLength int 373 algorithm crypto.SigningAlgorithm 374 } 375 376 signatureAlgorithms := []signatureAlgorithm{ 377 {"BLS_BLS12_381", crypto.KeyGenSeedMinLen, crypto.BLSBLS12381}, 378 {"ECDSA_P256", crypto.KeyGenSeedMinLen, crypto.ECDSAP256}, 379 {"ECDSA_secp256k1", crypto.KeyGenSeedMinLen, crypto.ECDSASecp256k1}, 380 } 381 BLSSignatureAlgorithm := signatureAlgorithms[0] 382 383 randomSK := func(t *testing.T, signatureAlgorithm signatureAlgorithm) crypto.PrivateKey { 384 seed := make([]byte, signatureAlgorithm.seedLength) 385 n, err := rand.Read(seed) 386 require.Equal(t, n, signatureAlgorithm.seedLength) 387 require.NoError(t, err) 388 sk, err := crypto.GeneratePrivateKey(signatureAlgorithm.algorithm, seed) 389 require.NoError(t, err) 390 return sk 391 } 392 393 testVerifyPoP := func() { 394 t.Run("verifyBLSPoP", newVMTest().run( 395 func( 396 t *testing.T, 397 vm fvm.VM, 398 chain flow.Chain, 399 ctx fvm.Context, 400 snapshotTree snapshot.SnapshotTree, 401 ) { 402 403 code := func(signatureAlgorithm signatureAlgorithm) []byte { 404 return []byte( 405 fmt.Sprintf( 406 ` 407 import Crypto 408 409 access(all) 410 fun main( 411 publicKey: [UInt8], 412 proof: [UInt8] 413 ): Bool { 414 let p = PublicKey( 415 publicKey: publicKey, 416 signatureAlgorithm: SignatureAlgorithm.%s 417 ) 418 return p.verifyPoP(proof) 419 } 420 `, 421 signatureAlgorithm.name, 422 ), 423 ) 424 } 425 426 t.Run("valid and correct BLS key", func(t *testing.T) { 427 428 sk := randomSK(t, BLSSignatureAlgorithm) 429 publicKey := testutil.BytesToCadenceArray( 430 sk.PublicKey().Encode(), 431 ) 432 433 proof, err := crypto.BLSGeneratePOP(sk) 434 require.NoError(t, err) 435 pop := testutil.BytesToCadenceArray( 436 proof, 437 ) 438 439 script := fvm.Script(code(BLSSignatureAlgorithm)).WithArguments( 440 jsoncdc.MustEncode(publicKey), 441 jsoncdc.MustEncode(pop), 442 ) 443 444 _, output, err := vm.Run(ctx, script, snapshotTree) 445 assert.NoError(t, err) 446 assert.NoError(t, output.Err) 447 assert.Equal(t, cadence.NewBool(true), output.Value) 448 449 }) 450 451 t.Run("valid but incorrect BLS key", func(t *testing.T) { 452 453 sk := randomSK(t, BLSSignatureAlgorithm) 454 publicKey := testutil.BytesToCadenceArray( 455 sk.PublicKey().Encode(), 456 ) 457 458 otherSk := randomSK(t, BLSSignatureAlgorithm) 459 proof, err := crypto.BLSGeneratePOP(otherSk) 460 require.NoError(t, err) 461 462 pop := testutil.BytesToCadenceArray( 463 proof, 464 ) 465 script := fvm.Script(code(BLSSignatureAlgorithm)).WithArguments( 466 jsoncdc.MustEncode(publicKey), 467 jsoncdc.MustEncode(pop), 468 ) 469 470 _, output, err := vm.Run(ctx, script, snapshotTree) 471 assert.NoError(t, err) 472 assert.NoError(t, output.Err) 473 assert.Equal(t, cadence.NewBool(false), output.Value) 474 475 }) 476 477 for _, signatureAlgorithm := range signatureAlgorithms[1:] { 478 t.Run("valid non BLS key/"+signatureAlgorithm.name, func(t *testing.T) { 479 sk := randomSK(t, signatureAlgorithm) 480 publicKey := testutil.BytesToCadenceArray( 481 sk.PublicKey().Encode(), 482 ) 483 484 random := make([]byte, crypto.SignatureLenBLSBLS12381) 485 _, err := rand.Read(random) 486 require.NoError(t, err) 487 pop := testutil.BytesToCadenceArray( 488 random, 489 ) 490 491 script := fvm.Script(code(signatureAlgorithm)).WithArguments( 492 jsoncdc.MustEncode(publicKey), 493 jsoncdc.MustEncode(pop), 494 ) 495 496 _, output, err := vm.Run(ctx, script, snapshotTree) 497 assert.NoError(t, err) 498 assert.Error(t, output.Err) 499 }) 500 } 501 }, 502 )) 503 } 504 505 testBLSSignatureAggregation := func() { 506 t.Run("aggregateBLSSignatures", newVMTest().run( 507 func( 508 t *testing.T, 509 vm fvm.VM, 510 chain flow.Chain, 511 ctx fvm.Context, 512 snapshotTree snapshot.SnapshotTree, 513 ) { 514 515 code := []byte( 516 ` 517 import Crypto 518 519 access(all) fun main( 520 signatures: [[UInt8]], 521 ): [UInt8]? { 522 return BLS.aggregateSignatures(signatures)! 523 } 524 `, 525 ) 526 527 // random message 528 input := make([]byte, 100) 529 _, err := rand.Read(input) 530 require.NoError(t, err) 531 532 // generate keys and signatures 533 numSigs := 50 534 sigs := make([]crypto.Signature, 0, numSigs) 535 536 kmac := msig.NewBLSHasher("test tag") 537 for i := 0; i < numSigs; i++ { 538 sk := randomSK(t, BLSSignatureAlgorithm) 539 // a valid BLS signature 540 s, err := sk.Sign(input, kmac) 541 require.NoError(t, err) 542 sigs = append(sigs, s) 543 } 544 545 t.Run("valid BLS signatures", func(t *testing.T) { 546 547 signatures := make([]cadence.Value, 0, numSigs) 548 for _, sig := range sigs { 549 s := testutil.BytesToCadenceArray(sig) 550 signatures = append(signatures, s) 551 } 552 553 script := fvm.Script(code).WithArguments( 554 jsoncdc.MustEncode(cadence.Array{ 555 Values: signatures, 556 ArrayType: &cadence.VariableSizedArrayType{ 557 ElementType: &cadence.VariableSizedArrayType{ 558 ElementType: cadence.UInt8Type, 559 }, 560 }, 561 }), 562 ) 563 564 _, output, err := vm.Run(ctx, script, snapshotTree) 565 assert.NoError(t, err) 566 assert.NoError(t, output.Err) 567 568 expectedSig, err := crypto.AggregateBLSSignatures(sigs) 569 require.NoError(t, err) 570 assert.Equal(t, cadence.Optional{Value: testutil.BytesToCadenceArray(expectedSig)}, output.Value) 571 }) 572 573 t.Run("at least one invalid BLS signature", func(t *testing.T) { 574 575 signatures := make([]cadence.Value, 0, numSigs) 576 // alter one random signature 577 tmp := sigs[numSigs/2] 578 sigs[numSigs/2] = crypto.BLSInvalidSignature() 579 580 for _, sig := range sigs { 581 s := testutil.BytesToCadenceArray(sig) 582 signatures = append(signatures, s) 583 } 584 585 script := fvm.Script(code).WithArguments( 586 jsoncdc.MustEncode(cadence.Array{ 587 Values: signatures, 588 ArrayType: &cadence.VariableSizedArrayType{ 589 ElementType: &cadence.VariableSizedArrayType{ 590 ElementType: cadence.UInt8Type, 591 }, 592 }, 593 }), 594 ) 595 596 // revert the change 597 sigs[numSigs/2] = tmp 598 599 _, output, err := vm.Run(ctx, script, snapshotTree) 600 assert.NoError(t, err) 601 assert.Error(t, output.Err) 602 assert.Equal(t, nil, output.Value) 603 }) 604 605 t.Run("empty signature list", func(t *testing.T) { 606 607 signatures := []cadence.Value{} 608 script := fvm.Script(code).WithArguments( 609 jsoncdc.MustEncode(cadence.Array{ 610 Values: signatures, 611 ArrayType: &cadence.VariableSizedArrayType{ 612 ElementType: &cadence.VariableSizedArrayType{ 613 ElementType: cadence.UInt8Type, 614 }, 615 }, 616 }), 617 ) 618 619 _, output, err := vm.Run(ctx, script, snapshotTree) 620 assert.NoError(t, err) 621 assert.Error(t, output.Err) 622 assert.Equal(t, nil, output.Value) 623 }) 624 }, 625 )) 626 } 627 628 testKeyAggregation := func() { 629 t.Run("aggregateBLSPublicKeys", newVMTest().run( 630 func( 631 t *testing.T, 632 vm fvm.VM, 633 chain flow.Chain, 634 ctx fvm.Context, 635 snapshotTree snapshot.SnapshotTree, 636 ) { 637 638 code := func(signatureAlgorithm signatureAlgorithm) []byte { 639 return []byte( 640 fmt.Sprintf( 641 ` 642 import Crypto 643 644 access(all) 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 _, output, err := vm.Run(ctx, script, snapshotTree) 690 assert.NoError(t, err) 691 assert.NoError(t, output.Err) 692 expectedPk, err := crypto.AggregateBLSPublicKeys(pks) 693 require.NoError(t, err) 694 695 assert.Equal(t, cadence.Optional{Value: testutil.BytesToCadenceArray(expectedPk.Encode())}, output.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 _, output, err := vm.Run(ctx, script, snapshotTree) 724 assert.NoError(t, err) 725 assert.Error(t, output.Err) 726 }) 727 } 728 729 t.Run("empty list", func(t *testing.T) { 730 731 var publicKeys []cadence.Value 732 script := fvm.Script(code(BLSSignatureAlgorithm)).WithArguments( 733 jsoncdc.MustEncode(cadence.Array{ 734 Values: publicKeys, 735 ArrayType: &cadence.VariableSizedArrayType{ 736 ElementType: &cadence.VariableSizedArrayType{ 737 ElementType: cadence.UInt8Type, 738 }, 739 }, 740 }), 741 ) 742 743 _, output, err := vm.Run(ctx, script, snapshotTree) 744 assert.NoError(t, err) 745 assert.Error(t, output.Err) 746 assert.Equal(t, nil, output.Value) 747 }) 748 }, 749 )) 750 } 751 752 testBLSCombinedAggregations := func() { 753 t.Run("Combined Aggregations", newVMTest().run( 754 func( 755 t *testing.T, 756 vm fvm.VM, 757 chain flow.Chain, 758 ctx fvm.Context, 759 snapshotTree snapshot.SnapshotTree, 760 ) { 761 762 message, cadenceMessage := createMessage("random_message") 763 tag := "random_tag" 764 765 code := []byte(` 766 import Crypto 767 768 access(all) 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 _, output, err := vm.Run(ctx, script, snapshotTree) 834 assert.NoError(t, err) 835 assert.NoError(t, output.Err) 836 assert.Equal(t, cadence.NewBool(true), output.Value) 837 }, 838 )) 839 } 840 841 testVerifyPoP() 842 testKeyAggregation() 843 testBLSSignatureAggregation() 844 testBLSCombinedAggregations() 845 }