Skip to content

Commit b48949f

Browse files
mllwchrryHrom131
andauthored
Witness overrides (#10)
* add witnessOverrides support and passConstraints check * Update versions & add unit test --------- Co-authored-by: Oleh Komendant <oleg02kom@gmail.com>
1 parent 85d907a commit b48949f

File tree

12 files changed

+296
-80
lines changed

12 files changed

+296
-80
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ await expect(matrix).with.witnessInputs({ a, b, c }).to.have.strict.witnessOutpu
5151
await expect(expect(matrix).with.witnessInputs({ a, b, c }).to.have.witnessOutputs({ e })).to.be.rejectedWith(
5252
`Expected output "e" to be "[[2,5,0],[17,26,0],[0,0,0]]", but got "[[1,4,0],[16,25,0],[0,0,0]]"`,
5353
);
54+
55+
// witness overrides intentionally break constraints to test failure case
56+
await expect(expect(matrix).with.witnessInputs({ a, b, c }, { "main.a": 10n }).to.passConstraints()).to.be.rejectedWith(
57+
"Expected witness to pass constraints, but it doesn't",
58+
);
5459
```
5560

5661
### Proof testing
@@ -63,10 +68,11 @@ await expect(matrix).to.generateProof({ a, b, c });
6368
await expect(matrix).to.not.generateProof({ b, c, d });
6469

6570
const proof = await matrix.generateProof({ a, b, c });
71+
const invalidProof = await matrix.generateProof({ a, b, c }, { "main.a": 10n });
6672

6773
// proof verification assertion
6874
await expect(matrix).to.verifyProof(proof);
69-
await expect(matrix).to.not.verifyProof(otherProof);
75+
await expect(matrix).to.not.verifyProof(invalidProof);
7076

7177
// use generated solidity verifier to verify the proof
7278
await expect(matrix).to.useSolidityVerifier(matrixVerifier).and.verifyProof(proof);

package-lock.json

Lines changed: 36 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solarity/chai-zkit",
3-
"version": "0.3.2",
3+
"version": "0.3.3",
44
"license": "MIT",
55
"author": "Distributed Lab",
66
"readme": "README.md",
@@ -44,14 +44,14 @@
4444
"snarkjs": "0.7.5"
4545
},
4646
"peerDependencies": {
47-
"@solarity/hardhat-zkit": ">=0.5.15 <0.6.0",
48-
"@solarity/zkit": ">=0.3.6 <0.4.0",
47+
"@solarity/hardhat-zkit": ">=0.5.16 <0.6.0",
48+
"@solarity/zkit": ">=0.3.7 <0.4.0",
4949
"chai": "^4.0.0"
5050
},
5151
"devDependencies": {
5252
"@nomicfoundation/hardhat-ethers": "3.0.5",
53-
"@solarity/hardhat-zkit": "^0.5.15",
54-
"@solarity/zkit": "^0.3.6",
53+
"@solarity/hardhat-zkit": "^0.5.16",
54+
"@solarity/zkit": "^0.3.7",
5555
"@types/chai": "^4.3.16",
5656
"@types/chai-as-promised": "^7.1.8",
5757
"@types/mocha": "^10.0.6",

src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ export const VERIFY_PROOF_METHOD: string = "verifyProof";
55
export const STRICT_PROPERTY: string = "strict";
66
export const WITNESS_INPUTS_METHOD: string = "witnessInputs";
77
export const WITNESS_OUTPUTS_METHOD: string = "witnessOutputs";
8+
export const WITNESS_PASS_CONSTRAINTS_METHOD: string = "passConstraints";
89

910
export const BN128_CURVE_NAME: string = "bn128";

src/core/proof.ts

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,37 @@ import { GENERATE_PROOF_METHOD, USE_SOLIDITY_VERIFIER_METHOD, VERIFY_PROOF_METHO
44
import { checkCircuitZKit } from "../utils";
55

66
export function proof(chai: Chai.ChaiStatic, utils: Chai.ChaiUtils): void {
7-
chai.Assertion.addMethod(GENERATE_PROOF_METHOD, function (this: any, inputs: Signals) {
8-
const obj = utils.flag(this, "object");
7+
chai.Assertion.addMethod(
8+
GENERATE_PROOF_METHOD,
9+
function (this: any, inputs: Signals, witnessOverrides?: Record<string, bigint>) {
10+
const obj = utils.flag(this, "object");
911

10-
checkCircuitZKit(obj, GENERATE_PROOF_METHOD);
12+
checkCircuitZKit(obj, GENERATE_PROOF_METHOD);
1113

12-
const promise = (this.then === undefined ? Promise.resolve() : this).then(async () => {
13-
let isGenerated = true;
14+
const promise = (this.then === undefined ? Promise.resolve() : this).then(async () => {
15+
let isGenerated = true;
1416

15-
try {
16-
const proof = await obj.generateProof(inputs);
17+
try {
18+
const proof = await obj.generateProof(inputs, witnessOverrides);
1719

18-
utils.flag(this, "generatedProof", proof);
19-
} catch (e) {
20-
isGenerated = false;
21-
}
20+
utils.flag(this, "generatedProof", proof);
21+
} catch (e) {
22+
isGenerated = false;
23+
}
2224

23-
this.assert(
24-
isGenerated,
25-
"Expected proof generation to be successful, but it isn't",
26-
"Expected proof generation NOT to be successful, but it is",
27-
);
28-
});
25+
this.assert(
26+
isGenerated,
27+
"Expected proof generation to be successful, but it isn't",
28+
"Expected proof generation NOT to be successful, but it is",
29+
);
30+
});
2931

30-
this.then = promise.then.bind(promise);
31-
this.catch = promise.catch.bind(promise);
32+
this.then = promise.then.bind(promise);
33+
this.catch = promise.catch.bind(promise);
3234

33-
return this;
34-
});
35+
return this;
36+
},
37+
);
3538

3639
chai.Assertion.addMethod(USE_SOLIDITY_VERIFIER_METHOD, function (this: any, verifierContract: any) {
3740
const obj = utils.flag(this, "object");

src/core/witness.ts

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
import { CircuitZKit, NumberLike, ProvingSystemType, Signals } from "@solarity/zkit";
1+
import * as snarkjs from "snarkjs";
22

3-
import { STRICT_PROPERTY, WITNESS_INPUTS_METHOD, WITNESS_OUTPUTS_METHOD } from "../constants";
3+
import { CircuitZKit, NumberLike, ProvingSystemType, Signals, writeWitnessFile } from "@solarity/zkit";
4+
5+
import {
6+
STRICT_PROPERTY,
7+
WITNESS_INPUTS_METHOD,
8+
WITNESS_OUTPUTS_METHOD,
9+
WITNESS_PASS_CONSTRAINTS_METHOD,
10+
} from "../constants";
411
import { checkCircuitZKit, loadOutputs, outputSignalsCompare } from "../utils";
512

613
export function witness(chai: Chai.ChaiStatic, utils: Chai.ChaiUtils): void {
@@ -10,23 +17,26 @@ export function witness(chai: Chai.ChaiStatic, utils: Chai.ChaiUtils): void {
1017
return this;
1118
});
1219

13-
chai.Assertion.addMethod(WITNESS_INPUTS_METHOD, function (this: any, inputs: Signals) {
14-
const obj = utils.flag(this, "object");
20+
chai.Assertion.addMethod(
21+
WITNESS_INPUTS_METHOD,
22+
function (this: any, inputs: Signals, witnessOverrides?: Record<string, bigint>) {
23+
const obj = utils.flag(this, "object");
1524

16-
checkCircuitZKit(obj, WITNESS_INPUTS_METHOD);
25+
checkCircuitZKit(obj, WITNESS_INPUTS_METHOD);
1726

18-
const promise = (this.then === undefined ? Promise.resolve() : this).then(async () => {
19-
const witness = await obj.calculateWitness(inputs);
27+
const promise = (this.then === undefined ? Promise.resolve() : this).then(async () => {
28+
const witness = await obj.calculateWitness(inputs, witnessOverrides);
2029

21-
utils.flag(this, "inputs", inputs);
22-
utils.flag(this, "witness", witness);
23-
});
30+
utils.flag(this, "inputs", inputs);
31+
utils.flag(this, "witness", witness);
32+
});
2433

25-
this.then = promise.then.bind(promise);
26-
this.catch = promise.catch.bind(promise);
34+
this.then = promise.then.bind(promise);
35+
this.catch = promise.catch.bind(promise);
2736

28-
return this;
29-
});
37+
return this;
38+
},
39+
);
3040

3141
chai.Assertion.addMethod(WITNESS_OUTPUTS_METHOD, function (this: any, outputs: Signals | NumberLike[]) {
3242
const obj = utils.flag(this, "object");
@@ -56,4 +66,39 @@ export function witness(chai: Chai.ChaiStatic, utils: Chai.ChaiUtils): void {
5666

5767
return this;
5868
});
69+
70+
chai.Assertion.addMethod(WITNESS_PASS_CONSTRAINTS_METHOD, function (this: any) {
71+
const obj = utils.flag(this, "object");
72+
73+
checkCircuitZKit(obj, WITNESS_PASS_CONSTRAINTS_METHOD);
74+
75+
const promise = (this.then === undefined ? Promise.resolve() : this).then(async () => {
76+
const witness = utils.flag(this, "witness");
77+
78+
if (!witness) {
79+
throw new Error("`passConstraints` is expected to be called after `witnessInputs`");
80+
}
81+
82+
const r1csFile = obj.mustGetArtifactsFilePath("r1cs");
83+
const witnessFile = obj.getTemporaryWitnessPath();
84+
85+
await writeWitnessFile(witnessFile, witness);
86+
87+
const constraintsPassed = await snarkjs.wtns.check(r1csFile, witnessFile, {
88+
info: () => {},
89+
warn: () => {},
90+
});
91+
92+
this.assert(
93+
constraintsPassed,
94+
"Expected witness to pass constraints, but it doesn't",
95+
"Expected witness NOT to pass constraints, but it does",
96+
);
97+
});
98+
99+
this.then = promise.then.bind(promise);
100+
this.catch = promise.catch.bind(promise);
101+
102+
return this;
103+
});
59104
}

0 commit comments

Comments
 (0)