diff --git a/compiler/integration-tests/circuits/recursion/Prover.toml b/compiler/integration-tests/circuits/recursion/Prover.toml deleted file mode 100644 index fd47e27df04..00000000000 --- a/compiler/integration-tests/circuits/recursion/Prover.toml +++ /dev/null @@ -1 +0,0 @@ -input_aggregation_object = ["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] \ No newline at end of file diff --git a/compiler/integration-tests/test/browser/compile_prove_verify.test.ts b/compiler/integration-tests/test/browser/compile_prove_verify.test.ts deleted file mode 100644 index dba51895bb8..00000000000 --- a/compiler/integration-tests/test/browser/compile_prove_verify.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { expect } from '@esm-bundle/chai'; -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 { getFile } from './utils.js'; - -const test_cases = [ - { - case: 'test_programs/execution_success/1_mul', - numPublicInputs: 0, - }, - { - case: 'test_programs/execution_success/assert_statement', - numPublicInputs: 1, - }, -]; - -const suite = Mocha.Suite.create(mocha.suite, 'Noir end to end test'); - -suite.timeout(60 * 20e3); //20mins - -async function getCircuit(projectPath: string) { - const fm = createFileManager('/'); - await fm.writeFile('./src/main.nr', await getFile(`${projectPath}/src/main.nr`)); - await fm.writeFile('./Nargo.toml', await getFile(`${projectPath}/Nargo.toml`)); - const result = await compile(fm); - if (!('program' in result)) { - throw new Error('Compilation failed'); - } - - return result.program; -} - -test_cases.forEach((testInfo) => { - const test_name = testInfo.case.split('/').pop(); - const mochaTest = new Mocha.Test(`${test_name} (Compile, Execute, Prove, Verify)`, async () => { - const base_relative_path = '../../../../..'; - const test_case = testInfo.case; - - let noir_program; - try { - noir_program = await getCircuit(`${base_relative_path}/${test_case}`); - - expect(noir_program, 'Compile output ').to.be.an('object'); - } catch (e) { - expect(e, 'Compilation Step').to.not.be.an('error'); - throw e; - } - - const backend = new BarretenbergBackend(noir_program); - const program = new Noir(noir_program, backend); - - const prover_toml = await new Response(await getFile(`${base_relative_path}/${test_case}/Prover.toml`)).text(); - const inputs: InputMap = TOML.parse(prover_toml) as InputMap; - - // JS Proving - - const proofWithPublicInputs = await program.generateProof(inputs); - - // JS verification - - const verified = await program.verifyProof(proofWithPublicInputs); - expect(verified, 'Proof fails verification in JS').to.be.true; - }); - - suite.addTest(mochaTest); -}); diff --git a/compiler/integration-tests/test/browser/recursion.test.ts b/compiler/integration-tests/test/browser/recursion.test.ts index a8927aa6a75..49e3e329090 100644 --- a/compiler/integration-tests/test/browser/recursion.test.ts +++ b/compiler/integration-tests/test/browser/recursion.test.ts @@ -21,6 +21,7 @@ await initACVM(); const base_relative_path = '../../../../..'; const circuit_main = 'test_programs/execution_success/assert_statement_recursive'; const circuit_recursion = 'compiler/integration-tests/circuits/recursion'; +const circuit_double_verify = 'test_programs/execution_success/double_verify_proof'; async function getCircuit(projectPath: string) { const fm = createFileManager('/'); @@ -40,7 +41,7 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. circuit_main_toml = await new Response(await getFile(`${base_relative_path}/${circuit_main}/Prover.toml`)).text(); }); - it('Should generate valid inner proof for correct input, then verify proof within a proof', async () => { + it('Should generate two valid inner proofs for correct input, then verify proofs within a proof', async () => { const main_program = await getCircuit(`${base_relative_path}/${circuit_main}`); const main_inputs: InputMap = TOML.parse(circuit_main_toml) as InputMap; @@ -49,33 +50,38 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. const { witness: main_witnessUint8Array } = await new Noir(main_program).execute(main_inputs); const main_proof = await main_backend.generateProof(main_witnessUint8Array); - const main_verification = await main_backend.verifyProof(main_proof); - - logger.debug('main_verification', main_verification); - - expect(main_verification).to.be.true; + const main_proof2 = await main_backend.generateProof(main_witnessUint8Array); const numPublicInputs = 1; const { proofAsFields, vkAsFields, vkHash } = await main_backend.generateRecursiveProofArtifacts( main_proof, numPublicInputs, ); + const { + proofAsFields: proofAsFields2, + vkAsFields: vkAsFields2, + vkHash: vkHash2, + } = await main_backend.generateRecursiveProofArtifacts(main_proof2, numPublicInputs); + expect(vkAsFields).to.be.deep.eq(vkAsFields2, 'two separate vks for the same program.'); + expect(vkHash).to.be.eq(vkHash2, 'two separate vk hashes for the same program.'); const recursion_inputs: InputMap = { verification_key: vkAsFields, proof: proofAsFields, public_inputs: [main_inputs.y as Field], key_hash: vkHash, + proof_b: proofAsFields2, }; logger.debug('recursion_inputs', recursion_inputs); - const recursion_program = await getCircuit(`${base_relative_path}/${circuit_recursion}`); + const recursion_program = await getCircuit(`${base_relative_path}/${circuit_double_verify}`); const recursion_backend = new BarretenbergBackend(recursion_program); const { witness: recursion_witnessUint8Array } = await new Noir(recursion_program).execute(recursion_inputs); + console.log('got here!'); const recursion_proof = await recursion_backend.generateProof(recursion_witnessUint8Array); // Causes an "unreachable" error. @@ -89,10 +95,10 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. // // logger.debug('recursion_proofAsFields', recursion_proofAsFields); - const recursion_verification = await recursion_backend.verifyProof(recursion_proof); + // const recursion_verification = await recursion_backend.verifyProof(recursion_proof); - logger.debug('recursion_verification', recursion_verification); + // logger.debug('recursion_verification', recursion_verification); - expect(recursion_verification).to.be.true; + // expect(recursion_verification).to.be.true; }).timeout(60 * 20e3); }); diff --git a/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts b/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts deleted file mode 100644 index 6147f770f16..00000000000 --- a/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { expect } from 'chai'; -import { ethers } from 'hardhat'; - -import { readFileSync } from 'node:fs'; -import { resolve, join } from 'path'; -import toml from 'toml'; - -import { Noir } from '@noir-lang/noir_js'; -import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; -import { Field, InputMap } from '@noir-lang/noirc_abi'; - -import { compile, createFileManager } from '@noir-lang/noir_wasm'; - -it(`smart contract can verify a recursive proof`, async () => { - const basePath = resolve(join(__dirname, '../../../../')); - const fm = createFileManager(basePath); - const innerCompilationResult = await compile( - fm, - join(basePath, './test_programs/execution_success/assert_statement_recursive'), - ); - if (!('program' in innerCompilationResult)) { - throw new Error('Compilation failed'); - } - const innerProgram = innerCompilationResult.program; - - const recursionCompilationResult = await compile( - fm, - join(basePath, './compiler/integration-tests/circuits/recursion'), - ); - if (!('program' in recursionCompilationResult)) { - throw new Error('Compilation failed'); - } - const recursionProgram = recursionCompilationResult.program; - - // Intermediate proof - - const inner_backend = new BarretenbergBackend(innerProgram); - const inner = new Noir(innerProgram); - - const inner_prover_toml = readFileSync( - join(basePath, `./test_programs/execution_success/assert_statement_recursive/Prover.toml`), - ).toString(); - - const inner_inputs = toml.parse(inner_prover_toml); - - const { witness: main_witness } = await inner.execute(inner_inputs); - const intermediate_proof = await inner_backend.generateProof(main_witness); - - expect(await inner_backend.verifyProof(intermediate_proof)).to.be.true; - - const { proofAsFields, vkAsFields, vkHash } = await inner_backend.generateRecursiveProofArtifacts( - intermediate_proof, - 1, // 1 public input - ); - - // Final proof - - const recursion_backend = new BarretenbergBackend(recursionProgram); - const recursion = new Noir(recursionProgram, recursion_backend); - - const recursion_inputs: InputMap = { - verification_key: vkAsFields, - proof: proofAsFields, - public_inputs: [inner_inputs.y as Field], - key_hash: vkHash, - }; - - const recursion_proof = await recursion.generateProof(recursion_inputs); - expect(await recursion.verifyProof(recursion_proof)).to.be.true; - - // Smart contract verification - - const contract = await ethers.deployContract('contracts/recursion.sol:UltraVerifier', []); - - const result = await contract.verify.staticCall(recursion_proof.proof, recursion_proof.publicInputs); - - expect(result).to.be.true; -}); diff --git a/compiler/integration-tests/test/node/recursion.test.ts b/compiler/integration-tests/test/node/recursion.test.ts new file mode 100644 index 00000000000..3067de023f4 --- /dev/null +++ b/compiler/integration-tests/test/node/recursion.test.ts @@ -0,0 +1,96 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { expect } from 'chai'; +import { Logger } from 'tslog'; +import { Noir } from '@noir-lang/noir_js'; + +import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { resolve, join } from 'path'; +import { Field, InputMap } from '@noir-lang/noirc_abi'; +import { createFileManager, compile } from '@noir-lang/noir_wasm'; + +const logger = new Logger({ name: 'test' }); + +const base_relative_path = '../../../../'; +const circuit_main = './test_programs/execution_success/assert_statement_recursive'; +const circuit_recursion = './compiler/integration-tests/circuits/recursion'; +const circuit_double_verify = './test_programs/execution_success/double_verify_proof'; + +async function getCircuit(projectPath: string) { + console.log(__dirname); + const basePath = resolve(join(__dirname, base_relative_path)); + console.log(basePath); + const absProjectPath = join(basePath, projectPath); + console.log(absProjectPath); + const fm = createFileManager(absProjectPath); + const result = await compile(fm); + if (!('program' in result)) { + throw new Error('Compilation failed'); + } + return result.program; +} + +describe('It compiles noir program code, receiving circuit bytes and abi object.', () => { + it('Should generate two valid inner proofs for correct input, then verify proofs within a proof', async () => { + const main_program = await getCircuit(circuit_main); + const main_inputs: InputMap = { + x: '3', + y: '3', + }; + + const main_backend = new BarretenbergBackend(main_program); + + const { witness: main_witnessUint8Array } = await new Noir(main_program).execute(main_inputs); + + const main_proof = await main_backend.generateProof(main_witnessUint8Array); + const main_proof2 = await main_backend.generateProof(main_witnessUint8Array); + + const numPublicInputs = 1; + const { proofAsFields, vkAsFields, vkHash } = await main_backend.generateRecursiveProofArtifacts( + main_proof, + numPublicInputs, + ); + const { + proofAsFields: proofAsFields2, + vkAsFields: vkAsFields2, + vkHash: vkHash2, + } = await main_backend.generateRecursiveProofArtifacts(main_proof2, numPublicInputs); + expect(vkAsFields).to.be.deep.eq(vkAsFields2, 'two separate vks for the same program.'); + expect(vkHash).to.be.eq(vkHash2, 'two separate vk hashes for the same program.'); + + const recursion_inputs: InputMap = { + verification_key: vkAsFields, + proof: proofAsFields, + public_inputs: [main_inputs.y as Field], + key_hash: vkHash, + proof_b: proofAsFields2, + }; + + logger.debug('recursion_inputs', recursion_inputs); + + const recursion_program = await getCircuit(circuit_double_verify); + + const recursion_backend = new BarretenbergBackend(recursion_program); + + const { witness: recursion_witnessUint8Array } = await new Noir(recursion_program).execute(recursion_inputs); + + console.log('got here!'); + const recursion_proof = await recursion_backend.generateProof(recursion_witnessUint8Array); + + // Causes an "unreachable" error. + // Due to the fact that it's a non-recursive proof? + // + // const recursion_numPublicInputs = 1; + // const { proofAsFields: recursion_proofAsFields } = await recursion_backend.generateRecursiveProofArtifacts( + // recursion_proof, + // recursion_numPublicInputs, + // ); + // + // logger.debug('recursion_proofAsFields', recursion_proofAsFields); + + // const recursion_verification = await recursion_backend.verifyProof(recursion_proof); + + // logger.debug('recursion_verification', recursion_verification); + + // expect(recursion_verification).to.be.true; + }).timeout(60 * 20e3); +}); diff --git a/compiler/integration-tests/test/node/smart_contract_verifier.test.ts b/compiler/integration-tests/test/node/smart_contract_verifier.test.ts deleted file mode 100644 index 79a0520da32..00000000000 --- a/compiler/integration-tests/test/node/smart_contract_verifier.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { expect } from 'chai'; -import { ethers } from 'hardhat'; - -import { readFileSync } from 'node:fs'; -import { resolve } from 'path'; -import toml from 'toml'; - -import { Noir } from '@noir-lang/noir_js'; -import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; - -import { compile, createFileManager } from '@noir-lang/noir_wasm'; - -const test_cases = [ - { - case: 'test_programs/execution_success/1_mul', - compiled: 'contracts/1_mul.sol:UltraVerifier', - numPublicInputs: 0, - }, - { - case: 'test_programs/execution_success/assert_statement', - compiled: 'contracts/assert_statement.sol:UltraVerifier', - numPublicInputs: 1, - }, -]; - -test_cases.forEach((testInfo) => { - const test_name = testInfo.case.split('/').pop(); - - it(`${test_name} (smart contract verifier)`, async () => { - const base_relative_path = '../..'; - const test_case = testInfo.case; - - const fm = createFileManager(resolve(`${base_relative_path}/${test_case}`)); - const compileResult = await compile(fm); - if (!('program' in compileResult)) { - throw new Error('Compilation failed'); - } - - const noir_program = compileResult.program; - - const backend = new BarretenbergBackend(noir_program); - const program = new Noir(noir_program, backend); - - // JS Proving - - const prover_toml = readFileSync(resolve(`${base_relative_path}/${test_case}/Prover.toml`)).toString(); - const inputs = toml.parse(prover_toml); - - const proofData = await program.generateProof(inputs); - - // JS verification - - const verified = await program.verifyProof(proofData); - expect(verified, 'Proof fails verification in JS').to.be.true; - - // Smart contract verification - - const contract = await ethers.deployContract(testInfo.compiled, []); - - const result = await contract.verify(proofData.proof, proofData.publicInputs); - - expect(result).to.be.true; - }); -});