diff --git a/.vscode/settings.json b/.vscode/settings.json index 95d849e..ddedc50 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,9 @@ // https://raw.githubusercontent.com/PKief/vscode-material-icon-theme/main/images/fileIcons.png "material-icon-theme.files.associations": { "*.circom": "Verilog", - "*.wtns": "Authors" + "*.wtns": "Authors", + "*.zkey": "Lock", + "*.r1cs": "Diff", + "*.sym": "Edge" } } diff --git a/circomkit.json b/circomkit.json index 24e65ac..8b56114 100644 --- a/circomkit.json +++ b/circomkit.json @@ -1,4 +1,6 @@ { "version": "2.1.4", - "verbose": true + "verbose": true, + "prime": "bn128", + "protocol": "groth16" } diff --git a/circuits.json b/circuits.json index 9723f1c..a0c95d0 100644 --- a/circuits.json +++ b/circuits.json @@ -3,5 +3,11 @@ "file": "multiplier", "template": "Multiplier", "params": [3] + }, + "someArrays_2_3": { + "file": "someArrays", + "template": "SomeArrays", + "params": [2, 3], + "pubs": ["in1D", "in2D"] } } diff --git a/circuits/main/someArrays_2_3.circom b/circuits/main/someArrays_2_3.circom new file mode 100644 index 0000000..ac61a22 --- /dev/null +++ b/circuits/main/someArrays_2_3.circom @@ -0,0 +1,6 @@ +// auto-generated by circomkit +pragma circom 2.1.4; + +include "../someArrays.circom"; + +component main {public[in1D, in2D]} = SomeArrays(2, 3); diff --git a/circuits/someArrays.circom b/circuits/someArrays.circom new file mode 100644 index 0000000..5f440ce --- /dev/null +++ b/circuits/someArrays.circom @@ -0,0 +1,20 @@ +pragma circom 2.0.0; + +template SomeArrays(N, M) { + signal input in; + signal input in1D[N]; + signal input in2D[N][M]; + + in === 1; + for (var i = 1; i < N; i++) { + in1D[i-1] + 1 === in1D[i]; + } + + for (var i = 0; i < N; i++) { + for (var j = 1; j < M; j++) { + in2D[i][j-1] + 1 === in2D[i][j]; + } + } + + log(1, N, N + M); +} diff --git a/inputs/someArrays_2_3/default.json b/inputs/someArrays_2_3/default.json new file mode 100644 index 0000000..e9318f5 --- /dev/null +++ b/inputs/someArrays_2_3/default.json @@ -0,0 +1,9 @@ +{ + "in": 1, + "in1D": [2, 3], + "in2D": [ + [4, 5], + [6, 7], + [8, 9] + ] +} diff --git a/src/circomkit.ts b/src/circomkit.ts index 1c1a565..aaf91f0 100644 --- a/src/circomkit.ts +++ b/src/circomkit.ts @@ -19,7 +19,7 @@ import type { } from './types/'; import {WitnessTester, ProofTester} from './testers/'; import {prettyStringify, primeToName} from './utils'; -import {defaultConfig, colors, CURVES, PROTOCOLS} from './utils/config'; +import {defaultConfig, colors, PRIMES, PROTOCOLS} from './utils/config'; /** * Circomkit is an opinionated wrapper around many SnarkJS functions. @@ -59,7 +59,7 @@ export class Circomkit { this.snarkjsLogger = this.config.verbose ? this.logger : undefined; // sanity checks - if (!CURVES.includes(this.config.prime)) { + if (!PRIMES.includes(this.config.prime)) { throw new Error('Invalid prime in configuration.'); } if (!PROTOCOLS.includes(this.config.protocol)) { @@ -297,14 +297,16 @@ export class Circomkit { if (this.config.protocol === 'fflonk') { throw new Error('Exporting calldata is not supported for fflonk yet.'); } - const [pubs, proof] = ( - await Promise.all( - (['pubs', 'proof'] as const) - .map(type => this.pathWithInput(circuit, input, type)) - .map(path => readFile(path, 'utf-8')) - ) - ).map(content => JSON.parse(content)); - return await snarkjs[this.config.protocol].exportSolidityCallData(proof, pubs); + + const pubs: snarkjs.PublicSignals = JSON.parse(await readFile(this.pathWithInput(circuit, input, 'pubs'), 'utf-8')); + const proof: snarkjs.Groth16Proof & snarkjs.PlonkProof & snarkjs.FflonkProof = JSON.parse( + await readFile(this.pathWithInput(circuit, input, 'proof'), 'utf-8') + ); + // TODO: we can write this ourselves by simply parsing the proof object, now that we know its type! + // this way, we may be able to fix the calldata issue as well for fflonk + const res = await snarkjs[this.config.protocol].exportSolidityCallData(proof, pubs); + // prettyCalldata(this.config.protocol, res); + return res; } /** Instantiate the `main` component. diff --git a/src/types/circomkit.ts b/src/types/circomkit.ts index 1335654..d86f2b6 100644 --- a/src/types/circomkit.ts +++ b/src/types/circomkit.ts @@ -1,10 +1,18 @@ import type {LogLevelDesc} from 'loglevel'; +/** + * Primes supported by Circom, as described for the `-p` option. + * @see https://github.com/iden3/circom/blob/master/program_structure/src/utils/constants.rs + */ +export type CircomkitPrimes = 'bn128' | 'bls12381' | 'goldilocks' | 'grumpkin' | 'pallas' | 'vesta' | 'secq256r1'; + +export type CircomkitProtocol = 'groth16' | 'plonk' | 'fflonk'; + export type CircomkitConfig = { /** Protocol to be used. */ - protocol: 'groth16' | 'plonk' | 'fflonk'; + protocol: CircomkitProtocol; /** Underlying prime field. */ - prime: 'bn128' | 'bls12381' | 'goldilocks'; + prime: CircomkitPrimes; /** Circuit configurations path. */ circuits: string; /** Directory to read circuits from. */ @@ -39,6 +47,8 @@ export type CircomkitConfig = { logLevel: LogLevelDesc; /** Whether to generate the C witness calculator. */ cWitness: boolean; + /** Whether to print Solidity copy-pasteable calldata. */ + prettyCalldata: false; }; /** Shorthand notations for which path to build in Circomkit. These paths require a circuit name. */ diff --git a/src/utils/calldata.ts b/src/utils/calldata.ts new file mode 100644 index 0000000..26a9355 --- /dev/null +++ b/src/utils/calldata.ts @@ -0,0 +1,14 @@ +// import {CircomkitProtocol} from '../types'; + +// /** +// * Prettifies the calldata. +// * +// * Since calldata always has the public signals at the end, and no matter the dimensions of those signals +// * they always get flattened to a 1D array, we can find the start of public signals at the last `[`. +// * +// * @param protocol protocol +// * @param calldata exported calldata string +// */ +// export function prettyCalldata(protocol: CircomkitProtocol, calldata: string) { +// // TODO: implement +// } diff --git a/src/utils/config.ts b/src/utils/config.ts index 11fdd76..b378567 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -2,7 +2,7 @@ import type {LogLevelNames} from 'loglevel'; import type {CircomkitConfig} from '../types/'; export const PROTOCOLS = ['groth16', 'plonk', 'fflonk'] as const; -export const CURVES = ['bn128', 'bls12381', 'goldilocks'] as const; +export const PRIMES = ['bn128', 'bls12381', 'goldilocks', 'grumpkin', 'pallas', 'vesta', 'secq256r1'] as const; /** Default configurations */ export const defaultConfig: Readonly = Object.seal({ @@ -24,6 +24,8 @@ export const defaultConfig: Readonly = Object.seal({ // groth16 phase-2 settings groth16numContributions: 1, groth16askForEntropy: false, + // solidity & calldata + prettyCalldata: false, // logger logLevel: 'INFO', verbose: true, diff --git a/src/utils/index.ts b/src/utils/index.ts index ef6b7ed..b0cbaff 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -5,13 +5,21 @@ export const primes: Record = { bn128: 21888242871839275222246405745257275088548364400416034343698204186575808495617n, bls12381: 52435875175126190479447740508185965837690552500527637822603658699938581184513n, goldilocks: 18446744069414584321n, -}; + grumpkin: 21888242871839275222246405745257275088696311157297823662689037894645226208583n, + pallas: 28948022309329048855892746252171976963363056481941560715954676764349967630337n, + vesta: 28948022309329048855892746252171976963363056481941647379679742748393362948097n, + secq256r1: 115792089210356248762697446949407573530086143415290314195533631308867097853951n, +} as const; /** A mapping from prime (decimals) to prime name as supported by Circom's `-p` option. */ export const primeToName: Record<`${bigint}`, CircomkitConfig['prime']> = { '21888242871839275222246405745257275088548364400416034343698204186575808495617': 'bn128', '52435875175126190479447740508185965837690552500527637822603658699938581184513': 'bls12381', '18446744069414584321': 'goldilocks', + '21888242871839275222246405745257275088696311157297823662689037894645226208583': 'grumpkin', + '28948022309329048855892746252171976963363056481941560715954676764349967630337': 'pallas', + '28948022309329048855892746252171976963363056481941647379679742748393362948097': 'vesta', + '115792089210356248762697446949407573530086143415290314195533631308867097853951': 'secq256r1', } as const; /** JSON Stringify with a prettier format. */