Skip to content

Commit

Permalink
Add negate tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
SoraSuegami committed Sep 29, 2023
1 parent 70a1277 commit 0cba201
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 916 deletions.
891 changes: 0 additions & 891 deletions packages/circom/circuits/common/timestamp.circom

This file was deleted.

4 changes: 2 additions & 2 deletions packages/circom/circuits/common/timestamp.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
},
{
"is_public": false,
"regex_def": "((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)+=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|\"|#|$|%|&|\\'|\\(|\\)|\\*|\\+|,|-|\\.|\\/|:|<|=|>|\\?|@|\\[|\\\\|\\]|\\^|_|`|{|\\||}|~| |\t|\n|\r|\\x0b|\\x0c)+; )+t=",
"max_size": 128
"regex_def": "((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)+=[^;]+; )+t=",
"max_size": 1024
},
{
"is_public": true,
Expand Down
20 changes: 20 additions & 0 deletions packages/circom/tests/circuits/negate1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"max_byte_size": 64,
"parts": [
{
"is_public": false,
"regex_def": "a:",
"max_size": 2
},
{
"is_public": true,
"regex_def": "[^abcdefghijklmnopqrstuvwxyz]+",
"max_size": 128
},
{
"is_public": false,
"regex_def": ".",
"max_size": 1
}
]
}
114 changes: 114 additions & 0 deletions packages/circom/tests/circuits/negate1_regex.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
pragma circom 2.1.5;

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

template Negate1Regex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;

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

component eq[4][num_bytes];
component lt[4][num_bytes];
component and[7][num_bytes];
component multi_or[2][num_bytes];
signal states[num_bytes+1][5];
component state_changed[num_bytes];

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

for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(4);
lt[0][i] = LessThan(8);
lt[0][i].in[0] <== 96;
lt[0][i].in[1] <== in[i];
lt[1][i] = LessThan(8);
lt[1][i].in[0] <== in[i];
lt[1][i].in[1] <== 123;
and[0][i] = AND();
and[0][i].a <== lt[0][i].out;
and[0][i].b <== lt[1][i].out;
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 46;
and[1][i] = AND();
and[1][i].a <== states[i][1];
multi_or[0][i] = MultiOR(2);
multi_or[0][i].in[0] <== and[0][i].out;
multi_or[0][i].in[1] <== eq[0][i].out;
and[1][i].b <== 1 - multi_or[0][i].out;
lt[2][i] = LessThan(8);
lt[2][i].in[0] <== 96;
lt[2][i].in[1] <== in[i];
lt[3][i] = LessThan(8);
lt[3][i].in[0] <== in[i];
lt[3][i].in[1] <== 123;
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][4];
and[3][i].b <== 1 - and[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[3][i].out;
states[i+1][1] <== multi_or[1][i].out;
state_changed[i].in[0] <== states[i+1][1];
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 46;
and[4][i] = AND();
and[4][i].a <== states[i][1];
and[4][i].b <== eq[1][i].out;
states[i+1][2] <== and[4][i].out;
state_changed[i].in[1] <== states[i+1][2];
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 97;
and[5][i] = AND();
and[5][i].a <== states[i][0];
and[5][i].b <== eq[2][i].out;
states[i+1][3] <== and[5][i].out;
state_changed[i].in[2] <== states[i+1][3];
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 58;
and[6][i] = AND();
and[6][i].a <== states[i][3];
and[6][i].b <== eq[3][i].out;
states[i+1][4] <== and[6][i].out;
state_changed[i].in[3] <== states[i+1][4];
states[i+1][0] <== 1 - state_changed[i].out;
}

component final_state_result = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
final_state_result.in[i] <== states[i][2];
}
out <== final_state_result.out;

