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: nonzero DataHasher #45

Merged
merged 5 commits into from
Nov 14, 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
5 changes: 0 additions & 5 deletions circuits/http/nivc/notes.md

This file was deleted.

8 changes: 6 additions & 2 deletions circuits/test/common/poseidon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,12 @@ export function DataHasher(input: number[]): bigint {
packedInput += BigInt(input[16 * i + j]) * BigInt(2 ** (8 * j));
}

// Compute next hash using previous hash and packed input
hashes.push(PoseidonModular([hashes[i], packedInput]));
// Compute next hash using previous hash and packed input, but if packed input is zero, don't hash it.
if (packedInput == BigInt(0)) {
hashes.push(hashes[i]);
} else {
hashes.push(PoseidonModular([hashes[i], packedInput]));
}
}

// Return the last hash
Expand Down
2 changes: 0 additions & 2 deletions circuits/test/full/full.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { assert } from "chai";
import { circomkit, WitnessTester, toByte } from "../common";
import { DataHasher } from "../common/poseidon";



// HTTP/1.1 200 OK
// content-type: application/json; charset=utf-8
// content-encoding: gzip
Expand Down
40 changes: 35 additions & 5 deletions circuits/test/utils/hash.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import assert from "assert";
import { circomkit, WitnessTester } from "../common";
import { PoseidonModular } from "../common/poseidon";
import { DataHasher, PoseidonModular } from "../common/poseidon";

describe("hash", () => {
describe("PoseidonModular_16", () => {
Expand Down Expand Up @@ -83,10 +84,9 @@ describe("hash", () => {

it("witness: in = [0,...x16]", async () => {
const input = Array(16).fill(0);
const hash = PoseidonModular([0, 0]);
await circuit.expectPass(
{ in: input },
{ out: hash }
{ out: 0 }
);
});

Expand Down Expand Up @@ -128,8 +128,23 @@ describe("hash", () => {
10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13,
10, 32, 32, 32, 125, 13, 10, 125]

const http_start_line = [
72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
];

describe("DataHasherHTTP", () => {
let circuit: WitnessTester<["in"], ["out"]>;
let circuit_small: WitnessTester<["in"], ["out"]>;

before(async () => {
circuit = await circomkit.WitnessTester(`DataHasher`, {
Expand All @@ -138,13 +153,28 @@ describe("hash", () => {
params: [320],
});
console.log("#constraints:", await circuit.getConstraintCount());

circuit_small = await circomkit.WitnessTester(`DataHasher`, {
file: "utils/hash",
template: "DataHasher",
params: [32],
});
console.log("#constraints:", await circuit.getConstraintCount());
});

it("witness: TEST HTTP BYTES", async () => {

let hash = DataHasher(TEST_HTTP_BYTES);
assert.deepEqual(String(hash), "2195365663909569734943279727560535141179588918483111718403427949138562480675");
await circuit.expectPass({ in: TEST_HTTP_BYTES }, { out: "2195365663909569734943279727560535141179588918483111718403427949138562480675" });
});

let hash = DataHasher(http_start_line);
it("witness: TEST HTTP START LINE MASK", async () => {
await circuit.expectPass({ in: http_start_line }, { out: hash });
});

it("witness: TEST HTTP START LINE MASK TRUNCATED", async () => {
await circuit_small.expectPass({ in: http_start_line.slice(0, 32) }, { out: hash });
});
});
});
});
8 changes: 5 additions & 3 deletions circuits/utils/hash.circom
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,18 @@ template DataHasher(DATA_BYTES) {
signal input in[DATA_BYTES];
signal output out;

signal not_to_hash[DATA_BYTES \ 16];
signal option_hash[DATA_BYTES \ 16];
signal hashes[DATA_BYTES \ 16 + 1];
hashes[0] <== 0;

for(var i = 0 ; i < DATA_BYTES \ 16 ; i++) {
var packedInput = 0;
for(var j = 0 ; j < 16 ; j++) {
packedInput += in[16 * i + j] * 2**(8*j);
}
hashes[i+1] <== PoseidonChainer()([hashes[i],packedInput]);
not_to_hash[i] <== IsZero()(packedInput);
option_hash[i] <== PoseidonChainer()([hashes[i],packedInput]);
hashes[i+1] <== not_to_hash[i] * (hashes[i] - option_hash[i]) + option_hash[i]; // same as: (1 - not_to_hash[i]) * option_hash[i] + not_to_hash[i] * hash[i];
}

out <== hashes[DATA_BYTES \ 16];
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "web-prover-circuits",
"description": "ZK Circuits for WebProofs",
"version": "0.5.3",
"version": "0.5.4",
"license": "Apache-2.0",
"repository": {
"type": "git",
Expand Down