BN128 Proof Verification Through BLS12_381 Functions


I was trying to use the existing tooling of zk-snark (snark-js) but their BLS12_381 based power of tau ceremony gets some error which I have forwarded on their Github issues. However in the hopes of using it successfully in Sophia language’s BLS12_381 functions and types with the values created within the scalar field of BN128 I am trying different approaches and one of those got me here…

Line 23 verificationKey() returns list(int): are verification keys in int then converted to fp
Line 54 points48ToVerify() returns list(int): are converted integers from Calldata (To verify: type proof)
Line 73 points32ToVerify() returns list(int): are converted integers from Calldata (To verify: type list(fr))

Init runs smoothly with higher gas amount but verify_proof() gives error:

       VerifyContract: Verify_proof_method:
     Error: Invocation failed: "Incomplete patterns"
      at d (node_modules/@aeternity/aepp-sdk/dist/aepp-sdk.js:1:99543)
      at (node_modules/@aeternity/aepp-sdk/dist/aepp-sdk.js:1:101493)
      at processTicksAndRejections (internal/process/task_queues.js:95:5)
      at async Context.<anonymous> (test/verifyTests.js:148:15)

And with the same points the Solidity Version is:

The valid call data that will return true upon running verifyProof with it in solidity is:


and I am currently not aware of how to pass fp or fr types from outside the contracts So I am using inner conversions to pass and convert integers to relative types and construct correct records like g1 , g2 & fp2. I tried passing bytes padded with 0 to match the requirement as 32 and 48 bytes for fr and fp but I was getting type errors. I hope you can also provide some more examples on it in the future regarding fp & fr (Montgomery) as inputs with editors or js-sdk.

Please let me know about this error and what should I do to solve it.

Tagging: @hanssv.chain @dimitar.chain

Best Regards,

1 Like

It is Saturday evening, so no place for a long and thorough answer… Using integers as input is perfectly fine I think, you can also push fr's/fp's and g1/g2's in there directly - have a look at the aeternity node tests in apps/aecontract/test/aecontract_SUITE.erl (the test case sophia_crypto_pairing) - and its contract test/contracts/crypto_pairing.aes. In Erlang there is the emcl library (basically a wrapper for mcl) - I guess there is something similar available in other languages if you wan’t to work with BLS12-381 points.

Also, unless I’ve misunderstood how elliptic curves work, you will not be able to use BLS12-381 functions to verify something from a different elliptic curve. The base point, the field size and everything else won’t match :thinking:


Thank you @hanssv.chain for the above information and sharings tests. I will also check emcl library.


I’m curious if you made some more progress?

Is snark-js targeting BLS12-381 out of the box? I remember having a hard time finding a proof-framework that supported BLS12-381 when I was adding it to FATE.


Sorry Hans, No progress yet! But I will try it out very soon again.

snarkjs do have bls12-381 support but the last time I tried it gave an error.

@hanssv.chain There are some minor developments from this side.

The code is tracked to fix the previous or next errors I got (using circom and snarkjs when compiling with bls12381 prime field and working with phase 2 of power of tau ceremony) That means the points we now get is from scalar field of bls12381.

Next there are 2 small obstacles:

  • Solidity only holds 256 bits as max int and these big numbers here are much bigger now which I am trying to find a way to perform addition or multiplication operation to get int operations to be done for numbers > 256 bits.
  • I am using aeproject this time for better results and got this error when called callDataToVerify.
TypeResolveError: Cannot resolve type: "MCL_BLS12_381.fp"
      at TypeResolver.resolveType (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:231:15)
      at TypeResolver.resolveType (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:126:25)
      at /home/ubuntu/aeternity-projects/bounty/zkp-aes/node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:251:56
      at (<anonymous>)
      at TypeResolver.resolveRecord (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:251:42)
      at TypeResolver.resolveType (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:212:25)
      at TypeResolver.resolveType (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:126:25)
      at TypeResolver.resolveType (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:126:25)
      at /home/ubuntu/aeternity-projects/bounty/zkp-aes/node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:251:56
      at (<anonymous>)
      at TypeResolver.resolveRecord (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:251:42)
      at TypeResolver.resolveType (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:212:25)
      at TypeResolver.resolveType (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:126:25)
      at TypeResolver.getReturnType (node_modules/@aeternity/aepp-calldata/src/TypeResolver.js:79:21)
      at Encoder.decode (node_modules/@aeternity/aepp-calldata/src/Encoder.js:99:41)
      at (node_modules/@aeternity/aepp-sdk/dist/aepp-sdk.js:1:97822)
      at processTicksAndRejections (internal/process/task_queues.js:95:5)
      at async Context.<anonymous> (test/zkp_verify_test.js:34:17)

