From 0af1603b31f5b0c009b06e2b580fda5a9c657a28 Mon Sep 17 00:00:00 2001 From: erhant Date: Sat, 17 Feb 2024 13:12:40 +0300 Subject: [PATCH] Minor fixes (#69) * add more tests for error catching * calldata fixes as well * bump version --- circuits.json | 6 ++-- circuits/{someArrays.circom => arrays.circom} | 2 +- circuits/errors.circom | 18 ++++++++++ .../default.json | 0 package.json | 2 +- src/circomkit.ts | 2 +- src/testers/witnessTester.ts | 7 +++- src/utils/calldata.ts | 19 ++++++----- tests/errors.test.ts | 34 +++++++++++++++++++ tests/witnessTester.test.ts | 8 ----- 10 files changed, 75 insertions(+), 23 deletions(-) rename circuits/{someArrays.circom => arrays.circom} (91%) create mode 100644 circuits/errors.circom rename inputs/{someArrays_2_3 => arrays_2_3}/default.json (100%) create mode 100644 tests/errors.test.ts diff --git a/circuits.json b/circuits.json index a0c95d0..3ab392e 100644 --- a/circuits.json +++ b/circuits.json @@ -4,9 +4,9 @@ "template": "Multiplier", "params": [3] }, - "someArrays_2_3": { - "file": "someArrays", - "template": "SomeArrays", + "arrays_2_3": { + "file": "arrays", + "template": "Arrays", "params": [2, 3], "pubs": ["in1D", "in2D"] } diff --git a/circuits/someArrays.circom b/circuits/arrays.circom similarity index 91% rename from circuits/someArrays.circom rename to circuits/arrays.circom index 5f440ce..0b98f42 100644 --- a/circuits/someArrays.circom +++ b/circuits/arrays.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; -template SomeArrays(N, M) { +template Arrays(N, M) { signal input in; signal input in1D[N]; signal input in2D[N][M]; diff --git a/circuits/errors.circom b/circuits/errors.circom new file mode 100644 index 0000000..17bdd81 --- /dev/null +++ b/circuits/errors.circom @@ -0,0 +1,18 @@ +pragma circom 2.0.0; + +// Run-time errors: +// - An input signal has more elements than expected +// - An input signal has less elements than expected +// - A signal is missing +// - A signal is extra +// - A run-time assertion error occurs. +// - Division-by-zero + +template Errors() { + signal input in; + signal input inin[2]; + signal output out; + + assert(in != 1); + out <== in + (inin[0] * inin[1]); +} diff --git a/inputs/someArrays_2_3/default.json b/inputs/arrays_2_3/default.json similarity index 100% rename from inputs/someArrays_2_3/default.json rename to inputs/arrays_2_3/default.json diff --git a/package.json b/package.json index 5d847e0..1002160 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "circomkit", - "version": "0.0.23", + "version": "0.0.24", "description": "A Circom development environment", "author": "erhant", "license": "MIT", diff --git a/src/circomkit.ts b/src/circomkit.ts index f0300c7..a95de26 100644 --- a/src/circomkit.ts +++ b/src/circomkit.ts @@ -576,7 +576,7 @@ export class Circomkit { circuit: string, circuitConfig: CircuitConfig & {recompile?: boolean} ) { - circuitConfig.dir ||= 'test'; // defaults to test directory + circuitConfig.dir ??= 'test'; // defaults to test directory const targetPath = this.instantiate(circuit, circuitConfig); const circomWasmTester: CircomWasmTester = await wasm_tester(targetPath, { diff --git a/src/testers/witnessTester.ts b/src/testers/witnessTester.ts index bd07245..cb64d0f 100644 --- a/src/testers/witnessTester.ts +++ b/src/testers/witnessTester.ts @@ -67,7 +67,12 @@ export class WitnessTester) { await this.calculateWitness(input).then( () => assert.fail('Expected witness calculation to fail.'), diff --git a/src/utils/calldata.ts b/src/utils/calldata.ts index 63ead2d..5ccf530 100644 --- a/src/utils/calldata.ts +++ b/src/utils/calldata.ts @@ -45,7 +45,7 @@ export function getCalldata( function publicSignalsCalldata(pubs: PublicSignals, pretty: boolean): string { const pubs256 = valuesToPaddedUint256s(pubs); if (pretty) { - return `uint[${pubs.length}] pubs = [\n ${pubs256.join(',\n ')}\n];`; + return `uint[${pubs.length}] memory pubs = [\n ${pubs256.join(',\n ')}\n];`; } else { return `[${pubs256.map(s => `"${s}"`).join(',')}]`; } @@ -67,7 +67,7 @@ function fflonkCalldata(proof: FflonkProof, pretty: boolean): string { ]); if (pretty) { - return `uint256[24] proof = [\n ${vals.join(',\n ')}\n];`; + return `uint256[24] memory proof = [\n ${vals.join(',\n ')}\n];`; } else { return `[${withQuotes(vals).join(',')}]`; } @@ -87,7 +87,7 @@ function plonkCalldata(proof: PlonkProof, pretty: boolean = false) { ]); if (pretty) { - return `uint[24] proof = [\n ${vals.join(',\n ')}\n];`; + return `uint[24] memory proof = [\n ${vals.join(',\n ')}\n];`; } else { return `[${withQuotes(vals).join(',')}]`; } @@ -95,15 +95,18 @@ function plonkCalldata(proof: PlonkProof, pretty: boolean = false) { function groth16Calldata(proof: Groth16Proof, pretty: boolean) { const pA = valuesToPaddedUint256s([proof.pi_a[0], proof.pi_a[1]]); - const pB0 = valuesToPaddedUint256s([proof.pi_b[0][1], proof.pi_b[0][1]]); - const pB1 = valuesToPaddedUint256s([proof.pi_b[1][1], proof.pi_b[1][1]]); const pC = valuesToPaddedUint256s([proof.pi_c[0], proof.pi_c[1]]); + // note that pB are reversed, notice the indexing is [1] and [0] instead of [0] and [1]. + const pB0 = valuesToPaddedUint256s([proof.pi_b[0][1], proof.pi_b[0][0]]); + const pB1 = valuesToPaddedUint256s([proof.pi_b[1][1], proof.pi_b[1][0]]); + if (pretty) { + // the eternal struggle between "should i use a template literal" or "join with \n" return [ - `uint[2] pA = [${pA.join(', ')}];`, - `uint[2][2] pB = [[${pB0.join(', ')}], [${pB1.join(', ')}]];`, - `uint[2] pC = [${pC.join(', ')}];`, + `uint[2] memory pA = [\n ${pA.join(',\n ')}\n];`, + `uint[2][2] memory pB = [\n [\n ${pB0.join(',\n ')}\n ],\n [\n ${pB1.join(',\n ')}\n ]\n];`, + `uint[2] memory pC = [\n ${pC.join(',\n ')}\n];`, ].join('\n'); } else { return [ diff --git a/tests/errors.test.ts b/tests/errors.test.ts new file mode 100644 index 0000000..81ab44d --- /dev/null +++ b/tests/errors.test.ts @@ -0,0 +1,34 @@ +import {Circomkit, WitnessTester} from '../src'; + +describe('error catching', () => { + let circuit: WitnessTester<['in', 'inin'], ['out']>; + + before(async () => { + const circomkit = new Circomkit({verbose: false, logLevel: 'silent'}); + circuit = await circomkit.WitnessTester('error_rt', {file: 'errors', template: 'Errors'}); + }); + + it('should fail for fewer inputs than expected', async () => { + await circuit.expectFail({in: 0, inin: [1]}); + }); + + it('should fail for more inputs than expected', async () => { + await circuit.expectFail({in: 0, inin: [1, 2, 3]}); + }); + + it('should fail due to false-assert', async () => { + await circuit.expectFail({in: 1, inin: [1, 2]}); + }); + + it('should fail due to missing signal', async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + await circuit.expectFail({inin: [1, 2, 3]}); + }); + + it('should fail due to extra signal', async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + await circuit.expectFail({inin: [1, 2, 3], idontexist: 1}); + }); +}); diff --git a/tests/witnessTester.test.ts b/tests/witnessTester.test.ts index 22522ae..cce9f29 100644 --- a/tests/witnessTester.test.ts +++ b/tests/witnessTester.test.ts @@ -26,14 +26,6 @@ describe('witness tester', () => { await circuit.expectPass(signals.input, signals.output); }); - it('should fail for fewer inputs than expected', async () => { - await circuit.expectFail({in: signals.input.in.slice(1)}); - }); - - it('should fail for more inputs than expected', async () => { - await circuit.expectFail({in: [0, ...signals.input.in]}); - }); - it('should fail for bad witness', async () => { await circuit.expectFail(signals.badInput); });