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

chore: add init method to Noir class for web #2920

Merged
merged 37 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
5ca20f7
Copy from Kobys Branch
kevaundray Sep 29, 2023
e120e24
revert to previous definition
kevaundray Sep 29, 2023
15ebc21
remove unused ignore file
kevaundray Sep 29, 2023
29d7f94
revert: group tooling workspace packages
kevaundray Sep 29, 2023
190f011
format
kevaundray Sep 29, 2023
c053aac
update yarn.lock
kevaundray Sep 29, 2023
9dcbbca
Import types into noir_js
kevaundray Sep 29, 2023
bbcf611
replace anonymous object with CompiledCircuit type
kevaundray Sep 29, 2023
7959844
export Noir
kevaundray Sep 29, 2023
ebaa551
lint fix
kevaundray Sep 29, 2023
894162d
update lockfile
kevaundray Sep 29, 2023
ef6ad1c
remove prettier
kevaundray Sep 29, 2023
01aee47
lint fix
kevaundray Sep 29, 2023
17b8956
copy barretenberg backend from ts
kevaundray Sep 29, 2023
e84e060
remove prettier
kevaundray Sep 29, 2023
1372c0d
remove compiled_examples from gitignore
kevaundray Sep 29, 2023
f4f0a79
remove lib folder
kevaundray Sep 29, 2023
0368617
add redundant methods
kevaundray Sep 29, 2023
9312121
extend mv syntax so that we convert all files to cjs in cjs folder
kevaundray Sep 29, 2023
8468b07
import backend
kevaundray Sep 29, 2023
8672a11
delete backend file
kevaundray Sep 29, 2023
7c72e68
add bb backend to workspace
kevaundray Sep 29, 2023
ab0c694
update index.ts in bb backend interface file
kevaundray Sep 29, 2023
331f157
update yarn.lock
kevaundray Sep 29, 2023
4f9a363
Merge remote-tracking branch 'origin/master' into kw/add-bb-backend-i…
kevaundray Sep 29, 2023
a0e327c
lint --fix
kevaundray Sep 29, 2023
5be1151
build bb.js wrapper
kevaundray Sep 29, 2023
26eeabf
Update tooling/noir_js_backend_barretenberg/src/serialize.ts
kevaundray Sep 29, 2023
3710d73
silence error if lib does not exist
kevaundray Sep 29, 2023
d8ddde0
chore: add gitignore
TomAFrench Sep 29, 2023
69b47e2
Merge remote-tracking branch 'origin/master' into kw/add-bb-backend-i…
kevaundray Oct 1, 2023
c2d850b
add init method to noir class
kevaundray Oct 1, 2023
619029e
chore: compile types package (#2921)
kevaundray Oct 2, 2023
59751cb
Update tooling/noir_js/src/program.ts
TomAFrench Oct 2, 2023
c662120
Update tooling/noir_js_backend_barretenberg/src/serialize.ts
TomAFrench Oct 2, 2023
55aadff
Merge branch 'master' into kw/add-init-to-noir
TomAFrench Oct 2, 2023
3b62219
fix merge resolution: extra build step
kevaundray Oct 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/test-noir-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ jobs:

- name: Build noirc_abi
run: yarn workspace @noir-lang/noirc_abi build

- name: Build barretenberg wrapper
run: yarn workspace @noir-lang/backend_barretenberg build

- name: Run noir_js tests
run: |
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"tooling/noir_js_types",
"tooling/noirc_abi_wasm",
"tooling/noir_js",
"tooling/noir_js_backend_barretenberg",
"acvm-repo/acvm_js",
"release-tests"
],
Expand Down
12 changes: 12 additions & 0 deletions tooling/noir_js/src/program.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Backend, CompiledCircuit } from '@noir-lang/types';
import { generateWitness } from './witness_generation.js';
import initAbi from '@noir-lang/noirc_abi';
import initACVM from '@noir-lang/acvm_js';

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

async init(): Promise<void> {
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
// If these are available, then we are in the
// web environment. For the node environment, this
// is a no-op.
if (typeof initAbi === 'function') {
initAbi();
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
initACVM();
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
}
}