signal is_consecutive[msg_bytes+1][2];
is_consecutive[msg_bytes][1] <== 1;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][2] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
}
signal is_substr0[msg_bytes][3];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr0[i][0] <== 0;
is_substr0[i][1] <== is_substr0[i][0] + states[i+1][4] * states[i+2][1];
is_substr0[i][2] <== is_substr0[i][1] + states[i+1][1] * states[i+2][1];
is_reveal0[i] <== is_substr0[i][2] * is_consecutive[i][1];
reveal0[i] <== in[i+1] * is_reveal0[i];
}
}
2 changes: 2 additions & 0 deletions packages/circom/tests/circuits/test_negate1_regex.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include "./negate1_regex.circom";
component main = Negate1Regex(64);
110 changes: 110 additions & 0 deletions packages/circom/tests/negate_regex.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
const ff = require('ffjavascript');
const stringifyBigInts = ff.utils.stringifyBigInts;
const circom_tester = require("circom_tester");
const wasm_tester = circom_tester.wasm;
import * as path from "path";
const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617";
const field = new ff.F1Field(p);
const apis = require("../../apis");
const option = {
include: path.join(__dirname, "../../../node_modules")
};

jest.setTimeout(120000);
describe("Negate Regex", () => {
it("case 1 with regex 1", async () => {
const input = "a: ABCDEFG XYZ.";
const paddedStr = apis.padString(input, 64);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_negate1_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const revealedIdx = [[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]];
for (let substr_idx = 0; substr_idx < 1; ++substr_idx) {
for (let idx = 0; idx < 64; ++idx) {
if (revealedIdx[substr_idx].includes(idx)) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + 64 * substr_idx + idx]);
} else {
expect(0n).toEqual(witness[2 + 64 * substr_idx + idx]);
}
}
}
});

it("case 2 with regex 1", async () => {
// Spanish character "í" has 2 bytes.
const input = "a: CRIPTOGRAFíA.";
const paddedStr = apis.padString(input, 64);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_negate1_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const revealedIdx = [[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]];
for (let substr_idx = 0; substr_idx < 1; ++substr_idx) {
for (let idx = 0; idx < 64; ++idx) {
if (revealedIdx[substr_idx].includes(idx)) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + 64 * substr_idx + idx]);
} else {
expect(0n).toEqual(witness[2 + 64 * substr_idx + idx]);
}
}
}
});

it("case 3 with regex 1", async () => {
/// Each Japanese character has 3 bytes.
const input = "a: あいう.";
const paddedStr = apis.padString(input, 64);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_negate1_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const revealedIdx = [[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]];
for (let substr_idx = 0; substr_idx < 1; ++substr_idx) {
for (let idx = 0; idx < 64; ++idx) {
if (revealedIdx[substr_idx].includes(idx)) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + 64 * substr_idx + idx]);
} else {
expect(0n).toEqual(witness[2 + 64 * substr_idx + idx]);
}
}
}
});

