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  }