// Initial inputs to your program
async generateFinalProof(inputs: any): Promise<Uint8Array> {
const serializedWitness = await generateWitness(this.circuit, inputs);
Expand Down
14 changes: 7 additions & 7 deletions tooling/noir_js/test/node/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect } from 'chai';
import assert_lt_json from '../noir_compiled_examples/assert_lt/target/assert_lt.json' assert { type: 'json' };
import { generateWitness } from '../../src/index.js';
import { Noir } from '../../src/program.js';
import { BarretenbergBackend as Backend } from '../backend/barretenberg.js';
import { BarretenbergBackend as Backend } from '@noir-lang/backend_barretenberg';

it('end-to-end proof creation and verification (outer)', async () => {
// Noir.Js part
Expand All @@ -15,7 +15,7 @@ it('end-to-end proof creation and verification (outer)', async () => {
// bb.js part
//
// Proof creation
const prover = await Backend.initialize(assert_lt_json);
const prover = new Backend(assert_lt_json);
const proof = await prover.generateFinalProof(serializedWitness);

// Proof verification
Expand All @@ -31,7 +31,7 @@ it('end-to-end proof creation and verification (outer) -- Program API', async ()
};

// Initialize backend
const backend = await Backend.initialize(assert_lt_json);
const backend = new Backend(assert_lt_json);
// Initialize program
const program = new Noir(assert_lt_json, backend);
// Generate proof
Expand All @@ -53,7 +53,7 @@ it('end-to-end proof creation and verification (inner)', async () => {
// bb.js part
//
// Proof creation
const prover = await Backend.initialize(assert_lt_json);
const prover = new Backend(assert_lt_json);
const proof = await prover.generateIntermediateProof(serializedWitness);

// Proof verification
Expand Down Expand Up @@ -82,12 +82,12 @@ it('[BUG] -- bb.js null function or function signature mismatch (different insta
const serializedWitness = await generateWitness(assert_lt_json, inputs);

// bb.js part
const prover = await Backend.initialize(assert_lt_json);
const prover = new Backend(assert_lt_json);

const proof = await prover.generateFinalProof(serializedWitness);

try {
const verifier = await Backend.initialize(assert_lt_json);
const verifier = new Backend(assert_lt_json);
await verifier.verifyFinalProof(proof);
expect.fail(
'bb.js currently returns a bug when we try to verify a proof with a different Barretenberg instance that created it.',
Expand Down Expand Up @@ -117,7 +117,7 @@ it('[BUG] -- bb.js null function or function signature mismatch (outer-inner) ',
//
// Proof creation
//
const prover = await Backend.initialize(assert_lt_json);
const prover = new Backend(assert_lt_json);
// Create a proof using both proving systems, the majority of the time
// one would only use outer proofs.
const proofOuter = await prover.generateFinalProof(serializedWitness);
Expand Down
1 change: 1 addition & 0 deletions tooling/noir_js_backend_barretenberg/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
3 changes: 3 additions & 0 deletions tooling/noir_js_backend_barretenberg/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: ["../../.eslintrc.js"],
};
2 changes: 2 additions & 0 deletions tooling/noir_js_backend_barretenberg/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
crs
lib
43 changes: 43 additions & 0 deletions tooling/noir_js_backend_barretenberg/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "@noir-lang/backend_barretenberg",
"collaborators": [
"The Noir Team <team@noir-lang.org>"
],
"version": "0.7.10",
"packageManager": "yarn@3.5.1",
"license": "(MIT OR Apache-2.0)",
"type": "module",
"source": "src/index.ts",
"main": "lib/cjs/index.cjs",
"module": "lib/esm/index.js",
"exports": {
"require": "./lib/cjs/index.cjs",
"default": "./lib/esm/index.js",
"types": "./lib/esm/index.d.ts"
},
"types": "lib/esm/index.d.ts",
"scripts": {
"dev": "tsc --watch",
"build": "yarn clean && tsc && tsc -p ./tsconfig.cjs.json && mv ./lib/cjs/index.js ./lib/cjs/index.cjs && mv ./lib/cjs/serialize.js ./lib/cjs/serialize.cjs && mv ./lib/cjs/base64_decode.js ./lib/cjs/base64_decode.cjs",
"clean": "rm -rf ./lib",
"prettier": "prettier 'src/**/*.ts'",
"prettier:fix": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
"lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0"
},
"dependencies": {
"@aztec/bb.js": "0.7.10",
"@noir-lang/types": "workspace:*",
"fflate": "^0.8.0"
},
"peerDependencies": {
"@noir-lang/backend_barretenberg": "workspace:*"
},
"devDependencies": {
"@types/node": "^20.6.2",
"@types/prettier": "^3",
"eslint": "^8.40.0",
"eslint-plugin-prettier": "^5.0.0",
"prettier": "3.0.3",
"typescript": "5.1.5"
}
}
13 changes: 13 additions & 0 deletions tooling/noir_js_backend_barretenberg/src/base64_decode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Since this is a simple function, we can use feature detection to
// see if we are in the nodeJs environment or the browser environment.
export function base64Decode(input: string): Uint8Array {
if (typeof Buffer !== 'undefined') {
// Node.js environment
return Buffer.from(input, 'base64');
} else if (typeof atob === 'function') {
// Browser environment
return Uint8Array.from(atob(input), (c) => c.charCodeAt(0));
} else {
throw new Error('No implementation found for base64 decoding.');
}
}
Original file line number Diff line number Diff line change
@@ -1,49 +1,38 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { Barretenberg, Crs, RawBuffer } from '@aztec/bb.js';
import { acirToUint8Array } from '../../src/index.js';
import { Backend } from '@noir-lang/types';
import { acirToUint8Array } from './serialize.js';
import { Backend, CompiledCircuit } from '@noir-lang/types';

export class BarretenbergBackend implements Backend {
// These type assertions are used so that we don't
// have to initialize `api` and `acirComposer` in the constructor.
// These are initialized asynchronously in the `init` function,
// constructors cannot be asynchronous which is why we do this.
api = {} as Barretenberg;
acirComposer = {} as any;
acirUncompressedBytecode: Uint8Array;
private api: any;
private acirComposer: any;
private acirUncompressedBytecode: Uint8Array;
private numberOfThreads = 1;

private constructor(acirCircuit: { bytecode: string }) {
constructor(acirCircuit: CompiledCircuit, numberOfThreads = 1) {
const acirBytecodeBase64 = acirCircuit.bytecode;
this.numberOfThreads = numberOfThreads;
this.acirUncompressedBytecode = acirToUint8Array(acirBytecodeBase64);
}

static async initialize(acirCircuit: { bytecode: string }): Promise<BarretenbergBackend> {
const backend = new BarretenbergBackend(acirCircuit);
await backend.init();
return backend;
}

private async init(): Promise<void> {
const numThreads = 4;

const { api, composer } = await this.initBarretenberg(numThreads, this.acirUncompressedBytecode);

this.api = api;
this.acirComposer = composer;
}

private async initBarretenberg(numThreads: number, acirUncompressedBytecode: Uint8Array) {
const api = await Barretenberg.new(numThreads);

const [_exact, _total, subgroupSize] = await api.acirGetCircuitSizes(acirUncompressedBytecode);
const crs = await Crs.new(subgroupSize + 1);
await api.commonInitSlabAllocator(subgroupSize);
await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data()));

const acirComposer = await api.acirNewAcirComposer(subgroupSize);
return { api: api, composer: acirComposer };
private async instantiate(): Promise<void> {
if (!this.api) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
const { Barretenberg, RawBuffer, Crs } = await import('@aztec/bb.js');
const api = await Barretenberg.new(this.numberOfThreads);

const [_exact, _total, subgroupSize] = await api.acirGetCircuitSizes(this.acirUncompressedBytecode);
const crs = await Crs.new(subgroupSize + 1);
await api.commonInitSlabAllocator(subgroupSize);
await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data()));

this.acirComposer = await api.acirNewAcirComposer(subgroupSize);
this.api = api;
}
}

// Generate an outer proof. This is the proof for the circuit which will verify
Expand Down Expand Up @@ -73,6 +62,7 @@ export class BarretenbergBackend implements Backend {
}

async generateProof(decompressedWitness: Uint8Array, makeEasyToVerifyInCircuit: boolean): Promise<Uint8Array> {
await this.instantiate();
const proof = await this.api.acirCreateProof(
this.acirComposer,
this.acirUncompressedBytecode,
Expand Down Expand Up @@ -100,6 +90,7 @@ export class BarretenbergBackend implements Backend {
vkAsFields: string[];
vkHash: string;
}> {
await this.instantiate();
const proofAsFields = await this.api.acirSerializeProofIntoFields(this.acirComposer, proof, numOfPublicInputs);

// TODO: perhaps we should put this in the init function. Need to benchmark
Expand Down Expand Up @@ -128,11 +119,15 @@ export class BarretenbergBackend implements Backend {
}

async verifyProof(proof: Uint8Array, makeEasyToVerifyInCircuit: boolean): Promise<boolean> {
await this.instantiate();
await this.api.acirInitVerificationKey(this.acirComposer);
return await this.api.acirVerifyProof(this.acirComposer, proof, makeEasyToVerifyInCircuit);
}

async destroy(): Promise<void> {
if (!this.api) {
return;
}
await this.api.destroy();
}
}
8 changes: 8 additions & 0 deletions tooling/noir_js_backend_barretenberg/src/serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { decompressSync as gunzip } from 'fflate';
import { base64Decode } from './base64_decode.js';

// Converts bytecode from a base64 string to a Uint8Array
export function acirToUint8Array(base64EncodedBytecode): Uint8Array {
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
const compressedByteCode = base64Decode(base64EncodedBytecode);
return gunzip(compressedByteCode);
}
7 changes: 7 additions & 0 deletions tooling/noir_js_backend_barretenberg/tsconfig.cjs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "CommonJS",
"outDir": "./lib/cjs"
},
}
16 changes: 16 additions & 0 deletions tooling/noir_js_backend_barretenberg/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "esnext",
"declaration": true,
"emitDeclarationOnly": false,
"module": "ESNext",
"moduleResolution": "NodeNext",
"outDir": "./lib/esm",
"esModuleInterop": true,
"resolveJsonModule": true,
"strict": true,
"noImplicitAny": false,
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
52 changes: 52 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ __metadata:
languageName: node
linkType: hard

"@aztec/bb.js@npm:0.7.10":
version: 0.7.10
resolution: "@aztec/bb.js@npm:0.7.10"
dependencies:
comlink: ^4.4.1
commander: ^10.0.1
debug: ^4.3.4
tslib: ^2.4.0
bin:
bb.js: dest/node/main.js
checksum: 0410278e6ec2a6ecdcbaa58633b181ec1d91e1c267c76e7e587fb69c8f2fd394e79f65bd96cfcdb2a2b20fe5abeb86ababd45bd6364ba07555fc0643bf0e4307
languageName: node
linkType: hard

"@aztec/bb.js@npm:0.7.2":
version: 0.7.2
resolution: "@aztec/bb.js@npm:0.7.2"
Expand Down Expand Up @@ -440,6 +454,24 @@ __metadata:
languageName: unknown
linkType: soft

"@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg":
version: 0.0.0-use.local
resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg"
dependencies:
"@aztec/bb.js": 0.7.10
"@noir-lang/types": "workspace:*"
"@types/node": ^20.6.2
"@types/prettier": ^3
eslint: ^8.40.0
eslint-plugin-prettier: ^5.0.0
fflate: ^0.8.0
prettier: 3.0.3
typescript: 5.1.5
peerDependencies:
"@noir-lang/backend_barretenberg": "workspace:*"
languageName: unknown
linkType: soft

"@noir-lang/noir_js@workspace:*, @noir-lang/noir_js@workspace:tooling/noir_js":
version: 0.0.0-use.local
resolution: "@noir-lang/noir_js@workspace:tooling/noir_js"
Expand Down Expand Up @@ -7549,6 +7581,16 @@ __metadata:
languageName: node
linkType: hard

"typescript@npm:5.1.5":
version: 5.1.5
resolution: "typescript@npm:5.1.5"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 0eef8699e05ae767096924dbed633c340b4d36e953bb8ed87fb12e9dd9dcea5055ceac7182c614a556dbd346a8a82df799d330e1e286ae66e17c84e1710f6a6f
languageName: node
linkType: hard

"typescript@npm:^5.0.4, typescript@npm:^5.2.2":
version: 5.2.2
resolution: "typescript@npm:5.2.2"
Expand All @@ -7569,6 +7611,16 @@ __metadata:
languageName: node
linkType: hard

"typescript@patch:typescript@5.1.5#~builtin<compat/typescript>":
version: 5.1.5
resolution: "typescript@patch:typescript@npm%3A5.1.5#~builtin<compat/typescript>::version=5.1.5&hash=5da071"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 12ff5d14888805f24479e54bc8a3f83647107a6345f6c29dffcd429fb345be55f584a37e262cca58a0105203e41d4cb4e31b1b9096c9abeca0e2ace8eb00935e
languageName: node
linkType: hard

"typescript@patch:typescript@^5.0.4#~builtin<compat/typescript>, typescript@patch:typescript@^5.2.2#~builtin<compat/typescript>":
version: 5.2.2
resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin<compat/typescript>::version=5.2.2&hash=f3b441"
Expand Down