Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/fix select regex reveal #214

Merged
merged 2 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions packages/circuits/tests/select-regex-reveal.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { wasm } from "circom_tester";
import path from "path";


describe("Select Regex Reveal", () => {
jest.setTimeout(10 * 60 * 1000); // 10 minutes

let circuit: any;

beforeAll(async () => {
circuit = await wasm(
path.join(__dirname, "./test-circuits/select-regex-reveal-test.circom"),
{
recompile: true,
include: path.join(__dirname, "../../../node_modules"),
}
);
});

it("should reveal the substring with maximum revealed length", async function () {
let input = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const startIndex = Math.floor(Math.random() * 24);
const revealed = Array.from("zk email").map(char => char.charCodeAt(0));
for (let i = 0; i < revealed.length; i++) {
input[startIndex + i] = revealed[i];
}
const witness = await circuit.calculateWitness({
in: input,
startIndex: startIndex,
});
await circuit.checkConstraints(witness);
await circuit.assertOut(witness, { out: revealed })
});

it("should reveal the substring with non-maximum revealed length", async function () {
let input = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const startIndex = 30;
const revealed = Array.from("zk").map(char => char.charCodeAt(0));
for (let i = 0; i < revealed.length; i++) {
input[startIndex + i] = revealed[i];
}
const witness = await circuit.calculateWitness({
in: input,
startIndex: startIndex,
});
await circuit.checkConstraints(witness);
await circuit.assertOut(witness, { out: revealed.concat([0, 0, 0, 0, 0, 0]) })
});

it("should fail when all zero", async function () {
let input = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const startIndex = Math.floor(Math.random() * 32);
try {
const witness = await circuit.calculateWitness({
in: input,
startIndex: startIndex,
});
await circuit.checkConstraints(witness);
} catch (error) {
expect((error as Error).message).toMatch("Assert Failed");
}
});

it("should fail when startIndex is 0", async function () {
let input = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const startIndex = 1 + Math.floor(Math.random() * 24);
const revealed = Array.from("zk email").map(char => char.charCodeAt(0));
for (let i = 0; i < revealed.length; i++) {
input[startIndex + i] = revealed[i];
}
try {
const witness = await circuit.calculateWitness({
in: input,
startIndex: startIndex - 1,
});
await circuit.checkConstraints(witness);
} catch (error) {
expect((error as Error).message).toMatch("Assert Failed");
}
});

it("should fail when startIndex is not before 0", async function () {
let input = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const startIndex = Math.floor(Math.random() * 23);
const revealed = Array.from("zk email").map(char => char.charCodeAt(0));
for (let i = 0; i < revealed.length; i++) {
input[startIndex + i] = revealed[i];
}
try {
const witness = await circuit.calculateWitness({
in: input,
startIndex: startIndex + 1,
});
await circuit.checkConstraints(witness);
} catch (error) {
expect((error as Error).message).toMatch("Assert Failed");
}
});

it("should fail when startIndex is larger than max length", async function () {
let input = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const startIndex = Math.floor(Math.random() * 24);
const revealed = Array.from("zk email").map(char => char.charCodeAt(0));
for (let i = 0; i < revealed.length; i++) {
input[startIndex + i] = revealed[i];
}
try {
const witness = await circuit.calculateWitness({
in: input,
startIndex: 32
});
await circuit.checkConstraints(witness);
} catch (error) {
expect((error as Error).message).toMatch("Assert Failed");
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.1.6;

include "../../utils/regex.circom";

component main = SelectRegexReveal(32,8);
5 changes: 5 additions & 0 deletions packages/circuits/utils/regex.circom
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ include "./bytes.circom";
/// @title SelectRegexReveal
/// @notice Returns reveal bytes of a regex match from the input
/// @notice Verifies data before and after (maxRevealLen) reveal part is zero
/// @notice Assumes that there is only one consecutive sequence of non-zero bytes in `in`.
/// @param maxArrayLen Maximum length of the input array
/// @param maxRevealLen Maximum length of the reveal part
/// @input in Input array; assumes elements to be bytes
Expand All @@ -26,6 +27,10 @@ template SelectRegexReveal(maxArrayLen, maxRevealLen) {
signal isPreviousZero[maxArrayLen];
signal isAboveMaxRevealLen[maxArrayLen];

// Assert startIndex < maxArrayLen
Copy link
Member

@saleel saleel Aug 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SoraSuegami Isn't this check already enforced in VarShiftLeft - https://github.com/zkemail/zk-email-verify/blob/main/packages/circuits/utils/array.circom#L121-L122 ?

(Num2Bits will fail if out of bounds)

Copy link
Member

@saleel saleel Aug 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SoraSuegami ^ Ignore above comment. I think we need both (bit range check and less thank check).

signal isValidStartIndex <== LessThan(bitLength)([startIndex, maxArrayLen]);
isValidStartIndex === 1;

isPreviousZero[0] <== 1;
for(var i = 0; i < maxArrayLen; i++) {
isStartIndex[i] <== IsEqual()([i, startIndex]);
Expand Down
Loading