From 4cb32ee4345f648b7382d6e533e2f4d863fd7ced Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 14 Nov 2024 13:51:59 -0700 Subject: [PATCH 1/5] update: use byte pack template --- circuits/aes-gcm/nivc/aes-gctr-nivc.circom | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom index 4293d88..b23ab5a 100644 --- a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom +++ b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom @@ -41,14 +41,8 @@ template AESGCTRFOLD(NUM_CHUNKS) { } } - - var packedPlaintext[NUM_CHUNKS]; - for(var i = 0 ; i < NUM_CHUNKS ; i++) { - packedPlaintext[i] = 0; - for(var j = 0 ; j < 16 ; j++) { - packedPlaintext[i] += plainText[i][j] * 2**(8*j); - } - } + signal packedPlaintext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(plainText); + signal hash[NUM_CHUNKS]; for(var i = 0 ; i < NUM_CHUNKS ; i++) { if(i == 0) { From 26e5da48c810c98d8dcf6c8647643d6f63443aa8 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 14 Nov 2024 13:58:47 -0700 Subject: [PATCH 2/5] feat: AESHasher --- circuits/aes-gcm/nivc/aes-gctr-nivc.circom | 27 +++++++++++++++------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom index b23ab5a..2ea3c04 100644 --- a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom +++ b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom @@ -42,14 +42,25 @@ template AESGCTRFOLD(NUM_CHUNKS) { } signal packedPlaintext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(plainText); + step_out[0] <== AESHasher(NUM_CHUNKS)(packedPlaintext, step_in[0]); +} + +// TODO (autoparallel): Could probably just have datahasher take in an initial hash as an input, but this was quicker to try first. +template AESHasher(NUM_CHUNKS) { + // TODO: add this assert back after witnesscalc supports + // assert(DATA_BYTES % 16 == 0); + signal input in[NUM_CHUNKS]; + signal input initial_hash; + signal output out; - signal hash[NUM_CHUNKS]; + signal not_to_hash[NUM_CHUNKS]; + signal option_hash[NUM_CHUNKS]; + signal hashes[NUM_CHUNKS + 1]; + hashes[0] <== initial_hash; for(var i = 0 ; i < NUM_CHUNKS ; i++) { - if(i == 0) { - hash[i] <== PoseidonChainer()([step_in[0],packedPlaintext[i]]); - } else { - hash[i] <== PoseidonChainer()([hash[i-1], packedPlaintext[i]]); - } + not_to_hash[i] <== IsZero()(in[i]); + option_hash[i] <== PoseidonChainer()([hashes[i],in[i]]); + 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]; } - step_out[0] <== hash[NUM_CHUNKS - 1]; -} + out <== hashes[NUM_CHUNKS]; +} \ No newline at end of file From 49964d93344152a1f3084c26fa8280341e43ae22 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 14 Nov 2024 14:28:42 -0700 Subject: [PATCH 3/5] feat: adaptive foldable AES encryption --- circuits/aes-gcm/nivc/aes-gctr-nivc.circom | 22 +++++++++++++----- .../test/aes-gcm/nivc/aes-gctr-nivc.test.ts | 23 ++++++++++++++++--- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom index 2ea3c04..de7a4a8 100644 --- a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom +++ b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom @@ -33,15 +33,25 @@ template AESGCTRFOLD(NUM_CHUNKS) { aes[i].aad <== aad; } - signal ciphertext_equal_check[NUM_CHUNKS][16]; + // Regroup the plaintext and ciphertext into byte packed form + var computedCipherText[NUM_CHUNKS][16]; + for(var i = 0 ; i < NUM_CHUNKS ; i++) { + computedCipherText[i] = aes[i].cipherText; + } + signal packedCiphertext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(cipherText); + signal packedComputedCiphertext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(computedCipherText); + + signal ciphertext_input_was_zero_chunk[NUM_CHUNKS]; + signal ciphertext_option[NUM_CHUNKS]; + signal ciphertext_equal_check[NUM_CHUNKS]; for(var i = 0 ; i < NUM_CHUNKS; i++) { - for(var j = 0 ; j < 16 ; j++) { - ciphertext_equal_check[i][j] <== IsEqual()([aes[i].cipherText[j], cipherText[i][j]]); - ciphertext_equal_check[i][j] === 1; - } + ciphertext_input_was_zero_chunk[i] <== IsZero()(packedCiphertext[i]); + ciphertext_option[i] <== (1 - ciphertext_input_was_zero_chunk[i]) * packedComputedCiphertext[i]; + ciphertext_equal_check[i] <== IsEqual()([packedCiphertext[i], ciphertext_option[i]]); + ciphertext_equal_check[i] === 1; } - signal packedPlaintext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(plainText); + signal packedPlaintext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(plainText); step_out[0] <== AESHasher(NUM_CHUNKS)(packedPlaintext, step_in[0]); } diff --git a/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts b/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts index c1f2de2..1d918b6 100644 --- a/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts +++ b/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts @@ -28,13 +28,14 @@ describe("aes-gctr-nivc", () => { let plainText = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let iv = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let aad = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - let ct = [0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78]; + // let ct = [0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78]; const ctr = [0x00, 0x00, 0x00, 0x01]; const step_in = 0; - const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText, aad: aad, ctr: ctr, cipherText: ct, step_in: step_in }, ["step_out"]) - assert.deepEqual(witness.step_out, PoseidonModular([step_in, bytesToBigInt(plainText)])); + const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText, aad: aad, ctr: ctr, cipherText: plainText, step_in: step_in }, ["step_out"]) + console.log(witness.step_out); + assert.deepEqual(witness.step_out, BigInt(0)); }); it("all correct for self generated single non zero pt block", async () => { @@ -110,4 +111,20 @@ describe("aes-gctr-nivc", () => { let hash_0 = PoseidonModular([step_in_0, bytesToBigInt(plainText1)]); assert.deepEqual(witness.step_out, PoseidonModular([hash_0, bytesToBigInt(plainText2)])); }); + + it("all correct for two folds at once one zero chunk", async () => { + circuit_two_block = await circomkit.WitnessTester("aes-gcm-fold", { + file: "aes-gcm/nivc/aes-gctr-nivc", + template: "AESGCTRFOLD", + params: [2] + }); + + const ctr_0 = [0x00, 0x00, 0x00, 0x01]; + const step_in_0 = 0; + let zero_chunk = Array(16).fill(0); + + const witness = await circuit_two_block.compute({ key: key, iv: iv, aad: aad, ctr: ctr_0, plainText: [plainText1, zero_chunk], cipherText: [ct_part1, zero_chunk], step_in: step_in_0 }, ["step_out"]) + let hash_0 = PoseidonModular([step_in_0, bytesToBigInt(plainText1)]); + assert.deepEqual(witness.step_out, hash_0); + }); }); \ No newline at end of file From 98fa81180b94e3d77cf14a3e4ffac49d62ae9c78 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 14 Nov 2024 14:44:11 -0700 Subject: [PATCH 4/5] fix: check both pt and ct are zero chunk --- circuits/aes-gcm/nivc/aes-gctr-nivc.circom | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom index de7a4a8..76e815e 100644 --- a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom +++ b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom @@ -40,18 +40,21 @@ template AESGCTRFOLD(NUM_CHUNKS) { } signal packedCiphertext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(cipherText); signal packedComputedCiphertext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(computedCipherText); + signal packedPlaintext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(plainText); + signal plaintext_input_was_zero_chunk[NUM_CHUNKS]; signal ciphertext_input_was_zero_chunk[NUM_CHUNKS]; + signal both_input_chunks_were_zero[NUM_CHUNKS]; signal ciphertext_option[NUM_CHUNKS]; signal ciphertext_equal_check[NUM_CHUNKS]; for(var i = 0 ; i < NUM_CHUNKS; i++) { + plaintext_input_was_zero_chunk[i] <== IsZero()(packedPlaintext[i]); ciphertext_input_was_zero_chunk[i] <== IsZero()(packedCiphertext[i]); - ciphertext_option[i] <== (1 - ciphertext_input_was_zero_chunk[i]) * packedComputedCiphertext[i]; + both_input_chunks_were_zero[i] <== plaintext_input_was_zero_chunk[i] * ciphertext_input_was_zero_chunk[i]; + ciphertext_option[i] <== (1 - both_input_chunks_were_zero[i]) * packedComputedCiphertext[i]; ciphertext_equal_check[i] <== IsEqual()([packedCiphertext[i], ciphertext_option[i]]); ciphertext_equal_check[i] === 1; } - - signal packedPlaintext[NUM_CHUNKS] <== GenericBytePackArray(NUM_CHUNKS, 16)(plainText); step_out[0] <== AESHasher(NUM_CHUNKS)(packedPlaintext, step_in[0]); } From 5c4d4649e7297bce9217f509f631d42274788722 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 14 Nov 2024 14:44:27 -0700 Subject: [PATCH 5/5] version: bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d3287f8..80d75cf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "web-prover-circuits", "description": "ZK Circuits for WebProofs", - "version": "0.5.4", + "version": "0.5.5", "license": "Apache-2.0", "repository": { "type": "git",