From 902925f9176ef41c75d367cf178e8e461abab4f7 Mon Sep 17 00:00:00 2001 From: Kyryl Riabov Date: Thu, 3 Oct 2024 14:02:30 +0300 Subject: [PATCH] Added support for Plonk Protocol per circuit --- package-lock.json | 12 ++--- package.json | 4 +- src/constants/protocol.ts | 4 ++ src/core/ZkitTSGenerator.ts | 46 ++++++++++++++++++ src/core/templates/circuit-wrapper.ts.ejs | 13 ++--- src/types/circuitArtifact.ts | 2 + src/types/typesGenerator.ts | 5 ++ ...AtomicQueryMTPOnChainVoting_artifacts.json | 1 + test/fixture-cache/Multiplier2_artifacts.json | 1 + ...key.json => Multiplier2.groth16.vkey.json} | 0 ...tiplier2.zkey => Multiplier2.groth16.zkey} | Bin ...rix.vkey.json => Matrix.groth16.vkey.json} | 0 .../{Matrix.zkey => Matrix.groth16.zkey} | Bin .../auth/EnhancedMultiplier_artifacts.json | 1 + test/fixture-cache/auth/Matrix_artifacts.json | 1 + .../auth/Multiplier2_artifacts.json | 1 + .../lib/Multiplier2_artifacts.json | 1 + test/helpers/index.ts | 10 ++++ 18 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 src/constants/protocol.ts rename test/fixture-cache/artifacts/Basic.circom/{Multiplier2.vkey.json => Multiplier2.groth16.vkey.json} (100%) rename test/fixture-cache/artifacts/Basic.circom/{Multiplier2.zkey => Multiplier2.groth16.zkey} (100%) rename test/fixture-cache/artifacts/auth/Matrix.circom/{Matrix.vkey.json => Matrix.groth16.vkey.json} (100%) rename test/fixture-cache/artifacts/auth/Matrix.circom/{Matrix.zkey => Matrix.groth16.zkey} (100%) create mode 100644 test/helpers/index.ts diff --git a/package-lock.json b/package-lock.json index b3ba777..55ad498 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@solarity/zktype", - "version": "0.3.1", + "version": "0.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@solarity/zktype", - "version": "0.3.1", + "version": "0.4.0", "license": "MIT", "dependencies": { "ejs": "3.1.10", @@ -32,7 +32,7 @@ "node": ">=18" }, "peerDependencies": { - "@solarity/zkit": "^0.2.4" + "@solarity/zkit": "^0.3.0-rc.0" } }, "node_modules/@ampproject/remapping": { @@ -1437,9 +1437,9 @@ } }, "node_modules/@solarity/zkit": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@solarity/zkit/-/zkit-0.2.4.tgz", - "integrity": "sha512-tWaM9rS+7MBqez9cRnqVKH5sEcGrRgXl3oKGJiwaUjDkJOepoBgeyQLZAeTOHDfUNVJhJ4asxe/WJuvWRK1Xhg==", + "version": "0.3.0-rc.0", + "resolved": "https://registry.npmjs.org/@solarity/zkit/-/zkit-0.3.0-rc.0.tgz", + "integrity": "sha512-yrPgJio6ws3okdLVOI4P4vT1dplA8F1JVhNy+Kyk5msf8yYGhv2gzHSUzGOkPBUVbDVWN+Y+95yMrskV2WlWIQ==", "peer": true, "dependencies": { "ejs": "3.1.10", diff --git a/package.json b/package.json index c3e7aec..3142bc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@solarity/zktype", - "version": "0.3.1", + "version": "0.4.0", "description": "Unleash TypeScript bindings for Circom circuits", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -49,7 +49,7 @@ "typescript": "5.5.4" }, "peerDependencies": { - "@solarity/zkit": "^0.2.4" + "@solarity/zkit": "^0.3.0-rc.0" }, "devDependencies": { "@types/chai": "^4.3.12", diff --git a/src/constants/protocol.ts b/src/constants/protocol.ts new file mode 100644 index 0000000..3d38d0a --- /dev/null +++ b/src/constants/protocol.ts @@ -0,0 +1,4 @@ +export const Groth16CalldataPointsType = + "[NumericString, NumericString], [[NumericString, NumericString], [NumericString, NumericString]], [NumericString, NumericString]"; + +export const PlonkCalldataPointsType = "NumericString[]"; diff --git a/src/core/ZkitTSGenerator.ts b/src/core/ZkitTSGenerator.ts index 1e18727..47444d3 100644 --- a/src/core/ZkitTSGenerator.ts +++ b/src/core/ZkitTSGenerator.ts @@ -19,6 +19,7 @@ import { import { normalizeName } from "../utils"; import { SignalTypeNames, SignalVisibilityNames } from "../constants"; +import { Groth16CalldataPointsType, PlonkCalldataPointsType } from "../constants/protocol"; export default class ZkitTSGenerator extends BaseTSGenerator { protected async _genHardhatZkitTypeExtension(circuits: { @@ -70,6 +71,8 @@ export default class ZkitTSGenerator extends BaseTSGenerator { circuitArtifact: CircuitArtifact, pathToGeneratedFile: string, ): Promise { + this._validateCircuitArtifact(circuitArtifact); + const template = fs.readFileSync(path.join(__dirname, "templates", "circuit-wrapper.ts.ejs"), "utf8"); let outputCounter: number = 0; @@ -114,11 +117,15 @@ export default class ZkitTSGenerator extends BaseTSGenerator { const pathToUtils = path.join(this.getOutputTypesDir(), "utils"); const templateParams: WrapperTemplateParams = { + protocolTypeName: circuitArtifact.baseCircuitInfo.protocol, + protocolImplementerName: this._getProtocolImplementerName(circuitArtifact), + proofTypeInternalName: this._getProofTypeInternalName(circuitArtifact), circuitClassName: this._getCircuitName(circuitArtifact), publicInputsTypeName: this._getTypeName(circuitArtifact, "Public"), calldataPubSignalsType: this._getCalldataPubSignalsType(calldataPubSignalsCount), publicInputs, privateInputs, + calldataPointsType: this._getCalldataPointsType(circuitArtifact), proofTypeName: this._getTypeName(circuitArtifact, "Proof"), privateInputsTypeName: this._getTypeName(circuitArtifact, "Private"), pathToUtils: path.relative(path.dirname(pathToGeneratedFile), pathToUtils), @@ -150,4 +157,43 @@ export default class ZkitTSGenerator extends BaseTSGenerator { return signal.dimension.reduce((acc: number, dim: string) => acc * Number(dim), 1); } + + private _getProtocolImplementerName(circuitArtifact: CircuitArtifact): any { + switch (circuitArtifact.baseCircuitInfo.protocol) { + case "groth16": + return "Groth16Implementer"; + case "plonk": + return "PlonkImplementer"; + default: + throw new Error(`Unknown protocol: ${circuitArtifact.baseCircuitInfo.protocol}`); + } + } + + private _getProofTypeInternalName(circuitArtifact: CircuitArtifact): any { + switch (circuitArtifact.baseCircuitInfo.protocol) { + case "groth16": + return "Groth16Proof"; + case "plonk": + return "PlonkProof"; + default: + throw new Error(`Unknown protocol: ${circuitArtifact.baseCircuitInfo.protocol}`); + } + } + + private _getCalldataPointsType(circuitArtifact: CircuitArtifact): any { + switch (circuitArtifact.baseCircuitInfo.protocol) { + case "groth16": + return Groth16CalldataPointsType; + case "plonk": + return PlonkCalldataPointsType; + default: + throw new Error(`Unknown protocol: ${circuitArtifact.baseCircuitInfo.protocol}`); + } + } + + private _validateCircuitArtifact(circuitArtifact: CircuitArtifact): void { + if (!circuitArtifact.baseCircuitInfo.protocol) { + throw new Error(`ZKType: Protocol is missing in the circuit artifact: ${circuitArtifact.circuitTemplateName}`); + } + } } diff --git a/src/core/templates/circuit-wrapper.ts.ejs b/src/core/templates/circuit-wrapper.ts.ejs index 627fc5a..fd97eda 100644 --- a/src/core/templates/circuit-wrapper.ts.ejs +++ b/src/core/templates/circuit-wrapper.ts.ejs @@ -2,9 +2,12 @@ import { CircuitZKit, CircuitZKitConfig, Groth16Proof, + PlonkProof, NumberLike, NumericString, PublicSignals, + Groth16Implementer, + PlonkImplementer, } from "@solarity/zkit"; import { normalizePublicSignals, denormalizePublicSignals } from "<%= pathToUtils %>"; @@ -22,20 +25,18 @@ export type <%= publicInputsTypeName %> = { } export type <%= proofTypeName %> = { - proof: Groth16Proof; + proof: <%= proofTypeInternalName %>; publicSignals: <%= publicInputsTypeName %>; } export type Calldata = [ - [NumericString, NumericString], - [[NumericString, NumericString], [NumericString, NumericString]], - [NumericString, NumericString], + <%= calldataPointsType %>, <%= calldataPubSignalsType %>, ]; -export class <%= circuitClassName %> extends CircuitZKit { +export class <%= circuitClassName %> extends CircuitZKit<"<%= protocolTypeName %>"> { constructor(config: CircuitZKitConfig) { - super(config); + super(config, new <%= protocolImplementerName %>()); } public async generateProof(inputs: <%= privateInputsTypeName %>): Promise<<%= proofTypeName %>> { diff --git a/src/types/circuitArtifact.ts b/src/types/circuitArtifact.ts index 07d9a7b..977afec 100644 --- a/src/types/circuitArtifact.ts +++ b/src/types/circuitArtifact.ts @@ -25,10 +25,12 @@ export type CircuitArtifact = { /** * Represents the base circuit information. * + * @param {string} protocol - The proving system protocol used in the circuit. * @param {number} constraintsNumber - The number of constraints in the circuit. * @param {SignalInfo[]} signals - The array of `input` and `output` signals used in the circuit. */ export type BaseCircuitInfo = { + protocol: "groth16" | "plonk"; constraintsNumber: number; signals: SignalInfo[]; }; diff --git a/src/types/typesGenerator.ts b/src/types/typesGenerator.ts index 763a5ee..965fc13 100644 --- a/src/types/typesGenerator.ts +++ b/src/types/typesGenerator.ts @@ -1,4 +1,5 @@ import { CircuitArtifact } from "./circuitArtifact"; +import { Groth16CalldataPointsType, PlonkCalldataPointsType } from "../constants/protocol"; export interface ArtifactWithPath { circuitArtifact: CircuitArtifact; @@ -16,9 +17,13 @@ export interface DefaultWrapperTemplateParams { } export interface WrapperTemplateParams { + protocolTypeName: "groth16" | "plonk"; + protocolImplementerName: "Groth16Implementer" | "PlonkImplementer"; + proofTypeInternalName: "Groth16Proof" | "PlonkProof"; publicInputsTypeName: string; privateInputs: Inputs[]; publicInputs: Inputs[]; + calldataPointsType: typeof Groth16CalldataPointsType | typeof PlonkCalldataPointsType; calldataPubSignalsType: string; proofTypeName: string; privateInputsTypeName: string; diff --git a/test/fixture-cache/CredentialAtomicQueryMTPOnChainVoting_artifacts.json b/test/fixture-cache/CredentialAtomicQueryMTPOnChainVoting_artifacts.json index 497f991..5fef3d8 100644 --- a/test/fixture-cache/CredentialAtomicQueryMTPOnChainVoting_artifacts.json +++ b/test/fixture-cache/CredentialAtomicQueryMTPOnChainVoting_artifacts.json @@ -5,6 +5,7 @@ "circuitSourceName": "circuits/fixture/credentialAtomicQueryMTPV2OnChainVoting.circom", "baseCircuitInfo": { "constraintsNumber": 86791, + "protocol": "groth16", "signals": [ { "name": "merklized", diff --git a/test/fixture-cache/Multiplier2_artifacts.json b/test/fixture-cache/Multiplier2_artifacts.json index 57d1e55..efa2caa 100644 --- a/test/fixture-cache/Multiplier2_artifacts.json +++ b/test/fixture-cache/Multiplier2_artifacts.json @@ -5,6 +5,7 @@ "circuitSourceName": "circuits/fixture/Basic.circom", "baseCircuitInfo": { "constraintsNumber": 1, + "protocol": "groth16", "signals": [ { "name": "in1", diff --git a/test/fixture-cache/artifacts/Basic.circom/Multiplier2.vkey.json b/test/fixture-cache/artifacts/Basic.circom/Multiplier2.groth16.vkey.json similarity index 100% rename from test/fixture-cache/artifacts/Basic.circom/Multiplier2.vkey.json rename to test/fixture-cache/artifacts/Basic.circom/Multiplier2.groth16.vkey.json diff --git a/test/fixture-cache/artifacts/Basic.circom/Multiplier2.zkey b/test/fixture-cache/artifacts/Basic.circom/Multiplier2.groth16.zkey similarity index 100% rename from test/fixture-cache/artifacts/Basic.circom/Multiplier2.zkey rename to test/fixture-cache/artifacts/Basic.circom/Multiplier2.groth16.zkey diff --git a/test/fixture-cache/artifacts/auth/Matrix.circom/Matrix.vkey.json b/test/fixture-cache/artifacts/auth/Matrix.circom/Matrix.groth16.vkey.json similarity index 100% rename from test/fixture-cache/artifacts/auth/Matrix.circom/Matrix.vkey.json rename to test/fixture-cache/artifacts/auth/Matrix.circom/Matrix.groth16.vkey.json diff --git a/test/fixture-cache/artifacts/auth/Matrix.circom/Matrix.zkey b/test/fixture-cache/artifacts/auth/Matrix.circom/Matrix.groth16.zkey similarity index 100% rename from test/fixture-cache/artifacts/auth/Matrix.circom/Matrix.zkey rename to test/fixture-cache/artifacts/auth/Matrix.circom/Matrix.groth16.zkey diff --git a/test/fixture-cache/auth/EnhancedMultiplier_artifacts.json b/test/fixture-cache/auth/EnhancedMultiplier_artifacts.json index 48bcef1..9428b41 100644 --- a/test/fixture-cache/auth/EnhancedMultiplier_artifacts.json +++ b/test/fixture-cache/auth/EnhancedMultiplier_artifacts.json @@ -5,6 +5,7 @@ "circuitSourceName": "circuits/fixture/auth/EMultiplier.circom", "baseCircuitInfo": { "constraintsNumber": 1, + "protocol": "groth16", "signals": [ { "name": "in1", diff --git a/test/fixture-cache/auth/Matrix_artifacts.json b/test/fixture-cache/auth/Matrix_artifacts.json index a3ccec3..6b6dfb0 100644 --- a/test/fixture-cache/auth/Matrix_artifacts.json +++ b/test/fixture-cache/auth/Matrix_artifacts.json @@ -5,6 +5,7 @@ "circuitSourceName": "circuits/fixture/auth/Matrix.circom", "baseCircuitInfo": { "constraintsNumber": 8, + "protocol": "groth16", "signals": [ { "name": "a", diff --git a/test/fixture-cache/auth/Multiplier2_artifacts.json b/test/fixture-cache/auth/Multiplier2_artifacts.json index 1c40176..f66efde 100644 --- a/test/fixture-cache/auth/Multiplier2_artifacts.json +++ b/test/fixture-cache/auth/Multiplier2_artifacts.json @@ -5,6 +5,7 @@ "circuitSourceName": "circuits/fixture/auth/BasicInAuth.circom", "baseCircuitInfo": { "constraintsNumber": 1, + "protocol": "groth16", "signals": [ { "name": "in1", diff --git a/test/fixture-cache/lib/Multiplier2_artifacts.json b/test/fixture-cache/lib/Multiplier2_artifacts.json index 1e143af..4a3ad5f 100644 --- a/test/fixture-cache/lib/Multiplier2_artifacts.json +++ b/test/fixture-cache/lib/Multiplier2_artifacts.json @@ -5,6 +5,7 @@ "circuitSourceName": "circuits/fixture/lib/BasicInLib.circom", "baseCircuitInfo": { "constraintsNumber": 1, + "protocol": "groth16", "signals": [ { "name": "in1", diff --git a/test/helpers/index.ts b/test/helpers/index.ts new file mode 100644 index 0000000..8255191 --- /dev/null +++ b/test/helpers/index.ts @@ -0,0 +1,10 @@ +import { CircuitTypesGenerator } from "../../src"; +import { findProjectRoot } from "../../src/utils"; + +const circuitTypesGenerator = new CircuitTypesGenerator({ + basePath: "test/fixture", + projectRoot: findProjectRoot(process.cwd()), + circuitsArtifactsPaths: ["test/fixture-cache/Multiplier2_artifacts.json"], +}); + +// circuitTypesGenerator.generateTypes().then(console.log).catch(console.error);