diff --git a/packages/circom/tests/caret.test.js b/packages/circom/tests/caret.test.js index 909732d..d4ffdfd 100644 --- a/packages/circom/tests/caret.test.js +++ b/packages/circom/tests/caret.test.js @@ -104,7 +104,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret1.json"), + path.join(__dirname, "./circuits/caret1.json"), "utf8" ) )[0]; @@ -129,7 +129,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret1.json"), + path.join(__dirname, "./circuits/caret1.json"), "utf8" ) )[0]; @@ -150,7 +150,7 @@ describe("Caret Regex", () => { }; const witness = await circuit1.calculateWitness(circuitInputs); await circuit1.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } @@ -164,7 +164,7 @@ describe("Caret Regex", () => { }; const witness = await circuit1.calculateWitness(circuitInputs); await circuit1.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } @@ -183,7 +183,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret2.json"), + path.join(__dirname, "./circuits/caret2.json"), "utf8" ) )[0]; @@ -208,7 +208,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret2.json"), + path.join(__dirname, "./circuits/caret2.json"), "utf8" ) )[0]; @@ -233,7 +233,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret2.json"), + path.join(__dirname, "./circuits/caret2.json"), "utf8" ) )[0]; @@ -254,14 +254,14 @@ describe("Caret Regex", () => { }; const witness = await circuit2.calculateWitness(circuitInputs); await circuit2.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } }); it("caret3 valid case 1", async () => { - const inputStr = `a7hv8a9b`; + const inputStr = `bb817267`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, @@ -272,7 +272,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret3.json"), + path.join(__dirname, "./circuits/caret3.json"), "utf8" ) )[0]; @@ -285,8 +285,8 @@ describe("Caret Regex", () => { } }); - it("caret3 invalid case 1", async () => { - const inputStr = ``; + it("caret3 valid case 2", async () => { + const inputStr = `818abbb9`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, @@ -297,7 +297,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret3.json"), + path.join(__dirname, "./circuits/caret3.json"), "utf8" ) )[0]; @@ -310,8 +310,22 @@ describe("Caret Regex", () => { } }); + it("caret3 invalid case 1", async () => { + const inputStr = `81b`; + const paddedStr = apis.padString(inputStr, 8); + const circuitInputs = { + msg: paddedStr, + }; + const witness = await circuit3.calculateWitness(circuitInputs); + await circuit3.checkConstraints(witness); + expect(0n).toEqual(witness[1]); + for (let idx = 0; idx < 8; ++idx) { + expect(0n).toEqual(witness[2 + idx]); + } + }); + it("caret4 valid case 1", async () => { - const inputStr = `abaaabba`; + const inputStr = `xabaaabb`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, @@ -322,7 +336,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret4.json"), + path.join(__dirname, "./circuits/caret4.json"), "utf8" ) )[0]; @@ -336,7 +350,7 @@ describe("Caret Regex", () => { }); it("caret4 valid case 2", async () => { - const inputStr = `baab82ab`; + const inputStr = `xbaab82a`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, @@ -347,7 +361,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret4.json"), + path.join(__dirname, "./circuits/caret4.json"), "utf8" ) )[0]; @@ -361,7 +375,7 @@ describe("Caret Regex", () => { }); it("caret4 valid case 3", async () => { - const inputStr = `7w1\nabba`; + const inputStr = `7w1\nxabb`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, @@ -372,7 +386,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret4.json"), + path.join(__dirname, "./circuits/caret4.json"), "utf8" ) )[0]; @@ -386,7 +400,7 @@ describe("Caret Regex", () => { }); it("caret4 valid case 4", async () => { - const inputStr = `7w\nbbba9`; + const inputStr = `7w\nxbbb9`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, @@ -397,7 +411,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret4.json"), + path.join(__dirname, "./circuits/caret4.json"), "utf8" ) )[0]; @@ -412,35 +426,35 @@ describe("Caret Regex", () => { it("caret4 invalid case 1", async () => { - const inputStr = `7w1nabba`; + const inputStr = `7w1nxaba`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, }; const witness = await circuit4.calculateWitness(circuitInputs); await circuit4.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } }); it("caret4 invalid case 2", async () => { - const inputStr = `7wnbbba9`; + const inputStr = `abba\nx`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, }; const witness = await circuit4.calculateWitness(circuitInputs); await circuit4.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } }); it("caret5 valid case 1", async () => { - const inputStr = `defabc81`; + const inputStr = `xdefabc1`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, @@ -451,7 +465,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret5.json"), + path.join(__dirname, "./circuits/caret5.json"), "utf8" ) )[0]; @@ -465,7 +479,7 @@ describe("Caret Regex", () => { }); it("caret5 valid case 2", async () => { - const inputStr = `91\n9eabc`; + const inputStr = `9\nx9eabc`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, @@ -476,7 +490,7 @@ describe("Caret Regex", () => { const prefixIdxes = apis.extractSubstrIdxes( inputStr, readFileSync( - path.join(__dirname, "../circuits/common/caret5.json"), + path.join(__dirname, "./circuits/caret5.json"), "utf8" ) )[0]; @@ -490,60 +504,61 @@ describe("Caret Regex", () => { }); it("caret5 invalid case 1", async () => { - const inputStr = `abc`; + const inputStr = `xabc`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, }; const witness = await circuit5.calculateWitness(circuitInputs); await circuit5.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } }); - it("caret5 invalid case 2", async () => { - const inputStr = `a8abc8`; + const inputStr = `1\ndef`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, }; const witness = await circuit5.calculateWitness(circuitInputs); await circuit5.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } }); - it("caret5 invalid case 2", async () => { - const inputStr = `71\na81ma`; + + + it("caret5 invalid case 3", async () => { + const inputStr = `a8abc8`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, }; const witness = await circuit5.calculateWitness(circuitInputs); await circuit5.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } }); - - it("caret5 invalid case 3", async () => { - const inputStr = `91n9eabc`; + it("caret5 invalid case 4", async () => { + const inputStr = `71\na81ma`; const paddedStr = apis.padString(inputStr, 8); const circuitInputs = { msg: paddedStr, }; const witness = await circuit5.calculateWitness(circuitInputs); await circuit5.checkConstraints(witness); - expect(1n).toEqual(witness[1]); + expect(0n).toEqual(witness[1]); for (let idx = 0; idx < 8; ++idx) { expect(0n).toEqual(witness[2 + idx]); } }); + }); diff --git a/packages/circom/tests/circuits/caret1_regex.circom b/packages/circom/tests/circuits/caret1_regex.circom index 40521ea..4fd42a8 100644 --- a/packages/circom/tests/circuits/caret1_regex.circom +++ b/packages/circom/tests/circuits/caret1_regex.circom @@ -14,52 +14,60 @@ template Caret1Regex(msg_bytes) { in[i+1] <== msg[i]; } - component eq[1][num_bytes]; - component and[1][num_bytes]; - signal states[num_bytes+1][2]; - signal states_tmp[num_bytes+1][2]; + component eq[2][num_bytes]; + component and[2][num_bytes]; + signal states[num_bytes+1][3]; + signal states_tmp[num_bytes+1][3]; signal from_zero_enabled[num_bytes+1]; from_zero_enabled[num_bytes] <== 0; component state_changed[num_bytes]; - for (var i = 1; i < 2; i++) { + for (var i = 1; i < 3; i++) { states[0][i] <== 0; } for (var i = 0; i < num_bytes; i++) { - state_changed[i] = MultiOR(1); + state_changed[i] = MultiOR(2); states[i][0] <== 1; eq[0][i] = IsEqual(); eq[0][i].in[0] <== in[i]; - eq[0][i].in[1] <== 97; + eq[0][i].in[1] <== 255; and[0][i] = AND(); and[0][i].a <== states[i][0]; and[0][i].b <== eq[0][i].out; states_tmp[i+1][1] <== 0; - from_zero_enabled[i] <== MultiNOR(1)([states_tmp[i+1][1]]); + eq[1][i] = IsEqual(); + eq[1][i].in[0] <== in[i]; + eq[1][i].in[1] <== 97; + and[1][i] = AND(); + and[1][i].a <== states[i][1]; + and[1][i].b <== eq[1][i].out; + states[i+1][2] <== and[1][i].out; + from_zero_enabled[i] <== MultiNOR(2)([states_tmp[i+1][1], states[i+1][2]]); 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]; } component final_state_result = MultiOR(num_bytes+1); for (var i = 0; i <= num_bytes; i++) { - final_state_result.in[i] <== states[i][1]; + final_state_result.in[i] <== states[i][2]; } out <== final_state_result.out; 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][1] * (1 - is_consecutive[msg_bytes-i][2]) + is_consecutive[msg_bytes-i][2]; + is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][2] * (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][1], is_consecutive[msg_bytes-1-i][1]]); + is_consecutive[msg_bytes-1-i][2] <== ORAnd()([(1 - from_zero_enabled[msg_bytes-i+1]), states[num_bytes-i][2], is_consecutive[msg_bytes-1-i][1]]); } - // substrings calculated: [{(0, 1)}] + // substrings calculated: [{(1, 2)}] 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: [(0, 1)] - is_substr0[i] <== MultiOR(1)([states[i+1][0] * states[i+2][1]]); + // the 0-th substring transitions: [(1, 2)] + is_substr0[i] <== MultiOR(1)([states[i+1][1] * states[i+2][2]]); is_reveal0[i] <== is_substr0[i] * is_consecutive[i][2]; reveal0[i] <== in[i+1] * is_reveal0[i]; } diff --git a/packages/circom/tests/circuits/caret2_regex.circom b/packages/circom/tests/circuits/caret2_regex.circom index 0f3ff7e..725b0cc 100644 --- a/packages/circom/tests/circuits/caret2_regex.circom +++ b/packages/circom/tests/circuits/caret2_regex.circom @@ -14,63 +14,71 @@ template Caret2Regex(msg_bytes) { in[i+1] <== msg[i]; } - component eq[3][num_bytes]; - component and[1][num_bytes]; + component eq[4][num_bytes]; + component and[2][num_bytes]; component multi_or[1][num_bytes]; - signal states[num_bytes+1][2]; - signal states_tmp[num_bytes+1][2]; + signal states[num_bytes+1][3]; + signal states_tmp[num_bytes+1][3]; signal from_zero_enabled[num_bytes+1]; from_zero_enabled[num_bytes] <== 0; component state_changed[num_bytes]; - for (var i = 1; i < 2; i++) { + for (var i = 1; i < 3; i++) { states[0][i] <== 0; } for (var i = 0; i < num_bytes; i++) { - state_changed[i] = MultiOR(1); + state_changed[i] = MultiOR(2); states[i][0] <== 1; eq[0][i] = IsEqual(); eq[0][i].in[0] <== in[i]; - eq[0][i].in[1] <== 97; + eq[0][i].in[1] <== 255; + and[0][i] = AND(); + and[0][i].a <== states[i][0]; + and[0][i].b <== eq[0][i].out; + states_tmp[i+1][1] <== 0; eq[1][i] = IsEqual(); eq[1][i].in[0] <== in[i]; - eq[1][i].in[1] <== 98; + eq[1][i].in[1] <== 97; eq[2][i] = IsEqual(); eq[2][i].in[0] <== in[i]; - eq[2][i].in[1] <== 99; - and[0][i] = AND(); - and[0][i].a <== states[i][0]; + eq[2][i].in[1] <== 98; + eq[3][i] = IsEqual(); + eq[3][i].in[0] <== in[i]; + eq[3][i].in[1] <== 99; + and[1][i] = AND(); + and[1][i].a <== states[i][1]; multi_or[0][i] = MultiOR(3); - multi_or[0][i].in[0] <== eq[0][i].out; - multi_or[0][i].in[1] <== eq[1][i].out; - multi_or[0][i].in[2] <== eq[2][i].out; - and[0][i].b <== multi_or[0][i].out; - states_tmp[i+1][1] <== 0; - from_zero_enabled[i] <== MultiNOR(1)([states_tmp[i+1][1]]); + multi_or[0][i].in[0] <== eq[1][i].out; + multi_or[0][i].in[1] <== eq[2][i].out; + multi_or[0][i].in[2] <== eq[3][i].out; + and[1][i].b <== multi_or[0][i].out; + states[i+1][2] <== and[1][i].out; + from_zero_enabled[i] <== MultiNOR(2)([states_tmp[i+1][1], states[i+1][2]]); 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]; } component final_state_result = MultiOR(num_bytes+1); for (var i = 0; i <= num_bytes; i++) { - final_state_result.in[i] <== states[i][1]; + final_state_result.in[i] <== states[i][2]; } out <== final_state_result.out; 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][1] * (1 - is_consecutive[msg_bytes-i][2]) + is_consecutive[msg_bytes-i][2]; + is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][2] * (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][1], is_consecutive[msg_bytes-1-i][1]]); + is_consecutive[msg_bytes-1-i][2] <== ORAnd()([(1 - from_zero_enabled[msg_bytes-i+1]), states[num_bytes-i][2], is_consecutive[msg_bytes-1-i][1]]); } - // substrings calculated: [{(0, 1)}] + // substrings calculated: [{(1, 2)}] 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: [(0, 1)] - is_substr0[i] <== MultiOR(1)([states[i+1][0] * states[i+2][1]]); + // the 0-th substring transitions: [(1, 2)] + is_substr0[i] <== MultiOR(1)([states[i+1][1] * states[i+2][2]]); is_reveal0[i] <== is_substr0[i] * is_consecutive[i][2]; reveal0[i] <== in[i+1] * is_reveal0[i]; } diff --git a/packages/circom/tests/circuits/caret3.json b/packages/circom/tests/circuits/caret3.json index 23a77bd..8d1c6e6 100644 --- a/packages/circom/tests/circuits/caret3.json +++ b/packages/circom/tests/circuits/caret3.json @@ -1,8 +1,12 @@ { "parts": [ + { + "is_public": false, + "regex_def": "(^|a)" + }, { "is_public": true, - "regex_def": "^.+" + "regex_def": "b+" } ] } \ No newline at end of file diff --git a/packages/circom/tests/circuits/caret3_regex.circom b/packages/circom/tests/circuits/caret3_regex.circom index bda330e..d692698 100644 --- a/packages/circom/tests/circuits/caret3_regex.circom +++ b/packages/circom/tests/circuits/caret3_regex.circom @@ -2,7 +2,7 @@ pragma circom 2.1.5; include "@zk-email/zk-regex-circom/circuits/regex_helpers.circom"; -// regex: ^.+ +// regex: (^|a)b+ template Caret3Regex(msg_bytes) { signal input msg[msg_bytes]; signal output out; @@ -14,394 +14,73 @@ template Caret3Regex(msg_bytes) { in[i+1] <== msg[i]; } - component eq[47][num_bytes]; - component lt[12][num_bytes]; - component and[29][num_bytes]; - component multi_or[7][num_bytes]; - signal states[num_bytes+1][9]; - signal states_tmp[num_bytes+1][9]; + component eq[3][num_bytes]; + component and[3][num_bytes]; + component multi_or[2][num_bytes]; + signal states[num_bytes+1][3]; + signal states_tmp[num_bytes+1][3]; signal from_zero_enabled[num_bytes+1]; from_zero_enabled[num_bytes] <== 0; component state_changed[num_bytes]; - for (var i = 1; i < 9; i++) { + for (var i = 1; i < 3; i++) { states[0][i] <== 0; } for (var i = 0; i < num_bytes; i++) { - state_changed[i] = MultiOR(8); + state_changed[i] = MultiOR(2); states[i][0] <== 1; - lt[0][i] = LessEqThan(8); - lt[0][i].in[0] <== 194; - lt[0][i].in[1] <== in[i]; - lt[1][i] = LessEqThan(8); - lt[1][i].in[0] <== in[i]; - lt[1][i].in[1] <== 223; - and[0][i] = AND(); - and[0][i].a <== lt[0][i].out; - and[0][i].b <== lt[1][i].out; - and[1][i] = AND(); - and[1][i].a <== states[i][0]; - and[1][i].b <== and[0][i].out; - lt[2][i] = LessEqThan(8); - lt[2][i].in[0] <== 160; - lt[2][i].in[1] <== in[i]; - lt[3][i] = LessEqThan(8); - lt[3][i].in[0] <== in[i]; - lt[3][i].in[1] <== 191; - and[2][i] = AND(); - and[2][i].a <== lt[2][i].out; - and[2][i].b <== lt[3][i].out; - and[3][i] = AND(); - and[3][i].a <== states[i][2]; - and[3][i].b <== and[2][i].out; - lt[4][i] = LessEqThan(8); - lt[4][i].in[0] <== 128; - lt[4][i].in[1] <== in[i]; - lt[5][i] = LessEqThan(8); - lt[5][i].in[0] <== in[i]; - lt[5][i].in[1] <== 191; - and[4][i] = AND(); - and[4][i].a <== lt[4][i].out; - and[4][i].b <== lt[5][i].out; - and[5][i] = AND(); - and[5][i].a <== states[i][3]; - and[5][i].b <== and[4][i].out; - lt[6][i] = LessEqThan(8); - lt[6][i].in[0] <== 128; - lt[6][i].in[1] <== in[i]; - lt[7][i] = LessEqThan(8); - lt[7][i].in[0] <== in[i]; - lt[7][i].in[1] <== 159; - and[6][i] = AND(); - and[6][i].a <== lt[6][i].out; - and[6][i].b <== lt[7][i].out; - and[7][i] = AND(); - and[7][i].a <== states[i][4]; - and[7][i].b <== and[6][i].out; - and[8][i] = AND(); - and[8][i].a <== states[i][8]; - and[8][i].b <== and[0][i].out; - multi_or[0][i] = MultiOR(4); - multi_or[0][i].in[0] <== and[3][i].out; - multi_or[0][i].in[1] <== and[5][i].out; - multi_or[0][i].in[2] <== and[7][i].out; - multi_or[0][i].in[3] <== and[8][i].out; - states_tmp[i+1][1] <== multi_or[0][i].out; eq[0][i] = IsEqual(); eq[0][i].in[0] <== in[i]; - eq[0][i].in[1] <== 224; - and[9][i] = AND(); - and[9][i].a <== states[i][0]; - and[9][i].b <== eq[0][i].out; - and[10][i] = AND(); - and[10][i].a <== states[i][8]; - and[10][i].b <== eq[0][i].out; - states_tmp[i+1][2] <== and[10][i].out; + eq[0][i].in[1] <== 97; eq[1][i] = IsEqual(); eq[1][i].in[0] <== in[i]; - eq[1][i].in[1] <== 225; + 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] <== 226; - eq[3][i] = IsEqual(); - eq[3][i].in[0] <== in[i]; - eq[3][i].in[1] <== 227; - eq[4][i] = IsEqual(); - eq[4][i].in[0] <== in[i]; - eq[4][i].in[1] <== 228; - eq[5][i] = IsEqual(); - eq[5][i].in[0] <== in[i]; - eq[5][i].in[1] <== 229; - eq[6][i] = IsEqual(); - eq[6][i].in[0] <== in[i]; - eq[6][i].in[1] <== 230; - eq[7][i] = IsEqual(); - eq[7][i].in[0] <== in[i]; - eq[7][i].in[1] <== 231; - eq[8][i] = IsEqual(); - eq[8][i].in[0] <== in[i]; - eq[8][i].in[1] <== 232; - eq[9][i] = IsEqual(); - eq[9][i].in[0] <== in[i]; - eq[9][i].in[1] <== 233; - eq[10][i] = IsEqual(); - eq[10][i].in[0] <== in[i]; - eq[10][i].in[1] <== 234; - eq[11][i] = IsEqual(); - eq[11][i].in[0] <== in[i]; - eq[11][i].in[1] <== 235; - eq[12][i] = IsEqual(); - eq[12][i].in[0] <== in[i]; - eq[12][i].in[1] <== 236; - eq[13][i] = IsEqual(); - eq[13][i].in[0] <== in[i]; - eq[13][i].in[1] <== 238; - eq[14][i] = IsEqual(); - eq[14][i].in[0] <== in[i]; - eq[14][i].in[1] <== 239; - and[11][i] = AND(); - and[11][i].a <== states[i][0]; - multi_or[1][i] = MultiOR(14); - multi_or[1][i].in[0] <== eq[1][i].out; - multi_or[1][i].in[1] <== eq[2][i].out; - multi_or[1][i].in[2] <== eq[3][i].out; - multi_or[1][i].in[3] <== eq[4][i].out; - multi_or[1][i].in[4] <== eq[5][i].out; - multi_or[1][i].in[5] <== eq[6][i].out; - multi_or[1][i].in[6] <== eq[7][i].out; - multi_or[1][i].in[7] <== eq[8][i].out; - multi_or[1][i].in[8] <== eq[9][i].out; - multi_or[1][i].in[9] <== eq[10][i].out; - multi_or[1][i].in[10] <== eq[11][i].out; - multi_or[1][i].in[11] <== eq[12][i].out; - multi_or[1][i].in[12] <== eq[13][i].out; - multi_or[1][i].in[13] <== eq[14][i].out; - and[11][i].b <== multi_or[1][i].out; - lt[8][i] = LessEqThan(8); - lt[8][i].in[0] <== 144; - lt[8][i].in[1] <== in[i]; - lt[9][i] = LessEqThan(8); - lt[9][i].in[0] <== in[i]; - lt[9][i].in[1] <== 191; - and[12][i] = AND(); - and[12][i].a <== lt[8][i].out; - and[12][i].b <== lt[9][i].out; - and[13][i] = AND(); - and[13][i].a <== states[i][5]; - and[13][i].b <== and[12][i].out; - and[14][i] = AND(); - and[14][i].a <== states[i][6]; - and[14][i].b <== and[4][i].out; - eq[15][i] = IsEqual(); - eq[15][i].in[0] <== in[i]; - eq[15][i].in[1] <== 128; - eq[16][i] = IsEqual(); - eq[16][i].in[0] <== in[i]; - eq[16][i].in[1] <== 129; - eq[17][i] = IsEqual(); - eq[17][i].in[0] <== in[i]; - eq[17][i].in[1] <== 130; - eq[18][i] = IsEqual(); - eq[18][i].in[0] <== in[i]; - eq[18][i].in[1] <== 131; - eq[19][i] = IsEqual(); - eq[19][i].in[0] <== in[i]; - eq[19][i].in[1] <== 132; - eq[20][i] = IsEqual(); - eq[20][i].in[0] <== in[i]; - eq[20][i].in[1] <== 133; - eq[21][i] = IsEqual(); - eq[21][i].in[0] <== in[i]; - eq[21][i].in[1] <== 134; - eq[22][i] = IsEqual(); - eq[22][i].in[0] <== in[i]; - eq[22][i].in[1] <== 135; - eq[23][i] = IsEqual(); - eq[23][i].in[0] <== in[i]; - eq[23][i].in[1] <== 136; - eq[24][i] = IsEqual(); - eq[24][i].in[0] <== in[i]; - eq[24][i].in[1] <== 137; - eq[25][i] = IsEqual(); - eq[25][i].in[0] <== in[i]; - eq[25][i].in[1] <== 138; - eq[26][i] = IsEqual(); - eq[26][i].in[0] <== in[i]; - eq[26][i].in[1] <== 139; - eq[27][i] = IsEqual(); - eq[27][i].in[0] <== in[i]; - eq[27][i].in[1] <== 140; - eq[28][i] = IsEqual(); - eq[28][i].in[0] <== in[i]; - eq[28][i].in[1] <== 141; - eq[29][i] = IsEqual(); - eq[29][i].in[0] <== in[i]; - eq[29][i].in[1] <== 142; - eq[30][i] = IsEqual(); - eq[30][i].in[0] <== in[i]; - eq[30][i].in[1] <== 143; - and[15][i] = AND(); - and[15][i].a <== states[i][7]; - multi_or[2][i] = MultiOR(16); - multi_or[2][i].in[0] <== eq[15][i].out; - multi_or[2][i].in[1] <== eq[16][i].out; - multi_or[2][i].in[2] <== eq[17][i].out; - multi_or[2][i].in[3] <== eq[18][i].out; - multi_or[2][i].in[4] <== eq[19][i].out; - multi_or[2][i].in[5] <== eq[20][i].out; - multi_or[2][i].in[6] <== eq[21][i].out; - multi_or[2][i].in[7] <== eq[22][i].out; - multi_or[2][i].in[8] <== eq[23][i].out; - multi_or[2][i].in[9] <== eq[24][i].out; - multi_or[2][i].in[10] <== eq[25][i].out; - multi_or[2][i].in[11] <== eq[26][i].out; - multi_or[2][i].in[12] <== eq[27][i].out; - multi_or[2][i].in[13] <== eq[28][i].out; - multi_or[2][i].in[14] <== eq[29][i].out; - multi_or[2][i].in[15] <== eq[30][i].out; - and[15][i].b <== multi_or[2][i].out; - and[16][i] = AND(); - and[16][i].a <== states[i][8]; - and[16][i].b <== multi_or[1][i].out; - multi_or[3][i] = MultiOR(4); - multi_or[3][i].in[0] <== and[13][i].out; - multi_or[3][i].in[1] <== and[14][i].out; - multi_or[3][i].in[2] <== and[15][i].out; - multi_or[3][i].in[3] <== and[16][i].out; - states_tmp[i+1][3] <== multi_or[3][i].out; - eq[31][i] = IsEqual(); - eq[31][i].in[0] <== in[i]; - eq[31][i].in[1] <== 237; - and[17][i] = AND(); - and[17][i].a <== states[i][0]; - and[17][i].b <== eq[31][i].out; - and[18][i] = AND(); - and[18][i].a <== states[i][8]; - and[18][i].b <== eq[31][i].out; - states_tmp[i+1][4] <== and[18][i].out; - eq[32][i] = IsEqual(); - eq[32][i].in[0] <== in[i]; - eq[32][i].in[1] <== 240; - and[19][i] = AND(); - and[19][i].a <== states[i][0]; - and[19][i].b <== eq[32][i].out; - and[20][i] = AND(); - and[20][i].a <== states[i][8]; - and[20][i].b <== eq[32][i].out; - states_tmp[i+1][5] <== and[20][i].out; - eq[33][i] = IsEqual(); - eq[33][i].in[0] <== in[i]; - eq[33][i].in[1] <== 241; - eq[34][i] = IsEqual(); - eq[34][i].in[0] <== in[i]; - eq[34][i].in[1] <== 242; - eq[35][i] = IsEqual(); - eq[35][i].in[0] <== in[i]; - eq[35][i].in[1] <== 243; - and[21][i] = AND(); - and[21][i].a <== states[i][0]; - multi_or[4][i] = MultiOR(3); - multi_or[4][i].in[0] <== eq[33][i].out; - multi_or[4][i].in[1] <== eq[34][i].out; - multi_or[4][i].in[2] <== eq[35][i].out; - and[21][i].b <== multi_or[4][i].out; - and[22][i] = AND(); - and[22][i].a <== states[i][8]; - and[22][i].b <== multi_or[4][i].out; - states_tmp[i+1][6] <== and[22][i].out; - eq[36][i] = IsEqual(); - eq[36][i].in[0] <== in[i]; - eq[36][i].in[1] <== 244; - and[23][i] = AND(); - and[23][i].a <== states[i][0]; - and[23][i].b <== eq[36][i].out; - and[24][i] = AND(); - and[24][i].a <== states[i][8]; - and[24][i].b <== eq[36][i].out; - states_tmp[i+1][7] <== and[24][i].out; - lt[10][i] = LessEqThan(8); - lt[10][i].in[0] <== 11; - lt[10][i].in[1] <== in[i]; - lt[11][i] = LessEqThan(8); - lt[11][i].in[0] <== in[i]; - lt[11][i].in[1] <== 127; - and[25][i] = AND(); - and[25][i].a <== lt[10][i].out; - and[25][i].b <== lt[11][i].out; - eq[37][i] = IsEqual(); - eq[37][i].in[0] <== in[i]; - eq[37][i].in[1] <== 0; - eq[38][i] = IsEqual(); - eq[38][i].in[0] <== in[i]; - eq[38][i].in[1] <== 1; - eq[39][i] = IsEqual(); - eq[39][i].in[0] <== in[i]; - eq[39][i].in[1] <== 2; - eq[40][i] = IsEqual(); - eq[40][i].in[0] <== in[i]; - eq[40][i].in[1] <== 3; - eq[41][i] = IsEqual(); - eq[41][i].in[0] <== in[i]; - eq[41][i].in[1] <== 4; - eq[42][i] = IsEqual(); - eq[42][i].in[0] <== in[i]; - eq[42][i].in[1] <== 5; - eq[43][i] = IsEqual(); - eq[43][i].in[0] <== in[i]; - eq[43][i].in[1] <== 6; - eq[44][i] = IsEqual(); - eq[44][i].in[0] <== in[i]; - eq[44][i].in[1] <== 7; - eq[45][i] = IsEqual(); - eq[45][i].in[0] <== in[i]; - eq[45][i].in[1] <== 8; - eq[46][i] = IsEqual(); - eq[46][i].in[0] <== in[i]; - eq[46][i].in[1] <== 9; - and[26][i] = AND(); - and[26][i].a <== states[i][0]; - multi_or[5][i] = MultiOR(11); - multi_or[5][i].in[0] <== and[25][i].out; - multi_or[5][i].in[1] <== eq[37][i].out; - multi_or[5][i].in[2] <== eq[38][i].out; - multi_or[5][i].in[3] <== eq[39][i].out; - multi_or[5][i].in[4] <== eq[40][i].out; - multi_or[5][i].in[5] <== eq[41][i].out; - multi_or[5][i].in[6] <== eq[42][i].out; - multi_or[5][i].in[7] <== eq[43][i].out; - multi_or[5][i].in[8] <== eq[44][i].out; - multi_or[5][i].in[9] <== eq[45][i].out; - multi_or[5][i].in[10] <== eq[46][i].out; - and[26][i].b <== multi_or[5][i].out; - and[27][i] = AND(); - and[27][i].a <== states[i][1]; - and[27][i].b <== and[4][i].out; - and[28][i] = AND(); - and[28][i].a <== states[i][8]; - and[28][i].b <== multi_or[5][i].out; - multi_or[6][i] = MultiOR(2); - multi_or[6][i].in[0] <== and[27][i].out; - multi_or[6][i].in[1] <== and[28][i].out; - states_tmp[i+1][8] <== multi_or[6][i].out; - from_zero_enabled[i] <== MultiNOR(8)([states_tmp[i+1][1], states_tmp[i+1][2], states_tmp[i+1][3], states_tmp[i+1][4], states_tmp[i+1][5], states_tmp[i+1][6], states_tmp[i+1][7], states_tmp[i+1][8]]); - states[i+1][1] <== MultiOR(2)([states_tmp[i+1][1], from_zero_enabled[i] * and[1][i].out]); - states[i+1][2] <== MultiOR(2)([states_tmp[i+1][2], from_zero_enabled[i] * and[9][i].out]); - states[i+1][3] <== MultiOR(2)([states_tmp[i+1][3], from_zero_enabled[i] * and[11][i].out]); - states[i+1][4] <== MultiOR(2)([states_tmp[i+1][4], from_zero_enabled[i] * and[17][i].out]); - states[i+1][5] <== MultiOR(2)([states_tmp[i+1][5], from_zero_enabled[i] * and[19][i].out]); - states[i+1][6] <== MultiOR(2)([states_tmp[i+1][6], from_zero_enabled[i] * and[21][i].out]); - states[i+1][7] <== MultiOR(2)([states_tmp[i+1][7], from_zero_enabled[i] * and[23][i].out]); - states[i+1][8] <== MultiOR(2)([states_tmp[i+1][8], from_zero_enabled[i] * and[26][i].out]); + eq[2][i].in[1] <== 98; + and[1][i] = AND(); + and[1][i].a <== states[i][1]; + and[1][i].b <== eq[2][i].out; + and[2][i] = AND(); + and[2][i].a <== states[i][2]; + and[2][i].b <== eq[2][i].out; + multi_or[1][i] = MultiOR(2); + multi_or[1][i].in[0] <== and[1][i].out; + multi_or[1][i].in[1] <== and[2][i].out; + states[i+1][2] <== multi_or[1][i].out; + from_zero_enabled[i] <== MultiNOR(2)([states_tmp[i+1][1], states[i+1][2]]); + 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]; - state_changed[i].in[4] <== states[i+1][5]; - state_changed[i].in[5] <== states[i+1][6]; - state_changed[i].in[6] <== states[i+1][7]; - state_changed[i].in[7] <== states[i+1][8]; } component final_state_result = MultiOR(num_bytes+1); for (var i = 0; i <= num_bytes; i++) { - final_state_result.in[i] <== states[i][8]; + final_state_result.in[i] <== states[i][2]; } out <== final_state_result.out; 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][8] * (1 - is_consecutive[msg_bytes-i][2]) + is_consecutive[msg_bytes-i][2]; + is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][2] * (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][8], is_consecutive[msg_bytes-1-i][1]]); + is_consecutive[msg_bytes-1-i][2] <== ORAnd()([(1 - from_zero_enabled[msg_bytes-i+1]), states[num_bytes-i][2], is_consecutive[msg_bytes-1-i][1]]); } - // substrings calculated: [{(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (1, 8), (2, 1), (3, 1), (4, 1), (5, 3), (6, 3), (7, 3), (8, 1), (8, 2), (8, 3), (8, 4), (8, 5), (8, 6), (8, 7), (8, 8)}] + // substrings calculated: [{(1, 2), (2, 2)}] 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: [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (1, 8), (2, 1), (3, 1), (4, 1), (5, 3), (6, 3), (7, 3), (8, 1), (8, 2), (8, 3), (8, 4), (8, 5), (8, 6), (8, 7), (8, 8)] - is_substr0[i] <== MultiOR(23)([states[i+1][0] * states[i+2][1], states[i+1][0] * states[i+2][2], states[i+1][0] * states[i+2][3], states[i+1][0] * states[i+2][4], states[i+1][0] * states[i+2][5], states[i+1][0] * states[i+2][6], states[i+1][0] * states[i+2][7], states[i+1][0] * states[i+2][8], states[i+1][1] * states[i+2][8], states[i+1][2] * states[i+2][1], states[i+1][3] * states[i+2][1], states[i+1][4] * states[i+2][1], states[i+1][5] * states[i+2][3], states[i+1][6] * states[i+2][3], states[i+1][7] * states[i+2][3], states[i+1][8] * states[i+2][1], states[i+1][8] * states[i+2][2], states[i+1][8] * states[i+2][3], states[i+1][8] * states[i+2][4], states[i+1][8] * states[i+2][5], states[i+1][8] * states[i+2][6], states[i+1][8] * states[i+2][7], states[i+1][8] * states[i+2][8]]); + // the 0-th substring transitions: [(1, 2), (2, 2)] + is_substr0[i] <== MultiOR(2)([states[i+1][1] * states[i+2][2], states[i+1][2] * states[i+2][2]]); is_reveal0[i] <== is_substr0[i] * is_consecutive[i][2]; reveal0[i] <== in[i+1] * is_reveal0[i]; } diff --git a/packages/circom/tests/circuits/caret4.json b/packages/circom/tests/circuits/caret4.json index 5ee7493..a8d097f 100644 --- a/packages/circom/tests/circuits/caret4.json +++ b/packages/circom/tests/circuits/caret4.json @@ -1,8 +1,12 @@ { "parts": [ + { + "is_public": false, + "regex_def": "(\n|^)x" + }, { "is_public": true, - "regex_def": "(\n|^)(a|b)+" + "regex_def": "(a|b)+" } ] } \ No newline at end of file diff --git a/packages/circom/tests/circuits/caret4_regex.circom b/packages/circom/tests/circuits/caret4_regex.circom index b906945..73e8524 100644 --- a/packages/circom/tests/circuits/caret4_regex.circom +++ b/packages/circom/tests/circuits/caret4_regex.circom @@ -2,7 +2,7 @@ pragma circom 2.1.5; include "@zk-email/zk-regex-circom/circuits/regex_helpers.circom"; -// regex: (\n|^)(a|b)+ +// regex: (\n|^)x(a|b)+ template Caret4Regex(msg_bytes) { signal input msg[msg_bytes]; signal output out; @@ -14,77 +14,87 @@ template Caret4Regex(msg_bytes) { in[i+1] <== msg[i]; } - component eq[3][num_bytes]; + component eq[5][num_bytes]; component and[4][num_bytes]; - component multi_or[2][num_bytes]; - signal states[num_bytes+1][3]; - signal states_tmp[num_bytes+1][3]; + component multi_or[3][num_bytes]; + signal states[num_bytes+1][4]; + signal states_tmp[num_bytes+1][4]; signal from_zero_enabled[num_bytes+1]; from_zero_enabled[num_bytes] <== 0; component state_changed[num_bytes]; - for (var i = 1; i < 3; i++) { + for (var i = 1; i < 4; i++) { states[0][i] <== 0; } for (var i = 0; i < num_bytes; i++) { - state_changed[i] = MultiOR(2); + state_changed[i] = MultiOR(3); states[i][0] <== 1; eq[0][i] = IsEqual(); eq[0][i].in[0] <== in[i]; - eq[0][i].in[1] <== 97; + eq[0][i].in[1] <== 10; eq[1][i] = IsEqual(); eq[1][i].in[0] <== in[i]; - eq[1][i].in[1] <== 98; + 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 <== multi_or[0][i].out; + 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; + eq[4][i] = IsEqual(); + eq[4][i].in[0] <== in[i]; + eq[4][i].in[1] <== 98; and[2][i] = AND(); and[2][i].a <== states[i][2]; - and[2][i].b <== multi_or[0][i].out; multi_or[1][i] = MultiOR(2); - multi_or[1][i].in[0] <== and[1][i].out; - multi_or[1][i].in[1] <== and[2][i].out; - states_tmp[i+1][1] <== multi_or[1][i].out; - eq[2][i] = IsEqual(); - eq[2][i].in[0] <== in[i]; - eq[2][i].in[1] <== 10; + multi_or[1][i].in[0] <== eq[3][i].out; + multi_or[1][i].in[1] <== eq[4][i].out; + and[2][i].b <== multi_or[1][i].out; and[3][i] = AND(); - and[3][i].a <== states[i][0]; - and[3][i].b <== eq[2][i].out; - states_tmp[i+1][2] <== 0; - from_zero_enabled[i] <== MultiNOR(2)([states_tmp[i+1][1], states_tmp[i+1][2]]); + and[3][i].a <== states[i][3]; + and[3][i].b <== multi_or[1][i].out; + multi_or[2][i] = MultiOR(2); + multi_or[2][i].in[0] <== and[2][i].out; + multi_or[2][i].in[1] <== and[3][i].out; + states[i+1][3] <== multi_or[2][i].out; + from_zero_enabled[i] <== MultiNOR(3)([states_tmp[i+1][1], states[i+1][2], states[i+1][3]]); states[i+1][1] <== MultiOR(2)([states_tmp[i+1][1], from_zero_enabled[i] * and[0][i].out]); - states[i+1][2] <== MultiOR(2)([states_tmp[i+1][2], from_zero_enabled[i] * and[3][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]; } component final_state_result = MultiOR(num_bytes+1); for (var i = 0; i <= num_bytes; i++) { - final_state_result.in[i] <== states[i][1]; + final_state_result.in[i] <== states[i][3]; } out <== final_state_result.out; 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][1] * (1 - is_consecutive[msg_bytes-i][2]) + is_consecutive[msg_bytes-i][2]; + is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][3] * (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][1], is_consecutive[msg_bytes-1-i][1]]); + is_consecutive[msg_bytes-1-i][2] <== ORAnd()([(1 - from_zero_enabled[msg_bytes-i+1]), states[num_bytes-i][3], is_consecutive[msg_bytes-1-i][1]]); } - // substrings calculated: [{(0, 1), (0, 2), (1, 1), (2, 1)}] + // substrings calculated: [{(2, 3), (3, 3)}] 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: [(0, 1), (0, 2), (1, 1), (2, 1)] - is_substr0[i] <== MultiOR(4)([states[i+1][0] * states[i+2][1], states[i+1][0] * states[i+2][2], states[i+1][1] * states[i+2][1], states[i+1][2] * states[i+2][1]]); + // the 0-th substring transitions: [(2, 3), (3, 3)] + is_substr0[i] <== MultiOR(2)([states[i+1][2] * states[i+2][3], states[i+1][3] * states[i+2][3]]); is_reveal0[i] <== is_substr0[i] * is_consecutive[i][2]; reveal0[i] <== in[i+1] * is_reveal0[i]; } diff --git a/packages/circom/tests/circuits/caret5.json b/packages/circom/tests/circuits/caret5.json index ccb614e..6d18627 100644 --- a/packages/circom/tests/circuits/caret5.json +++ b/packages/circom/tests/circuits/caret5.json @@ -1,8 +1,12 @@ { "parts": [ + { + "is_public": false, + "regex_def": "(\n|^)x" + }, { "is_public": true, - "regex_def": "(\n|^)[^abc]+" + "regex_def": "[^abc]+" } ] } \ No newline at end of file diff --git a/packages/circom/tests/circuits/caret5_regex.circom b/packages/circom/tests/circuits/caret5_regex.circom index a60bf6f..dbde513 100644 --- a/packages/circom/tests/circuits/caret5_regex.circom +++ b/packages/circom/tests/circuits/caret5_regex.circom @@ -2,7 +2,7 @@ pragma circom 2.1.5; include "@zk-email/zk-regex-circom/circuits/regex_helpers.circom"; -// regex: (\n|^)[^abc]+ +// regex: (\n|^)x[^abc]+ template Caret5Regex(msg_bytes) { signal input msg[msg_bytes]; signal output out; @@ -14,335 +14,366 @@ template Caret5Regex(msg_bytes) { in[i+1] <== msg[i]; } - component eq[37][num_bytes]; + component eq[40][num_bytes]; component lt[14][num_bytes]; - component and[30][num_bytes]; - component multi_or[7][num_bytes]; - signal states[num_bytes+1][9]; - signal states_tmp[num_bytes+1][9]; + component and[32][num_bytes]; + component multi_or[13][num_bytes]; + signal states[num_bytes+1][11]; + signal states_tmp[num_bytes+1][11]; signal from_zero_enabled[num_bytes+1]; from_zero_enabled[num_bytes] <== 0; component state_changed[num_bytes]; - for (var i = 1; i < 9; i++) { + for (var i = 1; i < 11; i++) { states[0][i] <== 0; } for (var i = 0; i < num_bytes; i++) { - state_changed[i] = MultiOR(8); + state_changed[i] = MultiOR(10); states[i][0] <== 1; + 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; lt[0][i] = LessEqThan(8); - lt[0][i].in[0] <== 0; + lt[0][i].in[0] <== 194; lt[0][i].in[1] <== in[i]; lt[1][i] = LessEqThan(8); lt[1][i].in[0] <== in[i]; - lt[1][i].in[1] <== 96; - and[0][i] = AND(); - and[0][i].a <== lt[0][i].out; - and[0][i].b <== lt[1][i].out; + lt[1][i].in[1] <== 223; + and[2][i] = AND(); + and[2][i].a <== lt[0][i].out; + and[2][i].b <== lt[1][i].out; + and[3][i] = AND(); + and[3][i].a <== states[i][2]; + and[3][i].b <== and[2][i].out; lt[2][i] = LessEqThan(8); - lt[2][i].in[0] <== 100; + lt[2][i].in[0] <== 160; lt[2][i].in[1] <== in[i]; lt[3][i] = LessEqThan(8); lt[3][i].in[0] <== in[i]; - lt[3][i].in[1] <== 127; - and[1][i] = AND(); - and[1][i].a <== lt[2][i].out; - and[1][i].b <== lt[3][i].out; - and[2][i] = AND(); - and[2][i].a <== states[i][0]; - multi_or[0][i] = MultiOR(2); - multi_or[0][i].in[0] <== and[0][i].out; - multi_or[0][i].in[1] <== and[1][i].out; - and[2][i].b <== multi_or[0][i].out; - and[3][i] = AND(); - and[3][i].a <== states[i][1]; - and[3][i].b <== multi_or[0][i].out; + lt[3][i].in[1] <== 191; + and[4][i] = AND(); + and[4][i].a <== lt[2][i].out; + and[4][i].b <== lt[3][i].out; + and[5][i] = AND(); + and[5][i].a <== states[i][4]; + and[5][i].b <== and[4][i].out; lt[4][i] = LessEqThan(8); lt[4][i].in[0] <== 128; lt[4][i].in[1] <== in[i]; lt[5][i] = LessEqThan(8); lt[5][i].in[0] <== in[i]; lt[5][i].in[1] <== 191; - and[4][i] = AND(); - and[4][i].a <== lt[4][i].out; - and[4][i].b <== lt[5][i].out; - and[5][i] = AND(); - and[5][i].a <== states[i][2]; - and[5][i].b <== and[4][i].out; - multi_or[1][i] = MultiOR(2); - multi_or[1][i].in[0] <== and[3][i].out; - multi_or[1][i].in[1] <== and[5][i].out; - states_tmp[i+1][1] <== multi_or[1][i].out; + and[6][i] = AND(); + and[6][i].a <== lt[4][i].out; + and[6][i].b <== lt[5][i].out; + and[7][i] = AND(); + and[7][i].a <== states[i][5]; + and[7][i].b <== and[6][i].out; lt[6][i] = LessEqThan(8); - lt[6][i].in[0] <== 194; + lt[6][i].in[0] <== 128; lt[6][i].in[1] <== in[i]; lt[7][i] = LessEqThan(8); lt[7][i].in[0] <== in[i]; - lt[7][i].in[1] <== 223; - and[6][i] = AND(); - and[6][i].a <== lt[6][i].out; - and[6][i].b <== lt[7][i].out; - and[7][i] = AND(); - and[7][i].a <== states[i][0]; - and[7][i].b <== and[6][i].out; + lt[7][i].in[1] <== 159; and[8][i] = AND(); - and[8][i].a <== states[i][1]; - and[8][i].b <== and[6][i].out; - lt[8][i] = LessEqThan(8); - lt[8][i].in[0] <== 160; - lt[8][i].in[1] <== in[i]; - lt[9][i] = LessEqThan(8); - lt[9][i].in[0] <== in[i]; - lt[9][i].in[1] <== 191; + and[8][i].a <== lt[6][i].out; + and[8][i].b <== lt[7][i].out; and[9][i] = AND(); - and[9][i].a <== lt[8][i].out; - and[9][i].b <== lt[9][i].out; + and[9][i].a <== states[i][6]; + and[9][i].b <== and[8][i].out; and[10][i] = AND(); - and[10][i].a <== states[i][3]; - and[10][i].b <== and[9][i].out; - and[11][i] = AND(); - and[11][i].a <== states[i][4]; - and[11][i].b <== and[4][i].out; - lt[10][i] = LessEqThan(8); - lt[10][i].in[0] <== 128; - lt[10][i].in[1] <== in[i]; - lt[11][i] = LessEqThan(8); - lt[11][i].in[0] <== in[i]; - lt[11][i].in[1] <== 159; - and[12][i] = AND(); - and[12][i].a <== lt[10][i].out; - and[12][i].b <== lt[11][i].out; - and[13][i] = AND(); - and[13][i].a <== states[i][5]; - and[13][i].b <== and[12][i].out; - multi_or[2][i] = MultiOR(4); - multi_or[2][i].in[0] <== and[8][i].out; - multi_or[2][i].in[1] <== and[10][i].out; - multi_or[2][i].in[2] <== and[11][i].out; - multi_or[2][i].in[3] <== and[13][i].out; - states_tmp[i+1][2] <== multi_or[2][i].out; - eq[0][i] = IsEqual(); - eq[0][i].in[0] <== in[i]; - eq[0][i].in[1] <== 224; - and[14][i] = AND(); - and[14][i].a <== states[i][0]; - and[14][i].b <== eq[0][i].out; - and[15][i] = AND(); - and[15][i].a <== states[i][1]; - and[15][i].b <== eq[0][i].out; - states_tmp[i+1][3] <== and[15][i].out; - eq[1][i] = IsEqual(); - eq[1][i].in[0] <== in[i]; - eq[1][i].in[1] <== 225; - eq[2][i] = IsEqual(); - eq[2][i].in[0] <== in[i]; - eq[2][i].in[1] <== 226; + and[10][i].a <== states[i][10]; + and[10][i].b <== and[2][i].out; + multi_or[1][i] = MultiOR(5); + multi_or[1][i].in[0] <== and[3][i].out; + multi_or[1][i].in[1] <== and[5][i].out; + multi_or[1][i].in[2] <== and[7][i].out; + multi_or[1][i].in[3] <== and[9][i].out; + multi_or[1][i].in[4] <== and[10][i].out; + states[i+1][3] <== multi_or[1][i].out; eq[3][i] = IsEqual(); eq[3][i].in[0] <== in[i]; - eq[3][i].in[1] <== 227; + eq[3][i].in[1] <== 224; + and[11][i] = AND(); + and[11][i].a <== states[i][2]; + and[11][i].b <== eq[3][i].out; + and[12][i] = AND(); + and[12][i].a <== states[i][10]; + and[12][i].b <== eq[3][i].out; + multi_or[2][i] = MultiOR(2); + multi_or[2][i].in[0] <== and[11][i].out; + multi_or[2][i].in[1] <== and[12][i].out; + states[i+1][4] <== multi_or[2][i].out; eq[4][i] = IsEqual(); eq[4][i].in[0] <== in[i]; - eq[4][i].in[1] <== 228; + eq[4][i].in[1] <== 225; eq[5][i] = IsEqual(); eq[5][i].in[0] <== in[i]; - eq[5][i].in[1] <== 229; + eq[5][i].in[1] <== 226; eq[6][i] = IsEqual(); eq[6][i].in[0] <== in[i]; - eq[6][i].in[1] <== 230; + eq[6][i].in[1] <== 227; eq[7][i] = IsEqual(); eq[7][i].in[0] <== in[i]; - eq[7][i].in[1] <== 231; + eq[7][i].in[1] <== 228; eq[8][i] = IsEqual(); eq[8][i].in[0] <== in[i]; - eq[8][i].in[1] <== 232; + eq[8][i].in[1] <== 229; eq[9][i] = IsEqual(); eq[9][i].in[0] <== in[i]; - eq[9][i].in[1] <== 233; + eq[9][i].in[1] <== 230; eq[10][i] = IsEqual(); eq[10][i].in[0] <== in[i]; - eq[10][i].in[1] <== 234; + eq[10][i].in[1] <== 231; eq[11][i] = IsEqual(); eq[11][i].in[0] <== in[i]; - eq[11][i].in[1] <== 235; + eq[11][i].in[1] <== 232; eq[12][i] = IsEqual(); eq[12][i].in[0] <== in[i]; - eq[12][i].in[1] <== 236; + eq[12][i].in[1] <== 233; eq[13][i] = IsEqual(); eq[13][i].in[0] <== in[i]; - eq[13][i].in[1] <== 238; + eq[13][i].in[1] <== 234; eq[14][i] = IsEqual(); eq[14][i].in[0] <== in[i]; - eq[14][i].in[1] <== 239; - and[16][i] = AND(); - and[16][i].a <== states[i][0]; - multi_or[3][i] = MultiOR(14); - multi_or[3][i].in[0] <== eq[1][i].out; - multi_or[3][i].in[1] <== eq[2][i].out; - multi_or[3][i].in[2] <== eq[3][i].out; - multi_or[3][i].in[3] <== eq[4][i].out; - multi_or[3][i].in[4] <== eq[5][i].out; - multi_or[3][i].in[5] <== eq[6][i].out; - multi_or[3][i].in[6] <== eq[7][i].out; - multi_or[3][i].in[7] <== eq[8][i].out; - multi_or[3][i].in[8] <== eq[9][i].out; - multi_or[3][i].in[9] <== eq[10][i].out; - multi_or[3][i].in[10] <== eq[11][i].out; - multi_or[3][i].in[11] <== eq[12][i].out; - multi_or[3][i].in[12] <== eq[13][i].out; - multi_or[3][i].in[13] <== eq[14][i].out; - and[16][i].b <== multi_or[3][i].out; - and[17][i] = AND(); - and[17][i].a <== states[i][1]; - and[17][i].b <== multi_or[3][i].out; - lt[12][i] = LessEqThan(8); - lt[12][i].in[0] <== 144; - lt[12][i].in[1] <== in[i]; - lt[13][i] = LessEqThan(8); - lt[13][i].in[0] <== in[i]; - lt[13][i].in[1] <== 191; - and[18][i] = AND(); - and[18][i].a <== lt[12][i].out; - and[18][i].b <== lt[13][i].out; - and[19][i] = AND(); - and[19][i].a <== states[i][6]; - and[19][i].b <== and[18][i].out; - and[20][i] = AND(); - and[20][i].a <== states[i][7]; - and[20][i].b <== and[4][i].out; + eq[14][i].in[1] <== 235; eq[15][i] = IsEqual(); eq[15][i].in[0] <== in[i]; - eq[15][i].in[1] <== 128; + eq[15][i].in[1] <== 236; eq[16][i] = IsEqual(); eq[16][i].in[0] <== in[i]; - eq[16][i].in[1] <== 129; + eq[16][i].in[1] <== 238; eq[17][i] = IsEqual(); eq[17][i].in[0] <== in[i]; - eq[17][i].in[1] <== 130; + eq[17][i].in[1] <== 239; + and[13][i] = AND(); + and[13][i].a <== states[i][2]; + multi_or[3][i] = MultiOR(14); + multi_or[3][i].in[0] <== eq[4][i].out; + multi_or[3][i].in[1] <== eq[5][i].out; + multi_or[3][i].in[2] <== eq[6][i].out; + multi_or[3][i].in[3] <== eq[7][i].out; + multi_or[3][i].in[4] <== eq[8][i].out; + multi_or[3][i].in[5] <== eq[9][i].out; + multi_or[3][i].in[6] <== eq[10][i].out; + multi_or[3][i].in[7] <== eq[11][i].out; + multi_or[3][i].in[8] <== eq[12][i].out; + multi_or[3][i].in[9] <== eq[13][i].out; + multi_or[3][i].in[10] <== eq[14][i].out; + multi_or[3][i].in[11] <== eq[15][i].out; + multi_or[3][i].in[12] <== eq[16][i].out; + multi_or[3][i].in[13] <== eq[17][i].out; + and[13][i].b <== multi_or[3][i].out; + lt[8][i] = LessEqThan(8); + lt[8][i].in[0] <== 144; + lt[8][i].in[1] <== in[i]; + lt[9][i] = LessEqThan(8); + lt[9][i].in[0] <== in[i]; + lt[9][i].in[1] <== 191; + and[14][i] = AND(); + and[14][i].a <== lt[8][i].out; + and[14][i].b <== lt[9][i].out; + and[15][i] = AND(); + and[15][i].a <== states[i][7]; + and[15][i].b <== and[14][i].out; + and[16][i] = AND(); + and[16][i].a <== states[i][8]; + and[16][i].b <== and[6][i].out; eq[18][i] = IsEqual(); eq[18][i].in[0] <== in[i]; - eq[18][i].in[1] <== 131; + eq[18][i].in[1] <== 128; eq[19][i] = IsEqual(); eq[19][i].in[0] <== in[i]; - eq[19][i].in[1] <== 132; + eq[19][i].in[1] <== 129; eq[20][i] = IsEqual(); eq[20][i].in[0] <== in[i]; - eq[20][i].in[1] <== 133; + eq[20][i].in[1] <== 130; eq[21][i] = IsEqual(); eq[21][i].in[0] <== in[i]; - eq[21][i].in[1] <== 134; + eq[21][i].in[1] <== 131; eq[22][i] = IsEqual(); eq[22][i].in[0] <== in[i]; - eq[22][i].in[1] <== 135; + eq[22][i].in[1] <== 132; eq[23][i] = IsEqual(); eq[23][i].in[0] <== in[i]; - eq[23][i].in[1] <== 136; + eq[23][i].in[1] <== 133; eq[24][i] = IsEqual(); eq[24][i].in[0] <== in[i]; - eq[24][i].in[1] <== 137; + eq[24][i].in[1] <== 134; eq[25][i] = IsEqual(); eq[25][i].in[0] <== in[i]; - eq[25][i].in[1] <== 138; + eq[25][i].in[1] <== 135; eq[26][i] = IsEqual(); eq[26][i].in[0] <== in[i]; - eq[26][i].in[1] <== 139; + eq[26][i].in[1] <== 136; eq[27][i] = IsEqual(); eq[27][i].in[0] <== in[i]; - eq[27][i].in[1] <== 140; + eq[27][i].in[1] <== 137; eq[28][i] = IsEqual(); eq[28][i].in[0] <== in[i]; - eq[28][i].in[1] <== 141; + eq[28][i].in[1] <== 138; eq[29][i] = IsEqual(); eq[29][i].in[0] <== in[i]; - eq[29][i].in[1] <== 142; + eq[29][i].in[1] <== 139; eq[30][i] = IsEqual(); eq[30][i].in[0] <== in[i]; - eq[30][i].in[1] <== 143; - and[21][i] = AND(); - and[21][i].a <== states[i][8]; - multi_or[4][i] = MultiOR(16); - multi_or[4][i].in[0] <== eq[15][i].out; - multi_or[4][i].in[1] <== eq[16][i].out; - multi_or[4][i].in[2] <== eq[17][i].out; - multi_or[4][i].in[3] <== eq[18][i].out; - multi_or[4][i].in[4] <== eq[19][i].out; - multi_or[4][i].in[5] <== eq[20][i].out; - multi_or[4][i].in[6] <== eq[21][i].out; - multi_or[4][i].in[7] <== eq[22][i].out; - multi_or[4][i].in[8] <== eq[23][i].out; - multi_or[4][i].in[9] <== eq[24][i].out; - multi_or[4][i].in[10] <== eq[25][i].out; - multi_or[4][i].in[11] <== eq[26][i].out; - multi_or[4][i].in[12] <== eq[27][i].out; - multi_or[4][i].in[13] <== eq[28][i].out; - multi_or[4][i].in[14] <== eq[29][i].out; - multi_or[4][i].in[15] <== eq[30][i].out; - and[21][i].b <== multi_or[4][i].out; - multi_or[5][i] = MultiOR(4); - multi_or[5][i].in[0] <== and[17][i].out; - multi_or[5][i].in[1] <== and[19][i].out; - multi_or[5][i].in[2] <== and[20][i].out; - multi_or[5][i].in[3] <== and[21][i].out; - states_tmp[i+1][4] <== multi_or[5][i].out; + eq[30][i].in[1] <== 140; eq[31][i] = IsEqual(); eq[31][i].in[0] <== in[i]; - eq[31][i].in[1] <== 237; - and[22][i] = AND(); - and[22][i].a <== states[i][0]; - and[22][i].b <== eq[31][i].out; - and[23][i] = AND(); - and[23][i].a <== states[i][1]; - and[23][i].b <== eq[31][i].out; - states_tmp[i+1][5] <== and[23][i].out; + eq[31][i].in[1] <== 141; eq[32][i] = IsEqual(); eq[32][i].in[0] <== in[i]; - eq[32][i].in[1] <== 240; - and[24][i] = AND(); - and[24][i].a <== states[i][0]; - and[24][i].b <== eq[32][i].out; - and[25][i] = AND(); - and[25][i].a <== states[i][1]; - and[25][i].b <== eq[32][i].out; - states_tmp[i+1][6] <== and[25][i].out; + eq[32][i].in[1] <== 142; eq[33][i] = IsEqual(); eq[33][i].in[0] <== in[i]; - eq[33][i].in[1] <== 241; + eq[33][i].in[1] <== 143; + and[17][i] = AND(); + and[17][i].a <== states[i][9]; + multi_or[4][i] = MultiOR(16); + multi_or[4][i].in[0] <== eq[18][i].out; + multi_or[4][i].in[1] <== eq[19][i].out; + multi_or[4][i].in[2] <== eq[20][i].out; + multi_or[4][i].in[3] <== eq[21][i].out; + multi_or[4][i].in[4] <== eq[22][i].out; + multi_or[4][i].in[5] <== eq[23][i].out; + multi_or[4][i].in[6] <== eq[24][i].out; + multi_or[4][i].in[7] <== eq[25][i].out; + multi_or[4][i].in[8] <== eq[26][i].out; + multi_or[4][i].in[9] <== eq[27][i].out; + multi_or[4][i].in[10] <== eq[28][i].out; + multi_or[4][i].in[11] <== eq[29][i].out; + multi_or[4][i].in[12] <== eq[30][i].out; + multi_or[4][i].in[13] <== eq[31][i].out; + multi_or[4][i].in[14] <== eq[32][i].out; + multi_or[4][i].in[15] <== eq[33][i].out; + and[17][i].b <== multi_or[4][i].out; + and[18][i] = AND(); + and[18][i].a <== states[i][10]; + and[18][i].b <== multi_or[3][i].out; + multi_or[5][i] = MultiOR(5); + multi_or[5][i].in[0] <== and[13][i].out; + multi_or[5][i].in[1] <== and[15][i].out; + multi_or[5][i].in[2] <== and[16][i].out; + multi_or[5][i].in[3] <== and[17][i].out; + multi_or[5][i].in[4] <== and[18][i].out; + states[i+1][5] <== multi_or[5][i].out; eq[34][i] = IsEqual(); eq[34][i].in[0] <== in[i]; - eq[34][i].in[1] <== 242; + eq[34][i].in[1] <== 237; + and[19][i] = AND(); + and[19][i].a <== states[i][2]; + and[19][i].b <== eq[34][i].out; + and[20][i] = AND(); + and[20][i].a <== states[i][10]; + and[20][i].b <== eq[34][i].out; + multi_or[6][i] = MultiOR(2); + multi_or[6][i].in[0] <== and[19][i].out; + multi_or[6][i].in[1] <== and[20][i].out; + states[i+1][6] <== multi_or[6][i].out; eq[35][i] = IsEqual(); eq[35][i].in[0] <== in[i]; - eq[35][i].in[1] <== 243; - and[26][i] = AND(); - and[26][i].a <== states[i][0]; - multi_or[6][i] = MultiOR(3); - multi_or[6][i].in[0] <== eq[33][i].out; - multi_or[6][i].in[1] <== eq[34][i].out; - multi_or[6][i].in[2] <== eq[35][i].out; - and[26][i].b <== multi_or[6][i].out; - and[27][i] = AND(); - and[27][i].a <== states[i][1]; - and[27][i].b <== multi_or[6][i].out; - states_tmp[i+1][7] <== and[27][i].out; + eq[35][i].in[1] <== 240; + and[21][i] = AND(); + and[21][i].a <== states[i][2]; + and[21][i].b <== eq[35][i].out; + and[22][i] = AND(); + and[22][i].a <== states[i][10]; + and[22][i].b <== eq[35][i].out; + multi_or[7][i] = MultiOR(2); + multi_or[7][i].in[0] <== and[21][i].out; + multi_or[7][i].in[1] <== and[22][i].out; + states[i+1][7] <== multi_or[7][i].out; eq[36][i] = IsEqual(); eq[36][i].in[0] <== in[i]; - eq[36][i].in[1] <== 244; + eq[36][i].in[1] <== 241; + eq[37][i] = IsEqual(); + eq[37][i].in[0] <== in[i]; + eq[37][i].in[1] <== 242; + eq[38][i] = IsEqual(); + eq[38][i].in[0] <== in[i]; + eq[38][i].in[1] <== 243; + and[23][i] = AND(); + and[23][i].a <== states[i][2]; + multi_or[8][i] = MultiOR(3); + multi_or[8][i].in[0] <== eq[36][i].out; + multi_or[8][i].in[1] <== eq[37][i].out; + multi_or[8][i].in[2] <== eq[38][i].out; + and[23][i].b <== multi_or[8][i].out; + and[24][i] = AND(); + and[24][i].a <== states[i][10]; + and[24][i].b <== multi_or[8][i].out; + multi_or[9][i] = MultiOR(2); + multi_or[9][i].in[0] <== and[23][i].out; + multi_or[9][i].in[1] <== and[24][i].out; + states[i+1][8] <== multi_or[9][i].out; + eq[39][i] = IsEqual(); + eq[39][i].in[0] <== in[i]; + eq[39][i].in[1] <== 244; + and[25][i] = AND(); + and[25][i].a <== states[i][2]; + and[25][i].b <== eq[39][i].out; + and[26][i] = AND(); + and[26][i].a <== states[i][10]; + and[26][i].b <== eq[39][i].out; + multi_or[10][i] = MultiOR(2); + multi_or[10][i].in[0] <== and[25][i].out; + multi_or[10][i].in[1] <== and[26][i].out; + states[i+1][9] <== multi_or[10][i].out; + lt[10][i] = LessEqThan(8); + lt[10][i].in[0] <== 0; + lt[10][i].in[1] <== in[i]; + lt[11][i] = LessEqThan(8); + lt[11][i].in[0] <== in[i]; + lt[11][i].in[1] <== 96; + and[27][i] = AND(); + and[27][i].a <== lt[10][i].out; + and[27][i].b <== lt[11][i].out; + lt[12][i] = LessEqThan(8); + lt[12][i].in[0] <== 100; + lt[12][i].in[1] <== in[i]; + lt[13][i] = LessEqThan(8); + lt[13][i].in[0] <== in[i]; + lt[13][i].in[1] <== 127; and[28][i] = AND(); - and[28][i].a <== states[i][0]; - and[28][i].b <== eq[36][i].out; + and[28][i].a <== lt[12][i].out; + and[28][i].b <== lt[13][i].out; and[29][i] = AND(); - and[29][i].a <== states[i][1]; - and[29][i].b <== eq[36][i].out; - states_tmp[i+1][8] <== and[29][i].out; - from_zero_enabled[i] <== MultiNOR(8)([states_tmp[i+1][1], states_tmp[i+1][2], states_tmp[i+1][3], states_tmp[i+1][4], states_tmp[i+1][5], states_tmp[i+1][6], states_tmp[i+1][7], states_tmp[i+1][8]]); - states[i+1][1] <== MultiOR(2)([states_tmp[i+1][1], from_zero_enabled[i] * and[2][i].out]); - states[i+1][2] <== MultiOR(2)([states_tmp[i+1][2], from_zero_enabled[i] * and[7][i].out]); - states[i+1][3] <== MultiOR(2)([states_tmp[i+1][3], from_zero_enabled[i] * and[14][i].out]); - states[i+1][4] <== MultiOR(2)([states_tmp[i+1][4], from_zero_enabled[i] * and[16][i].out]); - states[i+1][5] <== MultiOR(2)([states_tmp[i+1][5], from_zero_enabled[i] * and[22][i].out]); - states[i+1][6] <== MultiOR(2)([states_tmp[i+1][6], from_zero_enabled[i] * and[24][i].out]); - states[i+1][7] <== MultiOR(2)([states_tmp[i+1][7], from_zero_enabled[i] * and[26][i].out]); - states[i+1][8] <== MultiOR(2)([states_tmp[i+1][8], from_zero_enabled[i] * and[28][i].out]); + and[29][i].a <== states[i][2]; + multi_or[11][i] = MultiOR(2); + multi_or[11][i].in[0] <== and[27][i].out; + multi_or[11][i].in[1] <== and[28][i].out; + and[29][i].b <== multi_or[11][i].out; + and[30][i] = AND(); + and[30][i].a <== states[i][3]; + and[30][i].b <== and[6][i].out; + and[31][i] = AND(); + and[31][i].a <== states[i][10]; + and[31][i].b <== multi_or[11][i].out; + multi_or[12][i] = MultiOR(3); + multi_or[12][i].in[0] <== and[29][i].out; + multi_or[12][i].in[1] <== and[30][i].out; + multi_or[12][i].in[2] <== and[31][i].out; + states[i+1][10] <== multi_or[12][i].out; + from_zero_enabled[i] <== MultiNOR(10)([states_tmp[i+1][1], states[i+1][2], states[i+1][3], states[i+1][4], states[i+1][5], states[i+1][6], states[i+1][7], states[i+1][8], states[i+1][9], states[i+1][10]]); + 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]; @@ -351,27 +382,29 @@ template Caret5Regex(msg_bytes) { state_changed[i].in[5] <== states[i+1][6]; state_changed[i].in[6] <== states[i+1][7]; state_changed[i].in[7] <== states[i+1][8]; + state_changed[i].in[8] <== states[i+1][9]; + state_changed[i].in[9] <== states[i+1][10]; } component final_state_result = MultiOR(num_bytes+1); for (var i = 0; i <= num_bytes; i++) { - final_state_result.in[i] <== states[i][1]; + final_state_result.in[i] <== states[i][10]; } out <== final_state_result.out; 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][1] * (1 - is_consecutive[msg_bytes-i][2]) + is_consecutive[msg_bytes-i][2]; + is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][10] * (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][1], is_consecutive[msg_bytes-1-i][1]]); + is_consecutive[msg_bytes-1-i][2] <== ORAnd()([(1 - from_zero_enabled[msg_bytes-i+1]), states[num_bytes-i][10], is_consecutive[msg_bytes-1-i][1]]); } - // substrings calculated: [{(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (2, 1), (3, 2), (4, 2), (5, 2), (6, 4), (7, 4), (8, 4)}] + // substrings calculated: [{(2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10), (3, 10), (4, 3), (5, 3), (6, 3), (7, 5), (8, 5), (9, 5), (10, 3), (10, 4), (10, 5), (10, 6), (10, 7), (10, 8), (10, 9), (10, 10)}] 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: [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (2, 1), (3, 2), (4, 2), (5, 2), (6, 4), (7, 4), (8, 4)] - is_substr0[i] <== MultiOR(23)([states[i+1][0] * states[i+2][1], states[i+1][0] * states[i+2][2], states[i+1][0] * states[i+2][3], states[i+1][0] * states[i+2][4], states[i+1][0] * states[i+2][5], states[i+1][0] * states[i+2][6], states[i+1][0] * states[i+2][7], states[i+1][0] * states[i+2][8], states[i+1][1] * states[i+2][1], states[i+1][1] * states[i+2][2], states[i+1][1] * states[i+2][3], states[i+1][1] * states[i+2][4], states[i+1][1] * states[i+2][5], states[i+1][1] * states[i+2][6], states[i+1][1] * states[i+2][7], states[i+1][1] * states[i+2][8], states[i+1][2] * states[i+2][1], states[i+1][3] * states[i+2][2], states[i+1][4] * states[i+2][2], states[i+1][5] * states[i+2][2], states[i+1][6] * states[i+2][4], states[i+1][7] * states[i+2][4], states[i+1][8] * states[i+2][4]]); + // the 0-th substring transitions: [(2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10), (3, 10), (4, 3), (5, 3), (6, 3), (7, 5), (8, 5), (9, 5), (10, 3), (10, 4), (10, 5), (10, 6), (10, 7), (10, 8), (10, 9), (10, 10)] + is_substr0[i] <== MultiOR(23)([states[i+1][2] * states[i+2][3], states[i+1][2] * states[i+2][4], states[i+1][2] * states[i+2][5], states[i+1][2] * states[i+2][6], states[i+1][2] * states[i+2][7], states[i+1][2] * states[i+2][8], states[i+1][2] * states[i+2][9], states[i+1][2] * states[i+2][10], states[i+1][3] * states[i+2][10], states[i+1][4] * states[i+2][3], states[i+1][5] * states[i+2][3], states[i+1][6] * states[i+2][3], states[i+1][7] * states[i+2][5], states[i+1][8] * states[i+2][5], states[i+1][9] * states[i+2][5], states[i+1][10] * states[i+2][3], states[i+1][10] * states[i+2][4], states[i+1][10] * states[i+2][5], states[i+1][10] * states[i+2][6], states[i+1][10] * states[i+2][7], states[i+1][10] * states[i+2][8], states[i+1][10] * states[i+2][9], states[i+1][10] * states[i+2][10]]); is_reveal0[i] <== is_substr0[i] * is_consecutive[i][2]; reveal0[i] <== in[i+1] * is_reveal0[i]; } diff --git a/packages/compiler/src/lib.rs b/packages/compiler/src/lib.rs index ebafd20..c6ba852 100644 --- a/packages/compiler/src/lib.rs +++ b/packages/compiler/src/lib.rs @@ -13,7 +13,7 @@ use crate::regex::*; use itertools::Itertools; use petgraph::prelude::*; use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::{BTreeMap, BTreeSet, VecDeque}; use std::path::PathBuf; use thiserror::Error; @@ -31,7 +31,7 @@ pub enum CompilerError { /// A configuration of decomposed regexes. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DecomposedRegexConfig { - pub parts: Vec, + pub parts: VecDeque, } /// Decomposed regex part. @@ -64,7 +64,7 @@ pub struct DFAState { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DFAGraph { - states: Vec, + pub states: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -89,7 +89,7 @@ pub struct SubstrsDefsJson { } impl DecomposedRegexConfig { - pub fn to_regex_and_dfa(&self) -> Result { + pub fn to_regex_and_dfa(&mut self) -> Result { Ok(regex_and_dfa(self)) } } @@ -127,7 +127,7 @@ pub fn gen_from_decomposed( circom_template_name: Option<&str>, gen_substrs: Option, ) { - let decomposed_regex_config: DecomposedRegexConfig = + let mut decomposed_regex_config: DecomposedRegexConfig = serde_json::from_reader(File::open(decomposed_regex_path).unwrap()).unwrap(); let regex_and_dfa = decomposed_regex_config .to_regex_and_dfa() diff --git a/packages/compiler/src/regex.rs b/packages/compiler/src/regex.rs index 121feb7..2524fe0 100644 --- a/packages/compiler/src/regex.rs +++ b/packages/compiler/src/regex.rs @@ -1,4 +1,4 @@ -use crate::{DFAGraph, DFAState, DecomposedRegexConfig, RegexAndDFA, SubstrsDefs}; +use crate::{DFAGraph, DFAState, DecomposedRegexConfig, RegexAndDFA, RegexPartConfig, SubstrsDefs}; use regex::Regex; use regex_automata::dfa::{dense::DFA, StartKind}; use std::collections::{BTreeMap, BTreeSet}; @@ -252,7 +252,7 @@ fn add_dfa(net_dfa: &DFAGraph, graph: &DFAGraph) -> DFAGraph { net_dfa } -pub fn regex_and_dfa(decomposed_regex: &DecomposedRegexConfig) -> RegexAndDFA { +pub fn regex_and_dfa(decomposed_regex: &mut DecomposedRegexConfig) -> RegexAndDFA { let mut config = DFA::config().minimize(true); config = config.start_kind(StartKind::Anchored); config = config.byte_classes(false); @@ -260,17 +260,87 @@ pub fn regex_and_dfa(decomposed_regex: &DecomposedRegexConfig) -> RegexAndDFA { let mut net_dfa = DFAGraph { states: Vec::new() }; let mut substr_defs_array = Vec::new(); + + let caret_regex_index = { + let first_regex = decomposed_regex.parts[0].regex_def.as_bytes(); + let mut is_in_parenthesis = false; + let mut caret_found = false; + let mut idx = 0; + while idx < first_regex.len() { + let byte = first_regex[idx]; + if byte == b'\\' { + idx += 2; + } else if byte == b'(' { + is_in_parenthesis = true; + idx += 1; + } else if byte == b'[' { + idx += 2; + } else if byte == b')' { + debug_assert!(is_in_parenthesis, "Unmatched parenthesis"); + is_in_parenthesis = false; + idx += 1; + if caret_found { + break; + } + } else if byte == b'^' { + caret_found = true; + idx += 1; + if !is_in_parenthesis { + break; + } + } else { + idx += 1; + } + } - for regex in decomposed_regex.parts.iter() { - let regex_str = regex.regex_def.as_str(); - println!("{:?}", regex_str); + if caret_found { + Some(idx) + } else { + None + } + }; + if let Some(index) = caret_regex_index { + let caret_regex = decomposed_regex.parts[0].regex_def[0..index].to_string(); + decomposed_regex.parts.push_front(RegexPartConfig { + is_public: false, + regex_def: caret_regex, + }); + decomposed_regex.parts[1].regex_def = decomposed_regex.parts[1].regex_def[index..].to_string(); + } + + for (idx, regex) in decomposed_regex.parts.iter().enumerate() { let re = DFA::builder() .configure(config.clone()) - .build(&format!(r"^{}$", regex_str)) + .build(&format!(r"^{}$", regex.regex_def.as_str())) .unwrap(); let re_str = format!("{:?}", re); let mut graph = dfa_to_graph(&parse_dfa_output(&re_str)); - println!("{:?}", graph); + if idx == 0 && caret_regex_index.is_some() { + if regex.regex_def.as_str() == "^" { + graph = DFAGraph { + states: vec![ + DFAState { + r#type: "".to_string(), + edges: BTreeMap::from([(1, BTreeSet::from([255u8]))]), + state: 0, + }, + DFAState { + r#type: "accept".to_string(), + edges: BTreeMap::new(), + state: 1, + } + ], + } + } else { + if let Some(edge) = graph.states[0].edges.get_mut(&1) { + edge.insert(255u8); + } else { + graph.states[0].edges.insert(1, BTreeSet::from([255u8])); + } + graph.states[0].r#type = "".to_string(); + } + } + // println!("{:?}", graph); // Find max state in net_dfa let mut max_state_index = 0; for state in net_dfa.states.iter() { @@ -324,7 +394,7 @@ pub fn regex_and_dfa(decomposed_regex: &DecomposedRegexConfig) -> RegexAndDFA { net_dfa = add_dfa(&net_dfa, &graph); } - println!("{:?}", net_dfa); + // println!("{:?}", net_dfa); let mut regex_str = String::new(); for regex in decomposed_regex.parts.iter() { diff --git a/packages/compiler/src/wasm.rs b/packages/compiler/src/wasm.rs index ce79661..5099f68 100644 --- a/packages/compiler/src/wasm.rs +++ b/packages/compiler/src/wasm.rs @@ -5,7 +5,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen] #[allow(non_snake_case)] pub fn genFromDecomposed(decomposedRegexJson: &str, circomTemplateName: &str) -> String { - let decomposed_regex_config: DecomposedRegexConfig = + let mut decomposed_regex_config: DecomposedRegexConfig = serde_json::from_str(decomposedRegexJson).expect("failed to parse decomposed_regex json"); let regex_and_dfa = decomposed_regex_config .to_regex_and_dfa() @@ -30,8 +30,8 @@ pub fn genFromRaw(rawRegex: &str, substrsJson: &str, circomTemplateName: &str) - #[wasm_bindgen] #[allow(non_snake_case)] pub fn genRegexAndDfa(decomposedRegex: JsValue) -> JsValue { - let decomposed_regex_config: DecomposedRegexConfig = from_value(decomposedRegex).unwrap(); - let regex_and_dfa = regex_and_dfa(&decomposed_regex_config); + let mut decomposed_regex_config: DecomposedRegexConfig = from_value(decomposedRegex).unwrap(); + let regex_and_dfa = regex_and_dfa(&mut decomposed_regex_config); let dfa_val_str = serde_json::to_string(®ex_and_dfa).unwrap(); JsValue::from_str(&dfa_val_str) } @@ -39,8 +39,8 @@ pub fn genRegexAndDfa(decomposedRegex: JsValue) -> JsValue { #[wasm_bindgen] #[allow(non_snake_case)] pub fn genCircom(decomposedRegex: JsValue, circomTemplateName: &str) -> String { - let decomposed_regex_config: DecomposedRegexConfig = from_value(decomposedRegex).unwrap(); - let regex_and_dfa = regex_and_dfa(&decomposed_regex_config); + let mut decomposed_regex_config: DecomposedRegexConfig = from_value(decomposedRegex).unwrap(); + let regex_and_dfa = regex_and_dfa(&mut decomposed_regex_config); regex_and_dfa .gen_circom_str(&circomTemplateName) .expect("failed to generate circom")