diff --git a/barretenberg/acir_tests/browser-test-app/src/index.ts b/barretenberg/acir_tests/browser-test-app/src/index.ts index a30804536773..06370f5a82a0 100644 --- a/barretenberg/acir_tests/browser-test-app/src/index.ts +++ b/barretenberg/acir_tests/browser-test-app/src/index.ts @@ -1,11 +1,10 @@ import createDebug from "debug"; -import { inflate } from "pako"; createDebug.enable("*"); const debug = createDebug("browser-test-app"); async function runTest( - bytecode: Uint8Array, + bytecode: string, witness: Uint8Array, threads?: number ) { @@ -22,7 +21,7 @@ async function runTest( debug(`verifying...`); const verifier = new BarretenbergVerifier({ threads }); - const verified = await verifier.verifyUltrahonkProof(proof, verificationKey); + const verified = await verifier.verifyUltraHonkProof(proof, verificationKey); debug(`verified: ${verified}`); await verifier.destroy(); @@ -48,16 +47,13 @@ function base64ToUint8Array(base64: string) { // Update by extracting from ../acir_tests/verify_honk_proof. Specifically: // - The base64 representation of the ACIR is the bytecode section of program.json // - The base64 representation of the witness is obtained by encoding witness.gz -const acir = inflate( - base64ToUint8Array( +const acir = "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" - ) -); +; -const witness = inflate( +const witness = base64ToUint8Array( "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" - ) ); document.addEventListener("DOMContentLoaded", function () { diff --git a/barretenberg/acir_tests/headless-test/src/index.ts b/barretenberg/acir_tests/headless-test/src/index.ts index a318010c4277..cffd98997dcb 100644 --- a/barretenberg/acir_tests/headless-test/src/index.ts +++ b/barretenberg/acir_tests/headless-test/src/index.ts @@ -1,7 +1,6 @@ import { chromium, firefox, webkit } from "playwright"; import fs from "fs"; import { Command } from "commander"; -import { gunzipSync } from "zlib"; import chalk from "chalk"; import os from "os"; @@ -37,25 +36,14 @@ function formatAndPrintLog(message: string): void { console.log(formattedMessage); } -const readBytecodeFile = (path: string): Uint8Array => { - const extension = path.substring(path.lastIndexOf(".") + 1); - - if (extension == "json") { - const encodedCircuit = JSON.parse(fs.readFileSync(path, "utf8")); - const decompressed = gunzipSync( - Uint8Array.from(atob(encodedCircuit.bytecode), (c) => c.charCodeAt(0)) - ); - return decompressed; - } - - const encodedCircuit = fs.readFileSync(path); - const decompressed = gunzipSync(encodedCircuit); - return decompressed; +const readBytecodeFile = (path: string): string => { + const encodedCircuit = JSON.parse(fs.readFileSync(path, "utf8")); + return encodedCircuit.bytecode; }; const readWitnessFile = (path: string): Uint8Array => { const buffer = fs.readFileSync(path); - return gunzipSync(buffer); + return buffer; }; // Set up the command-line interface @@ -70,8 +58,8 @@ program ) .option( "-b, --bytecode-path ", - "Specify the path to the gzip encoded ACIR bytecode", - "./target/acir.gz" + "Specify the path to the ACIR artifact json file", + "./target/acir.json" ) .option( "-w, --witness-path ", @@ -102,19 +90,18 @@ program await page.goto("http://localhost:8080"); const result: boolean = await page.evaluate( - ([acirData, witnessData, threads]) => { + ([acir, witnessData, threads]: [string, number[], number]) => { // Convert the input data to Uint8Arrays within the browser context - const acirUint8Array = new Uint8Array(acirData as number[]); - const witnessUint8Array = new Uint8Array(witnessData as number[]); + const witnessUint8Array = new Uint8Array(witnessData); // Call the desired function and return the result return (window as any).runTest( - acirUint8Array, + acir, witnessUint8Array, threads ); }, - [Array.from(acir), Array.from(witness), threads] + [acir, Array.from(witness), threads] ); await browser.close(); diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 10fdc17b85de..c619210c4577 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -55,6 +55,7 @@ "comlink": "^4.4.1", "commander": "^10.0.1", "debug": "^4.3.4", + "fflate": "^0.8.0", "tslib": "^2.4.0" }, "devDependencies": { diff --git a/barretenberg/ts/src/barretenberg/backend.ts b/barretenberg/ts/src/barretenberg/backend.ts index 243ee8dc1b3b..0919f030e5c4 100644 --- a/barretenberg/ts/src/barretenberg/backend.ts +++ b/barretenberg/ts/src/barretenberg/backend.ts @@ -1,5 +1,13 @@ import { BackendOptions, Barretenberg } from './index.js'; import { RawBuffer } from '../types/raw_buffer.js'; +import { decompressSync as gunzip } from 'fflate'; +import { + deflattenFields, + flattenFieldsAsArray, + ProofData, + reconstructHonkProof, + reconstructUltraPlonkProof, +} from '../proof/index.js'; export class UltraPlonkBackend { // These type assertions are used so that we don't @@ -11,7 +19,11 @@ export class UltraPlonkBackend { // eslint-disable-next-line @typescript-eslint/no-explicit-any protected acirComposer: any; - constructor(protected acirUncompressedBytecode: Uint8Array, protected options: BackendOptions = { threads: 1 }) {} + protected acirUncompressedBytecode: Uint8Array; + + constructor(acirBytecode: string, protected options: BackendOptions = { threads: 1 }) { + this.acirUncompressedBytecode = acirToUint8Array(acirBytecode); + } /** @ignore */ async instantiate(): Promise { @@ -30,9 +42,25 @@ export class UltraPlonkBackend { } /** @description Generates a proof */ - async generateProof(uncompressedWitness: Uint8Array): Promise { + async generateProof(compressedWitness: Uint8Array): Promise { await this.instantiate(); - return this.api.acirCreateProof(this.acirComposer, this.acirUncompressedBytecode, uncompressedWitness); + const proofWithPublicInputs = await this.api.acirCreateProof( + this.acirComposer, + this.acirUncompressedBytecode, + gunzip(compressedWitness), + ); + + // This is the number of bytes in a UltraPlonk proof + // minus the public inputs. + const numBytesInProofWithoutPublicInputs = 2144; + + const splitIndex = proofWithPublicInputs.length - numBytesInProofWithoutPublicInputs; + + const publicInputsConcatenated = proofWithPublicInputs.slice(0, splitIndex); + const proof = proofWithPublicInputs.slice(splitIndex); + const publicInputs = deflattenFields(publicInputsConcatenated); + + return { proof, publicInputs }; } /** @@ -52,7 +80,7 @@ export class UltraPlonkBackend { * ``` */ async generateRecursiveProofArtifacts( - proof: Uint8Array, + proofData: ProofData, numOfPublicInputs = 0, ): Promise<{ proofAsFields: string[]; @@ -60,6 +88,8 @@ export class UltraPlonkBackend { vkHash: string; }> { await this.instantiate(); + + const proof = reconstructUltraPlonkProof(proofData); const proofAsFields = ( await this.api.acirSerializeProofIntoFields(this.acirComposer, proof, numOfPublicInputs) ).slice(numOfPublicInputs); @@ -79,9 +109,10 @@ export class UltraPlonkBackend { } /** @description Verifies a proof */ - async verifyProof(proof: Uint8Array): Promise { + async verifyProof(proofData: ProofData): Promise { await this.instantiate(); await this.api.acirInitVerificationKey(this.acirComposer); + const proof = reconstructUltraPlonkProof(proofData); return await this.api.acirVerifyProof(this.acirComposer, proof); } @@ -99,6 +130,12 @@ export class UltraPlonkBackend { } } +// Buffers are prepended with their size. The size takes 4 bytes. +const serializedBufferSize = 4; +const fieldByteSize = 32; +const publicInputOffset = 3; +const publicInputsOffsetBytes = publicInputOffset * fieldByteSize; + export class UltraHonkBackend { // These type assertions are used so that we don't // have to initialize `api` in the constructor. @@ -106,9 +143,11 @@ export class UltraHonkBackend { // constructors cannot be asynchronous which is why we do this. protected api!: Barretenberg; + protected acirUncompressedBytecode: Uint8Array; - constructor(protected acirUncompressedBytecode: Uint8Array, protected options: BackendOptions = { threads: 1 }) {} - + constructor(acirBytecode: string, protected options: BackendOptions = { threads: 1 }) { + this.acirUncompressedBytecode = acirToUint8Array(acirBytecode); + } /** @ignore */ async instantiate(): Promise { if (!this.api) { @@ -122,13 +161,39 @@ export class UltraHonkBackend { } } - async generateProof(uncompressedWitness: Uint8Array): Promise { + async generateProof(compressedWitness: Uint8Array): Promise { await this.instantiate(); - return this.api.acirProveUltraHonk(this.acirUncompressedBytecode, uncompressedWitness); + const proofWithPublicInputs = await this.api.acirProveUltraHonk( + this.acirUncompressedBytecode, + gunzip(compressedWitness), + ); + + const proofAsStrings = deflattenFields(proofWithPublicInputs.slice(4)); + + const numPublicInputs = Number(proofAsStrings[1]); + + // Account for the serialized buffer size at start + const publicInputsOffset = publicInputsOffsetBytes + serializedBufferSize; + // Get the part before and after the public inputs + const proofStart = proofWithPublicInputs.slice(0, publicInputsOffset); + const publicInputsSplitIndex = numPublicInputs * fieldByteSize; + const proofEnd = proofWithPublicInputs.slice(publicInputsOffset + publicInputsSplitIndex); + // Construct the proof without the public inputs + const proof = new Uint8Array([...proofStart, ...proofEnd]); + + // Fetch the number of public inputs out of the proof string + const publicInputsConcatenated = proofWithPublicInputs.slice( + publicInputsOffset, + publicInputsOffset + publicInputsSplitIndex, + ); + const publicInputs = deflattenFields(publicInputsConcatenated); + + return { proof, publicInputs }; } - async verifyProof(proof: Uint8Array): Promise { + async verifyProof(proofData: ProofData): Promise { await this.instantiate(); + const proof = reconstructHonkProof(flattenFieldsAsArray(proofData.publicInputs), proofData.proof); const vkBuf = await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode); return await this.api.acirVerifyUltraHonk(proof, new RawBuffer(vkBuf)); @@ -178,3 +243,24 @@ export class UltraHonkBackend { await this.api.destroy(); } } + +// Converts bytecode from a base64 string to a Uint8Array +function acirToUint8Array(base64EncodedBytecode: string): Uint8Array { + const compressedByteCode = base64Decode(base64EncodedBytecode); + return gunzip(compressedByteCode); +} + +// Since this is a simple function, we can use feature detection to +// see if we are in the nodeJs environment or the browser environment. +function base64Decode(input: string): Uint8Array { + if (typeof Buffer !== 'undefined') { + // Node.js environment + const b = Buffer.from(input, 'base64'); + return new Uint8Array(b.buffer, b.byteOffset, b.byteLength); + } 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.'); + } +} diff --git a/barretenberg/ts/src/barretenberg/verifier.ts b/barretenberg/ts/src/barretenberg/verifier.ts index c6bffc5109bd..e0c59f640395 100644 --- a/barretenberg/ts/src/barretenberg/verifier.ts +++ b/barretenberg/ts/src/barretenberg/verifier.ts @@ -1,5 +1,6 @@ import { BackendOptions, Barretenberg } from './index.js'; import { RawBuffer } from '../types/raw_buffer.js'; +import { flattenFieldsAsArray, ProofData, reconstructHonkProof, reconstructUltraPlonkProof } from '../proof/index.js'; // TODO: once UP is removed we can just roll this into the bas `Barretenberg` class. @@ -27,19 +28,21 @@ export class BarretenbergVerifier { } /** @description Verifies a proof */ - async verifyUltraplonkProof(proof: Uint8Array, verificationKey: Uint8Array): Promise { + async verifyUltraPlonkProof(proofData: ProofData, verificationKey: Uint8Array): Promise { await this.instantiate(); // The verifier can be used for a variety of ACIR programs so we should not assume that it // is preloaded with the correct verification key. await this.api.acirLoadVerificationKey(this.acirComposer, new RawBuffer(verificationKey)); + const proof = reconstructUltraPlonkProof(proofData); return await this.api.acirVerifyProof(this.acirComposer, proof); } /** @description Verifies a proof */ - async verifyUltrahonkProof(proof: Uint8Array, verificationKey: Uint8Array): Promise { + async verifyUltraHonkProof(proofData: ProofData, verificationKey: Uint8Array): Promise { await this.instantiate(); + const proof = reconstructHonkProof(flattenFieldsAsArray(proofData.publicInputs), proofData.proof); return await this.api.acirVerifyUltraHonk(proof, new RawBuffer(verificationKey)); } diff --git a/barretenberg/ts/src/index.ts b/barretenberg/ts/src/index.ts index d67bad794af3..dc3cee349376 100644 --- a/barretenberg/ts/src/index.ts +++ b/barretenberg/ts/src/index.ts @@ -8,4 +8,4 @@ export { UltraHonkBackend, } from './barretenberg/index.js'; export { RawBuffer, Fr } from './types/index.js'; -export { splitHonkProof, reconstructHonkProof } from './proof/index.js'; +export { splitHonkProof, reconstructHonkProof, ProofData } from './proof/index.js'; diff --git a/barretenberg/ts/src/proof/index.ts b/barretenberg/ts/src/proof/index.ts index 4219f167fc9b..9d099c8a9324 100644 --- a/barretenberg/ts/src/proof/index.ts +++ b/barretenberg/ts/src/proof/index.ts @@ -1,3 +1,14 @@ +/** + * @description + * The representation of a proof + * */ +export type ProofData = { + /** @description Public inputs of a proof */ + publicInputs: string[]; + /** @description An byte array representing the proof */ + proof: Uint8Array; +}; + // Buffers are prepended with their size. The size takes 4 bytes. const serializedBufferSize = 4; const fieldByteSize = 32; @@ -37,7 +48,17 @@ export function reconstructHonkProof(publicInputs: Uint8Array, proof: Uint8Array return proofWithPublicInputs; } -function deflattenFields(flattenedFields: Uint8Array): string[] { +export function reconstructUltraPlonkProof(proofData: ProofData): Uint8Array { + // Flatten publicInputs + const publicInputsConcatenated = flattenFieldsAsArray(proofData.publicInputs); + + // Concatenate publicInputs and proof + const proofWithPublicInputs = Uint8Array.from([...publicInputsConcatenated, ...proofData.proof]); + + return proofWithPublicInputs; +} + +export function deflattenFields(flattenedFields: Uint8Array): string[] { const publicInputSize = 32; const chunkedFlattenedPublicInputs: Uint8Array[] = []; @@ -49,6 +70,24 @@ function deflattenFields(flattenedFields: Uint8Array): string[] { return chunkedFlattenedPublicInputs.map(uint8ArrayToHex); } +export function flattenFieldsAsArray(fields: string[]): Uint8Array { + const flattenedPublicInputs = fields.map(hexToUint8Array); + return flattenUint8Arrays(flattenedPublicInputs); +} + +function flattenUint8Arrays(arrays: Uint8Array[]): Uint8Array { + const totalLength = arrays.reduce((acc, val) => acc + val.length, 0); + const result = new Uint8Array(totalLength); + + let offset = 0; + for (const arr of arrays) { + result.set(arr, offset); + offset += arr.length; + } + + return result; +} + function uint8ArrayToHex(buffer: Uint8Array): string { const hex: string[] = []; @@ -62,3 +101,20 @@ function uint8ArrayToHex(buffer: Uint8Array): string { return '0x' + hex.join(''); } + +function hexToUint8Array(hex: string): Uint8Array { + const sanitisedHex = BigInt(hex).toString(16).padStart(64, '0'); + + const len = sanitisedHex.length / 2; + const u8 = new Uint8Array(len); + + let i = 0; + let j = 0; + while (i < len) { + u8[i] = parseInt(sanitisedHex.slice(j, j + 2), 16); + i += 1; + j += 2; + } + + return u8; +} diff --git a/barretenberg/ts/yarn.lock b/barretenberg/ts/yarn.lock index 2f0f56bf747a..27108df1eeca 100644 --- a/barretenberg/ts/yarn.lock +++ b/barretenberg/ts/yarn.lock @@ -41,6 +41,7 @@ __metadata: debug: ^4.3.4 eslint: ^8.35.0 eslint-config-prettier: ^8.8.0 + fflate: ^0.8.0 html-webpack-plugin: ^5.5.1 idb-keyval: ^6.2.1 jest: ^29.5.0 @@ -3271,6 +3272,13 @@ __metadata: languageName: node linkType: hard +"fflate@npm:^0.8.0": + version: 0.8.2 + resolution: "fflate@npm:0.8.2" + checksum: 29470337b85d3831826758e78f370e15cda3169c5cd4477c9b5eea2402261a74b2975bae816afabe1c15d21d98591e0d30a574f7103aa117bff60756fa3035d4 + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" diff --git a/noir/noir-repo/.github/scripts/backend-barretenberg-build.sh b/noir/noir-repo/.github/scripts/backend-barretenberg-build.sh deleted file mode 100755 index d90995397d86..000000000000 --- a/noir/noir-repo/.github/scripts/backend-barretenberg-build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -eu - -yarn workspace @noir-lang/backend_barretenberg build diff --git a/noir/noir-repo/.github/scripts/backend-barretenberg-test.sh b/noir/noir-repo/.github/scripts/backend-barretenberg-test.sh deleted file mode 100755 index 1bd6f8e410d6..000000000000 --- a/noir/noir-repo/.github/scripts/backend-barretenberg-test.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -eu - -yarn workspace @noir-lang/backend_barretenberg test diff --git a/noir/noir-repo/.github/workflows/test-js-packages.yml b/noir/noir-repo/.github/workflows/test-js-packages.yml index ff894f061eef..0aa971a21f0f 100644 --- a/noir/noir-repo/.github/workflows/test-js-packages.yml +++ b/noir/noir-repo/.github/workflows/test-js-packages.yml @@ -73,7 +73,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: noirc_abi_wasm - path: | + path: | ./tooling/noirc_abi_wasm/nodejs ./tooling/noirc_abi_wasm/web retention-days: 10 @@ -263,9 +263,6 @@ jobs: - name: Build noir_js_types run: yarn workspace @noir-lang/types build - - name: Build barretenberg wrapper - run: yarn workspace @noir-lang/backend_barretenberg build - - name: Run noir_js tests run: | yarn workspace @noir-lang/noir_js build @@ -416,7 +413,7 @@ jobs: - name: Setup `integration-tests` run: | # Note the lack of spaces between package names. - PACKAGES_TO_BUILD="@noir-lang/types,@noir-lang/backend_barretenberg,@noir-lang/noir_js" + PACKAGES_TO_BUILD="@noir-lang/types,@noir-lang/noir_js" yarn workspaces foreach -vtp --from "{$PACKAGES_TO_BUILD}" run build - name: Run `integration-tests` @@ -461,7 +458,7 @@ jobs: - name: Setup `integration-tests` run: | # Note the lack of spaces between package names. - PACKAGES_TO_BUILD="@noir-lang/types,@noir-lang/backend_barretenberg,@noir-lang/noir_js" + PACKAGES_TO_BUILD="@noir-lang/types,@noir-lang/noir_js" yarn workspaces foreach -vtp --from "{$PACKAGES_TO_BUILD}" run build - name: Run `integration-tests` @@ -565,7 +562,7 @@ jobs: runs-on: ubuntu-latest # We want this job to always run (even if the dependant jobs fail) as we want this job to fail rather than skipping. if: ${{ always() }} - needs: + needs: - test-acvm_js-node - test-acvm_js-browser - test-noirc-abi diff --git a/noir/noir-repo/compiler/integration-tests/package.json b/noir/noir-repo/compiler/integration-tests/package.json index 64a638539d5c..e33179f31e7f 100644 --- a/noir/noir-repo/compiler/integration-tests/package.json +++ b/noir/noir-repo/compiler/integration-tests/package.json @@ -1,34 +1,34 @@ { - "name": "integration-tests", - "license": "(MIT OR Apache-2.0)", - "main": "index.js", - "private": true, - "scripts": { - "build": "echo Integration Test build step", - "test": "yarn test:browser && yarn test:node", - "test:node": "bash ./scripts/setup.sh && hardhat test test/node/prove_and_verify.test.ts && hardhat test test/node/smart_contract_verifier.test.ts && hardhat test test/node/onchain_recursive_verification.test.ts", - "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", - "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" - }, - "dependencies": { - "@noir-lang/backend_barretenberg": "workspace:*", - "@noir-lang/noir_js": "workspace:*", - "@noir-lang/noir_wasm": "workspace:*", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "@web/dev-server-esbuild": "^0.3.6", - "@web/dev-server-import-maps": "^0.2.0", - "@web/test-runner": "^0.18.1", - "@web/test-runner-playwright": "^0.11.0", - "eslint": "^8.57.0", - "eslint-plugin-prettier": "^5.1.3", - "ethers": "^6.7.1", - "hardhat": "^2.22.6", - "prettier": "3.2.5", - "smol-toml": "^1.1.2", - "toml": "^3.0.0", - "tslog": "^4.9.2" - } + "name": "integration-tests", + "license": "(MIT OR Apache-2.0)", + "main": "index.js", + "private": true, + "scripts": { + "build": "echo Integration Test build step", + "test": "yarn test:browser && yarn test:node", + "test:node": "bash ./scripts/setup.sh && hardhat test test/node/prove_and_verify.test.ts && hardhat test test/node/smart_contract_verifier.test.ts && hardhat test test/node/onchain_recursive_verification.test.ts", + "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", + "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" + }, + "dependencies": { + "@aztec/bb.js": "portal:../../../../barretenberg/ts", + "@noir-lang/noir_js": "workspace:*", + "@noir-lang/noir_wasm": "workspace:*", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@web/dev-server-esbuild": "^0.3.6", + "@web/dev-server-import-maps": "^0.2.0", + "@web/test-runner": "^0.18.1", + "@web/test-runner-playwright": "^0.11.0", + "eslint": "^8.57.0", + "eslint-plugin-prettier": "^5.1.3", + "ethers": "^6.7.1", + "hardhat": "^2.22.6", + "prettier": "3.2.5", + "smol-toml": "^1.1.2", + "toml": "^3.0.0", + "tslog": "^4.9.2" + } } diff --git a/noir/noir-repo/compiler/integration-tests/test/browser/compile_prove_verify.test.ts b/noir/noir-repo/compiler/integration-tests/test/browser/compile_prove_verify.test.ts index f18ceb85276b..8d24b27ac258 100644 --- a/noir/noir-repo/compiler/integration-tests/test/browser/compile_prove_verify.test.ts +++ b/noir/noir-repo/compiler/integration-tests/test/browser/compile_prove_verify.test.ts @@ -4,7 +4,7 @@ import * as TOML from 'smol-toml'; import { compile, createFileManager } from '@noir-lang/noir_wasm'; import { Noir } from '@noir-lang/noir_js'; import { InputMap } from '@noir-lang/noirc_abi'; -import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { UltraPlonkBackend } from '@aztec/bb.js'; import { getFile } from './utils.js'; @@ -59,7 +59,7 @@ test_cases.forEach((testInfo) => { const program = new Noir(noir_program); const { witness } = await program.execute(inputs); - const backend = new BarretenbergBackend(noir_program); + const backend = new UltraPlonkBackend(noir_program.bytecode); const proof = await backend.generateProof(witness); // JS verification diff --git a/noir/noir-repo/compiler/integration-tests/test/browser/recursion.test.ts b/noir/noir-repo/compiler/integration-tests/test/browser/recursion.test.ts index abbee7b96ad1..4ee92d5b7959 100644 --- a/noir/noir-repo/compiler/integration-tests/test/browser/recursion.test.ts +++ b/noir/noir-repo/compiler/integration-tests/test/browser/recursion.test.ts @@ -5,7 +5,7 @@ import { Logger } from 'tslog'; import { acvm, abi, Noir } from '@noir-lang/noir_js'; import * as TOML from 'smol-toml'; -import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { UltraPlonkBackend } from '@aztec/bb.js'; import { getFile } from './utils.js'; import { Field, InputMap } from '@noir-lang/noirc_abi'; import { createFileManager, compile } from '@noir-lang/noir_wasm'; @@ -45,7 +45,7 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. const main_program = await getCircuit(`${base_relative_path}/${circuit_main}`); const main_inputs: InputMap = TOML.parse(circuit_main_toml) as InputMap; - const main_backend = new BarretenbergBackend(main_program); + const main_backend = new UltraPlonkBackend(main_program.bytecode); const { witness: main_witnessUint8Array } = await new Noir(main_program).execute(main_inputs); @@ -73,7 +73,7 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. const recursion_program = await getCircuit(`${base_relative_path}/${circuit_recursion}`); - const recursion_backend = new BarretenbergBackend(recursion_program); + const recursion_backend = new UltraPlonkBackend(recursion_program.bytecode); const { witness: recursion_witnessUint8Array } = await new Noir(recursion_program).execute(recursion_inputs); diff --git a/noir/noir-repo/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts b/noir/noir-repo/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts index f4647c478f1b..b08d52e16042 100644 --- a/noir/noir-repo/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts +++ b/noir/noir-repo/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts @@ -6,7 +6,7 @@ import { resolve, join } from 'path'; import toml from 'toml'; import { Noir } from '@noir-lang/noir_js'; -import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { UltraPlonkBackend } from '@aztec/bb.js'; import { Field, InputMap } from '@noir-lang/noirc_abi'; import { compile, createFileManager } from '@noir-lang/noir_wasm'; @@ -35,7 +35,7 @@ it.skip(`smart contract can verify a recursive proof`, async () => { // Intermediate proof - const inner_backend = new BarretenbergBackend(innerProgram); + const inner_backend = new UltraPlonkBackend(innerProgram.bytecode); const inner = new Noir(innerProgram); const inner_prover_toml = readFileSync( @@ -67,7 +67,7 @@ it.skip(`smart contract can verify a recursive proof`, async () => { const { witness: recursionWitness } = await recursion.execute(recursion_inputs); - const recursion_backend = new BarretenbergBackend(recursionProgram); + const recursion_backend = new UltraPlonkBackend(recursionProgram.bytecode); const recursion_proof = await recursion_backend.generateProof(recursionWitness); expect(await recursion_backend.verifyProof(recursion_proof)).to.be.true; diff --git a/noir/noir-repo/compiler/integration-tests/test/node/prove_and_verify.test.ts b/noir/noir-repo/compiler/integration-tests/test/node/prove_and_verify.test.ts index babc8ca5bb82..4353bccd90d5 100644 --- a/noir/noir-repo/compiler/integration-tests/test/node/prove_and_verify.test.ts +++ b/noir/noir-repo/compiler/integration-tests/test/node/prove_and_verify.test.ts @@ -2,18 +2,13 @@ import { expect } from 'chai'; 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, - UltraHonkBackend, - UltraHonkVerifier, -} from '@noir-lang/backend_barretenberg'; +import { BarretenbergVerifier, UltraPlonkBackend, UltraHonkBackend } from '@aztec/bb.js'; import { CompiledCircuit } from '@noir-lang/types'; const assert_lt_program = assert_lt_json as CompiledCircuit; const fold_fibonacci_program = fold_fibonacci_json as CompiledCircuit; -const backend = new Backend(assert_lt_program); +const backend = new UltraPlonkBackend(assert_lt_program.bytecode); it('end-to-end proof creation and verification (outer)', async () => { // Noir.Js part @@ -53,8 +48,8 @@ it('end-to-end proof creation and verification (outer) -- Verifier API', async ( const verificationKey = await backend.getVerificationKey(); // Proof verification - const verifier = new Verifier(); - const isValid = await verifier.verifyProof(proof, verificationKey); + const verifier = new BarretenbergVerifier(); + const isValid = await verifier.verifyUltraPlonkProof(proof, verificationKey); expect(isValid).to.be.true; }); @@ -94,7 +89,7 @@ it('end-to-end proving and verification with different instances', async () => { // bb.js part const proof = await backend.generateProof(witness); - const verifier = new Backend(assert_lt_program); + const verifier = new UltraPlonkBackend(assert_lt_program.bytecode); const proof_is_valid = await verifier.verifyProof(proof); expect(proof_is_valid).to.be.true; }); @@ -148,7 +143,7 @@ it('end-to-end proof creation and verification for multiple ACIR circuits (inner // bb.js part // // Proof creation - const backend = new Backend(fold_fibonacci_program); + const backend = new UltraPlonkBackend(fold_fibonacci_program.bytecode); const proof = await backend.generateProof(witness); // Proof verification @@ -156,7 +151,7 @@ it('end-to-end proof creation and verification for multiple ACIR circuits (inner expect(isValid).to.be.true; }); -const honkBackend = new UltraHonkBackend(assert_lt_program); +const honkBackend = new UltraHonkBackend(assert_lt_program.bytecode); it('UltraHonk end-to-end proof creation and verification (outer)', async () => { // Noir.Js part @@ -196,8 +191,8 @@ it('UltraHonk end-to-end proof creation and verification (outer) -- Verifier API const verificationKey = await honkBackend.getVerificationKey(); // Proof verification - const verifier = new UltraHonkVerifier(); - const isValid = await verifier.verifyProof(proof, verificationKey); + const verifier = new BarretenbergVerifier(); + const isValid = await verifier.verifyUltraHonkProof(proof, verificationKey); expect(isValid).to.be.true; }); @@ -236,7 +231,7 @@ it('UltraHonk end-to-end proving and verification with different instances', asy // bb.js part const proof = await honkBackend.generateProof(witness); - const verifier = new UltraHonkBackend(assert_lt_program); + const verifier = new UltraHonkBackend(assert_lt_program.bytecode); const proof_is_valid = await verifier.verifyProof(proof); expect(proof_is_valid).to.be.true; }); @@ -283,7 +278,7 @@ it('UltraHonk end-to-end proof creation and verification for multiple ACIR circu // bb.js part // // Proof creation - const honkBackend = new UltraHonkBackend(fold_fibonacci_program); + const honkBackend = new UltraHonkBackend(fold_fibonacci_program.bytecode); const proof = await honkBackend.generateProof(witness); // Proof verification diff --git a/noir/noir-repo/compiler/integration-tests/test/node/smart_contract_verifier.test.ts b/noir/noir-repo/compiler/integration-tests/test/node/smart_contract_verifier.test.ts index e109cbcab6aa..c43fba014247 100644 --- a/noir/noir-repo/compiler/integration-tests/test/node/smart_contract_verifier.test.ts +++ b/noir/noir-repo/compiler/integration-tests/test/node/smart_contract_verifier.test.ts @@ -6,7 +6,7 @@ import { resolve } from 'path'; import toml from 'toml'; import { Noir } from '@noir-lang/noir_js'; -import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { UltraPlonkBackend } from '@aztec/bb.js'; import { compile, createFileManager } from '@noir-lang/noir_wasm'; @@ -46,7 +46,7 @@ test_cases.forEach((testInfo) => { const inputs = toml.parse(prover_toml); const { witness } = await program.execute(inputs); - const backend = new BarretenbergBackend(noir_program); + const backend = new UltraPlonkBackend(noir_program.bytecode); const proofData = await backend.generateProof(witness); // JS verification diff --git a/noir/noir-repo/docs/docs/how_to/how-to-recursion.md b/noir/noir-repo/docs/docs/how_to/how-to-recursion.md index c8c4dc9f5b43..fac79a9cf49c 100644 --- a/noir/noir-repo/docs/docs/how_to/how-to-recursion.md +++ b/noir/noir-repo/docs/docs/how_to/how-to-recursion.md @@ -1,6 +1,6 @@ --- title: How to use recursion on NoirJS -description: Learn how to implement recursion with NoirJS, a powerful tool for creating smart contracts on the EVM blockchain. This guide assumes familiarity with NoirJS, solidity verifiers, and the Barretenberg proving backend. Discover how to generate both final and intermediate proofs using `noir_js` and `backend_barretenberg`. +description: Learn how to implement recursion with NoirJS, a powerful tool for creating smart contracts on the EVM blockchain. This guide assumes familiarity with NoirJS, solidity verifiers, and the Barretenberg proving backend. Discover how to generate both final and intermediate proofs using `noir_js` and `bb.js`. keywords: [ "NoirJS", @@ -10,7 +10,6 @@ keywords: "solidity verifiers", "Barretenberg backend", "noir_js", - "backend_barretenberg", "intermediate proofs", "final proofs", "nargo compile", @@ -33,13 +32,6 @@ It is also assumed that you're not using `noir_wasm` for compilation, and instea As you've read in the [explainer](../explainers/explainer-recursion.md), a recursive proof is an intermediate proof. This means that it doesn't necessarily generate the final step that makes it verifiable in a smart contract. However, it is easy to verify within another circuit. -While "standard" usage of NoirJS packages abstracts final proofs, it currently lacks the necessary interface to abstract away intermediate proofs. This means that these proofs need to be created by using the backend directly. - -In short: - -- `noir_js` generates *only* final proofs -- `backend_barretenberg` generates both types of proofs - ::: In a standard recursive app, you're also dealing with at least two circuits. For the purpose of this guide, we will assume the following: @@ -147,7 +139,7 @@ Managing circuits and "who does what" can be confusing. To make sure your naming ```js const circuits = { - main: mainJSON, + main: mainJSON, recursive: recursiveJSON } const backends = { diff --git a/noir/noir-repo/package.json b/noir/noir-repo/package.json index 8abaced7bdda..00036838f9b9 100644 --- a/noir/noir-repo/package.json +++ b/noir/noir-repo/package.json @@ -8,7 +8,6 @@ "tooling/noirc_abi_wasm", "tooling/noir_js", "tooling/noir_codegen", - "tooling/noir_js_backend_barretenberg", "acvm-repo/acvm_js", "docs" ], diff --git a/noir/noir-repo/scripts/bump-bb.sh b/noir/noir-repo/scripts/bump-bb.sh index 36c1f78ca059..fb1a2b1d31ef 100755 --- a/noir/noir-repo/scripts/bump-bb.sh +++ b/noir/noir-repo/scripts/bump-bb.sh @@ -5,7 +5,7 @@ BB_VERSION=$1 sed -i.bak "s/^VERSION=.*/VERSION=\"$BB_VERSION\"/" ./scripts/install_bb.sh && rm ./scripts/install_bb.sh.bak tmp=$(mktemp) -BACKEND_BARRETENBERG_PACKAGE_JSON=./tooling/noir_js_backend_barretenberg/package.json -jq --arg v $BB_VERSION '.dependencies."@aztec/bb.js" = $v' $BACKEND_BARRETENBERG_PACKAGE_JSON > $tmp && mv $tmp $BACKEND_BARRETENBERG_PACKAGE_JSON +INTEGRATION_TESTS_PACKAGE_JSON=./compiler/integration_tests/package.json +jq --arg v $BB_VERSION '.dependencies."@aztec/bb.js" = $v' $INTEGRATION_TESTS_PACKAGE_JSON > $tmp && mv $tmp $INTEGRATION_TESTS_PACKAGE_JSON YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintignore b/noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintignore deleted file mode 100644 index b512c09d4766..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -node_modules \ No newline at end of file diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintrc.cjs b/noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintrc.cjs deleted file mode 100644 index 33335c2a8771..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintrc.cjs +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ["../../.eslintrc.js"], -}; diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/.gitignore b/noir/noir-repo/tooling/noir_js_backend_barretenberg/.gitignore deleted file mode 100644 index 689b3ca0701b..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -crs -lib diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/.mocharc.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/.mocharc.json deleted file mode 100644 index e1023f563275..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/.mocharc.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "require": "ts-node/register", - "loader": "ts-node/esm", - "extensions": [ - "ts", - "cjs" - ], - "spec": [ - "test/**/*.test.ts*" - ] -} diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/fixup.sh b/noir/noir-repo/tooling/noir_js_backend_barretenberg/fixup.sh deleted file mode 100755 index 80bd7ec71a58..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/fixup.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -# Put these package.json files in the cjs and -# mjs directory respectively, so that -# tools can recognise that the .js files are either -# commonjs or ESM files. -self_path=$(dirname "$(readlink -f "$0")") - -cjs_package='{ - "type": "commonjs" -}' - -esm_package='{ - "type": "module" -}' - -echo "$cjs_package" > $self_path/lib/cjs/package.json -echo "$esm_package" > $self_path/lib/esm/package.json \ No newline at end of file diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json deleted file mode 100644 index 42c15ae799e1..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "@noir-lang/backend_barretenberg", - "contributors": [ - "The Noir Team " - ], - "version": "0.35.0", - "packageManager": "yarn@3.5.1", - "license": "(MIT OR Apache-2.0)", - "type": "module", - "homepage": "https://noir-lang.org/", - "repository": { - "url": "https://github.com/noir-lang/noir.git", - "directory": "tooling/noir_js_backend_barretenberg", - "type": "git" - }, - "bugs": { - "url": "https://github.com/noir-lang/noir/issues" - }, - "source": "src/index.ts", - "main": "lib/cjs/index.js", - "module": "lib/esm/index.js", - "exports": { - "require": "./lib/cjs/index.js", - "types": "./lib/esm/index.d.ts", - "default": "./lib/esm/index.js" - }, - "types": "lib/esm/index.d.ts", - "files": [ - "lib", - "package.json" - ], - "scripts": { - "dev": "tsc --watch", - "generate:package": "bash ./fixup.sh", - "build": "yarn clean && tsc && tsc -p ./tsconfig.cjs.json && yarn generate:package", - "clean": "rm -rf ./lib", - "prettier": "prettier 'src/**/*.ts'", - "prettier:fix": "prettier --write 'src/**/*.ts' 'test/**/*.ts'", - "nightly:version": "jq --arg new_version \"-$(git rev-parse --short HEAD)$1\" '.version = .version + $new_version' package.json > package-tmp.json && mv package-tmp.json package.json", - "publish": "echo 📡 publishing `$npm_package_name` && yarn npm publish", - "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" - }, - "dependencies": { - "@aztec/bb.js": "portal:../../../../barretenberg/ts", - "@noir-lang/types": "workspace:*", - "fflate": "^0.8.0" - }, - "devDependencies": { - "@types/node": "^20.6.2", - "@types/prettier": "^3", - "eslint": "^8.57.0", - "eslint-plugin-prettier": "^5.1.3", - "prettier": "3.2.5", - "ts-node": "^10.9.1", - "typescript": "5.4.2" - } -} diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/backend.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/backend.ts deleted file mode 100644 index 785b0c734214..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/backend.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { acirToUint8Array } from './serialize.js'; -import { Backend, CompiledCircuit, ProofData, VerifierBackend } from '@noir-lang/types'; -import { deflattenFields } from './public_inputs.js'; -import { reconstructProofWithPublicInputs, reconstructProofWithPublicInputsHonk } from './verifier.js'; -import { BackendOptions, UltraPlonkBackend, UltraHonkBackend as UltraHonkBackendInternal } from '@aztec/bb.js'; -import { decompressSync as gunzip } from 'fflate'; - -// This is the number of bytes in a UltraPlonk proof -// minus the public inputs. -const numBytesInProofWithoutPublicInputs: number = 2144; - -export class BarretenbergBackend implements Backend, VerifierBackend { - protected backend!: UltraPlonkBackend; - - constructor(acirCircuit: CompiledCircuit, options: BackendOptions = { threads: 1 }) { - const acirBytecodeBase64 = acirCircuit.bytecode; - const acirUncompressedBytecode = acirToUint8Array(acirBytecodeBase64); - this.backend = new UltraPlonkBackend(acirUncompressedBytecode, options); - } - - /** @description Generates a proof */ - async generateProof(compressedWitness: Uint8Array): Promise { - const proofWithPublicInputs = await this.backend.generateProof(gunzip(compressedWitness)); - - const splitIndex = proofWithPublicInputs.length - numBytesInProofWithoutPublicInputs; - - const publicInputsConcatenated = proofWithPublicInputs.slice(0, splitIndex); - const proof = proofWithPublicInputs.slice(splitIndex); - const publicInputs = deflattenFields(publicInputsConcatenated); - - return { proof, publicInputs }; - } - - /** - * Generates artifacts that will be passed to a circuit that will verify this proof. - * - * Instead of passing the proof and verification key as a byte array, we pass them - * as fields which makes it cheaper to verify in a circuit. - * - * The proof that is passed here will have been created using a circuit - * that has the #[recursive] attribute on its `main` method. - * - * The number of public inputs denotes how many public inputs are in the inner proof. - * - * @example - * ```typescript - * const artifacts = await backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs); - * ``` - */ - async generateRecursiveProofArtifacts( - proofData: ProofData, - numOfPublicInputs = 0, - ): Promise<{ - proofAsFields: string[]; - vkAsFields: string[]; - vkHash: string; - }> { - const proof = reconstructProofWithPublicInputs(proofData); - return this.backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs); - } - - /** @description Verifies a proof */ - async verifyProof(proofData: ProofData): Promise { - const proof = reconstructProofWithPublicInputs(proofData); - return this.backend.verifyProof(proof); - } - - async getVerificationKey(): Promise { - return this.backend.getVerificationKey(); - } - - async destroy(): Promise { - await this.backend.destroy(); - } -} - -// Buffers are prepended with their size. The size takes 4 bytes. -const serializedBufferSize = 4; -const fieldByteSize = 32; -const publicInputOffset = 3; -const publicInputsOffsetBytes = publicInputOffset * fieldByteSize; - -export class UltraHonkBackend implements Backend, VerifierBackend { - // These type assertions are used so that we don't - // have to initialize `api` in the constructor. - // These are initialized asynchronously in the `init` function, - // constructors cannot be asynchronous which is why we do this. - - protected backend!: UltraHonkBackendInternal; - - constructor(acirCircuit: CompiledCircuit, options: BackendOptions = { threads: 1 }) { - const acirBytecodeBase64 = acirCircuit.bytecode; - const acirUncompressedBytecode = acirToUint8Array(acirBytecodeBase64); - this.backend = new UltraHonkBackendInternal(acirUncompressedBytecode, options); - } - - async generateProof(compressedWitness: Uint8Array): Promise { - const proofWithPublicInputs = await this.backend.generateProof(gunzip(compressedWitness)); - - const proofAsStrings = deflattenFields(proofWithPublicInputs.slice(4)); - - const numPublicInputs = Number(proofAsStrings[1]); - - // Account for the serialized buffer size at start - const publicInputsOffset = publicInputsOffsetBytes + serializedBufferSize; - // Get the part before and after the public inputs - const proofStart = proofWithPublicInputs.slice(0, publicInputsOffset); - const publicInputsSplitIndex = numPublicInputs * fieldByteSize; - const proofEnd = proofWithPublicInputs.slice(publicInputsOffset + publicInputsSplitIndex); - // Construct the proof without the public inputs - const proof = new Uint8Array([...proofStart, ...proofEnd]); - - // Fetch the number of public inputs out of the proof string - const publicInputsConcatenated = proofWithPublicInputs.slice( - publicInputsOffset, - publicInputsOffset + publicInputsSplitIndex, - ); - const publicInputs = deflattenFields(publicInputsConcatenated); - - return { proof, publicInputs }; - } - - async verifyProof(proofData: ProofData): Promise { - const proof = reconstructProofWithPublicInputsHonk(proofData); - return this.backend.verifyProof(proof); - } - - async getVerificationKey(): Promise { - return this.backend.getVerificationKey(); - } - - // TODO(https://github.com/noir-lang/noir/issues/5661): Update this to handle Honk recursive aggregation in the browser once it is ready in the backend itself - async generateRecursiveProofArtifacts( - proofData: ProofData, - numOfPublicInputs: number, - ): Promise<{ proofAsFields: string[]; vkAsFields: string[]; vkHash: string }> { - const proof = reconstructProofWithPublicInputsHonk(proofData); - return this.backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs); - } - - async destroy(): Promise { - await this.backend.destroy(); - } -} diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/base64_decode.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/base64_decode.ts deleted file mode 100644 index d53aed187c7f..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/base64_decode.ts +++ /dev/null @@ -1,13 +0,0 @@ -// 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.'); - } -} diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts deleted file mode 100644 index f1786396a2a0..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { BarretenbergBackend, UltraHonkBackend } from './backend.js'; -export { BarretenbergVerifier, UltraHonkVerifier } from './verifier.js'; - -// typedoc exports -export { Backend, CompiledCircuit, ProofData } from '@noir-lang/types'; -export { BackendOptions } from '@aztec/bb.js'; diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/public_inputs.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/public_inputs.ts deleted file mode 100644 index 10b4ee6ab326..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/public_inputs.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { WitnessMap } from '@noir-lang/types'; - -export function flattenFieldsAsArray(fields: string[]): Uint8Array { - const flattenedPublicInputs = fields.map(hexToUint8Array); - return flattenUint8Arrays(flattenedPublicInputs); -} - -export function deflattenFields(flattenedFields: Uint8Array): string[] { - const publicInputSize = 32; - const chunkedFlattenedPublicInputs: Uint8Array[] = []; - - for (let i = 0; i < flattenedFields.length; i += publicInputSize) { - const publicInput = flattenedFields.slice(i, i + publicInputSize); - chunkedFlattenedPublicInputs.push(publicInput); - } - - return chunkedFlattenedPublicInputs.map(uint8ArrayToHex); -} - -export function witnessMapToPublicInputs(publicInputs: WitnessMap): string[] { - const publicInputIndices = [...publicInputs.keys()].sort((a, b) => a - b); - const flattenedPublicInputs = publicInputIndices.map((index) => publicInputs.get(index) as string); - return flattenedPublicInputs; -} - -function flattenUint8Arrays(arrays: Uint8Array[]): Uint8Array { - const totalLength = arrays.reduce((acc, val) => acc + val.length, 0); - const result = new Uint8Array(totalLength); - - let offset = 0; - for (const arr of arrays) { - result.set(arr, offset); - offset += arr.length; - } - - return result; -} - -function uint8ArrayToHex(buffer: Uint8Array): string { - const hex: string[] = []; - - buffer.forEach(function (i) { - let h = i.toString(16); - if (h.length % 2) { - h = '0' + h; - } - hex.push(h); - }); - - return '0x' + hex.join(''); -} - -function hexToUint8Array(hex: string): Uint8Array { - const sanitised_hex = BigInt(hex).toString(16).padStart(64, '0'); - - const len = sanitised_hex.length / 2; - const u8 = new Uint8Array(len); - - let i = 0; - let j = 0; - while (i < len) { - u8[i] = parseInt(sanitised_hex.slice(j, j + 2), 16); - i += 1; - j += 2; - } - - return u8; -} diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/serialize.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/serialize.ts deleted file mode 100644 index b15931848a02..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/serialize.ts +++ /dev/null @@ -1,8 +0,0 @@ -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: string): Uint8Array { - const compressedByteCode = base64Decode(base64EncodedBytecode); - return gunzip(compressedByteCode); -} diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/verifier.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/verifier.ts deleted file mode 100644 index 885ec80caa80..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/verifier.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { ProofData } from '@noir-lang/types'; -import { flattenFieldsAsArray } from './public_inputs.js'; -import { BackendOptions, BarretenbergVerifier as BarretenbergVerifierInternal } from '@aztec/bb.js'; - -export class BarretenbergVerifier { - private verifier!: BarretenbergVerifierInternal; - - constructor(options: BackendOptions = { threads: 1 }) { - this.verifier = new BarretenbergVerifierInternal(options); - } - - /** @description Verifies a proof */ - async verifyProof(proofData: ProofData, verificationKey: Uint8Array): Promise { - const proof = reconstructProofWithPublicInputs(proofData); - return this.verifier.verifyUltraplonkProof(proof, verificationKey); - } - - async destroy(): Promise { - await this.verifier.destroy(); - } -} - -export function reconstructProofWithPublicInputs(proofData: ProofData): Uint8Array { - // Flatten publicInputs - const publicInputsConcatenated = flattenFieldsAsArray(proofData.publicInputs); - - // Concatenate publicInputs and proof - const proofWithPublicInputs = Uint8Array.from([...publicInputsConcatenated, ...proofData.proof]); - - return proofWithPublicInputs; -} - -export class UltraHonkVerifier { - private verifier!: BarretenbergVerifierInternal; - - constructor(options: BackendOptions = { threads: 1 }) { - this.verifier = new BarretenbergVerifierInternal(options); - } - - /** @description Verifies a proof */ - async verifyProof(proofData: ProofData, verificationKey: Uint8Array): Promise { - const proof = reconstructProofWithPublicInputsHonk(proofData); - return this.verifier.verifyUltrahonkProof(proof, verificationKey); - } - - async destroy(): Promise { - await this.verifier.destroy(); - } -} - -const serializedBufferSize = 4; -const fieldByteSize = 32; -const publicInputOffset = 3; -const publicInputsOffsetBytes = publicInputOffset * fieldByteSize; - -export function reconstructProofWithPublicInputsHonk(proofData: ProofData): Uint8Array { - // Flatten publicInputs - const publicInputsConcatenated = flattenFieldsAsArray(proofData.publicInputs); - - const proofStart = proofData.proof.slice(0, publicInputsOffsetBytes + serializedBufferSize); - const proofEnd = proofData.proof.slice(publicInputsOffsetBytes + serializedBufferSize); - - // Concatenate publicInputs and proof - const proofWithPublicInputs = Uint8Array.from([...proofStart, ...publicInputsConcatenated, ...proofEnd]); - - return proofWithPublicInputs; -} diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.cjs.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.cjs.json deleted file mode 100644 index ac1e37844804..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.cjs.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "CommonJS", - "moduleResolution": "Node", - "outDir": "./lib/cjs" - }, -} diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.json deleted file mode 100644 index 1e28c044bbad..000000000000 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "declaration": true, - "emitDeclarationOnly": false, - "module": "NodeNext", - "moduleResolution": "NodeNext", - "outDir": "./lib/esm", - "esModuleInterop": true, - "resolveJsonModule": true, - "strict": true, - "noImplicitAny": false, - }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules"], - "references": [ - { - "path": "../noir_js_types" - } - ] -} diff --git a/noir/noir-repo/yarn.lock b/noir/noir-repo/yarn.lock index 77708cc9b214..9df981f1af12 100644 --- a/noir/noir-repo/yarn.lock +++ b/noir/noir-repo/yarn.lock @@ -221,13 +221,14 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": +"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=integration-tests%40workspace%3Acompiler%2Fintegration-tests": version: 0.0.0-use.local - resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" + resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=integration-tests%40workspace%3Acompiler%2Fintegration-tests" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 + fflate: ^0.8.0 tslib: ^2.4.0 bin: bb.js: ./dest/node/main.js @@ -4156,23 +4157,6 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/backend_barretenberg@workspace:*, @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": "portal:../../../../barretenberg/ts" - "@noir-lang/types": "workspace:*" - "@types/node": ^20.6.2 - "@types/prettier": ^3 - eslint: ^8.57.0 - eslint-plugin-prettier: ^5.1.3 - fflate: ^0.8.0 - prettier: 3.2.5 - ts-node: ^10.9.1 - typescript: 5.4.2 - languageName: unknown - linkType: soft - "@noir-lang/noir_codegen@workspace:tooling/noir_codegen": version: 0.0.0-use.local resolution: "@noir-lang/noir_codegen@workspace:tooling/noir_codegen" @@ -12570,7 +12554,7 @@ __metadata: version: 0.0.0-use.local resolution: "integration-tests@workspace:compiler/integration-tests" dependencies: - "@noir-lang/backend_barretenberg": "workspace:*" + "@aztec/bb.js": "portal:../../../../barretenberg/ts" "@noir-lang/noir_js": "workspace:*" "@noir-lang/noir_wasm": "workspace:*" "@nomicfoundation/hardhat-chai-matchers": ^2.0.0 @@ -19749,7 +19733,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:5.4.2, typescript@npm:^5.4.2": +"typescript@npm:^5.4.2": version: 5.4.2 resolution: "typescript@npm:5.4.2" bin: @@ -19759,7 +19743,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@5.4.2#~builtin, typescript@patch:typescript@^5.4.2#~builtin": +"typescript@patch:typescript@^5.4.2#~builtin": version: 5.4.2 resolution: "typescript@patch:typescript@npm%3A5.4.2#~builtin::version=5.4.2&hash=f3b441" bin: diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index ecd52a2eb69a..ccecdbd1b24a 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -321,6 +321,7 @@ __metadata: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 + fflate: ^0.8.0 tslib: ^2.4.0 bin: bb.js: ./dest/node/main.js @@ -8835,6 +8836,13 @@ __metadata: languageName: node linkType: hard +"fflate@npm:^0.8.0": + version: 0.8.2 + resolution: "fflate@npm:0.8.2" + checksum: 29470337b85d3831826758e78f370e15cda3169c5cd4477c9b5eea2402261a74b2975bae816afabe1c15d21d98591e0d30a574f7103aa117bff60756fa3035d4 + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1"