it("case 4 with regex 1", async () => {
/// Arabian character "التشفير" has 14 bytes.
const input = "a: التشفير.";
const paddedStr = apis.padString(input, 64);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_negate1_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
console.log(witness);
console.log(paddedStr);
expect(1n).toEqual(witness[1]);
const revealedIdx = [[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]];
for (let substr_idx = 0; substr_idx < 1; ++substr_idx) {
for (let idx = 0; idx < 64; ++idx) {
if (revealedIdx[substr_idx].includes(idx)) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + 64 * substr_idx + idx]);
} else {
expect(0n).toEqual(witness[2 + 64 * substr_idx + idx]);
}
}
}
});
});
34 changes: 16 additions & 18 deletions packages/compiler/src/gen_circom.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,20 @@ function genCircomAllstr(graph_json, template_name) {
lines.push(`\t\tstate_changed[i] = MultiOR(${N - 1});`);
for (let i = 1; i < N; i++) {
const outputs = [];
let is_negates = [];
// let is_negates = [];
for (let prev_i of Object.keys(rev_graph[i])) {
const k = rev_graph[i][prev_i];
const eq_outputs = [];
let vals = new Set(k);
// let is_negate = false;
let is_negate = false;
if (vals.has(0xff)) {
vals.delete(0xff);
is_negates.push(true);
} else {
is_negates.push(false);
is_negate = true;
}
if (vals.size === 0) {
continue;
}
if (is_negates[is_negates.length - 1] === true) {
if (is_negate === true) {
for (let another_i = 1; another_i < N; another_i++) {
if (i === another_i) {
continue;
Expand Down Expand Up @@ -156,13 +154,21 @@ function genCircomAllstr(graph_json, template_name) {
lines.push(`\t\tand[${and_i}][i] = AND();`);
lines.push(`\t\tand[${and_i}][i].a <== states[i][${prev_i}];`);
if (eq_outputs.length === 1) {
lines.push(`\t\tand[${and_i}][i].b <== ${eq_outputs[0][0]}[${eq_outputs[0][1]}][i].out;`);
if (is_negate) {
lines.push(`\t\tand[${and_i}][i].b <== 1 - ${eq_outputs[0][0]}[${eq_outputs[0][1]}][i].out;`);
} else {
lines.push(`\t\tand[${and_i}][i].b <== ${eq_outputs[0][0]}[${eq_outputs[0][1]}][i].out;`);
}
} else if (eq_outputs.length > 1) {
lines.push(`\t\tmulti_or[${multi_or_i}][i] = MultiOR(${eq_outputs.length});`);
for (let output_i = 0; output_i < eq_outputs.length; output_i++) {
lines.push(`\t\tmulti_or[${multi_or_i}][i].in[${output_i}] <== ${eq_outputs[output_i][0]}[${eq_outputs[output_i][1]}][i].out;`);
}
lines.push(`\t\tand[${and_i}][i].b <== multi_or[${multi_or_i}][i].out;`);
if (is_negate) {
lines.push(`\t\tand[${and_i}][i].b <== 1 - multi_or[${multi_or_i}][i].out;`);
} else {
lines.push(`\t\tand[${and_i}][i].b <== multi_or[${multi_or_i}][i].out;`);
}
multi_or_i += 1
}

Expand All @@ -171,19 +177,11 @@ function genCircomAllstr(graph_json, template_name) {
}

if (outputs.length === 1) {
if (is_negates[0]) {
lines.push(`\t\tstates[i+1][${i}] <== 1 - and[${outputs[0]}][i].out;`);
} else {
lines.push(`\t\tstates[i+1][${i}] <== and[${outputs[0]}][i].out;`);
}
lines.push(`\t\tstates[i+1][${i}] <== and[${outputs[0]}][i].out;`);
} else if (outputs.length > 1) {
lines.push(`\t\tmulti_or[${multi_or_i}][i] = MultiOR(${outputs.length});`);
for (let output_i = 0; output_i < outputs.length; output_i++) {
if (is_negates[output_i]) {
lines.push(`\t\tmulti_or[${multi_or_i}][i].in[${output_i}] <== 1 - and[${outputs[output_i]}][i].out;`);
} else {
lines.push(`\t\tmulti_or[${multi_or_i}][i].in[${output_i}] <== and[${outputs[output_i]}][i].out;`);
}
lines.push(`\t\tmulti_or[${multi_or_i}][i].in[${output_i}] <== and[${outputs[output_i]}][i].out;`);
}
lines.push(`\t\tstates[i+1][${i}] <== multi_or[${multi_or_i}][i].out;`);
multi_or_i += 1
Expand Down
15 changes: 10 additions & 5 deletions packages/compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,7 @@ impl DecomposedRegexConfig {
if config.is_public {
public_config_indexes.push(idx);
}
let this_regex = config
.regex_def
.replace("^", "\\^")
.replace("[^", "[\u{ff}");
let this_regex = config.regex_def.replace("^", "\\^").replace("[^", "[");
if idx == 0 {
part_regexes.push(Regex::new(&this_regex)?);
} else {
Expand Down Expand Up @@ -450,13 +447,21 @@ pub(crate) fn add_graph_nodes(
continue;
}
}
let key_list: Vec<String> = serde_json::from_str(&key)?;
let key_list: Vec<String> = serde_json::from_str::<Vec<String>>(&key)?
.iter()
.filter(|s| s.as_str() != "\u{ff}")
.cloned()
.collect_vec();
// let mut key_str = String::new();
// for key_char in key_list.iter() {
// // println!("key_char {}", key_char);
// assert!(key_char.len() == 1);
// // key_str += key_char;
// }
// println!("key_list {:?}", key_list);
if key_list.len() == 0 {
continue;
}
assert_eq!(key_list[0].as_bytes().len(), 1);
graph.add_edge(
NodeIndex::from(next_node),
Expand Down

0 comments on commit 0cba201

Please sign in to comment.