Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: separate proving from noir_js #5072

Merged
merged 12 commits into from
May 31, 2024
5 changes: 5 additions & 0 deletions compiler/integration-tests/circuits/assert_lt/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "assert_lt"
type = "bin"
authors = [""]
[dependencies]
10 changes: 10 additions & 0 deletions compiler/integration-tests/circuits/assert_lt/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use dep::std;

fn main(x: u64, y: pub u64) -> pub u64 {
// We include a println statement to show that noirJS will ignore this and continue execution
std::println("foo");


assert(x < y);
x + y
}
7 changes: 7 additions & 0 deletions compiler/integration-tests/circuits/fold_fibonacci/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "fold_fibonacci"
type = "bin"
authors = [""]
compiler_version = ">=0.28.0"

[dependencies]
12 changes: 12 additions & 0 deletions compiler/integration-tests/circuits/fold_fibonacci/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn main(x: u32) {
assert(fibonacci(x) == 55);
}

#[fold]
fn fibonacci(x: u32) -> u32 {
if x <= 1 {
x
} else {
fibonacci(x - 1) + fibonacci(x - 2)
}
}
2 changes: 1 addition & 1 deletion compiler/integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"build": "echo Integration Test build step",
"test": "yarn test:browser && yarn test:node",
"test:node": "bash ./scripts/codegen-verifiers.sh && hardhat test test/node/**/*",
"test:node": "bash ./scripts/setup.sh && hardhat test test/node/**/*",
"test:browser": "web-test-runner",
"test:integration:browser": "web-test-runner test/browser/**/*.test.ts",
"test:integration:browser:watch": "web-test-runner test/browser/**/*.test.ts --watch",
Expand Down
1 change: 1 addition & 0 deletions compiler/integration-tests/scripts/codegen-verifiers.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -e

NARGO_BACKEND_PATH=${NARGO_BACKEND_PATH:-bb}

Expand Down
12 changes: 12 additions & 0 deletions compiler/integration-tests/scripts/compile-programs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e

self_path=$(dirname "$(readlink -f "$0")")

package_root=$self_path/../

assert_lt_dir=$package_root/circuits/assert_lt/
nargo --program-dir $assert_lt_dir compile

fold_fibonacci_dir=$package_root/circuits/fold_fibonacci/
nargo --program-dir $fold_fibonacci_dir compile
8 changes: 8 additions & 0 deletions compiler/integration-tests/scripts/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -e

self_path=$(dirname "$(readlink -f "$0")")


