Skip to content

Instantly share code, notes, and snippets.

Created August 11, 2023 19:46
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
the full script for the instructive page here:
import circuit from '../target/test.json' assert { type: 'json' };
import { decompressSync } from 'fflate';
import { Crs, newBarretenbergApiAsync, RawBuffer } from '@aztec/bb.js/dest/node/index.js';
import { ethers } from 'ethers'; // I'm lazy so I'm using ethers to pad my input
import { executeCircuit, compressWitness } from '@noir-lang/acvm_js';
async function main() {
const acirBuffer = Buffer.from(circuit.bytecode, 'base64');
const acirBufferUncompressed = decompressSync(acirBuffer);
const api = await newBarretenbergApiAsync(4);
const [exact, circuitSize, subgroup] = await api.acirGetCircuitSizes(acirBufferUncompressed);
const subgroupSize = Math.pow(2, Math.ceil(Math.log2(circuitSize)));
const crs = await + 1);
await api.commonInitSlabAllocator(subgroupSize);
await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data()));
const acirComposer = await api.acirNewAcirComposer(subgroupSize);
async function generateWitness(input: any, acirBuffer: Buffer): Promise<Uint8Array> {
const initialWitness = new Map<number, string>();
initialWitness.set(1, ethers.utils.hexZeroPad(`0x${input.x.toString(16)}`, 32));
initialWitness.set(2, ethers.utils.hexZeroPad(`0x${input.y.toString(16)}`, 32));
// initialWitness.set(3, ethers.utils.hexZeroPad(`0x${input.z.toString(16)}`, 32));
const witnessMap = await executeCircuit(acirBuffer, initialWitness, () => {
throw Error('unexpected oracle');
const witnessBuff = compressWitness(witnessMap);
return witnessBuff;
async function generateProof(witness: Uint8Array) {
const proof = await api.acirCreateProof(
return proof;
async function verifyProof(proof: Uint8Array) {
await api.acirInitProvingKey(acirComposer, acirBufferUncompressed);
const verified = await api.acirVerifyProof(acirComposer, proof, false);
return verified;
const input = { x: 3, y: 4 };
const witness = await generateWitness(input, acirBuffer);
console.log('Witness generated!');
const proof = await generateProof(witness);
console.log('Proof generated!');
await verifyProof(proof);
console.log('Proof verified!');
Copy link

chung080702 commented Aug 15, 2023

How to fix this error when I am trying to run the above code?

RuntimeError: unreachable
    at abort (wasm://wasm/025b415a:wasm-function[11127]:0x413b31)
    at throw_or_abort(std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char>> const&) (wasm://wasm/025b415a:wasm-function[89]:0x36e1e)
    at serde::BinaryDeserializer<serde::BincodeDeserializer>::read_byte() (wasm://wasm/025b415a:wasm-function[2520]:0x12c52a)
    at serde::BinaryDeserializer<serde::BincodeDeserializer>::deserialize_u64() (wasm://wasm/025b415a:wasm-function[2522]:0x12c586)
    at serde::BincodeDeserializer::deserialize_len() (wasm://wasm/025b415a:wasm-function[2513]:0x12c36b)
    at std::__2::vector<Circuit::Witness, std::__2::allocator<Circuit::Witness>> serde::Deserializable<std::__2::vector<Circuit::Witness, std::__2::allocator<Circuit::Witness>>>::deserialize<serde::BincodeDeserializer>(serde::BincodeDeserializer&) (wasm://wasm/025b415a:wasm-function[2509]:0x12c24d)
    at Circuit::PublicInputs serde::Deserializable<Circuit::PublicInputs>::deserialize<serde::BincodeDeserializer>(serde::BincodeDeserializer&) (wasm://wasm/025b415a:wasm-function[2511]:0x12c2eb)
    at Circuit::Circuit serde::Deserializable<Circuit::Circuit>::deserialize<serde::BincodeDeserializer>(serde::BincodeDeserializer&) (wasm://wasm/025b415a:wasm-function[2218]:0x126cce)
    at Circuit::Circuit::bincodeDeserialize(std::__2::vector<unsigned char, std::__2::allocator<unsigned char>>) (wasm://wasm/025b415a:wasm-function[2208]:0x1269f6)
    at acir_format::circuit_buf_to_acir_format(std::__2::vector<unsigned char, std::__2::allocator<unsigned char>> const&) (wasm://wasm/025b415a:wasm-function[2207]:0x12673e)

I got this error at line:
const [exact, circuitSize, subgroup] = await api.acirGetCircuitSizes(acirBufferUncompressed);

Config in package.json:

  "dependencies": {
    "@aztec/bb.js": "^0.3.6",
    "@noir-lang/acvm_js": "github:noir-lang/acvm-simulator-wasm",
    "ethers": "^5.7.2",
    "fflate": "^0.8.0"
  "devDependencies": {
    "@types/node": "^20.5.0"

Copy link

critesjosh commented Aug 15, 2023

what version of noir are you running?

Also sharing this info from our discord:

Known Issues with bb.js

I am aware that a recent update has caused a regression with bb.js, so it's not working on the latest nightly build currently. The engineering team is working on setting up e2e integration tests to avoid future regressions.

The current recommendation is to not use bb.js until we have a stable release combo with bb.js and Noir, but if you are feeling ambitious, you can install Noir at a specific commit using nix ( nix build "github:noir-lang/noir?ref/ref=??" I don't have a specific commit for you, but it was working around August 9th so you can try one of those 🙂

Thanks for bearing with us.

Copy link

critesjosh commented Aug 16, 2023

this should work with noir version >0.10.1 now. install with noirup -v 0.10.1

Copy link

Thanks, it worked.

Copy link

I have changed the circuit as follows:

fn main(x: Field, y: pub Field) -> pub Field{
    let z = std::hash::pedersen([x,y])[0];
    assert(z == std::hash::pedersen([x,y])[0]);

Then I run the code and print witnessMap. I received:

I think witness size of pedersen hash should be bigger. Where am I wrong? I read the noir book, but I still don't understand how you create constraints? I want my code to prove that the pedersen hash of x and y is calculated correctly in noir.

Copy link

critesjosh commented Aug 17, 2023

i think that's right actually. you can see that value 3 and 5 match and 4 and 6 match. This is what i get when i calculate the pedersen hash in noir.

["0x25ed48b406cb7ac716062c45023b0523f5ed4e9a0baa12876fdc70307a8ad2f5", "0x0c290c796ea74cf713eaa3e74f2afdbffff95bd128dc77c02fce10cc479dfd0a"]

Copy link

I used to work with SnarkJS and Circom. I noticed that the witness size of the Pedersen hash is much larger compared to here. I wonder how all the constraints can be covered with a witness like this.
Looking at the above, I can see that my code doesn't generate constraints during the Pedersen hash calculation process; it only calculates the Pedersen hash first and then creates constraints afterward.
During the proof generation process, does Noir cover all the constraints?

Copy link

Yes, noir will cover all of the constraints defined in the circuit during the proof generation process. I don't think the pedersen hash calculation requires generating constrains, you only really care about constraining the result, no?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment