Skip to content

Commit

Permalink
Add more dollar tests
Browse files Browse the repository at this point in the history
  • Loading branch information
SoraSuegami committed May 19, 2024
1 parent b1de7f8 commit 5863518
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 4 deletions.
12 changes: 12 additions & 0 deletions packages/circom/tests/circuits/dollar2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"parts": [
{
"is_public": false,
"regex_def": "(\n|^)x"
},
{
"is_public": true,
"regex_def": "a[bc]$"
}
]
}
115 changes: 115 additions & 0 deletions packages/circom/tests/circuits/dollar2_regex.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
pragma circom 2.1.5;

include "@zk-email/zk-regex-circom/circuits/regex_helpers.circom";

// regex: (\n|^)xa[bc]$
template Dollar2Regex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;

var num_bytes = msg_bytes+1;
signal in[num_bytes];
in[0]<==255;
for (var i = 0; i < msg_bytes; i++) {
in[i+1] <== msg[i];
}

component eq[6][num_bytes];
component and[4][num_bytes];
component multi_or[2][num_bytes];
signal states[num_bytes+1][5];
signal states_tmp[num_bytes+1][5];
signal from_zero_enabled[num_bytes+1];
from_zero_enabled[num_bytes] <== 0;
component state_changed[num_bytes];

signal padding_start[num_bytes+1];
padding_start[0] <== 0;
for (var i = 1; i < 5; i++) {
states[0][i] <== 0;
}

for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(4);
states[i][0] <== 1;
padding_start[i+1] <== IsNotZeroAcc()(padding_start[i], in[i]);
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 10;
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 255;
and[0][i] = AND();
and[0][i].a <== states[i][0];
multi_or[0][i] = MultiOR(2);
multi_or[0][i].in[0] <== eq[0][i].out;
multi_or[0][i].in[1] <== eq[1][i].out;
and[0][i].b <== multi_or[0][i].out;
states_tmp[i+1][1] <== 0;
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 120;
and[1][i] = AND();
and[1][i].a <== states[i][1];
and[1][i].b <== eq[2][i].out;
states[i+1][2] <== and[1][i].out;
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 97;
and[2][i] = AND();
and[2][i].a <== states[i][2];
and[2][i].b <== eq[3][i].out;
states[i+1][3] <== and[2][i].out;
eq[4][i] = IsEqual();
eq[4][i].in[0] <== in[i];
eq[4][i].in[1] <== 98;
eq[5][i] = IsEqual();
eq[5][i].in[0] <== in[i];
eq[5][i].in[1] <== 99;
and[3][i] = AND();
and[3][i].a <== states[i][3];
multi_or[1][i] = MultiOR(2);
multi_or[1][i].in[0] <== eq[4][i].out;
multi_or[1][i].in[1] <== eq[5][i].out;
and[3][i].b <== multi_or[1][i].out;
states[i+1][4] <== and[3][i].out;
from_zero_enabled[i] <== MultiNOR(4)([states_tmp[i+1][1], states[i+1][2], states[i+1][3], states[i+1][4]]);
states[i+1][1] <== MultiOR(2)([states_tmp[i+1][1], from_zero_enabled[i] * and[0][i].out]);
state_changed[i].in[0] <== states[i+1][1];
state_changed[i].in[1] <== states[i+1][2];
state_changed[i].in[2] <== states[i+1][3];
state_changed[i].in[3] <== states[i+1][4];
}

component is_accepted = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
is_accepted.in[i] <== states[i][4];
}
signal end_anchor_check[num_bytes+1][2];
end_anchor_check[0][1] <== 0;
for (var i = 0; i < num_bytes; i++) {
end_anchor_check[i+1][0] <== IsEqual()([i, padding_start[num_bytes]]);
end_anchor_check[i+1][1] <== end_anchor_check[i][1] + states[i][4] * end_anchor_check[i+1][0];
}
out <== is_accepted.out * end_anchor_check[num_bytes][1];
signal is_consecutive[msg_bytes+1][3];
is_consecutive[msg_bytes][2] <== 0;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][4] * (1 - is_consecutive[msg_bytes-i][2]) + is_consecutive[msg_bytes-i][2];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
is_consecutive[msg_bytes-1-i][2] <== ORAnd()([(1 - from_zero_enabled[msg_bytes-i+1]), states[num_bytes-i][4], is_consecutive[msg_bytes-1-i][1]]);
}
// substrings calculated: [{(2, 3), (3, 4)}]
signal prev_states0[2][msg_bytes];
signal is_substr0[msg_bytes];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
// the 0-th substring transitions: [(2, 3), (3, 4)]
prev_states0[0][i] <== (1 - from_zero_enabled[i+1]) * states[i+1][2];
prev_states0[1][i] <== (1 - from_zero_enabled[i+1]) * states[i+1][3];
is_substr0[i] <== MultiOR(2)([prev_states0[0][i] * states[i+2][3], prev_states0[1][i] * states[i+2][4]]);
is_reveal0[i] <== MultiAND(3)([out, is_substr0[i], is_consecutive[i][2]]);
reveal0[i] <== in[i+1] * is_reveal0[i];
}
}
3 changes: 3 additions & 0 deletions packages/circom/tests/circuits/test_dollar2_regex.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include "./dollar2_regex.circom";