$self_path/compile-programs.sh
$self_path/codegen-verifiers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,20 @@ test_cases.forEach((testInfo) => {
throw e;
}

const backend = new BarretenbergBackend(noir_program);
const program = new Noir(noir_program, backend);

const prover_toml = await new Response(await getFile(`${base_relative_path}/${test_case}/Prover.toml`)).text();
const inputs: InputMap = TOML.parse(prover_toml) as InputMap;

// JS Proving

const proofWithPublicInputs = await program.generateProof(inputs);
const program = new Noir(noir_program);
const { witness } = await program.execute(inputs);

const backend = new BarretenbergBackend(noir_program);
const proof = await backend.generateProof(witness);

// JS verification

const verified = await program.verifyProof(proofWithPublicInputs);
const verified = await backend.verifyProof(proof);
expect(verified, 'Proof fails verification in JS').to.be.true;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ it(`smart contract can verify a recursive proof`, async () => {

// Final proof

const recursion_backend = new BarretenbergBackend(recursionProgram);
const recursion = new Noir(recursionProgram, recursion_backend);
const recursion = new Noir(recursionProgram);

const recursion_inputs: InputMap = {
verification_key: vkAsFields,
Expand All @@ -65,8 +64,11 @@ it(`smart contract can verify a recursive proof`, async () => {
key_hash: vkHash,
};

const recursion_proof = await recursion.generateProof(recursion_inputs);
expect(await recursion.verifyProof(recursion_proof)).to.be.true;
const { witness: recursionWitness } = await recursion.execute(recursion_inputs);

const recursion_backend = new BarretenbergBackend(recursionProgram);
const recursion_proof = await recursion_backend.generateProof(recursionWitness);
expect(await recursion_backend.verifyProof(recursion_proof)).to.be.true;

// Smart contract verification

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from 'chai';
import assert_lt_json from '../noir_compiled_examples/assert_lt/target/assert_lt.json' assert { type: 'json' };
import fold_fibonacci_json from '../noir_compiled_examples/fold_fibonacci/target/fold_fibonacci.json' assert { type: 'json' };
import assert_lt_json from '../../circuits/assert_lt/target/assert_lt.json' assert { type: 'json' };
import fold_fibonacci_json from '../../circuits/fold_fibonacci/target/fold_fibonacci.json' assert { type: 'json' };
import { Noir } from '@noir-lang/noir_js';
import { BarretenbergBackend as Backend, BarretenbergVerifier as Verifier } from '@noir-lang/backend_barretenberg';
import { CompiledCircuit } from '@noir-lang/types';
Expand Down Expand Up @@ -30,38 +30,20 @@ it('end-to-end proof creation and verification (outer)', async () => {
expect(isValid).to.be.true;
});

it('end-to-end proof creation and verification (outer) -- Program API', async () => {
// Noir.Js part
const inputs = {
x: '2',
y: '3',
};

// Initialize backend
const backend = new Backend(assert_lt_program);
// Initialize program
const program = new Noir(assert_lt_program, backend);
// Generate proof
const proof = await program.generateProof(inputs);

// Proof verification
const isValid = await program.verifyProof(proof);
expect(isValid).to.be.true;
});

it('end-to-end proof creation and verification (outer) -- Verifier API', async () => {
// Noir.Js part
const inputs = {
x: '2',
y: '3',
};

// Initialize backend
const backend = new Backend(assert_lt_program);
// Initialize program
const program = new Noir(assert_lt_program, backend);
// Execute program
const program = new Noir(assert_lt_program);
const { witness } = await program.execute(inputs);

// Generate proof
const proof = await program.generateProof(inputs);
const backend = new Backend(assert_lt_program);
const proof = await backend.generateProof(witness);

const verificationKey = await backend.getVerificationKey();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,20 @@ test_cases.forEach((testInfo) => {

const noir_program = compileResult.program;

const backend = new BarretenbergBackend(noir_program);
const program = new Noir(noir_program, backend);
const program = new Noir(noir_program);

// JS Proving

const prover_toml = readFileSync(resolve(`${base_relative_path}/${test_case}/Prover.toml`)).toString();
const inputs = toml.parse(prover_toml);
const { witness } = await program.execute(inputs);

const proofData = await program.generateProof(inputs);
const backend = new BarretenbergBackend(noir_program);
const proofData = await backend.generateProof(witness);

// JS verification

const verified = await program.verifyProof(proofData);
const verified = await backend.verifyProof(proofData);
expect(verified, 'Proof fails verification in JS').to.be.true;

// Smart contract verification
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/how_to/how-to-oracles.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ For example, if your Noir program expects the host machine to provide CPU pseudo
```js
const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc

await noir.generateProof(inputs, foreignCallHandler)
await noir.execute(inputs, foreignCallHandler)
```

As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo.
Expand Down
9 changes: 5 additions & 4 deletions docs/docs/how_to/how-to-recursion.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ You can use the [`os.cpus()`](https://nodejs.org/api/os.html#oscpus) object in `
After instantiating the backend, you should also instantiate `noir_js`. We will use it to execute the circuit and get the witness.

```js
const noir = new Noir(circuit, backend)
const noir = new Noir(circuit)
const { witness } = noir.execute(input)
```

Expand Down Expand Up @@ -155,8 +155,8 @@ const backends = {
recursive: new BarretenbergBackend(circuits.recursive)
}
const noir_programs = {
main: new Noir(circuits.main, backends.main),
recursive: new Noir(circuits.recursive, backends.recursive)
main: new Noir(circuits.main),
recursive: new Noir(circuits.recursive)
}
```

Expand All @@ -173,7 +173,8 @@ const { proofAsFields, vkAsFields, vkHash } = await backends.main.generateRecurs
proof,
numPublicInputs,
);
const recursiveProof = await noir_programs.recursive.generateProof(recursiveInputs)
const { witness: recursiveWitness } = await noir_programs.recursive.execute(recursiveInputs)
const recursiveProof = await backends.recursive.generateProof(recursiveWitness);
```

:::
5 changes: 3 additions & 2 deletions docs/docs/tutorials/noirjs_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ And instantiate them inside our try-catch block:
```ts
// try {
const backend = new BarretenbergBackend(circuit);
const noir = new Noir(circuit, backend);
const noir = new Noir(circuit);
// }
```

Expand All @@ -288,7 +288,8 @@ Now we're ready to prove stuff! Let's feed some inputs to our circuit and calcul
await setup(); // let's squeeze our wasm inits here

display('logs', 'Generating proof... ⌛');
const proof = await noir.generateProof(input);
const { witness } = await noir.execute(input);
const proof = await backend.generateProof(witness);
display('logs', 'Generating proof... ✅');
display('results', proof.proof);
```
Expand Down
4 changes: 2 additions & 2 deletions tooling/noir_js/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as acvm from '@noir-lang/acvm_js';
import * as abi from '@noir-lang/noirc_abi';
import { CompiledCircuit, ProofData } from '@noir-lang/types';
import { CompiledCircuit } from '@noir-lang/types';

export {
ecdsa_secp256r1_verify,
Expand All @@ -22,4 +22,4 @@ export { ErrorWithPayload } from './witness_generation.js';
export { acvm, abi };

// type exports for typedoc
export { CompiledCircuit, ProofData };
export { CompiledCircuit };
61 changes: 2 additions & 59 deletions tooling/noir_js/src/program.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Backend, CompiledCircuit, ProofData } from '@noir-lang/types';
import { CompiledCircuit } from '@noir-lang/types';
import { generateWitness } from './witness_generation.js';
import initAbi, { abiDecode, InputMap, InputValue } from '@noir-lang/noirc_abi';
import initACVM, { compressWitnessStack, ForeignCallHandler } from '@noir-lang/acvm_js';

export class Noir {
constructor(
private circuit: CompiledCircuit,
private backend?: Backend,
) {}
constructor(private circuit: CompiledCircuit) {}

/** @ignore */
async init(): Promise<void> {
Expand All @@ -20,27 +16,6 @@ export class Noir {
}
}

/**
*
* @description
* Destroys the underlying backend instance.
*
* @example
* ```typescript
* await noir.destroy();
* ```
*
*/
async destroy(): Promise<void> {
await this.backend?.destroy();
}

private getBackend(): Backend {
if (this.backend === undefined) throw new Error('Operation requires a backend but none was provided');
return this.backend;
}

// Initial inputs to your program
/**
* @description
* Allows to execute a circuit to get its witness and return value.
Expand All @@ -60,36 +35,4 @@ export class Noir {
const { return_value: returnValue } = abiDecode(this.circuit.abi, main_witness);
return { witness: compressWitnessStack(witness_stack), returnValue };
}

/**
*
* @description
* Generates a witness and a proof given an object as input.
*
* @example
* ```typescript
* async generateProof(input)
* ```
*
*/
async generateProof(inputs: InputMap, foreignCallHandler?: ForeignCallHandler): Promise<ProofData> {
const { witness } = await this.execute(inputs, foreignCallHandler);
return this.getBackend().generateProof(witness);
}

/**
*
* @description
* Instantiates the verification key and verifies a proof.
*
*
* @example
* ```typescript
* async verifyProof(proof)
* ```
*
*/
async verifyProof(proofData: ProofData): Promise<boolean> {
return this.getBackend().verifyProof(proofData);
}
}
2 changes: 1 addition & 1 deletion tooling/noir_js/test/node/execute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const assert_lt_program = assert_lt_json as CompiledCircuit;
const assert_msg_runtime = assert_msg_json as CompiledCircuit;
const fold_fibonacci_program = fold_fibonacci_json as CompiledCircuit;

it('returns the return value of the circuit', async () => {
it('executes a single-ACIR program correctly', async () => {
const inputs = {
x: '2',
y: '3',
Expand Down
Loading