diff --git a/barretenberg/acir_tests/browser-test-app/src/index.ts b/barretenberg/acir_tests/browser-test-app/src/index.ts index a3080453677..06370f5a82a 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 a318010c427..cffd98997dc 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 10fdc17b85d..c619210c457 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 243ee8dc1b3..0919f030e5c 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 c6bffc5109b..e0c59f64039 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 d67bad794af..dc3cee34937 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 4219f167fc9..9d099c8a932 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 2f0f56bf747..27108df1eec 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 d90995397d8..00000000000 --- 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 1bd6f8e410d..00000000000 --- 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 ff894f061ee..0aa971a21f0 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 64a638539d5..e33179f31e7 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 f18ceb85276..8d24b27ac25 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 abbee7b96ad..4ee92d5b795 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 f4647c478f1..b08d52e1604 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 babc8ca5bb8..4353bccd90d 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 e109cbcab6a..c43fba01424 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 c8c4dc9f5b4..fac79a9cf49 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 8abaced7bdd..00036838f9b 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 36c1f78ca05..fb1a2b1d31e 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 b512c09d476..00000000000 --- 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 33335c2a877..00000000000 --- 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 689b3ca0701..00000000000 --- 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 e1023f56327..00000000000 --- 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 80bd7ec71a5..00000000000 --- 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 42c15ae799e..00000000000 --- 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 785b0c73421..00000000000 --- 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 d53aed187c7..00000000000 --- 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 f1786396a2a..00000000000 --- 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 10b4ee6ab32..00000000000 --- 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 b15931848a0..00000000000 --- 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 885ec80caa8..00000000000 --- 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 ac1e3784480..00000000000 --- 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 1e28c044bba..00000000000 --- 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 77708cc9b21..9df981f1af1 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 ecd52a2eb69..ccecdbd1b24 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"