component main = Dollar2Regex(8);
126 changes: 122 additions & 4 deletions packages/circom/tests/dollar.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const wasm_tester = circom_tester.wasm;
jest.setTimeout(600000);
describe("Caret Regex", () => {
let circuit1;
let circuit2;
beforeAll(async () => {
writeFileSync(
path.join(__dirname, "./circuits/dollar1_regex.circom"),
Expand All @@ -27,9 +28,23 @@ describe("Caret Regex", () => {
option
);

writeFileSync(
path.join(__dirname, "./circuits/dollar2_regex.circom"),
compiler.genFromDecomposed(
readFileSync(
path.join(__dirname, "./circuits/dollar2.json"),
"utf8"
),
"Dollar2Regex"
)
);
circuit2 = await wasm_tester(
path.join(__dirname, "./circuits/test_dollar2_regex.circom"),
option
);
});

it("caret1 valid case 1", async () => {
it("dollar1 valid case 1", async () => {
const inputStr = `ab`;
const paddedStr = apis.padString(inputStr, 8);
const circuitInputs = {
Expand All @@ -54,8 +69,8 @@ describe("Caret Regex", () => {
}
});

it("caret1 invalid case 1", async () => {
const inputStr = `abcg`;
it("dollar1 invalid case 1", async () => {
const inputStr = `abg`;
const paddedStr = apis.padString(inputStr, 8);
const circuitInputs = {
msg: paddedStr,
Expand All @@ -68,6 +83,109 @@ describe("Caret Regex", () => {
}
});


it("dollar1 invalid case 2", async () => {
const inputStr = `18abcg`;
const paddedStr = apis.padString(inputStr, 8);
const circuitInputs = {
msg: paddedStr,
};
const witness = await circuit1.calculateWitness(circuitInputs);
await circuit1.checkConstraints(witness);
expect(0n).toEqual(witness[1]);
for (let idx = 0; idx < 8; ++idx) {
expect(0n).toEqual(witness[2 + idx]);
}
});

it("dollar2 valid case 1", async () => {
const inputStr = `xab`;
const paddedStr = apis.padString(inputStr, 8);
const circuitInputs = {
msg: paddedStr,
};
const witness = await circuit2.calculateWitness(circuitInputs);
await circuit2.checkConstraints(witness);
expect(1n).toEqual(witness[1]);
const prefixIdxes = apis.extractSubstrIdxes(
inputStr,
readFileSync(
path.join(__dirname, "./circuits/dollar2.json"),
"utf8"
)
)[0];
for (let idx = 0; idx < 8; ++idx) {
if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]);
} else {
expect(0n).toEqual(witness[2 + idx]);
}
}
});

it("dollar2 valid case 2", async () => {
const inputStr = `ak\nxab`;
const paddedStr = apis.padString(inputStr, 8);
const circuitInputs = {
msg: paddedStr,
};
const witness = await circuit2.calculateWitness(circuitInputs);
await circuit2.checkConstraints(witness);
expect(1n).toEqual(witness[1]);
const prefixIdxes = apis.extractSubstrIdxes(
inputStr,
readFileSync(
path.join(__dirname, "./circuits/dollar2.json"),
"utf8"
)
)[0];
for (let idx = 0; idx < 8; ++idx) {
if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]);
} else {
expect(0n).toEqual(witness[2 + idx]);
}
}
});

it("dollar2 invalid case 1", async () => {
const inputStr = `abg`;
const paddedStr = apis.padString(inputStr, 8);
const circuitInputs = {
msg: paddedStr,
};
const witness = await circuit2.calculateWitness(circuitInputs);
await circuit2.checkConstraints(witness);
expect(0n).toEqual(witness[1]);
for (let idx = 0; idx < 8; ++idx) {
expect(0n).toEqual(witness[2 + idx]);
}
});

it("dollar2 invalid case 2", async () => {
const inputStr = `\nabg`;
const paddedStr = apis.padString(inputStr, 8);
const circuitInputs = {
msg: paddedStr,
};
const witness = await circuit2.calculateWitness(circuitInputs);
await circuit2.checkConstraints(witness);
expect(0n).toEqual(witness[1]);
for (let idx = 0; idx < 8; ++idx) {
expect(0n).toEqual(witness[2 + idx]);
}
});

it("dollar2 invalid case 2", async () => {
const inputStr = `\nabg`;
const paddedStr = apis.padString(inputStr, 8);
const circuitInputs = {
msg: paddedStr,
};
const witness = await circuit2.calculateWitness(circuitInputs);
await circuit2.checkConstraints(witness);
expect(0n).toEqual(witness[1]);
for (let idx = 0; idx < 8; ++idx) {
expect(0n).toEqual(witness[2 + idx]);
}
});
});

0 comments on commit 5863518

Please sign in to comment.