From 12ced74e07cdcfb009e412226aa8f4306cb12f22 Mon Sep 17 00:00:00 2001 From: Sambhav Dusad Date: Wed, 18 Dec 2024 00:51:41 +0530 Subject: [PATCH] Fix/http verification (#85) * fix: `zeroed_data` for `data_digest` in `http_verification` * add test for 1024 --- circuits/chacha20/authentication.circom | 3 +- circuits/http/verification.circom | 8 ++--- circuits/test/full/full.test.ts | 42 +++++++++++++++++-------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/circuits/chacha20/authentication.circom b/circuits/chacha20/authentication.circom index 405b313..973feef 100644 --- a/circuits/chacha20/authentication.circom +++ b/circuits/chacha20/authentication.circom @@ -131,7 +131,7 @@ template PlaintextAuthentication(DATA_BYTES) { component toCiphertextBytes[DATA_BYTES / 4]; signal bigEndianCiphertext[DATA_BYTES]; - + for (var i = 0 ; i < DATA_BYTES / 4 ; i++) { toCiphertextBytes[i] = fromLittleEndianToWords32(); for (var j = 0 ; j < 32 ; j++) { @@ -151,7 +151,6 @@ template PlaintextAuthentication(DATA_BYTES) { } signal plaintext_digest <== PolynomialDigest(DATA_BYTES)(zeroed_plaintext, ciphertext_digest); signal plaintext_digest_hashed <== Poseidon(1)([plaintext_digest]); - // TODO: I'm not sure we need to subtract the CT digest step_out[0] <== step_in[0] - ciphertext_digest + plaintext_digest_hashed; } \ No newline at end of file diff --git a/circuits/http/verification.circom b/circuits/http/verification.circom index 93396ff..6c53dc4 100644 --- a/circuits/http/verification.circom +++ b/circuits/http/verification.circom @@ -7,7 +7,7 @@ include "../utils/hash.circom"; template HTTPVerification(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { signal input step_in[1]; signal output step_out[1]; - + signal input ciphertext_digest; signal input data[DATA_BYTES]; @@ -49,7 +49,7 @@ template HTTPVerification(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { } signal main_monomials[DATA_BYTES]; - main_monomials[0] <== 1; + main_monomials[0] <== 1; signal is_line_change[DATA_BYTES-1]; signal was_cleared[DATA_BYTES-1]; @@ -95,7 +95,7 @@ template HTTPVerification(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { body_accum[i + 1] <== body_accum[i] + State[i + 1].parsing_body; body_switch[i] <== IsEqual()([body_accum[i + 1], 1]); body_monomials[i + 1] <== body_monomials[i] * ciphertext_digest + body_switch[i]; - body_digest[i + 1] <== body_digest[i] + body_monomials[i + 1] * data[i + 1]; + body_digest[i + 1] <== body_digest[i] + body_monomials[i + 1] * zeroed_data[i + 1]; } // Verify machine ends in a valid state @@ -117,6 +117,6 @@ template HTTPVerification(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { main_digests_hashed[i] <== (1 - not_contained[i]) * option_hash[i]; accumulated_main_digests_hashed += main_digests_hashed[i]; } - + step_out[0] <== step_in[0] + body_digest_hashed - accumulated_main_digests_hashed - data_digest_hashed; // TODO: data_digest is really plaintext_digest from before, consider changing names } diff --git a/circuits/test/full/full.test.ts b/circuits/test/full/full.test.ts index 4917608..13ca7db 100644 --- a/circuits/test/full/full.test.ts +++ b/circuits/test/full/full.test.ts @@ -23,17 +23,14 @@ import { poseidon1 } from "poseidon-lite"; // 320 bytes in the HTTP response -const DATA_BYTES = 320; -const MAX_NUMBER_OF_HEADERS = 2; -const MAX_STACK_HEIGHT = 5; +const DATA_BYTES = 1024; +const MAX_NUMBER_OF_HEADERS = 25; +const MAX_STACK_HEIGHT = 10; // These `check_*` are currently from Rust to ensure we have parity const check_ciphertext_digest = BigInt("5947802862726868637928743536818722886587721698845887498686185738472802646104"); const check_init_nivc_input = BigInt("10288873638660630335427615297930270928433661836597941144520949467184902553219"); -const [ciphertext_digest, init_nivc_input] = InitialDigest(MockManifest(), http_response_ciphertext, MAX_STACK_HEIGHT); -assert.deepEqual(ciphertext_digest, check_ciphertext_digest); -assert.deepEqual(init_nivc_input, check_init_nivc_input); describe("Example NIVC Proof", async () => { let PlaintextAuthentication: WitnessTester<["step_in", "plaintext", "key", "nonce", "counter"], ["step_out"]>; @@ -62,17 +59,28 @@ describe("Example NIVC Proof", async () => { it("Spotify Example", async () => { // Run PlaintextAuthentication + + let http_response_padded = http_response_plaintext.concat(Array(DATA_BYTES - http_response_plaintext.length).fill(-1)); + let http_response_0_padded = http_response_plaintext.concat(Array(DATA_BYTES - http_start_line.length).fill(0)); + let ciphertext_padded = http_response_ciphertext.concat(Array(DATA_BYTES - http_response_ciphertext.length).fill(-1)); + + + const [ciphertext_digest, init_nivc_input] = InitialDigest(MockManifest(), ciphertext_padded, MAX_STACK_HEIGHT); + assert.deepEqual(ciphertext_digest, check_ciphertext_digest); + assert.deepEqual(init_nivc_input, check_init_nivc_input); + const counterBits = uintArray32ToBits([1])[0] const keyIn = toInput(Buffer.from(Array(32).fill(0))); const nonceIn = toInput(Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00])); let plaintext_authentication = await PlaintextAuthentication.compute({ step_in: init_nivc_input, - plaintext: http_response_plaintext, + plaintext: http_response_padded, key: keyIn, nonce: nonceIn, counter: counterBits, }, ["step_out"]); - const http_response_plaintext_digest = PolynomialDigest(http_response_plaintext, ciphertext_digest); + + const http_response_plaintext_digest = PolynomialDigest(http_response_0_padded, ciphertext_digest); const http_response_plaintext_digest_hashed = poseidon1([http_response_plaintext_digest]); const correct_plaintext_authentication_step_out = modAdd(init_nivc_input - ciphertext_digest, http_response_plaintext_digest_hashed); assert.deepEqual(plaintext_authentication.step_out, correct_plaintext_authentication_step_out); @@ -81,17 +89,25 @@ describe("Example NIVC Proof", async () => { const start_line_digest = PolynomialDigest(http_start_line, ciphertext_digest); const header_0_digest = PolynomialDigest(http_header_0, ciphertext_digest); const header_1_digest = PolynomialDigest(http_header_1, ciphertext_digest); - const padded_http_body = http_body.concat(Array(320 - http_body.length).fill(-1)); + + let main_digests = Array(MAX_NUMBER_OF_HEADERS + 1).fill(0); + main_digests[0] = start_line_digest; + main_digests[1] = header_0_digest; + main_digests[2] = header_1_digest; + let step_in = BigInt(plaintext_authentication.step_out.toString(10)); let http_verification = await HTTPVerification.compute({ step_in, ciphertext_digest, - data: http_response_plaintext, - main_digests: [start_line_digest, header_0_digest, header_1_digest], + data: http_response_padded, + main_digests, }, ["step_out"]); - // (autoparallel) This next line gives me an aneurysm + + const padded_http_body = http_body.concat(Array(DATA_BYTES - http_body.length).fill(0)); let http_verification_step_out = BigInt((http_verification.step_out as number[])[0]); - const body_digest_hashed = poseidon1([PolynomialDigest(http_body, ciphertext_digest)]); + let body_digest = PolynomialDigest(http_body, ciphertext_digest); + + const body_digest_hashed = poseidon1([body_digest]); const start_line_digest_digest_hashed = poseidon1([start_line_digest]); const header_0_digest_hashed = poseidon1([header_0_digest]); const header_1_digest_hashed = poseidon1([header_1_digest]);