Skip to content

Commit

Permalink
feat: nonzero DataHasher (#45)
Browse files Browse the repository at this point in the history
* Delete notes.md

* feat: updated `DataHasher`

* feat: tested `DataHasher`

* test: one more example

* Update package.json

---------

Co-authored-by: Sambhav Dusad <[email protected]>
  • Loading branch information
Autoparallel and lonerapier authored Nov 14, 2024
1 parent 52d4bf6 commit 3fdfd5c
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 18 deletions.
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

0 comments on commit 3fdfd5c

Please sign in to comment.