Through Ae studio I get pattern incomplete when running some verification related method.

Also, the points are updated here: verification testing · GitHub

I made my repo public to better follow the static testing GitHub - devindirt/zk-using-bls12381: zk-using-bls12381

please provide full examples or open issues in the respective repositories. what’s the reason for just providing gists?

@hanssv.chain cannot tell you anything about aeproject for example. aeproject in general is the framework we provide for testing contracts by running a local environment with devmode activated and writing tests in javascript using the SDK.

the SDK in turn uses the calldata-lib.

here it seems like calldata-lib cannot handle this specific type, so my advise would be to open the issue directly in this repository:

in general it’s good to ping following people for the repositories:

1 Like

Sophia has no such limitations so I’m not sure what this comment means?

I have a reply pending here to @hanssv.chain previous post. I feel I should share as much as I know even if he is not involved!

The Gists I use to share quick required/desired files for development.

I will update the repo and open the issue…

It is easy to catch this statement. If it passes on solidity then I can rely on at least one thing working!

But if you can test it without any reference required in the first place (which I believe you can) then please try and also share the results as it will be good public testing for BLS12 381 capabilities provided by aeternity.

I have also explained the required points to get values from bls12381 scalar field
GitHub - devindirt/zk-using-bls12381: zk-using-bls12381 (Which is a (not the) repo @marco.chain :wink: )


@genievot I didn’t track the conversation you had before with Hans. I mainly reacted to the problems you mentioned in regards to tooling.

anyway, for everything I can support I am happy to help. in regards to bls12_381 I am absolutely not the right guy to talk to.

1 Like

@marco.chain Sorry I mixed up with ae-sdk-js and aeproject.

Please find latest issue here Cannot resolve type: "MCL_BLS12_381.fp" · Issue #412 · aeternity/aeproject · GitHub
and linked Cannot resolve type: "MCL_BLS12_381.fp · Issue #126 · aeternity/aepp-calldata-js · GitHub

Not sure it will be worth getting it to work in Solidity, but I know little about Solidity :sweat_smile:

I tried running zkpVerify.aes and indeed if you try to run verify_proof it fails with Revert: Incomplete patterns - I think the lists in calc_vk_x_ are not of equal length. The problem is when defining ic in init (line 162-171) there should be a , (comma) between the two values in the list. The verification still fails though but that should bring you a step further at least…

Tried to replicate the circom experiment, locally, but BLS12-381 doesn’t seem to be (well) supported - it fails with [ERROR] snarkJS: TypeError: Cannot read properties of undefined (reading 'q') - the fix mentioned in your issue doesn’t seem to be in whatever version the mighty npm decided to install. How did you work around that?

I found I wonder if that perhaps has a better support for BLS12-381 :thinking:


The [ERROR] snarkJS: TypeError: Cannot read properties of undefined (reading 'q') error was solved by changing the build/main.cjs file from ffjavascript like here Fix undefined `q` and `r` in `buildBls12381` by piotr-roslaniec · Pull Request #30 · iden3/ffjavascript · GitHub

You can find this in your global node_modules → under snarkjs node_modules → ffjavascript → build/main.cjs → Paste this whole code or search for bls12381wasm.q and perform commit mentioned changes.

The next error was with the wrong prime field getting built from curve params defined which can be fixed with:

from global node_modules → snarkjs → node_modules → ffjavascript → build → main.cjs (like before) and find buildEngine function.
set curve.q = e(params.q); , curve.r = e(params.r); & =; in the function definition.

Please try those fixes and let me know if you got any other error.

Thanks - does hacking those files qualify me as a JS-developer now? :sweat_smile:

It works - and I can translate the solidity verifier.sol into an equivalent (much simpler since Sophia has BLS12-381 built in) Sophia contract. Running the proof through the verification contract with 33 as the public input returns true, touching any parameter yields a false so I’d say it works :tada:

One caveat that I noticed was that the solidity code for some reason flipped x1 and x2 (and y1 and y2) in G2 constants for some reason… Don’t do this for Sophia, instead enter the numbers just like they are written in the JSON-files.

Also to keep your code slightly more tidy use mk_k1/mk_g2 to create G1/G2 values:

alpha = BLS12_381.mk_g1(3336208025895282801467121042590356419234644692143882069381168599475053878258325423048715471169591881823262687764052,

Thank you So much @hanssv.chain!

Excited to try it out myself through Sophia, Now I don’t need solidity for this :slight_smile:


glad to hear about the progress, thanks @hanssv.chain! :slight_smile: