From d21568d1db06b942a549c30c50320ed03828ad2c Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 5 Dec 2024 05:20:13 -0700 Subject: [PATCH] chore: remove unused circuit material (#72) * remove: extra HTTP material * remove: aes * fix: tests * remove: old `circuits.json` * cleanup: JSON * Delete json_nivc.circom * Delete extractor.circom * remove: unneeded utils * remove: more utils * consolidate bytes * fix: build --- .../http_verification_1024b.circom | 4 +- circuits.json | 218 +------ circuits/aes-gcm/aes-gcm.circom | 145 ----- circuits/aes-gcm/aes/cipher.circom | 159 ----- circuits/aes-gcm/aes/key_expansion.circom | 179 ------ circuits/aes-gcm/aes/mix_columns.circom | 209 ------- circuits/aes-gcm/aes/sbox.circom | 298 --------- circuits/aes-gcm/gctr.circom | 129 ---- circuits/aes-gcm/ghash/ghash.circom | 69 --- circuits/aes-gcm/ghash/gmul.circom | 133 ---- circuits/aes-gcm/nivc/aes-gctr-nivc.circom | 87 --- circuits/aes-gcm/nivc/gctr-nivc.circom | 76 --- circuits/chacha20/chacha-qr.circom | 2 +- circuits/chacha20/chacha-round.circom | 2 +- circuits/chacha20/chacha20.circom | 2 +- circuits/chacha20/nivc/chacha20_nivc.circom | 2 +- circuits/http/interpreter.circom | 107 ---- circuits/http/locker.circom | 181 ------ circuits/http/{parser => }/machine.circom | 3 +- circuits/http/nivc/body_mask.circom | 50 -- circuits/http/nivc/lock_header.circom | 131 ---- .../nivc/parse_and_lock_start_line.circom | 99 --- circuits/http/parser/language.circom | 27 - circuits/http/parser/parser.circom | 51 -- .../http_nivc.circom => verification.circom} | 24 +- circuits/json/extractor.circom | 164 ----- circuits/json/nivc/json_nivc.circom | 56 -- circuits/json/nivc/masker.circom | 1 + circuits/json/parser/language.circom | 10 +- circuits/json/parser/machine.circom | 18 +- circuits/json/parser/parser.circom | 32 +- circuits/test/aes-gcm/aes-gcm.test.ts | 67 -- circuits/test/aes-gcm/aes/cipher.test.ts | 193 ------ .../test/aes-gcm/aes/key_expansion.test.ts | 106 ---- circuits/test/aes-gcm/aes/sbox.test.ts | 125 ---- .../test/aes-gcm/aes/transformations.test.ts | 74 --- circuits/test/aes-gcm/gctr.test.ts | 31 - circuits/test/aes-gcm/ghash/ghash.test.ts | 30 - circuits/test/aes-gcm/ghash/gmul.test.ts | 117 ---- .../test/aes-gcm/nivc/aes-gctr-nivc.test.ts | 124 ---- circuits/test/full/full.test.ts | 383 +++--------- circuits/test/http/interpreter.test.ts | 111 ---- circuits/test/http/locker.test.ts | 136 ---- circuits/test/http/nivc/body_mask.test.ts | 127 ---- circuits/test/http/nivc/lock_header.test.ts | 100 --- .../nivc/parse_and_lock_start_line.test.ts | 86 --- ...http_nivc.test.ts => verification.test.ts} | 14 +- circuits/test/utils/array.test.ts | 582 +++++------------- circuits/test/utils/bits.test.ts | 25 + circuits/test/utils/bytes.test.ts | 170 ----- circuits/test/utils/search.test.ts | 245 +------- circuits/utils/array.circom | 281 --------- .../{generics-bits.circom => bits.circom} | 24 +- circuits/utils/bytes.circom | 258 -------- circuits/utils/search.circom | 254 -------- 55 files changed, 341 insertions(+), 5990 deletions(-) delete mode 100644 circuits/aes-gcm/aes-gcm.circom delete mode 100644 circuits/aes-gcm/aes/cipher.circom delete mode 100644 circuits/aes-gcm/aes/key_expansion.circom delete mode 100644 circuits/aes-gcm/aes/mix_columns.circom delete mode 100644 circuits/aes-gcm/aes/sbox.circom delete mode 100644 circuits/aes-gcm/gctr.circom delete mode 100644 circuits/aes-gcm/ghash/ghash.circom delete mode 100644 circuits/aes-gcm/ghash/gmul.circom delete mode 100644 circuits/aes-gcm/nivc/aes-gctr-nivc.circom delete mode 100644 circuits/aes-gcm/nivc/gctr-nivc.circom delete mode 100644 circuits/http/interpreter.circom delete mode 100644 circuits/http/locker.circom rename circuits/http/{parser => }/machine.circom (98%) delete mode 100644 circuits/http/nivc/body_mask.circom delete mode 100644 circuits/http/nivc/lock_header.circom delete mode 100644 circuits/http/nivc/parse_and_lock_start_line.circom delete mode 100644 circuits/http/parser/language.circom delete mode 100644 circuits/http/parser/parser.circom rename circuits/http/{nivc/http_nivc.circom => verification.circom} (82%) delete mode 100644 circuits/json/extractor.circom delete mode 100644 circuits/json/nivc/json_nivc.circom delete mode 100644 circuits/test/aes-gcm/aes-gcm.test.ts delete mode 100644 circuits/test/aes-gcm/aes/cipher.test.ts delete mode 100644 circuits/test/aes-gcm/aes/key_expansion.test.ts delete mode 100644 circuits/test/aes-gcm/aes/sbox.test.ts delete mode 100644 circuits/test/aes-gcm/aes/transformations.test.ts delete mode 100644 circuits/test/aes-gcm/gctr.test.ts delete mode 100644 circuits/test/aes-gcm/ghash/ghash.test.ts delete mode 100644 circuits/test/aes-gcm/ghash/gmul.test.ts delete mode 100644 circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts delete mode 100644 circuits/test/http/interpreter.test.ts delete mode 100644 circuits/test/http/locker.test.ts delete mode 100644 circuits/test/http/nivc/body_mask.test.ts delete mode 100644 circuits/test/http/nivc/lock_header.test.ts delete mode 100644 circuits/test/http/nivc/parse_and_lock_start_line.test.ts rename circuits/test/http/{nivc/http_nivc.test.ts => verification.test.ts} (96%) create mode 100644 circuits/test/utils/bits.test.ts delete mode 100644 circuits/test/utils/bytes.test.ts rename circuits/utils/{generics-bits.circom => bits.circom} (80%) delete mode 100644 circuits/utils/bytes.circom diff --git a/builds/target_1024b/http_verification_1024b.circom b/builds/target_1024b/http_verification_1024b.circom index 68ed7dd..c2e8855 100644 --- a/builds/target_1024b/http_verification_1024b.circom +++ b/builds/target_1024b/http_verification_1024b.circom @@ -1,5 +1,5 @@ pragma circom 2.1.9; -include "../../circuits/http/nivc/http_nivc.circom"; +include "../../circuits/http/verification.circom"; -component main { public [step_in] } = HttpNIVC(1024, 25); +component main { public [step_in] } = HTTPVerification(1024, 25); diff --git a/circuits.json b/circuits.json index 29fe196..cc1f043 100644 --- a/circuits.json +++ b/circuits.json @@ -1,218 +1,4 @@ { - "value_number_test": { - "file": "main/json_value_number_test", - "template": "ExtractNumValue", - "params": [ - 12, - 1, - 1, - 0, - 2 - ] - }, - "json-parser": { - "file": "json/parser/parser", - "template": "Parser", - "params": [ - 157, - 13 - ] - }, - "value_string_test": { - "file": "main/json_value_string_test", - "template": "ExtractStringValue", - "params": [ - 12, - 1, - 1, - 0, - 1 - ] - }, - "spotify_test": { - "file": "main/json_spotify_test", - "template": "ExtractStringValue", - "params": [ - 85, - 5, - 4, - 0, - 5, - 1, - 0, - 2, - 7, - 3, - 4, - 4, - 12 - ] - }, - "http-parser": { - "file": "http/parser/parser", - "template": "Parser", - "params": [ - 60 - ] - }, - "spotify_top_artists_test": { - "file": "main/http_spotify_top_artists_test", - "template": "LockHTTPResponse", - "params": [ - 203, - 85, - 8, - 3, - 2, - 12, - 31 - ] - }, - "value_array_number_test": { - "file": "main/json_value_array_number_test", - "template": "ExtractNumValue", - "params": [ - 73, - 2, - 1, - 0, - 2, - 1, - 4 - ] - }, - "value_array_object_test": { - "file": "main/json_value_array_object_test", - "template": "ExtractNumValue", - "params": [ - 29, - 4, - 1, - 0, - 0, - 1, - 1, - 2, - 0, - 3, - 1 - ] - }, - "value_string": { - "file": "main/json_value_string", - "template": "ExtractStringValue", - "params": [ - 12, - 1, - 1, - 0, - 1 - ] - }, - "two_keys_test": { - "file": "main/json_two_keys_test", - "template": "ExtractStringValue", - "params": [ - 40, - 1, - 4, - 0, - 3 - ] - }, - "get_request_test": { - "file": "main/http_get_request_test", - "template": "LockHTTPRequest", - "params": [ - 60, - 3, - 4, - 8, - 6, - 16, - 4, - 9 - ] - }, - "value_array_nested_test": { - "file": "main/json_value_array_nested_test", - "template": "ExtractNumValue", - "params": [ - 24, - 3, - 1, - 0, - 0, - 1, - 0, - 2, - 1 - ] - }, - "spotify_top_artists": { - "file": "main/extended_spotify_top_artists", - "template": "HttpJson", - "params": [ - 203, - 85, - 8, - 3, - 2, - 12, - 31, - 5, - 4, - 0, - 5, - 1, - 0, - 2, - 7, - 3, - 4, - 4, - 12 - ] - }, - "value_object_test": { - "file": "main/json_value_object_test", - "template": "ExtractStringValue", - "params": [ - 134, - 3, - 1, - 0, - 1, - 1, - 1 - ] - }, - "value_array_string_test": { - "file": "main/json_value_array_string_test", - "template": "ExtractStringValue", - "params": [ - 73, - 2, - 1, - 0, - 1, - 1, - 2 - ] - }, - "get_response_test": { - "file": "main/http_get_response_test", - "template": "LockHTTPResponse", - "params": [ - 89, - 18, - 8, - 3, - 2, - 12, - 16 - ] - }, "plaintext_authentication_1024b": { "file": "chacha20/nivc/chacha20_nivc", "template": "ChaCha20_NIVC", @@ -221,8 +7,8 @@ ] }, "http_verification_1024b": { - "file": "http/nivc/http_nivc", - "template": "HttpNIVC", + "file": "http/verification", + "template": "HTTPVerification", "params": [ 1024, 25 diff --git a/circuits/aes-gcm/aes-gcm.circom b/circuits/aes-gcm/aes-gcm.circom deleted file mode 100644 index ef9373b..0000000 --- a/circuits/aes-gcm/aes-gcm.circom +++ /dev/null @@ -1,145 +0,0 @@ -pragma circom 2.1.9; - -include "ghash/ghash.circom"; -include "aes/cipher.circom"; -include "../utils/array.circom"; -include "gctr.circom"; - - -/// AES-GCM with 128 bit key authenticated encryption according to: https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-38d.pdf -/// -/// Parameters: -/// l: length of the plaintext -/// -/// Inputs: -/// key: 128-bit key -/// iv: initialization vector -/// plainText: plaintext to be encrypted -/// aad: additional data to be authenticated -/// -/// Outputs: -/// cipherText: encrypted ciphertext -/// authTag: authentication tag -/// -template AESGCM(l) { - // Inputs - signal input key[16]; // 128-bit key - signal input iv[12]; // IV length is 96 bits (12 bytes) - signal input plainText[l]; - signal input aad[16]; // AAD length is 128 bits (16 bytes) - - // Outputs - signal output cipherText[l]; - signal output authTag[16]; // Authentication tag length is 128 bits (16 bytes) - - component zeroBlock = ToBlocks(16); - for (var i = 0; i < 16; i++) { - zeroBlock.stream[i] <== 0; - } - - // Step 1: Let H = aes(key, zeroBlock) - component cipherH = Cipher(); - cipherH.key <== key; - cipherH.block <== zeroBlock.blocks[0]; - - // Step 2: Define a block, J0 with 96 bits of iv and 32 bits of 0s - component J0builder = ToBlocks(16); - for (var i = 0; i < 12; i++) { - J0builder.stream[i] <== iv[i]; - } - for (var i = 12; i < 16; i++) { - J0builder.stream[i] <== 0; - } - component J0WordIncrementer = IncrementWord(); - J0WordIncrementer.in <== J0builder.blocks[0][3]; - - component J0WordIncrementer2 = IncrementWord(); - J0WordIncrementer2.in <== J0WordIncrementer.out; - - signal J0[4][4]; - for (var i = 0; i < 3; i++) { - J0[i] <== J0builder.blocks[0][i]; - } - J0[3] <== J0WordIncrementer2.out; - - // Step 3: Let C = GCTRK(inc32(J0), P) - component gctr = GCTR(l); - gctr.key <== key; - gctr.initialCounterBlock <== J0; - gctr.plainText <== plainText; - - - // Step 4: Let u and v (v is always zero with out key size and aad length) - var blockCount = l\16; - if(l%16 > 0){ - blockCount = blockCount + 1; - } - // so the reason there is a plus two is because - // the first block is the aad - // the second is the ciphertext - // the last is the length of the aad and ciphertext - // i.e. S = GHASHH (A || C || [len(A)] || [len(C)]). <- which is always 48 bytes: 3 blocks - var ghashblocks = blockCount + 2; - signal ghashMessage[ghashblocks][4][4]; - - // set aad as first block - for (var i=0; i < 4; i++) { - for (var j=0; j < 4; j++) { - ghashMessage[0][i][j] <== aad[i*4+j]; - } - } - // set cipher text block padded - component ciphertextBlocks = ToBlocks(l); - ciphertextBlocks.stream <== gctr.cipherText; - - for (var i=0; i> i*8+j) & 1; - } - ghashMessage[ghashblocks-1][i\4+2][i%4] <== byte_value; - } - - // Step 5: Define a block, S - // needs to take in the number of blocks - component ghash = GHASH(ghashblocks); - component hashKeyToStream = ToStream(1, 16); - hashKeyToStream.blocks[0] <== cipherH.cipher; - ghash.HashKey <== hashKeyToStream.stream; - // S = GHASHH (A || 0^v || C || 0^u || [len(A)] || [len(C)]). - component selectedBlocksToStream[ghashblocks]; - for (var i = 0 ; i 0 && round <= 10); - - var rcon[10][4] = [ - [0x01, 0x00, 0x00, 0x00], - [0x02, 0x00, 0x00, 0x00], - [0x04, 0x00, 0x00, 0x00], - [0x08, 0x00, 0x00, 0x00], - [0x10, 0x00, 0x00, 0x00], - [0x20, 0x00, 0x00, 0x00], - [0x40, 0x00, 0x00, 0x00], - [0x80, 0x00, 0x00, 0x00], - [0x1b, 0x00, 0x00, 0x00], - [0x36, 0x00, 0x00, 0x00] - ]; - - out <== rcon[round-1]; -} - -// Rotates an array of bytes to the left by a specified rotation -template Rotate(rotation, length) { - assert(rotation < length); - signal input bytes[length]; - signal output rotated[length]; - - for(var i = 0; i < length - rotation; i++) { - rotated[i] <== bytes[i + rotation]; - } - - for(var i = length - rotation; i < length; i++) { - rotated[i] <== bytes[i - length + rotation]; - } -} - -// Substitutes each byte in a word using the S-Box -template SubstituteWord() { - signal input bytes[4]; - signal output substituted[4]; - - component sbox[4]; - - for(var i = 0; i < 4; i++) { - sbox[i] = SBox128(); - sbox[i].in <== bytes[i]; - substituted[i] <== sbox[i].out; - } -} \ No newline at end of file diff --git a/circuits/aes-gcm/aes/mix_columns.circom b/circuits/aes-gcm/aes/mix_columns.circom deleted file mode 100644 index f52a40a..0000000 --- a/circuits/aes-gcm/aes/mix_columns.circom +++ /dev/null @@ -1,209 +0,0 @@ -// from: https://github.com/crema-labs/aes-circom/tree/main/circuits -pragma circom 2.1.9; - -include "key_expansion.circom"; -include "circomlib/circuits/bitify.circom"; -include "../../utils/bytes.circom"; - -// MixColumns: Applies the equation for each column: -// [s'0,c] [2 3 1 1][s0,c] -// [s'1,c] = [1 2 3 1][s1,c] -// [s'2,c] [1 1 2 3][s2,c] -// [s'3,c] [3 1 1 2][s3,c] -// Where c is the column number, s are input bytes, s' are output bytes -template MixColumns(){ - signal input state[4][4]; - signal output out[4][4]; - - component s0[4]; - component s1[4]; - component s2[4]; - component s3[4]; - - for (var i = 0; i < 4; i++) { - s0[i] = S0(); - s1[i] = S1(); - s2[i] = S2(); - s3[i] = S3(); - - for(var j = 0; j < 4; j++) { - s0[i].in[j] <== state[j][i]; - s1[i].in[j] <== state[j][i]; - s2[i].in[j] <== state[j][i]; - s3[i].in[j] <== state[j][i]; - } - - out[0][i] <== s0[i].out; - out[1][i] <== s1[i].out; - out[2][i] <== s2[i].out; - out[3][i] <== s3[i].out; - } -} - -// S0: Implements the equation -// out = (2 • in[0]) ⊕ (3 • in[1]) ⊕ in[2] ⊕ in[3] -template S0(){ - signal input in[4]; - signal output out; - component num2bits[4]; - component xor[3]; - - for (var i = 2; i < 4; i++) { - num2bits[i] = Num2Bits(8); - num2bits[i].in <== in[i]; - } - - num2bits[0] = Num2Bits(8); - num2bits[0].in <== TBox(0)(in[0]); - - num2bits[1] = Num2Bits(8); - num2bits[1].in <== TBox(1)(in[1]); - - xor[0] = BitwiseXor(8); - xor[0].a <== num2bits[0].out; - xor[0].b <== num2bits[1].out; - - xor[1] = BitwiseXor(8); - xor[1].a <== xor[0].out; - xor[1].b <== num2bits[2].out; - - xor[2] = BitwiseXor(8); - xor[2].a <== xor[1].out; - xor[2].b <== num2bits[3].out; - - component b2n = Bits2Num(8); - for (var i = 0; i < 8; i++) { - b2n.in[i] <== xor[2].out[i]; - } - - out <== b2n.out; -} - -// S1: Implements the equation -// out = in[0] ⊕ (2 • in[1]) ⊕ (3 • in[2]) ⊕ in[3] -template S1(){ - signal input in[4]; - signal output out; - component num2bits[4]; - component xor[3]; - - num2bits[0] = Num2Bits(8); - num2bits[0].in <== in[0]; - - num2bits[1] = Num2Bits(8); - num2bits[1].in <== TBox(0)(in[1]); - - num2bits[2] = Num2Bits(8); - num2bits[2].in <== TBox(1)(in[2]); - - num2bits[3] = Num2Bits(8); - num2bits[3].in <== in[3]; - - xor[0] = BitwiseXor(8); - xor[0].a <== num2bits[0].out; - xor[0].b <== num2bits[1].out; - - xor[1] = BitwiseXor(8); - xor[1].a <== xor[0].out; - xor[1].b <== num2bits[2].out; - - xor[2] = BitwiseXor(8); - xor[2].a <== xor[1].out; - xor[2].b <== num2bits[3].out; - - component b2n = Bits2Num(8); - for (var i = 0; i < 8; i++) { - b2n.in[i] <== xor[2].out[i]; - } - - out <== b2n.out; -} - -// S2: Implements the equation -// out = in[0] ⊕ in[1] ⊕ (2 • in[2]) ⊕ (3 • in[3]) -template S2() { - signal input in[4]; - signal output out; - component num2bits[4]; - component xor[3]; - - for (var i = 0; i < 2; i++) { - num2bits[i] = Num2Bits(8); - num2bits[i].in <== in[i]; - } - - num2bits[2] = Num2Bits(8); - num2bits[2].in <== TBox(0)(in[2]); - - num2bits[3] = Num2Bits(8); - num2bits[3].in <== TBox(1)(in[3]); - - xor[0] = BitwiseXor(8); - xor[0].a <== num2bits[0].out; - xor[0].b <== num2bits[1].out; - - xor[1] = BitwiseXor(8); - xor[1].a <== xor[0].out; - xor[1].b <== num2bits[2].out; - - xor[2] = BitwiseXor(8); - xor[2].a <== xor[1].out; - xor[2].b <== num2bits[3].out; - - component b2n = Bits2Num(8); - for (var i = 0; i < 8; i++) { - b2n.in[i] <== xor[2].out[i]; - } - - out <== b2n.out; -} - -// S3: Implements the equation -// out = (3 • in[0]) ⊕ in[1] ⊕ in[2] ⊕ (2 • in[3]) -template S3() { - signal input in[4]; - signal output out; - component num2bits[4]; - component xor[3]; - - for (var i = 1; i < 3; i++) { - num2bits[i] = Num2Bits(8); - num2bits[i].in <== in[i]; - } - - num2bits[0] = Num2Bits(8); - num2bits[0].in <== TBox(1)(in[0]); - - num2bits[3] = Num2Bits(8); - num2bits[3].in <== TBox(0)(in[3]); - - xor[0] = BitwiseXor(8); - xor[0].a <== num2bits[0].out; - xor[0].b <== num2bits[1].out; - - xor[1] = BitwiseXor(8); - xor[1].a <== xor[0].out; - xor[1].b <== num2bits[2].out; - - xor[2] = BitwiseXor(8); - xor[2].a <== num2bits[3].out; - xor[2].b <== xor[1].out; - - component b2n = Bits2Num(8); - for (var i = 0; i < 8; i++) { - b2n.in[i] <== xor[2].out[i]; - } - - out <== b2n.out; -} - -template TBox(index) { - signal input subindex; - signal output out; - - if (index == 0) { - out <== FieldMul2()(subindex); - } else if (index == 1) { - out <== FieldMul3()(subindex); - } -} \ No newline at end of file diff --git a/circuits/aes-gcm/aes/sbox.circom b/circuits/aes-gcm/aes/sbox.circom deleted file mode 100644 index bbea049..0000000 --- a/circuits/aes-gcm/aes/sbox.circom +++ /dev/null @@ -1,298 +0,0 @@ -// from: https://github.com/crema-labs/aes-circom/tree/main/circuits -pragma circom 2.1.9; - -include "circomlib/circuits/comparators.circom"; -include "circomlib/circuits/bitify.circom"; -include "circomlib/circuits/gates.circom"; -include "../../utils/array.circom"; -include "../../utils/bytes.circom"; - -template SBox128() { - signal input in; - signal output out; - - signal inv <== FieldInv()(in); - signal invBits[8] <== Num2Bits(8)(inv); - signal outBits[8] <== AffineTransform()(invBits); - out <== Bits2Num(8)(outBits); -} - - - -// All this is for a properly constrained sbox since we don't have lookup arguments -// Finite field addition, the signal variable plus a compile-time constant -template FieldAddConst(c) { - signal input in[8]; - // control bit, if 0, then do not perform addition - signal input control; - signal output out[8]; - - for (var i=0; i<8; i++) { - if(c & (1<>1 if LSB1(Vi) = 0; - // Vi+1 ⎨ - // ⎩ (Vi >>1) ⊕ R if LSB1(Vi) =1. - // - component bit[16]; - component z_i_update[128]; - component mulx[128]; - component bytesToBits = BytesToBits(16); - bytesToBits.in <== X; - signal bitsX[16*8]; - bitsX <== bytesToBits.out; - for (var i = 0; i < 128; i++) { - // z_i_update - z_i_update[i] = Z_UPDATE(16); - z_i_update[i].Z <== Z[i]; - z_i_update[i].V <== V[i]; - z_i_update[i].bit_val <== bitsX[i]; - Z[i + 1] <== z_i_update[i].Z_new; - - // mulx to update V - mulx[i] = Mulx(16); - mulx[i].in <== V[i]; - V[i + 1] <== mulx[i].out; - } - // 4. Return Z128. - out <== Z[128]; -} - - -// if bit value is 0, then Z_new = Z -// if bit value is 1, then Z_new = Z xor V -template Z_UPDATE(n_bytes) { - signal input Z[n_bytes]; // this is Zero block in first itteration - signal input V[n_bytes]; // this is Y in first itteration - signal input bit_val; - signal output Z_new[n_bytes]; - - component mux = ArrayMux(n_bytes); - mux.sel <== bit_val; - mux.a <== Z; - component xorBlock = XORBLOCK(n_bytes); - xorBlock.a <== Z; - xorBlock.b <== V; - mux.b <== xorBlock.out; - Z_new <== mux.out; -} - - - - -// right shift by one bit. If msb is 1: -// then we xor the first byte with 0xE1 (11100001: 1 + X + X^2 + X^7) -// this is the irreducible polynomial used in AES-GCM -template Mulx(n_bytes) { - signal input in[n_bytes]; - signal output out[n_bytes]; - - signal intermediate[n_bytes]; - - component blockRightShift = BlockRightShift(n_bytes); - blockRightShift.in <== in; - intermediate <== blockRightShift.out; - - component xorByte = XorByte(); - xorByte.a <== intermediate[0]; - xorByte.b <== 0xE1; // 11100001 - - // if msb is 1, then we xor the first byte with R[0] - component mux = Mux1(); - mux.s <== blockRightShift.msb; - mux.c[0] <== intermediate[0]; - mux.c[1] <== xorByte.out; - - for (var i = 1; i < n_bytes; i++) { - out[i] <== intermediate[i]; - } - out[0] <== mux.out; -} - -// right shifts 16 bytes by one bit and returns the msb before the shift -template BlockRightShift(n_bytes) { - signal input in[n_bytes]; - signal output out[n_bytes]; - signal output msb; - - signal shiftedbits[n_bytes*8]; - component bytesToBits = BytesToBits(n_bytes); - for (var i = 0; i < n_bytes; i++) { - bytesToBits.in[i] <== in[i]; - } - msb <== bytesToBits.out[n_bytes*8 - 1]; - - component BitwiseRightShift = BitwiseRightShift(n_bytes*8, 1); - BitwiseRightShift.in <== bytesToBits.out; - shiftedbits <== BitwiseRightShift.out; - - component bitsToBytes = BitsToBytes(n_bytes); - bitsToBytes.in <== shiftedbits; - out <== bitsToBytes.out; -} \ No newline at end of file diff --git a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom deleted file mode 100644 index c8ce9dd..0000000 --- a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom +++ /dev/null @@ -1,87 +0,0 @@ -pragma circom 2.1.9; - -include "gctr-nivc.circom"; -include "../../utils/array.circom"; -include "../../utils/hash.circom"; - -// Compute AES-GCTR -template AESGCTRFOLD(NUM_CHUNKS) { - signal input key[16]; - signal input iv[12]; - signal input aad[16]; - - signal input ctr[4]; - - signal input plainText[NUM_CHUNKS][16]; - signal input cipherText[NUM_CHUNKS][16]; - - signal input step_in[1]; - signal output step_out[1]; - - component aes[NUM_CHUNKS]; - for(var i = 0 ; i < NUM_CHUNKS ; i++) { - aes[i] = AESGCTRFOLDABLE(); - if( i == 0) { - aes[i].plainText <== plainText[i]; - aes[i].lastCounter <== ctr; - } else { - aes[i].plainText <== plainText[i]; - aes[i].lastCounter <== aes[i - 1].counter; - } - aes[i].key <== key; - aes[i].iv <== iv; - aes[i].aad <== aad; - } - - // 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; - } - - // verify that ciphertext supplied as private input match the computed one - signal matchedCiphertext[NUM_CHUNKS]; - for (var i = 0 ; i < NUM_CHUNKS ; i++) { - matchedCiphertext[i] <== IsEqualArray(16)([cipherText[i], aes[i].cipherText]); - matchedCiphertext[i] === 1; - } - - 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]); - 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; - } - 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 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++) { - 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]; - } - out <== hashes[NUM_CHUNKS]; -} \ No newline at end of file diff --git a/circuits/aes-gcm/nivc/gctr-nivc.circom b/circuits/aes-gcm/nivc/gctr-nivc.circom deleted file mode 100644 index bde7fc9..0000000 --- a/circuits/aes-gcm/nivc/gctr-nivc.circom +++ /dev/null @@ -1,76 +0,0 @@ -pragma circom 2.1.9; - -include "../aes/cipher.circom"; -include "../../utils/array.circom"; -include "../gctr.circom"; - -/// AES-GCTR with 128 bit key encryption according to: https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-38d.pdf -/// -/// Parameters: -/// l: length of the plaintext -/// -/// Inputs: -/// key: 128-bit key -/// iv: initialization vector -/// plainText: plaintext to be encrypted -/// aad: additional data to be authenticated -/// -/// Outputs: -/// cipherText: encrypted ciphertext -/// -/// This folds a single block without authentication via ghash. -template AESGCTRFOLDABLE() { - // Inputs - signal input key[16]; // 128-bit key - signal input iv[12]; // IV length is 96 bits (12 bytes) - signal input plainText[16]; // only fold 16 bytes at a time. - signal input aad[16]; // AAD length is 128 bits (16 bytes) - - // Fold inputs - signal input lastCounter[4]; // Always start at one, then bring forward last counter. - - // Fold outputs - signal output counter[4]; - signal output cipherText[16]; - - component zeroBlock = ToBlocks(16); - for (var i = 0; i < 16; i++) { - zeroBlock.stream[i] <== 0; - } - - // Step 1: Let HashKey = aes(key, zeroBlock) - component cipherH = Cipher(); - cipherH.key <== key; - cipherH.block <== zeroBlock.blocks[0]; - - // Step 2: Define a block, J0 with 96 bits of iv and 32 bits of 0s - component J0builder = ToBlocks(16); - for (var i = 0; i < 12; i++) { - J0builder.stream[i] <== iv[i]; - } - // Use the fold counter as input. - for (var i = 12; i < 16; i++) { - J0builder.stream[i] <== lastCounter[i%4]; // initialize to 0001. - } - - component J0WordIncrementer = IncrementWord(); - J0WordIncrementer.in <== J0builder.blocks[0][3]; - - signal J0[4][4]; - for (var i = 0; i < 3; i++) { - J0[i] <== J0builder.blocks[0][i]; - } - J0[3] <== J0WordIncrementer.out; - - // Step 3: Let C = GCTRK(inc32(J0), P) - component gctr = GCTR(16); - gctr.key <== key; - gctr.initialCounterBlock <== J0; - gctr.plainText <== plainText; - cipherText <== gctr.cipherText; - - // extract the counter column wise. - for (var i = 0; i < 4; i++) { - counter[i] <== J0[i][3]; - } -} \ No newline at end of file diff --git a/circuits/chacha20/chacha-qr.circom b/circuits/chacha20/chacha-qr.circom index 7ce1487..7cc7466 100644 --- a/circuits/chacha20/chacha-qr.circom +++ b/circuits/chacha20/chacha-qr.circom @@ -2,7 +2,7 @@ // modified for our needs pragma circom 2.1.9; -include "../utils/generics-bits.circom"; +include "../utils/bits.circom"; /** * Perform ChaCha Quarter Round diff --git a/circuits/chacha20/chacha-round.circom b/circuits/chacha20/chacha-round.circom index 95e4340..0f5feda 100644 --- a/circuits/chacha20/chacha-round.circom +++ b/circuits/chacha20/chacha-round.circom @@ -3,7 +3,7 @@ pragma circom 2.1.9; include "./chacha-qr.circom"; -include "../utils/generics-bits.circom"; +include "../utils/bits.circom"; template Round() { // in => 16 32-bit words diff --git a/circuits/chacha20/chacha20.circom b/circuits/chacha20/chacha20.circom index b9290a8..ea85ffe 100644 --- a/circuits/chacha20/chacha20.circom +++ b/circuits/chacha20/chacha20.circom @@ -4,7 +4,7 @@ pragma circom 2.1.9; include "./chacha-round.circom"; include "./chacha-qr.circom"; -include "../utils/generics-bits.circom"; +include "../utils/bits.circom"; /** ChaCha20 in counter mode */ // Chacha20 opperates a 4x4 matrix of 32-bit words where the first 4 words are constants: C diff --git a/circuits/chacha20/nivc/chacha20_nivc.circom b/circuits/chacha20/nivc/chacha20_nivc.circom index d7fdad2..b528ced 100644 --- a/circuits/chacha20/nivc/chacha20_nivc.circom +++ b/circuits/chacha20/nivc/chacha20_nivc.circom @@ -4,7 +4,7 @@ pragma circom 2.1.9; include "../chacha-round.circom"; include "../chacha-qr.circom"; -include "../../utils/generics-bits.circom"; +include "../../utils/bits.circom"; include "../../utils/hash.circom"; include "../../utils/array.circom"; diff --git a/circuits/http/interpreter.circom b/circuits/http/interpreter.circom deleted file mode 100644 index 79e6278..0000000 --- a/circuits/http/interpreter.circom +++ /dev/null @@ -1,107 +0,0 @@ -pragma circom 2.1.9; - -include "parser/language.circom"; -include "../utils/search.circom"; -include "../utils/array.circom"; - -template inStartLine() { - signal input parsing_start; - signal output out; - - signal isBeginning <== IsEqual()([parsing_start, 1]); - signal isMiddle <== IsEqual()([parsing_start, 2]); - signal isEnd <== IsEqual()([parsing_start, 3]); - - out <== isBeginning + isMiddle + isEnd; -} - -template inStartMiddle() { - signal input parsing_start; - signal output out; - - out <== IsEqual()([parsing_start, 2]); -} - -template inStartEnd() { - signal input parsing_start; - signal output out; - - out <== IsEqual()([parsing_start, 3]); -} - -// TODO: This likely isn't really an "Intepreter" thing -template MethodMatch(dataLen, methodLen) { - signal input data[dataLen]; - signal input method[methodLen]; - - signal input index; - - signal isMatch <== SubstringMatchWithIndex(dataLen, methodLen)(data, method, index); - isMatch === 1; -} - -// https://www.rfc-editor.org/rfc/rfc9112.html#name-field-syntax -template HeaderFieldNameValueMatch(dataLen, nameLen, valueLen) { - signal input data[dataLen]; - signal input headerName[nameLen]; - signal input headerValue[valueLen]; - signal input index; - - // is name matches - signal headerNameMatch <== SubstringMatchWithIndex(dataLen, nameLen)(data, headerName, index); - - // next byte to name should be COLON - signal endOfHeaderName <== IndexSelector(dataLen)(data, index + nameLen); - signal isNextByteColon <== IsEqual()([endOfHeaderName, 58]); - - signal headerNameMatchAndNextByteColon <== headerNameMatch * isNextByteColon; - - // field-name: SP field-value - signal headerValueMatch <== SubstringMatchWithIndex(dataLen, valueLen)(data, headerValue, index + nameLen + 2); - - // header name matches + header value matches - signal output out <== headerNameMatchAndNextByteColon * headerValueMatch; -} - -// https://www.rfc-editor.org/rfc/rfc9112.html#name-field-syntax -template HeaderFieldNameValueMatchPadded(dataLen, maxNameLen, maxValueLen) { - signal input data[dataLen]; - signal input headerName[maxNameLen]; - signal input nameLen; - signal input headerValue[maxValueLen]; - signal input valueLen; - signal input index; - - // is name matchesnameLen - signal headerNameMatch <== SubstringMatchWithIndexPadded(dataLen, maxNameLen)(data, headerName, nameLen, index); - - // next byte to name should be COLON - signal endOfHeaderName <== IndexSelector(dataLen)(data, index + nameLen); - signal isNextByteColon <== IsEqual()([endOfHeaderName, 58]); - - signal headerNameMatchAndNextByteColon <== headerNameMatch * isNextByteColon; - - // field-name: SP field-value - signal headerValueMatch <== SubstringMatchWithIndexPadded(dataLen, maxValueLen)(data, headerValue, valueLen, index + nameLen + 2); - - // header name matches + header value matches - signal output out <== headerNameMatchAndNextByteColon * headerValueMatch; -} - -// https://www.rfc-editor.org/rfc/rfc9112.html#name-field-syntax -template HeaderFieldNameMatch(dataLen, nameLen) { - signal input data[dataLen]; - signal input headerName[nameLen]; - signal input index; - - // is name matches - signal headerNameMatch <== SubstringMatchWithIndex(dataLen, nameLen)(data, headerName, index); - - // next byte to name should be COLON - signal endOfHeaderName <== IndexSelector(dataLen)(data, index + nameLen); - signal isNextByteColon <== IsEqual()([endOfHeaderName, 58]); - - // header name matches - signal output out; - out <== headerNameMatch * isNextByteColon; -} \ No newline at end of file diff --git a/circuits/http/locker.circom b/circuits/http/locker.circom deleted file mode 100644 index cd8c439..0000000 --- a/circuits/http/locker.circom +++ /dev/null @@ -1,181 +0,0 @@ -pragma circom 2.1.9; - -include "interpreter.circom"; -include "parser/machine.circom"; -include "../utils/bytes.circom"; -include "../utils/search.circom"; -include "circomlib/circuits/gates.circom"; -include "@zk-email/circuits/utils/array.circom"; - -template LockStartLine(DATA_BYTES, beginningLen, middleLen, finalLen) { - signal input data[DATA_BYTES]; - signal input beginning[beginningLen]; - signal input middle[middleLen]; - signal input final[finalLen]; - - //--------------------------------------------------------------------------------------------// - //-CONSTRAINTS--------------------------------------------------------------------------------// - //--------------------------------------------------------------------------------------------// - component dataASCII = ASCII(DATA_BYTES); - dataASCII.in <== data; - //--------------------------------------------------------------------------------------------// - - // Initialze the parser - component State[DATA_BYTES]; - State[0] = HttpStateUpdate(); - State[0].byte <== data[0]; - State[0].parsing_start <== 1; - State[0].parsing_header <== 0; - State[0].parsing_field_name <== 0; - State[0].parsing_field_value <== 0; - State[0].parsing_body <== 0; - State[0].line_status <== 0; - - /* - Note, because we know a beginning is the very first thing in a request - we can make this more efficient by just comparing the first `beginningLen` bytes - of the data ASCII against the beginning ASCII itself. - */ - // Check first beginning byte - signal beginningIsEqual[beginningLen]; - beginningIsEqual[0] <== IsEqual()([data[0],beginning[0]]); - beginningIsEqual[0] === 1; - - // Setup to check middle bytes - signal startLineMask[DATA_BYTES]; - signal middleMask[DATA_BYTES]; - signal finalMask[DATA_BYTES]; - - var middle_start_counter = 1; - var middle_end_counter = 1; - var final_end_counter = 1; - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - State[data_idx] = HttpStateUpdate(); - State[data_idx].byte <== data[data_idx]; - State[data_idx].parsing_start <== State[data_idx - 1].next_parsing_start; - State[data_idx].parsing_header <== State[data_idx - 1].next_parsing_header; - State[data_idx].parsing_field_name <== State[data_idx-1].next_parsing_field_name; - State[data_idx].parsing_field_value <== State[data_idx-1].next_parsing_field_value; - State[data_idx].parsing_body <== State[data_idx - 1].next_parsing_body; - State[data_idx].line_status <== State[data_idx - 1].next_line_status; - - // Check remaining beginning bytes - if(data_idx < beginningLen) { - beginningIsEqual[data_idx] <== IsEqual()([data[data_idx], beginning[data_idx]]); - beginningIsEqual[data_idx] === 1; - } - - // Middle - startLineMask[data_idx] <== inStartLine()(State[data_idx].parsing_start); - middleMask[data_idx] <== inStartMiddle()(State[data_idx].parsing_start); - finalMask[data_idx] <== inStartEnd()(State[data_idx].parsing_start); - middle_start_counter += startLineMask[data_idx] - middleMask[data_idx] - finalMask[data_idx]; - // The end of middle is the start of the final - middle_end_counter += startLineMask[data_idx] - finalMask[data_idx]; - final_end_counter += startLineMask[data_idx]; - - // Debugging - log("State[", data_idx, "].parsing_start = ", State[data_idx].parsing_start); - log("State[", data_idx, "].parsing_header = ", State[data_idx].parsing_header); - log("State[", data_idx, "].parsing_field_name = ", State[data_idx].parsing_field_name); - log("State[", data_idx, "].parsing_field_value = ", State[data_idx].parsing_field_value); - log("State[", data_idx, "].parsing_body = ", State[data_idx].parsing_body); - log("State[", data_idx, "].line_status = ", State[data_idx].line_status); - log("------------------------------------------------"); - log("middle_start_counter = ", middle_start_counter); - log("middle_end_counter = ", middle_end_counter); - log("final_end_counter = ", final_end_counter); - log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - } - - // Debugging - log("State[", DATA_BYTES, "].parsing_start ", "= ", State[DATA_BYTES-1].next_parsing_start); - log("State[", DATA_BYTES, "].parsing_header ", "= ", State[DATA_BYTES-1].next_parsing_header); - log("State[", DATA_BYTES, "].parsing_field_name ", "= ", State[DATA_BYTES-1].parsing_field_name); - log("State[", DATA_BYTES, "].parsing_field_value", "= ", State[DATA_BYTES-1].parsing_field_value); - log("State[", DATA_BYTES, "].parsing_body ", "= ", State[DATA_BYTES-1].next_parsing_body); - log("State[", DATA_BYTES, "].line_status ", "= ", State[DATA_BYTES-1].next_line_status); - log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - - // Additionally verify beginning had correct length - beginningLen === middle_start_counter - 1; - - // Check middle is correct by substring match and length check - signal middleMatch <== SubstringMatchWithIndex(DATA_BYTES, middleLen)(data, middle, middle_start_counter); - middleMatch === 1; - middleLen === middle_end_counter - middle_start_counter - 1; - - // Check final is correct by substring match and length check - signal finalMatch <== SubstringMatchWithIndex(DATA_BYTES, finalLen)(data, final, middle_end_counter); - finalMatch === 1; - // -2 here for the CRLF - finalLen === final_end_counter - middle_end_counter - 2; -} - -template LockHeader(DATA_BYTES, headerNameLen, headerValueLen) { - signal input data[DATA_BYTES]; - signal input header[headerNameLen]; - signal input value[headerValueLen]; - - //--------------------------------------------------------------------------------------------// - //-CONSTRAINTS--------------------------------------------------------------------------------// - //--------------------------------------------------------------------------------------------// - component dataASCII = ASCII(DATA_BYTES); - dataASCII.in <== data; - //--------------------------------------------------------------------------------------------// - - // Initialze the parser - component State[DATA_BYTES]; - State[0] = HttpStateUpdate(); - State[0].byte <== data[0]; - State[0].parsing_start <== 1; - State[0].parsing_header <== 0; - State[0].parsing_field_name <== 0; - State[0].parsing_field_value <== 0; - State[0].parsing_body <== 0; - State[0].line_status <== 0; - - component headerFieldNameValueMatch[DATA_BYTES]; - signal isHeaderFieldNameValueMatch[DATA_BYTES]; - - isHeaderFieldNameValueMatch[0] <== 0; - var hasMatched = 0; - - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - State[data_idx] = HttpStateUpdate(); - State[data_idx].byte <== data[data_idx]; - State[data_idx].parsing_start <== State[data_idx - 1].next_parsing_start; - State[data_idx].parsing_header <== State[data_idx - 1].next_parsing_header; - State[data_idx].parsing_field_name <== State[data_idx-1].next_parsing_field_name; - State[data_idx].parsing_field_value <== State[data_idx-1].next_parsing_field_value; - State[data_idx].parsing_body <== State[data_idx - 1].next_parsing_body; - State[data_idx].line_status <== State[data_idx - 1].next_line_status; - - headerFieldNameValueMatch[data_idx] = HeaderFieldNameValueMatch(DATA_BYTES, headerNameLen, headerValueLen); - headerFieldNameValueMatch[data_idx].data <== data; - headerFieldNameValueMatch[data_idx].headerName <== header; - headerFieldNameValueMatch[data_idx].headerValue <== value; - headerFieldNameValueMatch[data_idx].index <== data_idx; - isHeaderFieldNameValueMatch[data_idx] <== isHeaderFieldNameValueMatch[data_idx-1] + headerFieldNameValueMatch[data_idx].out; - - // Debugging - log("State[", data_idx, "].parsing_start ", "= ", State[data_idx].parsing_start); - log("State[", data_idx, "].parsing_header ", "= ", State[data_idx].parsing_header); - log("State[", data_idx, "].parsing_field_name ", "= ", State[data_idx].parsing_field_name); - log("State[", data_idx, "].parsing_field_value", "= ", State[data_idx].parsing_field_value); - log("State[", data_idx, "].parsing_body ", "= ", State[data_idx].parsing_body); - log("State[", data_idx, "].line_status ", "= ", State[data_idx].line_status); - log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - } - - // Debugging - log("State[", DATA_BYTES, "].parsing_start ", "= ", State[DATA_BYTES-1].next_parsing_start); - log("State[", DATA_BYTES, "].parsing_header ", "= ", State[DATA_BYTES-1].next_parsing_header); - log("State[", DATA_BYTES, "].parsing_field_name ", "= ", State[DATA_BYTES-1].parsing_field_name); - log("State[", DATA_BYTES, "].parsing_field_value", "= ", State[DATA_BYTES-1].parsing_field_value); - log("State[", DATA_BYTES, "].parsing_body ", "= ", State[DATA_BYTES-1].next_parsing_body); - log("State[", DATA_BYTES, "].line_status ", "= ", State[DATA_BYTES-1].next_line_status); - log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - - isHeaderFieldNameValueMatch[DATA_BYTES - 1] === 1; -} \ No newline at end of file diff --git a/circuits/http/parser/machine.circom b/circuits/http/machine.circom similarity index 98% rename from circuits/http/parser/machine.circom rename to circuits/http/machine.circom index 438a178..e5d0e44 100644 --- a/circuits/http/parser/machine.circom +++ b/circuits/http/machine.circom @@ -1,7 +1,6 @@ pragma circom 2.1.9; -include "language.circom"; -include "../../utils/array.circom"; +include "../utils/array.circom"; template HttpStateUpdate() { signal input parsing_start; // flag that counts up to 3 for each value in the start line diff --git a/circuits/http/nivc/body_mask.circom b/circuits/http/nivc/body_mask.circom deleted file mode 100644 index d8956ed..0000000 --- a/circuits/http/nivc/body_mask.circom +++ /dev/null @@ -1,50 +0,0 @@ -pragma circom 2.1.9; - -include "../parser/machine.circom"; -include "../../utils/hash.circom"; - -template HTTPMaskBodyNIVC(DATA_BYTES) { - signal input step_in[1]; - signal output step_out[1]; - - // Authenticate the plaintext we are passing in - signal input data[DATA_BYTES]; - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - - // ------------------------------------------------------------------------------------------------------------------ // - // PARSE - // Initialze the parser - component State[DATA_BYTES]; - State[0] = HttpStateUpdate(); - State[0].byte <== data[0]; - State[0].parsing_start <== 1; - State[0].parsing_header <== 0; - State[0].parsing_field_name <== 0; - State[0].parsing_field_value <== 0; - State[0].parsing_body <== 0; - State[0].line_status <== 0; - - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - State[data_idx] = HttpStateUpdate(); - State[data_idx].byte <== data[data_idx]; - State[data_idx].parsing_start <== State[data_idx - 1].next_parsing_start; - State[data_idx].parsing_header <== State[data_idx - 1].next_parsing_header; - State[data_idx].parsing_field_name <== State[data_idx - 1].next_parsing_field_name; - State[data_idx].parsing_field_value <== State[data_idx - 1].next_parsing_field_value; - State[data_idx].parsing_body <== State[data_idx - 1].next_parsing_body; - State[data_idx].line_status <== State[data_idx - 1].next_line_status; - } - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // Mask out just the JSON body - signal bodyMasked[DATA_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - bodyMasked[i] <== data[i] * State[i].next_parsing_body; - } - - // Hash the new data so this can now be used in the chain later - step_out[0] <== DataHasher(DATA_BYTES)(bodyMasked); -} - diff --git a/circuits/http/nivc/lock_header.circom b/circuits/http/nivc/lock_header.circom deleted file mode 100644 index 2cb109e..0000000 --- a/circuits/http/nivc/lock_header.circom +++ /dev/null @@ -1,131 +0,0 @@ -pragma circom 2.1.9; - -include "../parser/machine.circom"; -include "../interpreter.circom"; -include "../../utils/array.circom"; -include "circomlib/circuits/comparators.circom"; -include "@zk-email/circuits/utils/array.circom"; - -// TODO: should use a MAX_HEADER_NAME_LENGTH and a MAX_HEADER_VALUE_LENGTH -template LockHeader(DATA_BYTES, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH) { - - assert(DATA_BYTES >= MAX_HEADER_NAME_LENGTH + MAX_HEADER_VALUE_LENGTH); - - signal input step_in[1]; - signal output step_out[1]; - - // Authenticate the plaintext we are passing in - signal input data[DATA_BYTES]; - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - step_out[0] <== step_in[0]; - - // ------------------------------------------------------------------------------------------------------------------ // - // PARSE - // Initialze the parser - component State[DATA_BYTES]; - State[0] = HttpStateUpdate(); - State[0].byte <== data[0]; - State[0].parsing_start <== 1; - State[0].parsing_header <== 0; - State[0].parsing_field_name <== 0; - State[0].parsing_field_value <== 0; - State[0].parsing_body <== 0; - State[0].line_status <== 0; - - // TODO (autoparallel): Redundant as fuck, but I'm doing this quickly sorry. I don't think this actually adds constraints - signal httpParserState[DATA_BYTES * 5]; - - - var middle_start_counter = 1; - var middle_end_counter = 1; - var final_end_counter = 1; - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - State[data_idx] = HttpStateUpdate(); - State[data_idx].byte <== data[data_idx]; - State[data_idx].parsing_start <== State[data_idx - 1].next_parsing_start; - State[data_idx].parsing_header <== State[data_idx - 1].next_parsing_header; - State[data_idx].parsing_field_name <== State[data_idx - 1].next_parsing_field_name; - State[data_idx].parsing_field_value <== State[data_idx - 1].next_parsing_field_value; - State[data_idx].parsing_body <== State[data_idx - 1].next_parsing_body; - State[data_idx].line_status <== State[data_idx - 1].next_line_status; - } - // ------------------------------------------------------------------------------------------------------------------ // - - - // TODO (autoparallel): again bad - // Get those redundant variables - for(var i = 0 ; i < DATA_BYTES ; i++) { - httpParserState[i * 5] <== State[i].next_parsing_start; - httpParserState[i * 5 + 1] <== State[i].next_parsing_header; - httpParserState[i * 5 + 2] <== State[i].next_parsing_field_name; - httpParserState[i * 5 + 3] <== State[i].next_parsing_field_value; - httpParserState[i * 5 + 4] <== State[i].next_parsing_body; - } - - - // TODO: Better naming for these variables - signal input header[MAX_HEADER_NAME_LENGTH]; - signal input headerNameLength; - signal input value[MAX_HEADER_VALUE_LENGTH]; - signal input headerValueLength; - - // find header location - signal headerNameLocation <== FirstStringMatch(DATA_BYTES, MAX_HEADER_NAME_LENGTH)(data, header); - - // TODO (autoparallel): This could probably be optimized by selecting a subarray of length `MAX_HEADER_NAME_LENGTH + MAX_HEADER_VALUE_LENGTH` at `headerNameLocation` - // This is the assertion that we have locked down the correct header - - // signal dataSubArray[MAX_HEADER_NAME_LENGTH + MAX_HEADER_VALUE_LENGTH] <== SelectSubArray(DATA_BYTES, MAX_HEADER_NAME_LENGTH + MAX_HEADER_VALUE_LENGTH)(data, headerNameLocation, MAX_HEADER_NAME_LENGTH + MAX_HEADER_VALUE_LENGTH); - // signal headerFieldNameValueMatch <== HeaderFieldNameValueMatchPadded(MAX_HEADER_NAME_LENGTH + MAX_HEADER_VALUE_LENGTH, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH)(dataSubArray, header, headerNameLength, value, headerValueLength, headerNameLocation); - signal headerFieldNameValueMatch <== HeaderFieldNameValueMatchPadded(DATA_BYTES, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH)(data, header, headerNameLength, value, headerValueLength, headerNameLocation); - headerFieldNameValueMatch === 1; - - // parser state should be parsing header upto 2^10 max headers - signal isParsingHeader <== IndexSelector(DATA_BYTES * 5)(httpParserState, headerNameLocation * 5 + 1); - signal parsingHeader <== GreaterThan(10)([isParsingHeader, 0]); - parsingHeader === 1; -} - -// TODO: Handrolled template that I haven't tested YOLO. -template FirstStringMatch(dataLen, maxKeyLen) { - signal input data[dataLen]; - signal input key[maxKeyLen]; - signal output position; - - signal paddedData[dataLen + maxKeyLen]; - for (var i = 0 ; i < dataLen ; i++) { - paddedData[i] <== data[i]; - } - for (var i = 0 ; i < maxKeyLen ; i++) { - paddedData[dataLen + i] <== 0; - } - - signal isMatched[dataLen+1]; - isMatched[0] <== 0; - - var counter = 0; - component stringMatch[dataLen]; - component hasMatched[dataLen]; - signal isKeyOutOfBounds[maxKeyLen]; - signal isFirstMatchAndInsideBound[dataLen * maxKeyLen]; - for (var i = 0 ; i < maxKeyLen ; i++) { - isKeyOutOfBounds[i] <== IsZero()(key[i]); - } - - for (var idx = 0 ; idx < dataLen ; idx++) { - stringMatch[idx] = IsEqualArray(maxKeyLen); - stringMatch[idx].in[0] <== key; - for (var key_idx = 0 ; key_idx < maxKeyLen ; key_idx++) { - isFirstMatchAndInsideBound[idx * maxKeyLen + key_idx] <== (1 - isMatched[idx]) * (1 - isKeyOutOfBounds[key_idx]); - stringMatch[idx].in[1][key_idx] <== paddedData[idx + key_idx] * isFirstMatchAndInsideBound[idx * maxKeyLen + key_idx]; - } - hasMatched[idx] = IsEqual(); - hasMatched[idx].in <== [stringMatch[idx].out, 1]; - isMatched[idx+1] <== isMatched[idx] + hasMatched[idx].out; - counter += (1 - isMatched[idx+1]); // TODO: Off by one? Move before? - } - position <== counter; -} - - diff --git a/circuits/http/nivc/parse_and_lock_start_line.circom b/circuits/http/nivc/parse_and_lock_start_line.circom deleted file mode 100644 index 32cc4ec..0000000 --- a/circuits/http/nivc/parse_and_lock_start_line.circom +++ /dev/null @@ -1,99 +0,0 @@ -pragma circom 2.1.9; - -include "../parser/machine.circom"; -include "../interpreter.circom"; -include "../../utils/bytes.circom"; - -template ParseAndLockStartLine(DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH) { - var MINIMUM_PARSE_LENGTH = MAX_BEGINNING_LENGTH + MAX_MIDDLE_LENGTH + MAX_FINAL_LENGTH; - assert(DATA_BYTES >= MINIMUM_PARSE_LENGTH); - - signal input step_in[1]; - signal output step_out[1]; - - // Authenticate the plaintext we are passing in - signal input data[DATA_BYTES]; - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - step_out[0] <== step_in[0]; - - signal dataToParse[MINIMUM_PARSE_LENGTH]; - for(var i = 0 ; i < MINIMUM_PARSE_LENGTH ; i++) { - dataToParse[i] <== data[i]; - } - - signal input beginning[MAX_BEGINNING_LENGTH]; - signal input beginning_length; - signal input middle[MAX_MIDDLE_LENGTH]; - signal input middle_length; - signal input final[MAX_FINAL_LENGTH]; - signal input final_length; - - // Initialze the parser, note that we only need to parse as much as the `MINIMUM_PARSE_LENGTH` - // since the start line could not possibly go past this point, or else this would fail anyway - component State[MINIMUM_PARSE_LENGTH]; - State[0] = HttpStateUpdate(); - State[0].byte <== dataToParse[0]; - State[0].parsing_start <== 1; - State[0].parsing_header <== 0; - State[0].parsing_field_name <== 0; - State[0].parsing_field_value <== 0; - State[0].parsing_body <== 0; - State[0].line_status <== 0; - - /* - Note, because we know a beginning is the very first thing in a request - we can make this more efficient by just comparing the first `BEGINNING_LENGTH` bytes - of the data ASCII against the beginning ASCII itself. - */ - - // Setup to check middle bytes - signal startLineMask[MINIMUM_PARSE_LENGTH]; - signal middleMask[MINIMUM_PARSE_LENGTH]; - signal finalMask[MINIMUM_PARSE_LENGTH]; - startLineMask[0] <== inStartLine()(State[0].parsing_start); - middleMask[0] <== inStartMiddle()(State[0].parsing_start); - finalMask[0] <== inStartEnd()(State[0].parsing_start); - - - var middle_start_counter = 1; - var middle_end_counter = 1; - var final_end_counter = 1; - for(var data_idx = 1; data_idx < MINIMUM_PARSE_LENGTH; data_idx++) { - State[data_idx] = HttpStateUpdate(); - State[data_idx].byte <== dataToParse[data_idx]; - State[data_idx].parsing_start <== State[data_idx - 1].next_parsing_start; - State[data_idx].parsing_header <== State[data_idx - 1].next_parsing_header; - State[data_idx].parsing_field_name <== State[data_idx - 1].next_parsing_field_name; - State[data_idx].parsing_field_value <== State[data_idx - 1].next_parsing_field_value; - State[data_idx].parsing_body <== State[data_idx - 1].next_parsing_body; - State[data_idx].line_status <== State[data_idx - 1].next_line_status; - - // Set the masks based on parser state - startLineMask[data_idx] <== inStartLine()(State[data_idx].parsing_start); - middleMask[data_idx] <== inStartMiddle()(State[data_idx].parsing_start); - finalMask[data_idx] <== inStartEnd()(State[data_idx].parsing_start); - - // Increment counters based on mask information - middle_start_counter += startLineMask[data_idx] - middleMask[data_idx] - finalMask[data_idx]; - middle_end_counter += startLineMask[data_idx] - finalMask[data_idx]; - final_end_counter += startLineMask[data_idx]; - } - - // Additionally verify beginning had correct length - beginning_length === middle_start_counter - 1; - - signal beginningMatch <== SubstringMatchWithIndexPadded(MINIMUM_PARSE_LENGTH, MAX_BEGINNING_LENGTH)(dataToParse, beginning, beginning_length, 0); - - // Check middle is correct by substring match and length check - signal middleMatch <== SubstringMatchWithIndexPadded(MINIMUM_PARSE_LENGTH, MAX_MIDDLE_LENGTH)(dataToParse, middle, middle_length, middle_start_counter); - middleMatch === 1; - middle_length === middle_end_counter - middle_start_counter - 1; - - // Check final is correct by substring match and length check - signal finalMatch <== SubstringMatchWithIndexPadded(MINIMUM_PARSE_LENGTH, MAX_FINAL_LENGTH)(dataToParse, final, final_length, middle_end_counter); - finalMatch === 1; - // -2 here for the CRLF - final_length === final_end_counter - middle_end_counter - 2; -} - diff --git a/circuits/http/parser/language.circom b/circuits/http/parser/language.circom deleted file mode 100644 index 742cf90..0000000 --- a/circuits/http/parser/language.circom +++ /dev/null @@ -1,27 +0,0 @@ -pragma circom 2.1.9; - -// All the possible request methods: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods - -template HttpSyntax() { - //-Delimeters---------------------------------------------------------------------------------// - // - ASCII char `:` - signal output COLON <== 58; - // - ASCII char `;` - signal output SEMICOLON <== 59; - // - ASCII char `,` - signal output COMMA <== 44; - // - ASCII char `"` - signal output QUOTE <== 34; - //-White_space--------------------------------------------------------------------------------// - // https://www.rfc-editor.org/rfc/rfc2616#section-2.2 - // https://www.rfc-editor.org/rfc/rfc7230#section-3.5 - // - ASCII char `\r` (carriage return) - signal output CR <== 13; - // - ASCII char `\n` (line feed) - signal output LF <== 10; - // - ASCII char: ` ` - signal output SPACE <== 32; - //-Escape-------------------------------------------------------------------------------------// - // - ASCII char: `\` - signal output ESCAPE <== 92; -} \ No newline at end of file diff --git a/circuits/http/parser/parser.circom b/circuits/http/parser/parser.circom deleted file mode 100644 index dc00454..0000000 --- a/circuits/http/parser/parser.circom +++ /dev/null @@ -1,51 +0,0 @@ -pragma circom 2.1.9; - -include "../../utils/bytes.circom"; -include "machine.circom"; - - -template Parser(DATA_BYTES) { - signal input data[DATA_BYTES]; - - signal output Method; - - //--------------------------------------------------------------------------------------------// - //-CONSTRAINTS--------------------------------------------------------------------------------// - //--------------------------------------------------------------------------------------------// - component dataASCII = ASCII(DATA_BYTES); - dataASCII.in <== data; - //--------------------------------------------------------------------------------------------// - - // Initialze the parser - component State[DATA_BYTES]; - State[0] = HttpStateUpdate(); - State[0].byte <== data[0]; - State[0].parsing_start <== 1; - State[0].parsing_header <== 0; - State[0].parsing_body <== 0; - State[0].line_status <== 0; - - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - State[data_idx] = HttpStateUpdate(); - State[data_idx].byte <== data[data_idx]; - State[data_idx].parsing_start <== State[data_idx - 1].next_parsing_start; - State[data_idx].parsing_header <== State[data_idx - 1].next_parsing_header; - State[data_idx].parsing_body <== State[data_idx - 1].next_parsing_body; - State[data_idx].line_status <== State[data_idx - 1].next_line_status; - - // Debugging - log("State[", data_idx, "].parsing_start ", "= ", State[data_idx].parsing_start); - log("State[", data_idx, "].parsing_header", "= ", State[data_idx].parsing_header); - log("State[", data_idx, "].parsing_body ", "= ", State[data_idx].parsing_body); - log("State[", data_idx, "].line_status ", "= ", State[data_idx].line_status); - log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - } - - // Debugging - log("State[", DATA_BYTES, "].parsing_start ", "= ", State[DATA_BYTES-1].next_parsing_start); - log("State[", DATA_BYTES, "].parsing_header", "= ", State[DATA_BYTES-1].next_parsing_header); - log("State[", DATA_BYTES, "].parsing_body ", "= ", State[DATA_BYTES-1].next_parsing_body); - log("State[", DATA_BYTES, "].line_status ", "= ", State[DATA_BYTES-1].next_line_status); - log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - -} \ No newline at end of file diff --git a/circuits/http/nivc/http_nivc.circom b/circuits/http/verification.circom similarity index 82% rename from circuits/http/nivc/http_nivc.circom rename to circuits/http/verification.circom index 8187c1b..124ff63 100644 --- a/circuits/http/nivc/http_nivc.circom +++ b/circuits/http/verification.circom @@ -1,10 +1,9 @@ pragma circom 2.1.9; -include "../parser/machine.circom"; -include "../interpreter.circom"; -include "../../utils/bytes.circom"; +include "machine.circom"; +include "../utils/hash.circom"; -template HttpNIVC(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { +template HTTPVerification(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { signal input step_in[1]; signal output step_out[1]; @@ -44,11 +43,11 @@ template HttpNIVC(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { signal not_start_line_mask[DATA_BYTES]; for(var i = 0 ; i < DATA_BYTES ; i++) { not_start_line_mask[i] <== IsZero()(State[i].parsing_start); - start_line[i] <== data[i] * (1 - not_start_line_mask[i]); + start_line[i] <== data[i] * (1 - not_start_line_mask[i]); } - signal inner_start_line_hash <== DataHasher(DATA_BYTES)(start_line); + signal inner_start_line_hash <== DataHasher(DATA_BYTES)(start_line); signal start_line_hash_equal_check <== IsEqual()([inner_start_line_hash, start_line_hash]); - start_line_hash_equal_check === 1; + start_line_hash_equal_check === 1; // Get the header shit signal header[MAX_NUMBER_OF_HEADERS][DATA_BYTES]; @@ -63,8 +62,8 @@ template HttpNIVC(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { signal header_is_unused[MAX_NUMBER_OF_HEADERS]; // If a header hash is passed in as 0, it is not used (no way to compute preimage of 0) signal header_hashes_equal_check[MAX_NUMBER_OF_HEADERS]; for(var i = 0 ; i < MAX_NUMBER_OF_HEADERS ; i++) { - header_is_unused[i] <== IsZero()(header_hashes[i]); - inner_header_hashes[i] <== DataHasher(DATA_BYTES)(header[i]); + header_is_unused[i] <== IsZero()(header_hashes[i]); + inner_header_hashes[i] <== DataHasher(DATA_BYTES)(header[i]); header_hashes_equal_check[i] <== IsEqual()([(1 - header_is_unused[i]) * inner_header_hashes[i], header_hashes[i]]); header_hashes_equal_check[i] === 1; } @@ -72,12 +71,11 @@ template HttpNIVC(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { // Get the body shit signal body[DATA_BYTES]; for(var i = 0 ; i < DATA_BYTES ; i++) { - body[i] <== data[i] * State[i].parsing_body; + body[i] <== data[i] * State[i].parsing_body; } - signal inner_body_hash <== DataHasher(DATA_BYTES)(body); + signal inner_body_hash <== DataHasher(DATA_BYTES)(body); signal body_hash_equal_check <== IsEqual()([inner_body_hash, body_hash]); - body_hash_equal_check === 1; - + body_hash_equal_check === 1; step_out[0] <== inner_body_hash; } diff --git a/circuits/json/extractor.circom b/circuits/json/extractor.circom deleted file mode 100644 index b58da5c..0000000 --- a/circuits/json/extractor.circom +++ /dev/null @@ -1,164 +0,0 @@ -pragma circom 2.1.9; - -include "interpreter.circom"; - -template ObjectExtractor(DATA_BYTES, MAX_STACK_HEIGHT, maxKeyLen, maxValueLen) { - assert(MAX_STACK_HEIGHT >= 2); - - // Declaration of signals. - signal input data[DATA_BYTES]; - signal input key[maxKeyLen]; - signal input keyLen; - - signal output value[maxValueLen]; - - // Constraints. - signal value_starting_index[DATA_BYTES - maxKeyLen]; - // flag determining whether this byte is matched value - signal is_value_match[DATA_BYTES - maxKeyLen]; - // final mask - signal mask[DATA_BYTES - maxKeyLen]; - - component State[DATA_BYTES - maxKeyLen]; - State[0] = StateUpdate(MAX_STACK_HEIGHT); - State[0].byte <== data[0]; - for(var i = 0; i < MAX_STACK_HEIGHT; i++) { - State[0].stack[i] <== [0,0]; - } - State[0].parsing_string <== 0; - State[0].parsing_number <== 0; - - signal parsing_key[DATA_BYTES - maxKeyLen]; - signal parsing_value[DATA_BYTES - maxKeyLen]; - signal parsing_object_value[DATA_BYTES - maxKeyLen]; - signal is_key_match[DATA_BYTES - maxKeyLen]; - signal is_key_match_for_value[DATA_BYTES+1 - maxKeyLen]; - is_key_match_for_value[0] <== 0; - signal is_next_pair_at_depth[DATA_BYTES - maxKeyLen]; - signal or[DATA_BYTES - maxKeyLen]; - - // initialise first iteration - - // check inside key or value - parsing_key[0] <== InsideKey()(State[0].next_stack[0], State[0].next_parsing_string, State[0].next_parsing_number); - parsing_value[0] <== InsideValueObject()(State[0].next_stack[0], State[0].next_stack[1], State[0].next_parsing_string, State[0].next_parsing_number); - - is_key_match[0] <== 0; - is_next_pair_at_depth[0] <== NextKVPairAtDepth(MAX_STACK_HEIGHT)(State[0].next_stack, data[0], 0); - is_key_match_for_value[1] <== Mux1()([is_key_match_for_value[0] * (1-is_next_pair_at_depth[0]), is_key_match[0] * (1-is_next_pair_at_depth[0])], is_key_match[0]); - is_value_match[0] <== parsing_value[0] * is_key_match_for_value[1]; - - mask[0] <== data[0] * is_value_match[0]; - - for(var data_idx = 1; data_idx < DATA_BYTES - maxKeyLen; data_idx++) { - State[data_idx] = StateUpdate(MAX_STACK_HEIGHT); - State[data_idx].byte <== data[data_idx]; - State[data_idx].stack <== State[data_idx - 1].next_stack; - State[data_idx].parsing_string <== State[data_idx - 1].next_parsing_string; - State[data_idx].parsing_number <== State[data_idx - 1].next_parsing_number; - - // - parsing key - // - parsing value (different for string/numbers and array) - // - key match (key 1, key 2) - // - is next pair - // - is key match for value - // - value_mask - // - mask - - // check if inside key or not - parsing_key[data_idx] <== InsideKey()(State[data_idx].next_stack[0], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number); - // check if inside value - parsing_value[data_idx] <== InsideValueObject()(State[data_idx].next_stack[0], State[data_idx].next_stack[1], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number); - - // to get correct value, check: - // - key matches at current index and depth of key is as specified - // - whether next KV pair starts - // - whether key matched for a value (propogate key match until new KV pair of lower depth starts) - is_key_match[data_idx] <== KeyMatchAtIndex(DATA_BYTES, maxKeyLen, data_idx)(data, key, keyLen, parsing_key[data_idx]); - is_next_pair_at_depth[data_idx] <== NextKVPairAtDepth(MAX_STACK_HEIGHT)(State[data_idx].next_stack, data[data_idx], 0); - is_key_match_for_value[data_idx+1] <== Mux1()([is_key_match_for_value[data_idx] * (1-is_next_pair_at_depth[data_idx]), is_key_match[data_idx] * (1-is_next_pair_at_depth[data_idx])], is_key_match[data_idx]); - is_value_match[data_idx] <== is_key_match_for_value[data_idx+1] * parsing_value[data_idx]; - - or[data_idx] <== OR()(is_value_match[data_idx], is_value_match[data_idx - 1]); - - // mask = currently parsing value and all subsequent keys matched - mask[data_idx] <== data[data_idx] * or[data_idx]; - } - - // find starting index of value in data by matching mask - signal is_zero_mask[DATA_BYTES]; - signal is_prev_starting_index[DATA_BYTES]; - value_starting_index[0] <== 0; - is_prev_starting_index[0] <== 0; - is_zero_mask[0] <== IsZero()(mask[0]); - for (var i=1 ; i= 2); - - signal input data[DATA_BYTES]; - signal input index; - - signal output value[maxValueLen]; - - // value starting index in `data` - signal value_starting_index[DATA_BYTES]; - // final mask - signal mask[DATA_BYTES]; - - component State[DATA_BYTES]; - State[0] = StateUpdate(MAX_STACK_HEIGHT); - State[0].byte <== data[0]; - for(var i = 0; i < MAX_STACK_HEIGHT; i++) { - State[0].stack[i] <== [0,0]; - } - State[0].parsing_string <== 0; - State[0].parsing_number <== 0; - - signal parsing_array[DATA_BYTES]; - signal or[DATA_BYTES]; - - parsing_array[0] <== InsideArrayIndexObject()(State[0].next_stack[0], State[0].next_stack[1], State[0].next_parsing_string, State[0].next_parsing_number, index); - mask[0] <== data[0] * parsing_array[0]; - - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - State[data_idx] = StateUpdate(MAX_STACK_HEIGHT); - State[data_idx].byte <== data[data_idx]; - State[data_idx].stack <== State[data_idx - 1].next_stack; - State[data_idx].parsing_string <== State[data_idx - 1].next_parsing_string; - State[data_idx].parsing_number <== State[data_idx - 1].next_parsing_number; - - parsing_array[data_idx] <== InsideArrayIndexObject()(State[data_idx].next_stack[0], State[data_idx].next_stack[1], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number, index); - - or[data_idx] <== OR()(parsing_array[data_idx], parsing_array[data_idx - 1]); - mask[data_idx] <== data[data_idx] * or[data_idx]; - } - - signal is_zero_mask[DATA_BYTES]; - signal is_prev_starting_index[DATA_BYTES]; - value_starting_index[0] <== 0; - is_prev_starting_index[0] <== 0; - is_zero_mask[0] <== IsZero()(mask[0]); - for (var i=1 ; i= 2); // TODO (autoparallel): idk if we need this now diff --git a/circuits/json/parser/language.circom b/circuits/json/parser/language.circom index 8063503..0566d74 100644 --- a/circuits/json/parser/language.circom +++ b/circuits/json/parser/language.circom @@ -18,14 +18,16 @@ template Syntax() { signal output COMMA <== 44; //-White_space--------------------------------------------------------------------------------// // - ASCII char: `\n` - signal output NEWLINE <== 10; + // signal output NEWLINE <== 10; // - ASCII char: ` ` - signal output SPACE <== 32; + // signal output SPACE <== 32; //-Escape-------------------------------------------------------------------------------------// // - ASCII char: `\` - signal output ESCAPE <== 92; + // signal output ESCAPE <== 92; //-Number_Remapping---------------------------------------------------------------------------// - signal output NUMBER <== 256; // past a u8 -- reserved for ANY numerical ASCII (48 - 57) + signal output NUMBER_START <== 48; + signal output NUMBER_END <== 57; + } template Command() { diff --git a/circuits/json/parser/machine.circom b/circuits/json/parser/machine.circom index 21c8a87..ff82988 100644 --- a/circuits/json/parser/machine.circom +++ b/circuits/json/parser/machine.circom @@ -24,7 +24,6 @@ Tests for this module are located in the files: `circuits/test/parser/*.test.ts pragma circom 2.1.9; include "../../utils/array.circom"; -include "../../utils/bytes.circom"; include "../../utils/operators.circom"; include "language.circom"; @@ -57,37 +56,38 @@ template StateUpdate(MAX_STACK_HEIGHT) { signal output next_parsing_number; component Command = Command(); + component Syntax = Syntax(); //--------------------------------------------------------------------------------------------// // Break down what was read // * read in a start brace `{` * component readStartBrace = IsEqual(); - readStartBrace.in <== [byte, 123]; + readStartBrace.in <== [byte, Syntax.START_BRACE]; // * read in an end brace `}` * component readEndBrace = IsEqual(); - readEndBrace.in <== [byte, 125]; + readEndBrace.in <== [byte, Syntax.END_BRACE]; // * read in a start bracket `[` * component readStartBracket = IsEqual(); - readStartBracket.in <== [byte, 91]; + readStartBracket.in <== [byte, Syntax.START_BRACKET]; // * read in an end bracket `]` * component readEndBracket = IsEqual(); - readEndBracket.in <== [byte, 93]; + readEndBracket.in <== [byte, Syntax.END_BRACKET]; // * read in a colon `:` * component readColon = IsEqual(); - readColon.in <== [byte, 58]; + readColon.in <== [byte, Syntax.COLON]; // * read in a comma `,` * component readComma = IsEqual(); - readComma.in <== [byte, 44]; + readComma.in <== [byte, Syntax.COMMA]; // * read in some delimeter * signal readDelimeter <== readStartBrace.out + readEndBrace.out + readStartBracket.out + readEndBracket.out + readColon.out + readComma.out; // * read in some number * component readNumber = InRange(8); readNumber.in <== byte; - readNumber.range <== [48, 57]; // This is the range where ASCII digits are + readNumber.range <== [Syntax.NUMBER_START, Syntax.NUMBER_END]; // This is the range where ASCII digits are // * read in a quote `"` * component readQuote = IsEqual(); - readQuote.in <== [byte, 34]; + readQuote.in <== [byte, Syntax.QUOTE]; component readOther = IsZero(); readOther.in <== readDelimeter + readNumber.out + readQuote.out; //--------------------------------------------------------------------------------------------// diff --git a/circuits/json/parser/parser.circom b/circuits/json/parser/parser.circom index 8a435ca..f8f153a 100644 --- a/circuits/json/parser/parser.circom +++ b/circuits/json/parser/parser.circom @@ -1,18 +1,10 @@ pragma circom 2.1.9; -include "../../utils/bytes.circom"; include "machine.circom"; template Parser(DATA_BYTES, MAX_STACK_HEIGHT) { signal input data[DATA_BYTES]; - // TODO: Add assertions on the inputs here! - - //--------------------------------------------------------------------------------------------// - //-CONSTRAINTS--------------------------------------------------------------------------------// - //--------------------------------------------------------------------------------------------// - component dataASCII = ASCII(DATA_BYTES); - dataASCII.in <== data; //--------------------------------------------------------------------------------------------// // Initialze the parser component State[DATA_BYTES]; @@ -30,24 +22,12 @@ template Parser(DATA_BYTES, MAX_STACK_HEIGHT) { State[data_idx].stack <== State[data_idx - 1].next_stack; State[data_idx].parsing_string <== State[data_idx - 1].next_parsing_string; State[data_idx].parsing_number <== State[data_idx - 1].next_parsing_number; - - // Debugging - for(var i = 0; i { - let circuit: WitnessTester<["key", "iv", "plainText", "aad"], ["cipherText", "tag"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`aes-gcm`, { - file: "aes-gcm/aes-gcm", - template: "AESGCM", - params: [16], - }); - }); - - it("should have correct output", async () => { - let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - 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 expected_output = [0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78]; - - const witness = await circuit.compute({ key: key, iv: iv, plainText: plainText, aad: aad }, ["cipherText", "authTag"]) - - assert.deepEqual(witness.cipherText, hexBytesToBigInt(expected_output)) - }); - - it("should work for self generated test case", async () => { - let circuit_one_block: WitnessTester<["key", "iv", "plainText", "aad"], ["cipherText", "tag"]>; - circuit_one_block = await circomkit.WitnessTester(`aes-gcm`, { - file: "aes-gcm/aes-gcm", - template: "AESGCM", - params: [16], - }); - - const key = hexToBytes('31313131313131313131313131313131'); - const iv = hexToBytes('313131313131313131313131'); - const msg = hexToBytes('7465737468656c6c6f30303030303030'); - const aad = hexToBytes('00000000000000000000000000000000') - const ct = hexToBytes('2929d2bb1ae94804402b8e776e0d3356'); - const auth_tag = hexToBytes('0cab39e1a491b092185965f7b554aea0'); - - const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: msg, aad: aad }, ["cipherText", "authTag"]) - - assert.deepEqual(witness.cipherText, hexBytesToBigInt(ct)) - }); - - it("should work for multiple blocks", async () => { - let circuit_one_block: WitnessTester<["key", "iv", "plainText", "aad"], ["cipherText", "tag"]>; - circuit_one_block = await circomkit.WitnessTester(`aes-gcm`, { - file: "aes-gcm/aes-gcm", - template: "AESGCM", - params: [32], - }); - - const key = hexToBytes('31313131313131313131313131313131'); - const iv = hexToBytes('313131313131313131313131'); - const msg = hexToBytes('7465737468656c6c6f303030303030307465737468656c6c6f30303030303030'); - const aad = hexToBytes('00000000000000000000000000000000') - const ct = hexToBytes('2929d2bb1ae94804402b8e776e0d335626756530713e4c065af1d3c4f56e0204'); - const auth_tag = hexToBytes('438542d7f387568c84d23df60b223ecb'); - - const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: msg, aad: aad }, ["cipherText", "authTag"]) - - assert.deepEqual(witness.cipherText, hexBytesToBigInt(ct)) - }); -}); \ No newline at end of file diff --git a/circuits/test/aes-gcm/aes/cipher.test.ts b/circuits/test/aes-gcm/aes/cipher.test.ts deleted file mode 100644 index f54d90d..0000000 --- a/circuits/test/aes-gcm/aes/cipher.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "../../common"; - -describe("Cipher", () => { - let circuit: WitnessTester<["block", "key"], ["cipher"]>; - it("should perform Cipher#1", async () => { - circuit = await circomkit.WitnessTester(`Cipher`, { - file: "aes-gcm/aes/cipher", - template: "Cipher", - }); - - await circuit.expectPass( - { - block: [ - [0x32, 0x88, 0x31, 0xe0], - [0x43, 0x5a, 0x31, 0x37], - [0xf6, 0x30, 0x98, 0x07], - [0xa8, 0x8d, 0xa2, 0x34], - ], - key: [ - 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, - 0x88, 0x09, 0xcf, 0x4f, 0x3c, - ], - }, - { - cipher: [ - [0x39, 0x02, 0xdc, 0x19], - [0x25, 0xdc, 0x11, 0x6a], - [0x84, 0x09, 0x85, 0x0b], - [0x1d, 0xfb, 0x97, 0x32], - ], - } - ); - }); - - // in : f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff - // out : ec8cdf7398607cb0f2d21675ea9ea1e4 - // key : 2b7e151628aed2a6abf7158809cf4f3c - it("should perform Cipher#2", async () => { - circuit = await circomkit.WitnessTester(`Cipher`, { - file: "aes-gcm/aes/cipher", - template: "Cipher", - }); - - await circuit.expectPass( - { - block: [ - [0xf0, 0xf4, 0xf8, 0xfc], - [0xf1, 0xf5, 0xf9, 0xfd], - [0xf2, 0xf6, 0xfa, 0xfe], - [0xf3, 0xf7, 0xfb, 0xff], - ], - key: [ - 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, - 0x88, 0x09, 0xcf, 0x4f, 0x3c, - ], - }, - { - cipher: [ - [0xec, 0x98, 0xf2, 0xea], - [0x8c, 0x60, 0xd2, 0x9e], - [0xdf, 0x7c, 0x16, 0xa1], - [0x73, 0xb0, 0x75, 0xe4], - ], - } - ); - }); - describe("AddRoundKey", () => { - let circuit: WitnessTester<["state", "roundKey"], ["newState"]>; - it("should perform AddRoundKey", async () => { - circuit = await circomkit.WitnessTester(`AddRoundKey`, { - file: "aes-gcm/aes/cipher", - template: "AddRoundKey", - }); - - // 0x57 . 2 = 0xae - await circuit.expectPass( - { - state: [ - [4, 224, 72, 40], - [102, 203, 248, 6], - [129, 25, 211, 38], - [229, 154, 122, 76], - ], - roundKey: [ - [160, 250, 254, 23], - [136, 84, 44, 177], - [35, 163, 57, 57], - [42, 108, 118, 5], - ], - }, - { - newState: [ - [164, 104, 107, 2], - [156, 159, 91, 106], - [127, 53, 234, 80], - [242, 43, 67, 73], - ], - } - ); - }); - }); - - describe("NextRound", () => { - async function generatePassCase( - round: number, - key: number[][], - expectedKey: number[][] - ) { - circuit = await circomkit.WitnessTester(`NextRound_${4}_${4}`, { - file: "aes-gcm/aes/cipher", - template: "NextRound", - }); - } - - it("should compute correctly", async () => { - const key = [ - [0x2b, 0x7e, 0x15, 0x16], - [0x28, 0xae, 0xd2, 0xa6], - [0xab, 0xf7, 0x15, 0x88], - [0x09, 0xcf, 0x4f, 0x3c], - ]; - - const expectedNextKey = [ - [0xa0, 0xfa, 0xfe, 0x17], - [0x88, 0x54, 0x2c, 0xb1], - [0x23, 0xa3, 0x39, 0x39], - [0x2a, 0x6c, 0x76, 0x05], - ]; - - await generatePassCase(1, key, expectedNextKey); - }); - }); - - describe("SubBlock", () => { - let circuit: WitnessTester<["state"], ["newState"]>; - it("should perform SubBlock", async () => { - circuit = await circomkit.WitnessTester(`SubBlock`, { - file: "aes-gcm/aes/cipher", - template: "SubBlock", - }); - // 0x57 . 2 = 0xae - await circuit.expectPass( - { - state: [ - [25, 160, 154, 233], - [61, 244, 198, 248], - [227, 226, 141, 72], - [190, 43, 42, 8], - ], - }, - { - newState: [ - [212, 224, 184, 30], - [39, 191, 180, 65], - [17, 152, 93, 82], - [174, 241, 229, 48], - ], - } - ); - }); - }); - - describe("ShiftRows", () => { - let circuit: WitnessTester<["state"], ["newState"]>; - it("should perform ShiftRows", async () => { - circuit = await circomkit.WitnessTester(`ShiftRows`, { - file: "aes-gcm/aes/cipher", - template: "ShiftRows", - params: [], - }); - // 0x57 . 2 = 0xae - await circuit.expectPass( - { - state: [ - [212, 224, 184, 30], - [39, 191, 180, 65], - [17, 152, 93, 82], - [174, 241, 229, 48], - ], - }, - { - newState: [ - [212, 224, 184, 30], - [191, 180, 65, 39], - [93, 82, 17, 152], - [48, 174, 241, 229], - ], - } - ); - }); - }); -}); diff --git a/circuits/test/aes-gcm/aes/key_expansion.test.ts b/circuits/test/aes-gcm/aes/key_expansion.test.ts deleted file mode 100644 index 906fc44..0000000 --- a/circuits/test/aes-gcm/aes/key_expansion.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "../../common"; - -describe("KeyExpansion", () => { - it("should compute correctly for aes128", async () => { - const circuit: WitnessTester<["key"], ["keyExpanded"]> = await circomkit.WitnessTester(`SubBytes`, { - file: "aes-gcm/aes/key_expansion", - template: "KeyExpansion", - params: [], - }); - const key = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c]; - const keyExpanded = [ - [0x2b, 0x7e, 0x15, 0x16], - [0x28, 0xae, 0xd2, 0xa6], - [0xab, 0xf7, 0x15, 0x88], - [0x09, 0xcf, 0x4f, 0x3c], - [0xa0, 0xfa, 0xfe, 0x17], - [0x88, 0x54, 0x2c, 0xb1], - [0x23, 0xa3, 0x39, 0x39], - [0x2a, 0x6c, 0x76, 0x05], - [0xf2, 0xc2, 0x95, 0xf2], - [0x7a, 0x96, 0xb9, 0x43], - [0x59, 0x35, 0x80, 0x7a], - [0x73, 0x59, 0xf6, 0x7f], - [0x3d, 0x80, 0x47, 0x7d], - [0x47, 0x16, 0xfe, 0x3e], - [0x1e, 0x23, 0x7e, 0x44], - [0x6d, 0x7a, 0x88, 0x3b], - [0xef, 0x44, 0xa5, 0x41], - [0xa8, 0x52, 0x5b, 0x7f], - [0xb6, 0x71, 0x25, 0x3b], - [0xdb, 0x0b, 0xad, 0x00], - [0xd4, 0xd1, 0xc6, 0xf8], - [0x7c, 0x83, 0x9d, 0x87], - [0xca, 0xf2, 0xb8, 0xbc], - [0x11, 0xf9, 0x15, 0xbc], - [0x6d, 0x88, 0xa3, 0x7a], - [0x11, 0x0b, 0x3e, 0xfd], - [0xdb, 0xf9, 0x86, 0x41], - [0xca, 0x00, 0x93, 0xfd], - [0x4e, 0x54, 0xf7, 0x0e], - [0x5f, 0x5f, 0xc9, 0xf3], - [0x84, 0xa6, 0x4f, 0xb2], - [0x4e, 0xa6, 0xdc, 0x4f], - [0xea, 0xd2, 0x73, 0x21], - [0xb5, 0x8d, 0xba, 0xd2], - [0x31, 0x2b, 0xf5, 0x60], - [0x7f, 0x8d, 0x29, 0x2f], - [0xac, 0x77, 0x66, 0xf3], - [0x19, 0xfa, 0xdc, 0x21], - [0x28, 0xd1, 0x29, 0x41], - [0x57, 0x5c, 0x00, 0x6e], - [0xd0, 0x14, 0xf9, 0xa8], - [0xc9, 0xee, 0x25, 0x89], - [0xe1, 0x3f, 0x0c, 0xc8], - [0xb6, 0x63, 0x0c, 0xa6], - ]; - await circuit.expectPass({ key }, { keyExpanded }); - }); - - describe("Rotate", () => { - let circuit: WitnessTester<["bytes"], ["rotated"]>; - - it("should rotate correctly", async () => { - circuit = await circomkit.WitnessTester(`Rotate`, { - file: "aes-gcm/aes/key_expansion", - template: "Rotate", - params: [1, 4], - }); - await circuit.expectPass({ bytes: [0x01, 0x12, 0x02, 0x30] }, { rotated: [0x12, 0x02, 0x30, 0x01] }); - }); - }); - - describe("SubstituteWord", () => { - let circuit: WitnessTester<["bytes"], ["substituted"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`SubstituteWord`, { - file: "aes-gcm/aes/key_expansion", - template: "SubstituteWord", - }); - }); - - it("should substitute correctly", async () => { - await circuit.expectPass({ bytes: [0x00, 0x10, 0x20, 0x30] }, { substituted: [0x63, 0xca, 0xb7, 0x04] }); - }); - }); - - describe("RCon", () => { - let circuit: WitnessTester<[], ["out"]>; - - async function generatePassCase(round: number, out: number[]) { - circuit = await circomkit.WitnessTester(`RCon`, { - file: "aes-gcm/aes/key_expansion", - template: "RCon", - params: [round] - }); - await circuit.expectPass({}, { out: out }); - } - - it("should compute round constant correctly", async () => { - await generatePassCase(1, [0x01, 0x00, 0x00, 0x00]); - await generatePassCase(2, [0x02, 0x00, 0x00, 0x00]); - await generatePassCase(10, [0x36, 0x00, 0x00, 0x00]); - }); - }); -}); diff --git a/circuits/test/aes-gcm/aes/sbox.test.ts b/circuits/test/aes-gcm/aes/sbox.test.ts deleted file mode 100644 index 13b344a..0000000 --- a/circuits/test/aes-gcm/aes/sbox.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "../../common"; - -describe("SBox", () => { - let circuit: WitnessTester<["in"], ["out"]>; - - describe("SubBox", () => { - before(async () => { - circuit = await circomkit.WitnessTester(`SubBytes`, { - file: "aes-gcm/aes/sbox", - template: "SBox128", - }); - }); - - it("should compute correctly", async () => { - await circuit.expectPass({ in: 0x53 }, { out: 0xed }); - await circuit.expectPass({ in: 0x00 }, { out: 0x63 }); - }); - }); -}); - -describe("Field", () => { - let circuit: WitnessTester<["in"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`FieldInv`, { - file: "aes-gcm/aes/sbox", - template: "FieldInv", - }); - }); - - let inverses = [0x00, 0x01, 0x8d, 0xf6, 0xcb, 0x52, 0x7b, 0xd1, 0xe8, 0x4f, 0x29, 0xc0, 0xb0, 0xe1, 0xe5, 0xc7, - 0x74, 0xb4, 0xaa, 0x4b, 0x99, 0x2b, 0x60, 0x5f, 0x58, 0x3f, 0xfd, 0xcc, 0xff, 0x40, 0xee, 0xb2, - 0x3a, 0x6e, 0x5a, 0xf1, 0x55, 0x4d, 0xa8, 0xc9, 0xc1, 0x0a, 0x98, 0x15, 0x30, 0x44, 0xa2, 0xc2, - 0x2c, 0x45, 0x92, 0x6c, 0xf3, 0x39, 0x66, 0x42, 0xf2, 0x35, 0x20, 0x6f, 0x77, 0xbb, 0x59, 0x19, - 0x1d, 0xfe, 0x37, 0x67, 0x2d, 0x31, 0xf5, 0x69, 0xa7, 0x64, 0xab, 0x13, 0x54, 0x25, 0xe9, 0x09, - 0xed, 0x5c, 0x05, 0xca, 0x4c, 0x24, 0x87, 0xbf, 0x18, 0x3e, 0x22, 0xf0, 0x51, 0xec, 0x61, 0x17, - 0x16, 0x5e, 0xaf, 0xd3, 0x49, 0xa6, 0x36, 0x43, 0xf4, 0x47, 0x91, 0xdf, 0x33, 0x93, 0x21, 0x3b, - 0x79, 0xb7, 0x97, 0x85, 0x10, 0xb5, 0xba, 0x3c, 0xb6, 0x70, 0xd0, 0x06, 0xa1, 0xfa, 0x81, 0x82, - 0x83, 0x7e, 0x7f, 0x80, 0x96, 0x73, 0xbe, 0x56, 0x9b, 0x9e, 0x95, 0xd9, 0xf7, 0x02, 0xb9, 0xa4, - 0xde, 0x6a, 0x32, 0x6d, 0xd8, 0x8a, 0x84, 0x72, 0x2a, 0x14, 0x9f, 0x88, 0xf9, 0xdc, 0x89, 0x9a, - 0xfb, 0x7c, 0x2e, 0xc3, 0x8f, 0xb8, 0x65, 0x48, 0x26, 0xc8, 0x12, 0x4a, 0xce, 0xe7, 0xd2, 0x62, - 0x0c, 0xe0, 0x1f, 0xef, 0x11, 0x75, 0x78, 0x71, 0xa5, 0x8e, 0x76, 0x3d, 0xbd, 0xbc, 0x86, 0x57, - 0x0b, 0x28, 0x2f, 0xa3, 0xda, 0xd4, 0xe4, 0x0f, 0xa9, 0x27, 0x53, 0x04, 0x1b, 0xfc, 0xac, 0xe6, - 0x7a, 0x07, 0xae, 0x63, 0xc5, 0xdb, 0xe2, 0xea, 0x94, 0x8b, 0xc4, 0xd5, 0x9d, 0xf8, 0x90, 0x6b, - 0xb1, 0x0d, 0xd6, 0xeb, 0xc6, 0x0e, 0xcf, 0xad, 0x08, 0x4e, 0xd7, 0xe3, 0x5d, 0x50, 0x1e, 0xb3, - 0x5b, 0x23, 0x38, 0x34, 0x68, 0x46, 0x03, 0x8c, 0xdd, 0x9c, 0x7d, 0xa0, 0xcd, 0x1a, 0x41, 0x1c]; - - it("should compute correctly", async () => { - for (let i = 0; i < 256; i++) { - await circuit.expectPass({ in: i }, { out: inverses[i] }); - } - }); - - describe("XTimes1 with XTimes", () => { - let circuit: WitnessTester<["in"], ["out"]>; - it("should perform 1 times with XTERMS", async () => { - circuit = await circomkit.WitnessTester(`XTimes`, { - file: "aes-gcm/aes/sbox", - template: "XTimes", - params: [0x1], - }); - // 0x57 . 2 = 0xae - await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [1, 1, 1, 0, 1, 0, 1, 0] }); - // 0x54 . 2 = 0xa8 - await circuit.expectPass({ in: [0, 0, 1, 0, 1, 0, 1, 0] }, { out: [0, 0, 1, 0, 1, 0, 1, 0] }); - // 0xae . 2 = 0x47 - await circuit.expectPass({ in: [0, 1, 1, 1, 0, 1, 0, 1] }, { out: [0, 1, 1, 1, 0, 1, 0, 1] }); - // 0x47 . 2 = 0x8e - await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [1, 1, 1, 0, 1, 0, 1, 0] }); - }); - }); - - describe("XTimes2", () => { - let circuit: WitnessTester<["in"], ["out"]>; - it("should perform 2 times", async () => { - circuit = await circomkit.WitnessTester(`XTimes2`, { - file: "aes-gcm/aes/sbox", - template: "XTimes2", - }); - - // 0x57 . 2 = 0xae - await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [0, 1, 1, 1, 0, 1, 0, 1] }); - // 0x54 . 2 = 0xa8 - await circuit.expectPass({ in: [0, 0, 1, 0, 1, 0, 1, 0] }, { out: [0, 0, 0, 1, 0, 1, 0, 1] }); - // 0xae . 2 = 0x47 - await circuit.expectPass({ in: [0, 1, 1, 1, 0, 1, 0, 1] }, { out: [1, 1, 1, 0, 0, 0, 1, 0] }); - // 0x47 . 2 = 0x8e - await circuit.expectPass({ in: [1, 1, 1, 0, 0, 0, 1, 0] }, { out: [0, 1, 1, 1, 0, 0, 0, 1] }); - }); - }); - - describe("XTimes", () => { - let circuit: WitnessTester<["in"], ["out"]>; - it("should perform xtimes", async () => { - circuit = await circomkit.WitnessTester(`XTimes`, { - file: "aes-gcm/aes/sbox", - template: "XTimes", - params: [0x13], - }); - // 0x57 . 0x13 = 0xfe - await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [0, 1, 1, 1, 1, 1, 1, 1] }); - }); - }); - - describe("XTimes2 with XTimes", () => { - let circuit: WitnessTester<["in"], ["out"]>; - it("should perform 2 times with XTERMS", async () => { - circuit = await circomkit.WitnessTester(`XTimes`, { - file: "aes-gcm/aes/sbox", - template: "XTimes", - params: [0x2], - }); - // 0x57 . 2 = 0xae - await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [0, 1, 1, 1, 0, 1, 0, 1] }); - // 0x54 . 2 = 0xa8 - await circuit.expectPass({ in: [0, 0, 1, 0, 1, 0, 1, 0] }, { out: [0, 0, 0, 1, 0, 1, 0, 1] }); - // 0xae . 2 = 0x47 - await circuit.expectPass({ in: [0, 1, 1, 1, 0, 1, 0, 1] }, { out: [1, 1, 1, 0, 0, 0, 1, 0] }); - // 0x47 . 2 = 0x8e - await circuit.expectPass({ in: [1, 1, 1, 0, 0, 0, 1, 0] }, { out: [0, 1, 1, 1, 0, 0, 0, 1] }); - }); - }); -}); - diff --git a/circuits/test/aes-gcm/aes/transformations.test.ts b/circuits/test/aes-gcm/aes/transformations.test.ts deleted file mode 100644 index 79f11f8..0000000 --- a/circuits/test/aes-gcm/aes/transformations.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "../../common"; - -describe("MixColumns", () => { - it("s0 should compute correctly", async () => { - let circuit: WitnessTester<["in"], ["out"]>; - circuit = await circomkit.WitnessTester(`s0`, { - file: "aes-gcm/aes/mix_columns", - template: "S0", - params: [], - }); - - await circuit.expectPass({ in: [0xd4, 0xbf, 0x5d, 0x30] }, { out: 0x04 }); - }); - - it("s1 should compute correctly", async () => { - let circuit: WitnessTester<["in"], ["out"]>; - circuit = await circomkit.WitnessTester(`s1`, { - file: "aes-gcm/aes/mix_columns", - template: "S1", - params: [], - }); - - await circuit.expectPass({ in: [0xd4, 0xbf, 0x5d, 0x30] }, { out: 0x66 }); - }); - - it("s2 should compute correctly", async () => { - let circuit: WitnessTester<["in"], ["out"]>; - circuit = await circomkit.WitnessTester(`s2`, { - file: "aes-gcm/aes/mix_columns", - template: "S2", - params: [], - }); - - await circuit.expectPass({ in: [0xd4, 0xbf, 0x5d, 0x30] }, { out: 0x81 }); - }); - - it("s3 should compute correctly", async () => { - let circuit: WitnessTester<["in"], ["out"]>; - circuit = await circomkit.WitnessTester(`s3`, { - file: "aes-gcm/aes/mix_columns", - template: "S3", - params: [], - }); - - await circuit.expectPass({ in: [0xd4, 0xbf, 0x5d, 0x30] }, { out: 0xe5 }); - }); - - it("s4 should compute correctly", async () => { - let circuit: WitnessTester<["state"], ["out"]>; - circuit = await circomkit.WitnessTester(`MixColumns`, { - file: "aes-gcm/aes/mix_columns", - template: "MixColumns", - params: [], - }); - const state = [ - [0xd4, 0xe0, 0xb8, 0x1e], - [0xbf, 0xb4, 0x41, 0x27], - [0x5d, 0x52, 0x11, 0x98], - [0x30, 0xae, 0xf1, 0xe5], - ]; - - const out = [ - [0x04, 0xe0, 0x48, 0x28], - [0x66, 0xcb, 0xf8, 0x06], - [0x81, 0x19, 0xd3, 0x26], - [0xe5, 0x9a, 0x7a, 0x4c], - ]; - - await circuit.expectPass({ state }, { out }); - }); -}); - - diff --git a/circuits/test/aes-gcm/gctr.test.ts b/circuits/test/aes-gcm/gctr.test.ts deleted file mode 100644 index 4af80f7..0000000 --- a/circuits/test/aes-gcm/gctr.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "../common"; -import { assert } from "chai"; - -describe("GCTR", () => { - let circuit: WitnessTester<["plainText", "initialCounterBlock", "key"], ["cipherText"]>; - it("should encrypt the plaintext", async () => { - circuit = await circomkit.WitnessTester(`GCTR`, { - file: "aes-gcm/gctr", - template: "GCTR", - params: [16], - }); - - // GOOD TEST CASE. - const key = [0xca, 0xaa, 0x3f, 0x6f, 0xd3, 0x18, 0x22, 0xed, 0x2d, 0x21, 0x25, 0xf2, 0x25, 0xb0, 0x16, 0x9f]; - const column_wise_icb = [0x7f, 0x48, 0x12, 0x00, 0x6d, 0x3e, 0xfa, 0x00, 0x90, 0x8c, 0x55, 0x00, 0x41, 0x14, 0x2a, 0x02]; - const pt = [0x84, 0xc9, 0x07, 0xb1, 0x1a, 0xe3, 0xb7, 0x9f, 0xc4, 0x45, 0x1d, 0x1b, 0xf1, 0x7f, 0x4a, 0x99]; - const ct = [0xfd, 0xb4, 0xaa, 0xfa, 0x35, 0x19, 0xd3, 0xc0, 0x55, 0xbe, 0x8b, 0x34, 0x77, 0x64, 0xea, 0x33]; - - const witness = await circuit.compute({ key: key, initialCounterBlock: column_wise_icb, plainText: pt }, ["cipherText"]) - - assert.deepEqual(witness.cipherText, hexBytesToBigInt(ct)) - }); -}); - -function hexBytesToBigInt(hexBytes: number[]): any[] { - return hexBytes.map(byte => { - let n = BigInt(byte); - return n; - }); - } \ No newline at end of file diff --git a/circuits/test/aes-gcm/ghash/ghash.test.ts b/circuits/test/aes-gcm/ghash/ghash.test.ts deleted file mode 100644 index bddebca..0000000 --- a/circuits/test/aes-gcm/ghash/ghash.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "../../common"; - - - -describe("GHASH", () => { - let circuit: WitnessTester<["HashKey", "msg"], ["tag"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`ghash`, { - file: "aes-gcm/ghash/ghash", - template: "GHASH", - params: [2], - }); - }); - - it("test ghash", async () => { - // https://datatracker.ietf.org/doc/html/rfc8452#appendix-A - const H = [0x25, 0x62, 0x93, 0x47, 0x58, 0x92, 0x42, 0x76, 0x1d, 0x31, 0xf8, 0x26, 0xba, 0x4b, 0x75, 0x7b]; - const X1 = [0x4f, 0x4f, 0x95, 0x66, 0x8c, 0x83, 0xdf, 0xb6, 0x40, 0x17, 0x62, 0xbb, 0x2d, 0x01, 0xa2, 0x62]; - const X2 = [0xd1, 0xa2, 0x4d, 0xdd, 0x27, 0x21, 0xd0, 0x06, 0xbb, 0xe4, 0x5f, 0x20, 0xd3, 0xc9, 0xf3, 0x62]; - const M = X1.concat(X2); - const EXPECT = [0xbd, 0x9b, 0x39, 0x97, 0x04, 0x67, 0x31, 0xfb, 0x96, 0x25, 0x1b, 0x91, 0xf9, 0xc9, 0x9d, 0x7a]; - await circuit.expectPass({ HashKey: H, msg: M }, { tag: EXPECT }); - }); -}); - - - - diff --git a/circuits/test/aes-gcm/ghash/gmul.test.ts b/circuits/test/aes-gcm/ghash/gmul.test.ts deleted file mode 100644 index b0b65ba..0000000 --- a/circuits/test/aes-gcm/ghash/gmul.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "../../common"; - - -describe("GhashMul", () => { - let circuit: WitnessTester<["X", "Y"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester("ghash_gmul", { - file: "aes-gcm/ghash/gmul", - template: "GhashMul", - }); - }); - - it("Should Compute GhashMul Correctly", async () => { - - let X = [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - let Y = [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - - const expected = [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - await circuit.expectPass({ X: X, Y: Y }, { out: expected }); - }); - - it("Should Compute NistGMulByte of LSB=1 Correctly", async () => { - - let X = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]; - let Y = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]; - - const expected = [0xe6, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03]; - await circuit.expectPass({ X: X, Y: Y }, { out: expected }); - }); - it("Should Compute NistGMulByte of LSB=1 Correctly", async () => { - - // x = "aae06992acbf52a3e8f4a96ec9300bd7" - // y = "98e7247c07f0fe411c267e4384b0f600" - // expected = "90e87315fb7d4e1b4092ec0cbfda5d7d" - let X = [0xaa, 0xe0, 0x69, 0x92, 0xac, 0xbf, 0x52, 0xa3, 0xe8, 0xf4, 0xa9, 0x6e, 0xc9, 0x30, 0x0b, 0xd7]; - let Y = [0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00]; - - const expected = [0x90, 0xe8, 0x73, 0x15, 0xfb, 0x7d, 0x4e, 0x1b, 0x40, 0x92, 0xec, 0x0c, 0xbf, 0xda, 0x5d, 0x7d]; - await circuit.expectPass({ X: X, Y: Y }, { out: expected }); - }); - - describe("BlockRightShift", () => { - let circuit: WitnessTester<["in"], ["out", "msb"]>; - - before(async () => { - circuit = await circomkit.WitnessTester("BlockRightShift", { - file: "aes-gcm/ghash/gmul", - template: "BlockRightShift", - params: [16] - }); - }); - - it("Should Compute BlockRightShift Correctly", async () => { - let input = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - const expected = [0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - await circuit.expectPass({ in: input }, { out: expected, msb: 0 }); - }); - it("Should Compute BlockRightShift Correctly", async () => { - let input = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]; - const expected = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - await circuit.expectPass({ in: input }, { out: expected, msb: 1 }); - }); - }); - - describe("Mulx", () => { - let circuit: WitnessTester<["in"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester("Mulx", { - file: "aes-gcm/ghash/gmul", - template: "Mulx", - params: [16] - }); - }); - // msb is 1 so we xor the first byte with 0xE1 - it("Should Compute Mulx Correctly", async () => { - let input = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]; - const expected = [0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - await circuit.expectPass({ in: input }, { out: expected }); - }); - }); - - describe("Z_UPDATE", () => { - let circuit: WitnessTester<["Z", "V", "bit_val"], ["Z_new"]>; - - before(async () => { - circuit = await circomkit.WitnessTester("XORBLOCK", { - file: "aes-gcm/ghash/gmul", - template: "Z_UPDATE", - params: [16] - }); - }); - // msb is 1 so we xor the first byte with 0xE1 - it("Should Compute block XOR Correctly", async () => { - let inputZ = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - let inputV = [0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]; - let inputc = 0x00; - let expected = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - await circuit.expectPass({ Z: inputZ, V: inputV, bit_val: inputc }, { Z_new: expected }); - }); - - it("Should Compute block XOR Correctly", async () => { - let inputa = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - let inputb = [0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]; - let inputc = 0x01; - const expected = [0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]; - await circuit.expectPass({ Z: inputa, V: inputb, bit_val: inputc }, { Z_new: expected }); - }); - }); - - -}); - - - diff --git a/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts b/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts deleted file mode 100644 index d44afa4..0000000 --- a/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { assert } from "chai"; -import { WitnessTester } from "circomkit"; -import { circomkit, bytesToBigInt } from "../../common"; -import { PoseidonModular } from "../../common/poseidon"; - -describe("aes-gctr-nivc", () => { - let circuit_one_block: WitnessTester<["key", "iv", "plainText", "aad", "ctr", "cipherText", "step_in"], ["step_out"]>; - - - it("all correct for self generated single zero pt block case", async () => { - circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { - file: "aes-gcm/nivc/aes-gctr-nivc", - template: "AESGCTRFOLD", - params: [1] - }); - - let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - 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]; - - 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"]) - console.log(witness.step_out); - assert.deepEqual(witness.step_out, BigInt(0)); - }); - - it("all correct for self generated single non zero pt block", async () => { - circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { - file: "aes-gcm/nivc/aes-gctr-nivc", - template: "AESGCTRFOLD", - params: [1] - }); - - let key = [0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31]; - let plainText = [0x74, 0x65, 0x73, 0x74, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30]; - let iv = [0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31]; - let aad = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - let ct = [0x29, 0x29, 0xd2, 0xbb, 0x1a, 0xe9, 0x48, 0x04, 0x40, 0x2b, 0x8e, 0x77, 0x6e, 0x0d, 0x33, 0x56]; - - 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)])); - }); - - let key = [0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31]; - let plainText1 = [0x74, 0x65, 0x73, 0x74, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30]; - let plainText2 = [0x74, 0x65, 0x73, 0x74, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30]; - let iv = [0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31]; - let aad = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - let ct_part1 = [0x29, 0x29, 0xd2, 0xbb, 0x1a, 0xe9, 0x48, 0x04, 0x40, 0x2b, 0x8e, 0x77, 0x6e, 0x0d, 0x33, 0x56]; - let ct_part2 = [0x26, 0x75, 0x65, 0x30, 0x71, 0x3e, 0x4c, 0x06, 0x5a, 0xf1, 0xd3, 0xc4, 0xf5, 0x6e, 0x02, 0x04]; - // 2929d2bb1ae94804402b8e776e0d3356 - // 52101644195b206a35c1e3f4c55e3234 - // be0fe3e07b837d0103332436f8f0bbd - - it("all correct for self generated two block case first fold", async () => { - circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { - file: "aes-gcm/nivc/aes-gctr-nivc", - template: "AESGCTRFOLD", - params: [1] - }); - - const ctr = [0x00, 0x00, 0x00, 0x01]; - const step_in = 0; - - const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText1, aad: aad, ctr: ctr, cipherText: ct_part1, step_in: step_in }, ["step_out"]) - assert.deepEqual(witness.step_out, PoseidonModular([step_in, bytesToBigInt(plainText1)])); - }); - - it("all correct for self generated two block case second fold", async () => { - circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { - file: "aes-gcm/nivc/aes-gctr-nivc", - template: "AESGCTRFOLD", - params: [1] - }); - - const ctr_0 = [0x00, 0x00, 0x00, 0x01]; - const ctr_1 = [0x00, 0x00, 0x00, 0x02]; - const step_in_0 = 0; - - const witness_0 = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText1, aad: aad, ctr: ctr_0, cipherText: ct_part1, step_in: step_in_0 }, ["step_out"]) - const witness_1 = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText2, aad: aad, ctr: ctr_1, cipherText: ct_part2, step_in: witness_0.step_out }, ["step_out"]) - assert.deepEqual(witness_1.step_out, PoseidonModular([BigInt(witness_0.step_out.toString()), bytesToBigInt(plainText2)])); - }); - - let circuit_two_block: WitnessTester<["key", "iv", "plainText", "aad", "ctr", "cipherText", "step_in"], ["step_out"]>; - it("all correct for two folds at once", 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; - - const witness = await circuit_two_block.compute({ key: key, iv: iv, aad: aad, ctr: ctr_0, plainText: [plainText1, plainText2], cipherText: [ct_part1, ct_part2], step_in: step_in_0 }, ["step_out"]) - 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); - let zero_ct = [0x52, 0x10, 0x16, 0x44, 0x19, 0x5b, 0x20, 0x6a, 0x35, 0xc1, 0xe3, 0xf4, 0xc5, 0x5e, 0x32, 0x34]; - - const witness = await circuit_two_block.compute({ key: key, iv: iv, aad: aad, ctr: ctr_0, plainText: [plainText1, zero_chunk], cipherText: [ct_part1, zero_ct], 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 diff --git a/circuits/test/full/full.test.ts b/circuits/test/full/full.test.ts index f675c43..1647ed6 100644 --- a/circuits/test/full/full.test.ts +++ b/circuits/test/full/full.test.ts @@ -228,8 +228,8 @@ const json_key3_mask = [ ]; const json_key3_mask_hash = DataHasher(json_key3_mask); -describe("NIVC_FULL_AES", async () => { - let aesCircuit: WitnessTester<["key", "iv", "aad", "ctr", "plainText", "cipherText", "step_in"], ["step_out"]>; +describe("NIVC_FULL_CHACHA", async () => { + let chacha20Circuit: WitnessTester<["key", "nonce", "counter", "plainText", "cipherText", "step_in"], ["step_out"]>; let httpCircuit: WitnessTester<["step_in", "data", "start_line_hash", "header_hashes", "body_hash"], ["step_out"]>; let json_mask_object_circuit: WitnessTester<["step_in", "data", "key", "keyLen"], ["step_out"]>; let json_mask_arr_circuit: WitnessTester<["step_in", "data", "index"], ["step_out"]>; @@ -241,315 +241,92 @@ describe("NIVC_FULL_AES", async () => { const MAX_KEY_LENGTH = 8; const MAX_VALUE_LENGTH = 32; - before(async () => { - aesCircuit = await circomkit.WitnessTester("AESGCTRFOLD", { - file: "aes-gcm/nivc/aes-gctr-nivc", - template: "AESGCTRFOLD", - params: [1] - }); - console.log("#constraints (AES):", await aesCircuit.getConstraintCount()); - - httpCircuit = await circomkit.WitnessTester(`HttpNIVC`, { - file: "http/nivc/http_nivc", - template: "HttpNIVC", - params: [DATA_BYTES, MAX_NUMBER_OF_HEADERS], - }); - console.log("#constraints (HttpNIVC):", await httpCircuit.getConstraintCount()); - - json_mask_object_circuit = await circomkit.WitnessTester(`JsonMaskObjectNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskObjectNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH], - }); - console.log("#constraints (JSON-MASK-OBJECT):", await json_mask_object_circuit.getConstraintCount()); - - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskArrayIndexNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], - }); - console.log("#constraints (JSON-MASK-ARRAY-INDEX):", await json_mask_arr_circuit.getConstraintCount()); - - extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { - file: "json/nivc/extractor", - template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_VALUE_LENGTH], - }); - console.log("#constraints (JSON-MASK-EXTRACT-FINAL):", await extract_value_circuit.getConstraintCount()); - }); - it("NIVC_CHAIN", async () => { - const init_nivc_input = 0; - // Run AES chain - let ctr = [0x00, 0x00, 0x00, 0x01]; - let pt = http_response_plaintext.slice(0, 16); - let ct = aes_http_response_ciphertext.slice(0, 16); - let aes_gcm = await aesCircuit.compute({ key: Array(16).fill(0), iv: Array(12).fill(0), ctr: ctr, plainText: pt, aad: Array(16).fill(0), cipherText: ct, step_in: init_nivc_input }, ["step_out"]); - let i = 0; - console.log("AES `step_out[", i, "]`: ", aes_gcm.step_out); - for (i = 1; i < (DATA_BYTES / 16); i++) { - ctr[3] += 1; // This will work since we don't run a test that overlows a byte - let pt = http_response_plaintext.slice(i * 16, i * 16 + 16); - let ct = aes_http_response_ciphertext.slice(i * 16, i * 16 + 16); - aes_gcm = await aesCircuit.compute({ key: Array(16).fill(0), iv: Array(12).fill(0), ctr: ctr, plainText: pt, aad: Array(16).fill(0), cipherText: ct, step_in: aes_gcm.step_out }, ["step_out"]); - console.log("AES `step_out[", i, "]`: ", aes_gcm.step_out); - } - assert.deepEqual(http_response_hash, aes_gcm.step_out); - - let http = await httpCircuit.compute({ step_in: aes_gcm.step_out, data: http_response_plaintext, start_line_hash: http_start_line_hash, header_hashes: [http_header_0_hash, http_header_1_hash], body_hash: http_body_mask_hash }, ["step_out"]); - console.log("HttpNIVC `step_out`:", http.step_out); - - let key0 = [100, 97, 116, 97, 0, 0, 0, 0]; // "data" - let key0Len = 4; - let key1 = [105, 116, 101, 109, 115, 0, 0, 0]; // "items" - let key1Len = 5; - let key2 = [112, 114, 111, 102, 105, 108, 101, 0]; // "profile" - let key2Len = 7; - let key3 = [110, 97, 109, 101, 0, 0, 0, 0]; // "name" - let key3Len = 4; - - let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: http.step_out, data: http_body, key: key0, keyLen: key0Len }, ["step_out"]); - console.log("JSON Extract key0 `step_out`:", json_extract_key0.step_out); - assert.deepEqual(json_extract_key0.step_out, json_key0_mask_hash); - - let json_extract_key1 = await json_mask_object_circuit.compute({ step_in: json_extract_key0.step_out, data: json_key0_mask, key: key1, keyLen: key1Len }, ["step_out"]); - assert.deepEqual(json_extract_key1.step_out, json_key1_mask_hash); - console.log("JSON Extract key1 `step_out`:", json_extract_key1.step_out); - - let json_extract_arr = await json_mask_arr_circuit.compute({ step_in: json_extract_key1.step_out, data: json_key1_mask, index: 0 }, ["step_out"]); - assert.deepEqual(json_extract_arr.step_out, json_arr_mask_hash); - console.log("JSON Extract arr `step_out`:", json_extract_arr.step_out); - - let json_extract_key2 = await json_mask_object_circuit.compute({ step_in: json_extract_arr.step_out, data: json_arr_mask, key: key2, keyLen: key2Len }, ["step_out"]); - assert.deepEqual(json_extract_key2.step_out, json_key2_mask_hash); - console.log("JSON Extract key2 `step_out`:", json_extract_key2.step_out); - - let json_extract_key3 = await json_mask_object_circuit.compute({ step_in: json_extract_key2.step_out, data: json_key2_mask, key: key3, keyLen: key3Len }, ["step_out"]); - assert.deepEqual(json_extract_key3.step_out, json_key3_mask_hash); - console.log("JSON Extract key3 `step_out`:", json_extract_key3.step_out); - - // TODO (autoparallel): we need to rethink extraction here. - let finalOutput = toByte("\"Taylor Swift\""); - let finalOutputPadded = finalOutput.concat(Array(Math.max(0, MAX_VALUE_LENGTH - finalOutput.length)).fill(0)); - let final_value_hash = DataHasher(finalOutputPadded); - let extractValue = await extract_value_circuit.compute({ step_in: json_extract_key3.step_out, data: json_key3_mask }, ["step_out"]); - console.log("finalValue", extractValue.step_out); - assert.deepEqual(extractValue.step_out, final_value_hash); + chacha20Circuit = await circomkit.WitnessTester("CHACHA20", { + file: "chacha20/nivc/chacha20_nivc", + template: "ChaCha20_NIVC", + params: [80] // 80 * 32 = 2560 bits / 8 = 320 bytes }); -}); + console.log("#constraints (CHACHA20):", await chacha20Circuit.getConstraintCount()); -describe("NIVC_FULL_CHACHA", async () => { - let chacha20Circuit: WitnessTester<["key", "nonce", "counter", "plainText", "cipherText", "step_in"], ["step_out"]>; - let httpCircuit: WitnessTester<["step_in", "data", "start_line_hash", "header_hashes", "body_hash"], ["step_out"]>; - let json_mask_object_circuit: WitnessTester<["step_in", "data", "key", "keyLen"], ["step_out"]>; - let json_mask_arr_circuit: WitnessTester<["step_in", "data", "index"], ["step_out"]>; - let extract_value_circuit: WitnessTester<["step_in", "data"], ["step_out"]>; + httpCircuit = await circomkit.WitnessTester(`HttpNIVC`, { + file: "http/verification", + template: "HTTPVerification", + params: [DATA_BYTES, MAX_NUMBER_OF_HEADERS], + }); + console.log("#constraints (HttpNIVC):", await httpCircuit.getConstraintCount()); - const MAX_NUMBER_OF_HEADERS = 2; - const DATA_BYTES = 320; - const MAX_STACK_HEIGHT = 5; - const MAX_KEY_LENGTH = 8; - const MAX_VALUE_LENGTH = 32; + json_mask_object_circuit = await circomkit.WitnessTester(`JsonMaskObjectNIVC`, { + file: "json/nivc/masker", + template: "JsonMaskObjectNIVC", + params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH], + }); + console.log("#constraints (JSON-MASK-OBJECT):", await json_mask_object_circuit.getConstraintCount()); - before(async () => { - chacha20Circuit = await circomkit.WitnessTester("CHACHA20", { - file: "chacha20/nivc/chacha20_nivc", - template: "ChaCha20_NIVC", - params: [80] // 80 * 32 = 2560 bits / 8 = 320 bytes - }); - console.log("#constraints (CHACHA20):", await chacha20Circuit.getConstraintCount()); - - httpCircuit = await circomkit.WitnessTester(`HttpNIVC`, { - file: "http/nivc/http_nivc", - template: "HttpNIVC", - params: [DATA_BYTES, MAX_NUMBER_OF_HEADERS], - }); - console.log("#constraints (HttpNIVC):", await httpCircuit.getConstraintCount()); - - json_mask_object_circuit = await circomkit.WitnessTester(`JsonMaskObjectNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskObjectNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH], - }); - console.log("#constraints (JSON-MASK-OBJECT):", await json_mask_object_circuit.getConstraintCount()); - - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskArrayIndexNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], - }); - console.log("#constraints (JSON-MASK-ARRAY-INDEX):", await json_mask_arr_circuit.getConstraintCount()); - - extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { - file: "json/nivc/extractor", - template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_VALUE_LENGTH], - }); - console.log("#constraints (JSON-MASK-EXTRACT-FINAL):", await extract_value_circuit.getConstraintCount()); + json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { + file: "json/nivc/masker", + template: "JsonMaskArrayIndexNIVC", + params: [DATA_BYTES, MAX_STACK_HEIGHT], }); + console.log("#constraints (JSON-MASK-ARRAY-INDEX):", await json_mask_arr_circuit.getConstraintCount()); - it("NIVC_CHAIN", async () => { - const init_nivc_input = 0; - // Run ChaCha20 - const counterBits = uintArray32ToBits([1])[0] - const ptIn = toInput(Buffer.from(http_response_plaintext)); - const ctIn = toInput(Buffer.from(chacha20_http_response_ciphertext)); - 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 chacha20 = await chacha20Circuit.compute({ key: keyIn, nonce: nonceIn, counter: counterBits, plainText: ptIn, cipherText: ctIn, step_in: init_nivc_input }, ["step_out"]); - console.log("ChaCha20 `step_out`:", chacha20.step_out); - assert.deepEqual(http_response_hash, chacha20.step_out); - - let http = await httpCircuit.compute({ step_in: chacha20.step_out, data: http_response_plaintext, start_line_hash: http_start_line_hash, header_hashes: [http_header_0_hash, http_header_1_hash], body_hash: http_body_mask_hash }, ["step_out"]); - console.log("HttpNIVC `step_out`:", http.step_out); - - let key0 = [100, 97, 116, 97, 0, 0, 0, 0]; // "data" - let key0Len = 4; - let key1 = [105, 116, 101, 109, 115, 0, 0, 0]; // "items" - let key1Len = 5; - let key2 = [112, 114, 111, 102, 105, 108, 101, 0]; // "profile" - let key2Len = 7; - let key3 = [110, 97, 109, 101, 0, 0, 0, 0]; // "name" - let key3Len = 4; - - let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: http.step_out, data: http_body, key: key0, keyLen: key0Len }, ["step_out"]); - console.log("JSON Extract key0 `step_out`:", json_extract_key0.step_out); - assert.deepEqual(json_extract_key0.step_out, json_key0_mask_hash); - - let json_extract_key1 = await json_mask_object_circuit.compute({ step_in: json_extract_key0.step_out, data: json_key0_mask, key: key1, keyLen: key1Len }, ["step_out"]); - assert.deepEqual(json_extract_key1.step_out, json_key1_mask_hash); - console.log("JSON Extract key1 `step_out`:", json_extract_key1.step_out); - - let json_extract_arr = await json_mask_arr_circuit.compute({ step_in: json_extract_key1.step_out, data: json_key1_mask, index: 0 }, ["step_out"]); - assert.deepEqual(json_extract_arr.step_out, json_arr_mask_hash); - console.log("JSON Extract arr `step_out`:", json_extract_arr.step_out); - - let json_extract_key2 = await json_mask_object_circuit.compute({ step_in: json_extract_arr.step_out, data: json_arr_mask, key: key2, keyLen: key2Len }, ["step_out"]); - assert.deepEqual(json_extract_key2.step_out, json_key2_mask_hash); - console.log("JSON Extract key2 `step_out`:", json_extract_key2.step_out); - - let json_extract_key3 = await json_mask_object_circuit.compute({ step_in: json_extract_key2.step_out, data: json_key2_mask, key: key3, keyLen: key3Len }, ["step_out"]); - assert.deepEqual(json_extract_key3.step_out, json_key3_mask_hash); - console.log("JSON Extract key3 `step_out`:", json_extract_key3.step_out); - - // TODO (autoparallel): we need to rethink extraction here. - let finalOutput = toByte("\"Taylor Swift\""); - let finalOutputPadded = finalOutput.concat(Array(Math.max(0, MAX_VALUE_LENGTH - finalOutput.length)).fill(0)); - let final_value_hash = DataHasher(finalOutputPadded); - let extractValue = await extract_value_circuit.compute({ step_in: json_extract_key3.step_out, data: json_key3_mask }, ["step_out"]); - console.log("finalValue", extractValue.step_out); - assert.deepEqual(extractValue.step_out, final_value_hash); + extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { + file: "json/nivc/extractor", + template: "MaskExtractFinal", + params: [DATA_BYTES, MAX_VALUE_LENGTH], }); + console.log("#constraints (JSON-MASK-EXTRACT-FINAL):", await extract_value_circuit.getConstraintCount()); + + const init_nivc_input = 0; + // Run ChaCha20 + const counterBits = uintArray32ToBits([1])[0] + const ptIn = toInput(Buffer.from(http_response_plaintext)); + const ctIn = toInput(Buffer.from(chacha20_http_response_ciphertext)); + 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 chacha20 = await chacha20Circuit.compute({ key: keyIn, nonce: nonceIn, counter: counterBits, plainText: ptIn, cipherText: ctIn, step_in: init_nivc_input }, ["step_out"]); + console.log("ChaCha20 `step_out`:", chacha20.step_out); + assert.deepEqual(http_response_hash, chacha20.step_out); + + let http = await httpCircuit.compute({ step_in: chacha20.step_out, data: http_response_plaintext, start_line_hash: http_start_line_hash, header_hashes: [http_header_0_hash, http_header_1_hash], body_hash: http_body_mask_hash }, ["step_out"]); + console.log("HttpNIVC `step_out`:", http.step_out); + + let key0 = [100, 97, 116, 97, 0, 0, 0, 0]; // "data" + let key0Len = 4; + let key1 = [105, 116, 101, 109, 115, 0, 0, 0]; // "items" + let key1Len = 5; + let key2 = [112, 114, 111, 102, 105, 108, 101, 0]; // "profile" + let key2Len = 7; + let key3 = [110, 97, 109, 101, 0, 0, 0, 0]; // "name" + let key3Len = 4; + + let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: http.step_out, data: http_body, key: key0, keyLen: key0Len }, ["step_out"]); + console.log("JSON Extract key0 `step_out`:", json_extract_key0.step_out); + assert.deepEqual(json_extract_key0.step_out, json_key0_mask_hash); + + let json_extract_key1 = await json_mask_object_circuit.compute({ step_in: json_extract_key0.step_out, data: json_key0_mask, key: key1, keyLen: key1Len }, ["step_out"]); + assert.deepEqual(json_extract_key1.step_out, json_key1_mask_hash); + console.log("JSON Extract key1 `step_out`:", json_extract_key1.step_out); + + let json_extract_arr = await json_mask_arr_circuit.compute({ step_in: json_extract_key1.step_out, data: json_key1_mask, index: 0 }, ["step_out"]); + assert.deepEqual(json_extract_arr.step_out, json_arr_mask_hash); + console.log("JSON Extract arr `step_out`:", json_extract_arr.step_out); + + let json_extract_key2 = await json_mask_object_circuit.compute({ step_in: json_extract_arr.step_out, data: json_arr_mask, key: key2, keyLen: key2Len }, ["step_out"]); + assert.deepEqual(json_extract_key2.step_out, json_key2_mask_hash); + console.log("JSON Extract key2 `step_out`:", json_extract_key2.step_out); + + let json_extract_key3 = await json_mask_object_circuit.compute({ step_in: json_extract_key2.step_out, data: json_key2_mask, key: key3, keyLen: key3Len }, ["step_out"]); + assert.deepEqual(json_extract_key3.step_out, json_key3_mask_hash); + console.log("JSON Extract key3 `step_out`:", json_extract_key3.step_out); + + // TODO (autoparallel): we need to rethink extraction here. + let finalOutput = toByte("\"Taylor Swift\""); + let finalOutputPadded = finalOutput.concat(Array(Math.max(0, MAX_VALUE_LENGTH - finalOutput.length)).fill(0)); + let final_value_hash = DataHasher(finalOutputPadded); + let extractValue = await extract_value_circuit.compute({ step_in: json_extract_key3.step_out, data: json_key3_mask }, ["step_out"]); + console.log("finalValue", extractValue.step_out); + assert.deepEqual(extractValue.step_out, final_value_hash); }); -describe("NIVC_FULL_2_AES", async () => { - let aesCircuit: WitnessTester<["key", "iv", "aad", "ctr", "plainText", "cipherText", "step_in"], ["step_out"]>; - let httpCircuit: WitnessTester<["step_in", "data", "start_line_hash", "header_hashes", "body_hash"], ["step_out"]>; - let json_mask_object_circuit: WitnessTester<["step_in", "data", "key", "keyLen"], ["step_out"]>; - let json_mask_arr_circuit: WitnessTester<["step_in", "data", "index"], ["step_out"]>; - let extract_value_circuit: WitnessTester<["step_in", "data"], ["step_out"]>; - - const MAX_NUMBER_OF_HEADERS = 2; - const DATA_BYTES = 320; - const MAX_STACK_HEIGHT = 5; - const MAX_KEY_LENGTH = 8; - const MAX_VALUE_LENGTH = 32; - - before(async () => { - aesCircuit = await circomkit.WitnessTester("AESGCTRFOLD", { - file: "aes-gcm/nivc/aes-gctr-nivc", - template: "AESGCTRFOLD", - params: [2] - }); - console.log("#constraints (AES):", await aesCircuit.getConstraintCount()); - - httpCircuit = await circomkit.WitnessTester(`HttpNIVC`, { - file: "http/nivc/http_nivc", - template: "HttpNIVC", - params: [DATA_BYTES, MAX_NUMBER_OF_HEADERS], - }); - console.log("#constraints (HttpNIVC):", await httpCircuit.getConstraintCount()); - - json_mask_object_circuit = await circomkit.WitnessTester(`JsonMaskObjectNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskObjectNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH], - }); - console.log("#constraints (JSON-MASK-OBJECT):", await json_mask_object_circuit.getConstraintCount()); - - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskArrayIndexNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], - }); - console.log("#constraints (JSON-MASK-ARRAY-INDEX):", await json_mask_arr_circuit.getConstraintCount()); - - extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { - file: "json/nivc/extractor", - template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_VALUE_LENGTH], - }); - console.log("#constraints (JSON-MASK-EXTRACT-FINAL):", await extract_value_circuit.getConstraintCount()); - }); - - it("NIVC_CHAIN_2", async () => { - const init_nivc_input = 0; - - // Run AES chain - let ctr = [0x00, 0x00, 0x00, 0x01]; - let pt = [http_response_plaintext.slice(0, 16), http_response_plaintext.slice(16, 32)]; - let ct = [aes_http_response_ciphertext.slice(0, 16), aes_http_response_ciphertext.slice(16, 32)]; - let aes_gcm = await aesCircuit.compute({ key: Array(16).fill(0), iv: Array(12).fill(0), ctr: ctr, plainText: pt, aad: Array(16).fill(0), cipherText: ct, step_in: init_nivc_input }, ["step_out"]); - let i = 0; - console.log("AES `step_out[", i, "]`: ", aes_gcm.step_out); - for (i = 1; i < (DATA_BYTES / (16 * 2)); i++) { - ctr[3] += 2; // This will work since we don't run a test that overlows a byte - let pt = [http_response_plaintext.slice(i * 32, i * 32 + 16), http_response_plaintext.slice(i * 32 + 16, i * 32 + 32)]; - let ct = [aes_http_response_ciphertext.slice(i * 32, i * 32 + 16), aes_http_response_ciphertext.slice(i * 32 + 16, i * 32 + 32)]; - aes_gcm = await aesCircuit.compute({ key: Array(16).fill(0), iv: Array(12).fill(0), ctr: ctr, plainText: pt, aad: Array(16).fill(0), cipherText: ct, step_in: aes_gcm.step_out }, ["step_out"]); - console.log("AES `step_out[", i, "]`: ", aes_gcm.step_out); - } - assert.deepEqual(http_response_hash, aes_gcm.step_out); - - let http = await httpCircuit.compute({ step_in: aes_gcm.step_out, data: http_response_plaintext, start_line_hash: http_start_line_hash, header_hashes: [http_header_0_hash, http_header_1_hash], body_hash: http_body_mask_hash }, ["step_out"]); - console.log("HttpNIVC `step_out`:", http.step_out); - - let key0 = [100, 97, 116, 97, 0, 0, 0, 0]; // "data" - let key0Len = 4; - let key1 = [105, 116, 101, 109, 115, 0, 0, 0]; // "items" - let key1Len = 5; - let key2 = [112, 114, 111, 102, 105, 108, 101, 0]; // "profile" - let key2Len = 7; - let key3 = [110, 97, 109, 101, 0, 0, 0, 0]; // "name" - let key3Len = 4; - - let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: http.step_out, data: http_body, key: key0, keyLen: key0Len }, ["step_out"]); - console.log("JSON Extract key0 `step_out`:", json_extract_key0.step_out); - assert.deepEqual(json_extract_key0.step_out, json_key0_mask_hash); - - let json_extract_key1 = await json_mask_object_circuit.compute({ step_in: json_extract_key0.step_out, data: json_key0_mask, key: key1, keyLen: key1Len }, ["step_out"]); - assert.deepEqual(json_extract_key1.step_out, json_key1_mask_hash); - console.log("JSON Extract key1 `step_out`:", json_extract_key1.step_out); - - let json_extract_arr = await json_mask_arr_circuit.compute({ step_in: json_extract_key1.step_out, data: json_key1_mask, index: 0 }, ["step_out"]); - assert.deepEqual(json_extract_arr.step_out, json_arr_mask_hash); - console.log("JSON Extract arr `step_out`:", json_extract_arr.step_out); - - let json_extract_key2 = await json_mask_object_circuit.compute({ step_in: json_extract_arr.step_out, data: json_arr_mask, key: key2, keyLen: key2Len }, ["step_out"]); - assert.deepEqual(json_extract_key2.step_out, json_key2_mask_hash); - console.log("JSON Extract key2 `step_out`:", json_extract_key2.step_out); - - let json_extract_key3 = await json_mask_object_circuit.compute({ step_in: json_extract_key2.step_out, data: json_key2_mask, key: key3, keyLen: key3Len }, ["step_out"]); - assert.deepEqual(json_extract_key3.step_out, json_key3_mask_hash); - console.log("JSON Extract key3 `step_out`:", json_extract_key3.step_out); - - // TODO (autoparallel): we need to rethink extraction here. - let finalOutput = toByte("\"Taylor Swift\""); - let finalOutputPadded = finalOutput.concat(Array(Math.max(0, MAX_VALUE_LENGTH - finalOutput.length)).fill(0)); - let final_value_hash = DataHasher(finalOutputPadded); - let extractValue = await extract_value_circuit.compute({ step_in: json_extract_key3.step_out, data: json_key3_mask }, ["step_out"]); - console.log("finalValue", extractValue.step_out); - assert.deepEqual(extractValue.step_out, final_value_hash); - }); -}); \ No newline at end of file diff --git a/circuits/test/http/interpreter.test.ts b/circuits/test/http/interpreter.test.ts deleted file mode 100644 index 5bc6968..0000000 --- a/circuits/test/http/interpreter.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { circomkit, WitnessTester, generateDescription, toByte } from "../common"; -import { readHTTPInputFile } from "../common/http"; - -describe("HTTP :: Interpreter", async () => { - describe("MethodMatch", async () => { - let circuit: WitnessTester<["data", "method", "index"], []>; - - function generatePassCase(input: number[], method: number[], index: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`LockRequestLineData`, { - file: "http/interpreter", - template: "MethodMatch", - params: [input.length, method.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass({ data: input, method: method, index: index }, {}); - }); - } - - function generateFailCase(input: number[], method: number[], index: number, desc: string) { - const description = generateDescription(input); - - it(`(invalid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`LockRequestLineData`, { - file: "http/interpreter", - template: "MethodMatch", - params: [input.length, method.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectFail({ data: input, method: method, index: index }); - }); - } - - let parsedHttp = readHTTPInputFile("get_request.http"); - generatePassCase(parsedHttp.input, toByte("GET"), 0, ""); - generateFailCase(parsedHttp.input, toByte("POST"), 0, ""); - }); -}); - -// 320 bytes in the HTTP response -let http_response_plaintext = [ - 72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 99, 111, 110, 116, 101, 110, - 116, 45, 116, 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, - 115, 111, 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 99, - 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, - 112, 13, 10, 84, 114, 97, 110, 115, 102, 101, 114, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, - 32, 99, 104, 117, 110, 107, 101, 100, 13, 10, 13, 10, 123, 13, 10, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, - 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, - 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, - 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, - 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, - 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]; - -describe("HeaderFieldNameValueMatchPadded", async () => { - let circuit: WitnessTester<["data", "headerName", "nameLen", "headerValue", "valueLen", "index"], ["out"]>; - - let DATA_BYTES = 320; - let MAX_NAME_LENGTH = 20; - let MAX_VALUE_LENGTH = 35; - - before(async () => { - circuit = await circomkit.WitnessTester(`HeaderFieldNameValueMatchPadded`, { - file: "http/interpreter", - template: "HeaderFieldNameValueMatchPadded", - params: [DATA_BYTES, MAX_NAME_LENGTH, MAX_VALUE_LENGTH], - }); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - input["headerName"] = input["headerName"].concat(Array(MAX_NAME_LENGTH - input["headerName"].length).fill(0)); - input["headerValue"] = input["headerValue"].concat(Array(MAX_VALUE_LENGTH - input["headerValue"].length).fill(0)); - - it(`(valid) witness: ${desc}`, async () => { - // console.log(JSON.stringify(await circuit.compute(input, ["step_out"]))) - await circuit.expectPass(input, expected); - }); - - } - - let header_name = toByte("content-type"); - let header_value = toByte("application/json; charset=utf-8"); - - let input = { - data: http_response_plaintext, - headerName: header_name, - nameLen: header_name.length, - headerValue: header_value, - valueLen: header_value.length, - index: 17, - } - generatePassCase(input, { out: 1 }, "header name and value matches"); - - let input2 = { - data: http_response_plaintext, - headerName: header_name, - nameLen: header_name.length, - headerValue: header_value, - valueLen: header_value.length, - index: 16, - } - generatePassCase(input2, { out: 0 }, "incorrect index"); -}); \ No newline at end of file diff --git a/circuits/test/http/locker.test.ts b/circuits/test/http/locker.test.ts deleted file mode 100644 index 34f32be..0000000 --- a/circuits/test/http/locker.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { circomkit, WitnessTester, generateDescription, toByte } from "../common"; -import { readHTTPInputFile } from "../common/http"; - -describe("HTTP :: Locker :: Request Line", async () => { - let circuit: WitnessTester<["data", "beginning", "middle", "final"], []>; - - function generatePassCase(input: number[], beginning: number[], middle: number[], final: number[], desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`LockStartLine`, { - file: "http/locker", - template: "LockStartLine", - params: [input.length, beginning.length, middle.length, final.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass({ data: input, beginning: beginning, middle: middle, final: final }, {}); - }); - } - - function generateFailCase(input: number[], beginning: number[], middle: number[], final: number[], desc: string) { - const description = generateDescription(input); - - it(`(invalid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`LockStartLine`, { - file: "http/locker", - template: "LockStartLine", - params: [input.length, beginning.length, middle.length, final.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectFail({ data: input, beginning: beginning, middle: middle, final: final }); - }); - } - - describe("GET", async () => { - let parsedHttp = readHTTPInputFile("get_request.http"); - generatePassCase(parsedHttp.input, toByte("GET"), toByte("/api"), toByte("HTTP/1.1"), ""); - generateFailCase(parsedHttp.input.slice(0), toByte("POST"), toByte("/api"), toByte("HTTP/1.1"), ""); - generateFailCase(parsedHttp.input.slice(0), toByte("GET"), toByte("/"), toByte("HTTP/1.1"), ""); - generateFailCase(parsedHttp.input.slice(0), toByte("GET"), toByte("/api"), toByte("HTTP"), ""); - }); - - describe("POST", async () => { - let parsedHttp = readHTTPInputFile("post_request.http"); - generatePassCase(parsedHttp.input, toByte("POST"), toByte("/contact_form.php"), toByte("HTTP/1.1"), ""); - generateFailCase(parsedHttp.input.slice(0), toByte("GET"), toByte("/contact_form.php"), toByte("HTTP/1.1"), ""); - generateFailCase(parsedHttp.input.slice(0), toByte("POST"), toByte("/"), toByte("HTTP/1.1"), ""); - generateFailCase(parsedHttp.input.slice(0), toByte("POST"), toByte("/contact_form.php"), toByte("HTTP"), ""); - }); -}); - -describe("HTTP :: Locker :: Status Line", async () => { - let circuit: WitnessTester<["data", "beginning", "middle", "final"], []>; - - function generatePassCase(input: number[], beginning: number[], middle: number[], final: number[], desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`LockStartLine`, { - file: "http/locker", - template: "LockStartLine", - params: [input.length, beginning.length, middle.length, final.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass({ data: input, beginning: beginning, middle: middle, final: final }, {}); - }); - } - - function generateFailCase(input: number[], beginning: number[], middle: number[], final: number[], desc: string) { - const description = generateDescription(input); - - it(`(invalid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`LockStartLine`, { - file: "http/locker", - template: "LockStartLine", - params: [input.length, beginning.length, middle.length, final.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectFail({ data: input, beginning: beginning, middle: middle, final: final }); - }); - } - - describe("GET", async () => { - let parsedHttp = readHTTPInputFile("get_response.http"); - generatePassCase(parsedHttp.input, toByte("HTTP/1.1"), toByte("200"), toByte("OK"), ""); - generateFailCase(parsedHttp.input, toByte("HTTP"), toByte("200"), toByte("OK"), ""); - generateFailCase(parsedHttp.input, toByte("HTTP/1.1"), toByte("404"), toByte("OK"), ""); - generateFailCase(parsedHttp.input, toByte("HTTP/1.1"), toByte("200"), toByte("Not Found"), ""); - }); -}); - -describe("HTTP :: Locker :: Header", async () => { - let circuit: WitnessTester<["data", "header", "value"], []>; - - function generatePassCase(input: number[], header: number[], value: number[], desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`LockHeader`, { - file: "http/locker", - template: "LockHeader", - params: [input.length, header.length, value.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass({ data: input, header: header, value: value }, {}); - }); - } - - function generateFailCase(input: number[], header: number[], value: number[], desc: string) { - const description = generateDescription(input); - - it(`(invalid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`LockHeader`, { - file: "http/locker", - template: "LockHeader", - params: [input.length, header.length, value.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectFail({ data: input, header: header, value: value }); - }); - } - - describe("GET", async () => { - let parsedHttp = readHTTPInputFile("get_request.http"); - generatePassCase(parsedHttp.input, toByte("Host"), toByte("localhost"), ""); - generateFailCase(parsedHttp.input, toByte("Accept"), toByte("localhost"), ""); - generateFailCase(parsedHttp.input, toByte("Host"), toByte("venmo.com"), ""); - generateFailCase(parsedHttp.input, toByte("Connection"), toByte("keep-alive"), ""); - }); -}); \ No newline at end of file diff --git a/circuits/test/http/nivc/body_mask.test.ts b/circuits/test/http/nivc/body_mask.test.ts deleted file mode 100644 index 04067cb..0000000 --- a/circuits/test/http/nivc/body_mask.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { circomkit, WitnessTester, toByte } from "../../common"; -import { assert } from "chai"; -import { DataHasher } from "../../common/poseidon"; - -// HTTP/1.1 200 OK -// content-type: application/json; charset=utf-8 -// content-encoding: gzip -// Transfer-Encoding: chunked -// -// { -// "data": { -// "items": [ -// { -// "data": "Artist", -// "profile": { -// "name": "Taylor Swift" -// } -// } -// ] -// } -// } - -// 320 bytes in the HTTP response -let http_response_plaintext = [ - 72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 99, 111, 110, 116, 101, 110, - 116, 45, 116, 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, - 115, 111, 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 99, - 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, - 112, 13, 10, 84, 114, 97, 110, 115, 102, 101, 114, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, - 32, 99, 104, 117, 110, 107, 101, 100, 13, 10, 13, 10, 123, 13, 10, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, - 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, - 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, - 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, - 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, - 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_body = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 123, 13, 10, 32, 32, 32, 34, - 100, 97, 116, 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, - 115, 34, 58, 32, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, - 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, - 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 125, 13, 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 lengthDiff = http_response_plaintext.length - http_body.length; - -// Create an array of zeros with the length difference -const padding = new Array(lengthDiff).fill(0); - -// Concatenate the padding with http_body -const padded_http_body = [...padding, ...http_body]; - -const http_response_hash = DataHasher(http_response_plaintext); -const http_body_mask_hash = DataHasher(padded_http_body); - -describe("NIVC_HTTP", async () => { - let httpParseAndLockStartLineCircuit: WitnessTester<["step_in", "data", "beginning", "beginning_length", "middle", "middle_length", "final", "final_length"], ["step_out"]>; - let lockHeaderCircuit: WitnessTester<["step_in", "data", "header", "headerNameLength", "value", "headerValueLength"], ["step_out"]>; - let bodyMaskCircuit: WitnessTester<["step_in", "data"], ["step_out"]>; - - const DATA_BYTES = 320; - const TOTAL_BYTES_ACROSS_NIVC = 1; - - const MAX_HEADER_NAME_LENGTH = 20; - const MAX_HEADER_VALUE_LENGTH = 35; - const MAX_BEGINNING_LENGTH = 10; - const MAX_MIDDLE_LENGTH = 30; - const MAX_FINAL_LENGTH = 10; - - const beginning = [72, 84, 84, 80, 47, 49, 46, 49]; // HTTP/1.1 - const middle = [50, 48, 48]; // 200 - const final = [79, 75]; // OK - - before(async () => { - httpParseAndLockStartLineCircuit = await circomkit.WitnessTester(`ParseAndLockStartLine`, { - file: "http/nivc/parse_and_lock_start_line", - template: "ParseAndLockStartLine", - params: [DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], - }); - console.log("#constraints:", await httpParseAndLockStartLineCircuit.getConstraintCount()); - - lockHeaderCircuit = await circomkit.WitnessTester(`LockHeader`, { - file: "http/nivc/lock_header", - template: "LockHeader", - params: [DATA_BYTES, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], - }); - console.log("#constraints:", await lockHeaderCircuit.getConstraintCount()); - - bodyMaskCircuit = await circomkit.WitnessTester(`BodyMask`, { - file: "http/nivc/body_mask", - template: "HTTPMaskBodyNIVC", - params: [DATA_BYTES], - }); - console.log("#constraints:", await bodyMaskCircuit.getConstraintCount()); - }); - - let extendedJsonInput = http_response_plaintext.concat(Array(Math.max(0, TOTAL_BYTES_ACROSS_NIVC - http_response_plaintext.length)).fill(0)); - - let headerName = toByte("content-type"); - let headerValue = toByte("application/json; charset=utf-8"); - - let headerNamePadded = headerName.concat(Array(MAX_HEADER_NAME_LENGTH - headerName.length).fill(0)); - let headerValuePadded = headerValue.concat(Array(MAX_HEADER_VALUE_LENGTH - headerValue.length).fill(0)); - let beginningPadded = beginning.concat(Array(MAX_BEGINNING_LENGTH - beginning.length).fill(0)); - let middlePadded = middle.concat(Array(MAX_MIDDLE_LENGTH - middle.length).fill(0)); - let finalPadded = final.concat(Array(MAX_FINAL_LENGTH - final.length).fill(0)); - it("HTTPParseAndExtract", async () => { - let parseAndLockStartLine = await httpParseAndLockStartLineCircuit.compute({ step_in: http_response_hash, data: http_response_plaintext, beginning: beginningPadded, beginning_length: beginning.length, middle: middlePadded, middle_length: middle.length, final: finalPadded, final_length: final.length }, ["step_out"]); - let lockHeader = await lockHeaderCircuit.compute({ step_in: parseAndLockStartLine.step_out, data: http_response_plaintext, header: headerNamePadded, headerNameLength: headerName.length, value: headerValuePadded, headerValueLength: headerValue.length }, ["step_out"]); - let bodyMask = await bodyMaskCircuit.compute({ step_in: lockHeader.step_out, data: http_response_plaintext }, ["step_out"]); - console.log("GOT TRHOUGH THIRD CIRCUIT"); - - assert.deepEqual(bodyMask.step_out, http_body_mask_hash); - }); -}); \ No newline at end of file diff --git a/circuits/test/http/nivc/lock_header.test.ts b/circuits/test/http/nivc/lock_header.test.ts deleted file mode 100644 index 14cc914..0000000 --- a/circuits/test/http/nivc/lock_header.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { circomkit, WitnessTester, toByte } from "../../common"; -import { readHTTPInputFile } from "../../common/http"; -import { DataHasher } from "../../common/poseidon"; - -describe("HTTPLockHeader", async () => { - let httpParseAndLockStartLineCircuit: WitnessTester<["step_in", "data", "beginning", "beginning_length", "middle", "middle_length", "final", "final_length"], ["step_out"]>; - let lockHeaderCircuit: WitnessTester<["step_in", "data", "header", "headerNameLength", "value", "headerValueLength"], ["step_out"]>; - - const DATA_BYTES = 336; - - const MAX_BEGINNING_LENGTH = 10; - const MAX_MIDDLE_LENGTH = 50; - const MAX_FINAL_LENGTH = 10; - const MAX_HEADER_NAME_LENGTH = 20; - const MAX_HEADER_VALUE_LENGTH = 35; - - before(async () => { - httpParseAndLockStartLineCircuit = await circomkit.WitnessTester(`ParseAndLockStartLine`, { - file: "http/nivc/parse_and_lock_start_line", - template: "ParseAndLockStartLine", - params: [DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], - }); - console.log("#constraints:", await httpParseAndLockStartLineCircuit.getConstraintCount()); - - lockHeaderCircuit = await circomkit.WitnessTester(`LockHeader`, { - file: "http/nivc/lock_header", - template: "LockHeader", - params: [DATA_BYTES, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], - }); - console.log("#constraints:", await lockHeaderCircuit.getConstraintCount()); - }); - - function generatePassCase(input: number[], beginning: number[], middle: number[], final: number[], headerName: number[], headerValue: number[], desc: string) { - it(`should pass: \"${headerName}: ${headerValue}\", ${desc}`, async () => { - let extendedInput = input.concat(Array(Math.max(0, DATA_BYTES - input.length)).fill(0)); - const http_response_hash = DataHasher(extendedInput); - - let beginningPadded = beginning.concat(Array(MAX_BEGINNING_LENGTH - beginning.length).fill(0)); - let middlePadded = middle.concat(Array(MAX_MIDDLE_LENGTH - middle.length).fill(0)); - let finalPadded = final.concat(Array(MAX_FINAL_LENGTH - final.length).fill(0)); - - let headerNamePadded = headerName.concat(Array(MAX_HEADER_NAME_LENGTH - headerName.length).fill(0)); - let headerValuePadded = headerValue.concat(Array(MAX_HEADER_VALUE_LENGTH - headerValue.length).fill(0)); - - let parseAndLockStartLine = await httpParseAndLockStartLineCircuit.compute({ step_in: http_response_hash, data: extendedInput, beginning: beginningPadded, beginning_length: beginning.length, middle: middlePadded, middle_length: middle.length, final: finalPadded, final_length: final.length }, ["step_out"]); - - await lockHeaderCircuit.expectPass({ step_in: parseAndLockStartLine.step_out, data: extendedInput, header: headerNamePadded, headerNameLength: headerName.length, value: headerValuePadded, headerValueLength: headerValue.length }); - }); - } - - function generateFailCase(input: number[], beginning: number[], middle: number[], final: number[], headerName: number[], headerValue: number[], desc: string) { - it(`should fail: ${desc}`, async () => { - let extendedInput = input.concat(Array(Math.max(0, DATA_BYTES - input.length)).fill(0)); - const http_response_hash = DataHasher(extendedInput); - - let beginningPadded = beginning.concat(Array(MAX_BEGINNING_LENGTH - beginning.length).fill(0)); - let middlePadded = middle.concat(Array(MAX_MIDDLE_LENGTH - middle.length).fill(0)); - let finalPadded = final.concat(Array(MAX_FINAL_LENGTH - final.length).fill(0)); - - let headerNamePadded = headerName.concat(Array(MAX_HEADER_NAME_LENGTH - headerName.length).fill(0)); - let headerValuePadded = headerValue.concat(Array(MAX_HEADER_VALUE_LENGTH - headerValue.length).fill(0)); - - let parseAndLockStartLine = await httpParseAndLockStartLineCircuit.compute({ step_in: http_response_hash, data: extendedInput, beginning: beginningPadded, beginning_length: beginning.length, middle: middlePadded, middle_length: middle.length, final: finalPadded, final_length: final.length }, ["step_out"]); - - await lockHeaderCircuit.expectFail({ step_in: parseAndLockStartLine.step_out, data: extendedInput, header: headerNamePadded, headerNameLength: headerName.length, value: headerValuePadded, headerValueLength: headerValue.length }); - }); - } - - describe("request", async () => { - let { input, headers } = readHTTPInputFile("post_request.http"); - - let beginning = toByte("POST"); - let middle = toByte("/contact_form.php"); - let final = toByte("HTTP/1.1"); - - let headerName = toByte("Host"); - let headerValue = toByte("developer.mozilla.org"); - - for (const [key, value] of Object.entries(headers)) { - generatePassCase(input, beginning, middle, final, toByte(key), toByte(value), "request"); - } - let incorrectHeaderValue = toByte("application/json"); - generateFailCase(input, beginning, middle, final, headerName, incorrectHeaderValue, "incorrect header value"); - }); - - describe("response", async () => { - let { input, headers } = readHTTPInputFile("spotify_top_artists_response.http"); - let beginning = toByte("HTTP/1.1"); - let middle = toByte("200"); - let final = toByte("OK"); - - for (const [key, value] of Object.entries(headers)) { - generatePassCase(input, beginning, middle, final, toByte(key), toByte(value), "response"); - } - - let headerName = toByte("content-encoding"); - let invalidHeaderValue = toByte("chunked"); - generateFailCase(input, beginning, middle, final, headerName, invalidHeaderValue, "should fail: invalid header value"); - }); -}); \ No newline at end of file diff --git a/circuits/test/http/nivc/parse_and_lock_start_line.test.ts b/circuits/test/http/nivc/parse_and_lock_start_line.test.ts deleted file mode 100644 index 202650c..0000000 --- a/circuits/test/http/nivc/parse_and_lock_start_line.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { circomkit, WitnessTester, toByte } from "../../common"; -import { readHTTPInputFile } from "../../common/http"; -import { DataHasher } from "../../common/poseidon"; - -describe("HTTPParseAndLockStartLine", async () => { - let httpParseAndLockStartLineCircuit: WitnessTester<["step_in", "data", "beginning", "beginning_length", "middle", "middle_length", "final", "final_length"], ["step_out"]>; - - const DATA_BYTES = 336; - - const MAX_BEGINNING_LENGTH = 10; - const MAX_MIDDLE_LENGTH = 50; - const MAX_FINAL_LENGTH = 10; - - before(async () => { - httpParseAndLockStartLineCircuit = await circomkit.WitnessTester(`ParseAndLockStartLine`, { - file: "http/nivc/parse_and_lock_start_line", - template: "ParseAndLockStartLine", - params: [DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], - }); - console.log("#constraints:", await httpParseAndLockStartLineCircuit.getConstraintCount()); - }); - - function generatePassCase(input: number[], beginning: number[], middle: number[], final: number[], desc: string) { - it(`(valid) witness: ${desc}`, async () => { - let extendedInput = input.concat(Array(Math.max(0, DATA_BYTES - input.length)).fill(0)); - const http_response_hash = DataHasher(extendedInput); - - let beginningPadded = beginning.concat(Array(MAX_BEGINNING_LENGTH - beginning.length).fill(0)); - let middlePadded = middle.concat(Array(MAX_MIDDLE_LENGTH - middle.length).fill(0)); - let finalPadded = final.concat(Array(MAX_FINAL_LENGTH - final.length).fill(0)); - - await httpParseAndLockStartLineCircuit.expectPass({ step_in: [http_response_hash], data: extendedInput, beginning: beginningPadded, beginning_length: beginning.length, middle: middlePadded, middle_length: middle.length, final: finalPadded, final_length: final.length }); - }); - } - - function generateFailCase(input: number[], beginning: number[], middle: number[], final: number[], desc: string) { - it(`(valid) witness: ${desc}`, async () => { - let extendedInput = input.concat(Array(Math.max(0, DATA_BYTES - input.length)).fill(0)); - const http_response_hash = DataHasher(extendedInput); - - - let beginningPadded = beginning.concat(Array(MAX_BEGINNING_LENGTH - beginning.length).fill(0)); - let middlePadded = middle.concat(Array(MAX_MIDDLE_LENGTH - middle.length).fill(0)); - let finalPadded = final.concat(Array(MAX_FINAL_LENGTH - final.length).fill(0)); - - await httpParseAndLockStartLineCircuit.expectFail({ step_in: [http_response_hash], data: extendedInput, beginning: beginningPadded, beginning_length: beginning.length, middle: middlePadded, middle_length: middle.length, final: finalPadded, final_length: final.length }); - }); - } - - describe("request", async () => { - let { input, } = readHTTPInputFile("spotify_top_artists_request.http"); - - let beginning = toByte("GET"); - let middle = toByte("/v1/me/top/artists?time_range=medium_term&limit=1"); - let final = toByte("HTTP/1.1"); - - generatePassCase(input, beginning, middle, final, "should pass request"); - - let incorrectBeginning = toByte("DELETE"); - generateFailCase(input, incorrectBeginning, middle, final, "should fail: incorrect BEGINNING"); - - let incorrectMiddle = toByte("/contact_form.php"); - generateFailCase(input, beginning, incorrectMiddle, final, "should fail: incorrect MIDDLE"); - - let incorrectFinal = toByte("HTTP/2"); - generateFailCase(input, beginning, middle, incorrectFinal, "should fail: incorrect FINAL"); - }) - - describe("response", async () => { - let { input, } = readHTTPInputFile("spotify_top_artists_response.http"); - let beginning = toByte("HTTP/1.1"); - let middle = toByte("200"); - let final = toByte("OK"); - - generatePassCase(input, beginning, middle, final, "should pass response"); it - - let incorrectBeginning = toByte("HTTP/2"); - generateFailCase(input, incorrectBeginning, middle, final, "should fail: incorrect BEGINNING"); - - let incorrectMiddle = toByte("2000"); - generateFailCase(input, beginning, incorrectMiddle, final, "should fail: incorrect MIDDLE"); - - let incorrectFinal = toByte("INVALID"); - generateFailCase(input, beginning, middle, incorrectFinal, "should fail: incorrect FINAL"); - }); -}); \ No newline at end of file diff --git a/circuits/test/http/nivc/http_nivc.test.ts b/circuits/test/http/verification.test.ts similarity index 96% rename from circuits/test/http/nivc/http_nivc.test.ts rename to circuits/test/http/verification.test.ts index 295c787..065ab51 100644 --- a/circuits/test/http/nivc/http_nivc.test.ts +++ b/circuits/test/http/verification.test.ts @@ -1,6 +1,6 @@ -import { circomkit, WitnessTester, toByte } from "../../common"; +import { circomkit, WitnessTester, toByte } from "../common"; import { assert } from "chai"; -import { DataHasher } from "../../common/poseidon"; +import { DataHasher } from "../common/poseidon"; // HTTP/1.1 200 OK // content-type: application/json; charset=utf-8 @@ -97,9 +97,9 @@ const TEST_HTTP_BODY = [ ]; const DATA_BYTES = 320; -const TOTAL_BYTES_ACROSS_NIVC = 1; +const MAX_NUMBER_OF_HEADERS = 2; -describe("HTTP_NIVC", async () => { +describe("HTTP Verfication", async () => { let dataHasher: WitnessTester<["in"], ["out"]>; let httpNivc: WitnessTester<["step_in", "data", "start_line_hash", "header_hashes", "body_hash"], ["step_out"]>; before(async () => { @@ -110,9 +110,9 @@ describe("HTTP_NIVC", async () => { }); httpNivc = await circomkit.WitnessTester("http_nivc", { - file: "http/nivc/http_nivc", - template: "HttpNIVC", - params: [320, 2] + file: "http/verification", + template: "HTTPVerification", + params: [DATA_BYTES, MAX_NUMBER_OF_HEADERS] }); }); diff --git a/circuits/test/utils/array.test.ts b/circuits/test/utils/array.test.ts index e95512c..1202a47 100644 --- a/circuits/test/utils/array.test.ts +++ b/circuits/test/utils/array.test.ts @@ -1,476 +1,166 @@ import { circomkit, WitnessTester } from "../common"; describe("IsEqualArray", () => { - let circuit: WitnessTester<["in"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`IsEqualArray`, { - file: "utils/array", - template: "IsEqualArray", - params: [3], - }); - console.log("#constraints:", await circuit.getConstraintCount()); + let circuit: WitnessTester<["in"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`IsEqualArray`, { + file: "utils/array", + template: "IsEqualArray", + params: [3], }); + console.log("#constraints:", await circuit.getConstraintCount()); + }); - it("witness: [[0,0,0],[0,0,0]]", async () => { - await circuit.expectPass( - { in: [[0, 0, 0], [0, 0, 0]] }, - { out: 1 } - ); - }); + it("witness: [[0,0,0],[0,0,0]]", async () => { + await circuit.expectPass( + { in: [[0, 0, 0], [0, 0, 0]] }, + { out: 1 } + ); + }); - it("witness: [[1,420,69],[1,420,69]]", async () => { - await circuit.expectPass( - { in: [[1, 420, 69], [1, 420, 69]] }, - { out: 1 }, - ); - }); + it("witness: [[1,420,69],[1,420,69]]", async () => { + await circuit.expectPass( + { in: [[1, 420, 69], [1, 420, 69]] }, + { out: 1 }, + ); + }); - it("witness: [[0,0,0],[1,420,69]]", async () => { - await circuit.expectPass( - { in: [[0, 0, 0], [1, 420, 69]] }, - { out: 0 }, - ); - }); + it("witness: [[0,0,0],[1,420,69]]", async () => { + await circuit.expectPass( + { in: [[0, 0, 0], [1, 420, 69]] }, + { out: 0 }, + ); + }); - it("witness: [[1,420,0],[1,420,69]]", async () => { - await circuit.expectPass( - { in: [[1, 420, 0], [1, 420, 69]] }, - { out: 0 }, - ); - }); + it("witness: [[1,420,0],[1,420,69]]", async () => { + await circuit.expectPass( + { in: [[1, 420, 0], [1, 420, 69]] }, + { out: 0 }, + ); + }); - it("witness: [[1,0,69],[1,420,69]]", async () => { - await circuit.expectPass( - { in: [[1, 0, 69], [1, 420, 69]] }, - { out: 0 }, - ); - }); + it("witness: [[1,0,69],[1,420,69]]", async () => { + await circuit.expectPass( + { in: [[1, 0, 69], [1, 420, 69]] }, + { out: 0 }, + ); + }); - it("witness: [[0,420,69],[1,420,69]]", async () => { - await circuit.expectPass( - { in: [[0, 420, 69], [1, 420, 69]] }, - { out: 0 }, - ); - }); + it("witness: [[0,420,69],[1,420,69]]", async () => { + await circuit.expectPass( + { in: [[0, 420, 69], [1, 420, 69]] }, + { out: 0 }, + ); + }); }); describe("Contains", () => { - let circuit: WitnessTester<["in", "array"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`Contains`, { - file: "utils/array", - template: "Contains", - params: [3], - }); - console.log("#constraints:", await circuit.getConstraintCount()); + let circuit: WitnessTester<["in", "array"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`Contains`, { + file: "utils/array", + template: "Contains", + params: [3], }); + console.log("#constraints:", await circuit.getConstraintCount()); + }); - it("witness: in = 0, array = [0,1,2]", async () => { - await circuit.expectPass( - { in: 0, array: [0, 1, 2] }, - { out: 1 } - ); - }); + it("witness: in = 0, array = [0,1,2]", async () => { + await circuit.expectPass( + { in: 0, array: [0, 1, 2] }, + { out: 1 } + ); + }); - it("witness: in = 1, array = [0,1,2]", async () => { - await circuit.expectPass( - { in: 1, array: [0, 1, 2] }, - { out: 1 } - ); - }); + it("witness: in = 1, array = [0,1,2]", async () => { + await circuit.expectPass( + { in: 1, array: [0, 1, 2] }, + { out: 1 } + ); + }); - it("witness: in = 2, array = [0,1,2]", async () => { - await circuit.expectPass( - { in: 2, array: [0, 1, 2] }, - { out: 1 } - ); - }); + it("witness: in = 2, array = [0,1,2]", async () => { + await circuit.expectPass( + { in: 2, array: [0, 1, 2] }, + { out: 1 } + ); + }); - it("witness: in = 42069, array = [0,1,2]", async () => { - await circuit.expectPass( - { in: 42069, array: [0, 1, 2] }, - { out: 0 } - ); - }); + it("witness: in = 42069, array = [0,1,2]", async () => { + await circuit.expectPass( + { in: 42069, array: [0, 1, 2] }, + { out: 0 } + ); + }); }); describe("ArrayAdd", () => { - let circuit: WitnessTester<["lhs", "rhs"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`ArrayAdd`, { - file: "utils/array", - template: "ArrayAdd", - params: [3], - }); - console.log("#constraints:", await circuit.getConstraintCount()); + let circuit: WitnessTester<["lhs", "rhs"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`ArrayAdd`, { + file: "utils/array", + template: "ArrayAdd", + params: [3], }); + console.log("#constraints:", await circuit.getConstraintCount()); + }); - it("witness: lhs = [0,1,2], rhs = [3,5,7]", async () => { - await circuit.expectPass( - { lhs: [0, 1, 2], rhs: [3, 5, 7] }, - { out: [3, 6, 9] } - ); - }); + it("witness: lhs = [0,1,2], rhs = [3,5,7]", async () => { + await circuit.expectPass( + { lhs: [0, 1, 2], rhs: [3, 5, 7] }, + { out: [3, 6, 9] } + ); + }); }); describe("ArrayMul", () => { - let circuit: WitnessTester<["lhs", "rhs"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`ArrayMul`, { - file: "utils/array", - template: "ArrayMul", - params: [3], - }); - console.log("#constraints:", await circuit.getConstraintCount()); + let circuit: WitnessTester<["lhs", "rhs"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`ArrayMul`, { + file: "utils/array", + template: "ArrayMul", + params: [3], }); + console.log("#constraints:", await circuit.getConstraintCount()); + }); - it("witness: lhs = [0,1,2], rhs = [3,5,7]", async () => { - await circuit.expectPass( - { lhs: [0, 1, 2], rhs: [3, 5, 7] }, - { out: [0, 5, 14] } - ); - }); + it("witness: lhs = [0,1,2], rhs = [3,5,7]", async () => { + await circuit.expectPass( + { lhs: [0, 1, 2], rhs: [3, 5, 7] }, + { out: [0, 5, 14] } + ); + }); }); describe("GenericArrayAdd", () => { - let circuit: WitnessTester<["arrays"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`ArrayAdd`, { - file: "utils/array", - template: "GenericArrayAdd", - params: [3, 2], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("witness: arrays = [[0,1,2],[3,5,7]]", async () => { - await circuit.expectPass( - { arrays: [[0, 1, 2], [3, 5, 7]] }, - { out: [3, 6, 9] } - ); - }); - -}); - -describe("array_builder", () => { - it("test array builder", async () => { - let circuit: WitnessTester<["array_to_write_to", "array_to_write_at_index", "index"], ["out"]>; - circuit = await circomkit.WitnessTester(`ArrayBuilder`, { - file: "utils/array", - template: "WriteToIndex", - params: [160, 16], - }); - - let array_to_write_to = new Array(160).fill(0x00); - let array_to_write_at_index = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10]; - let expected = array_to_write_at_index.concat(new Array(160 - array_to_write_at_index.length).fill(0x00)); - let index = 0; - - await circuit.expectPass( - { - array_to_write_to: array_to_write_to, - array_to_write_at_index: array_to_write_at_index, - index: index - }, - { - out: expected - } - ); - }); - it("test array builder", async () => { - let circuit: WitnessTester<["array_to_write_to", "array_to_write_at_index", "index"], ["out"]>; - circuit = await circomkit.WitnessTester(`ArrayBuilder`, { - file: "utils/array", - template: "WriteToIndex", - params: [160, 16], - }); - - let array_to_write_to = new Array(160).fill(0x00); - let array_to_write_at_index = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10]; - let expected = [0x00].concat(array_to_write_at_index).concat(new Array(160 - array_to_write_at_index.length - 1).fill(0x00)); - let index = 1; - - await circuit.expectPass( - { - array_to_write_to: array_to_write_to, - array_to_write_at_index: array_to_write_at_index, - index: index - }, - { - out: expected - } - ); - }); - it("test array builder", async () => { - let circuit: WitnessTester<["array_to_write_to", "array_to_write_at_index", "index"], ["out"]>; - circuit = await circomkit.WitnessTester(`ArrayBuilder`, { - file: "utils/array", - template: "WriteToIndex", - params: [160, 16], - }); - - let array_to_write_to = new Array(160).fill(0x00); - let array_to_write_at_index = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10]; - let expected = [0x00, 0x00].concat(array_to_write_at_index).concat(new Array(160 - array_to_write_at_index.length - 2).fill(0x00)); - let index = 2; - - await circuit.expectPass( - { - array_to_write_to: array_to_write_to, - array_to_write_at_index: array_to_write_at_index, - index: index - }, - { - out: expected - } - ); - }); - it("test array builder with index = n", async () => { - let circuit: WitnessTester<["array_to_write_to", "array_to_write_at_index", "index"], ["out"]>; - circuit = await circomkit.WitnessTester(`ArrayBuilder`, { - file: "utils/array", - template: "WriteToIndex", - params: [37, 16], - }); - - let array_to_write_to = new Array(37).fill(0x00); - let array_to_write_at_index = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10]; - let expected = new Array(16).fill(0x00).concat(array_to_write_at_index).concat(new Array(37 - array_to_write_at_index.length - 16).fill(0x00)); - let index = 16; - - await circuit.expectPass( - { - array_to_write_to: array_to_write_to, - array_to_write_at_index: array_to_write_at_index, - index: index - }, - { - out: expected - } - ); - }); - - it("test array builder with index > n", async () => { - let circuit: WitnessTester<["array_to_write_to", "array_to_write_at_index", "index"], ["out"]>; - circuit = await circomkit.WitnessTester(`ArrayBuilder`, { - file: "utils/array", - template: "WriteToIndex", - params: [37, 4], - }); - - let array_to_write_to = [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x88, 0xDA, 0xCE, 0x60, 0xB6, 0xA3, 0x92, 0xF3, 0x28, 0xC2, 0xB9, 0x71, 0xB2, 0xFE, 0x78, - 0x00, 0x00, 0x00, 0x00, 0x00 - ]; - let array_to_write_at_index = [0x00, 0x00, 0x00, 0x01]; - let expected = [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x88, 0xDA, 0xCE, 0x60, 0xB6, 0xA3, 0x92, 0xF3, 0x28, 0xC2, 0xB9, 0x71, 0xB2, 0xFE, 0x78, - 0x00, 0x00, 0x00, 0x01, 0x00 - ]; - let index = 32; - - await circuit.expectPass( - { - array_to_write_to: array_to_write_to, - array_to_write_at_index: array_to_write_at_index, - index: index - }, - { - out: expected - } - ); - }); -}); - -describe("ToBlocks", () => { - let circuit: WitnessTester<["stream"], ["blocks"]>; - it("should convert stream to block", async () => { - circuit = await circomkit.WitnessTester(`ToBlocks`, { - file: "utils/array", - template: "ToBlocks", - params: [16], - }); - await circuit.expectPass( - { - stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x34], - }, - { - blocks: [ - [ - [0x32, 0x43, 0xf6, 0xa8], - [0x88, 0x5a, 0x30, 0x8d], - [0x31, 0x31, 0x98, 0xa2], - [0xe0, 0x37, 0x07, 0x34], - ], - ], - } - ); - }); - it("should pad 1 in block", async () => { - circuit = await circomkit.WitnessTester(`ToBlocks`, { - file: "utils/array", - template: "ToBlocks", - params: [15], - }); - await circuit.expectPass( - { - stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2], - }, - { - blocks: [ - [ - [0x32, 0x43, 0xf6, 0xa8], - [0x88, 0x5a, 0x30, 0x8d], - [0x31, 0x31, 0x98, 0xa2], - [0xe0, 0x37, 0x07, 0x01], - ], - ], - } - ); - }); - it("should pad 0's in block", async () => { - circuit = await circomkit.WitnessTester(`ToBlocks`, { - file: "utils/array", - template: "ToBlocks", - params: [14], - }); - await circuit.expectPass( - { - stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d], - }, - { - blocks: [ - [ - [0x32, 0x43, 0xf6, 0xa8], - [0x88, 0x5a, 0x30, 0x8d], - [0x31, 0x31, 0x98, 0x01], - [0xe0, 0x37, 0x07, 0x00], - ], - ], - } - ); - }); - it("should generate enough blocks", async () => { - circuit = await circomkit.WitnessTester(`ToBlocks`, { - file: "utils/array", - template: "ToBlocks", - params: [17], - }); - await circuit.expectPass( - { - stream: [0x32, 0x88, 0x31, 0xe0, 0x42, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x34, 0x12], - }, - { - blocks: [ - [ - [0x32, 0x42, 0xf6, 0xa8], - [0x88, 0x5a, 0x30, 0x8d], - [0x31, 0x31, 0x98, 0xa2], - [0xe0, 0x37, 0x07, 0x34], - ], - [ - [0x12, 0x00, 0x00, 0x00], - [0x01, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00], - ], - ], - } - ); + let circuit: WitnessTester<["arrays"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`ArrayAdd`, { + file: "utils/array", + template: "GenericArrayAdd", + params: [3, 2], }); + console.log("#constraints:", await circuit.getConstraintCount()); }); - - - describe("ToStream", () => { - let circuit: WitnessTester<["blocks"], ["stream"]>; - it("should convert blocks to stream#1", async () => { - circuit = await circomkit.WitnessTester(`ToStream`, { - file: "utils/array", - template: "ToStream", - params: [1, 16], - }); - await circuit.expectPass( - { - blocks: [ - [ - [0x32, 0x43, 0xf6, 0xa8], - [0x88, 0x5a, 0x30, 0x8d], - [0x31, 0x31, 0x98, 0xa2], - [0xe0, 0x37, 0x07, 0x34], - ], - ], - }, - { - stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x34], - } - ); - }); - it("should convert blocks to stream#2", async () => { - circuit = await circomkit.WitnessTester(`ToStream`, { - file: "utils/array", - template: "ToStream", - params: [1, 15], - }); - await circuit.expectPass( - { - blocks: [ - [ - [0x32, 0x43, 0xf6, 0xa8], - [0x88, 0x5a, 0x30, 0x8d], - [0x31, 0x31, 0x98, 0xa2], - [0xe0, 0x37, 0x07, 0x01], - ], - ], - }, - { - stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2], - } - ); - }); - it("should convert multiple blocks to stream", async () => { - circuit = await circomkit.WitnessTester(`ToStream`, { - file: "utils/array", - template: "ToStream", - params: [2, 18], - }); - await circuit.expectPass( - { - blocks: [ - [ - [0x32, 0x43, 0xf6, 0xa8], - [0x88, 0x5a, 0x30, 0x8d], - [0x31, 0x31, 0x98, 0xa2], - [0xe0, 0x37, 0x07, 0x01], - ], - [ - [0x32, 0x43, 0xf6, 0xa8], - [0x88, 0x5a, 0x30, 0x8d], - [0x31, 0x31, 0x98, 0xa2], - [0xe0, 0x37, 0x07, 0x01], - ], - ], - }, - { - stream: [ - 0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x01, 0x32, 0x88, - ], - } - ); - }); + + it("witness: arrays = [[0,1,2],[3,5,7]]", async () => { + await circuit.expectPass( + { arrays: [[0, 1, 2], [3, 5, 7]] }, + { out: [3, 6, 9] } + ); }); +}); describe("fromLittleEndianToWords32", () => { let circuit: WitnessTester<["data"], ["words"]>; - it("fromLittleEndianToWords32", async () => { - circuit = await circomkit.WitnessTester(`fromLittleEndianToWords32`, { - file: "utils/array", - template: "fromLittleEndianToWords32", - }); + it("fromLittleEndianToWords32", async () => { + circuit = await circomkit.WitnessTester(`fromLittleEndianToWords32`, { + file: "utils/array", + template: "fromLittleEndianToWords32", + }); console.log("#constraints:", await circuit.getConstraintCount()); let input = [ @@ -479,26 +169,28 @@ describe("fromLittleEndianToWords32", () => { 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0 ]; - await circuit.expectPass({data: input}, {words: [72, 84, 84, 80]}) + await circuit.expectPass({ data: input }, { words: [72, 84, 84, 80] }) }); }); describe("fromWords32ToLittleEndian", () => { let circuit: WitnessTester<["words"], ["data"]>; - it("fromWords32ToLittleEndian", async () => { - circuit = await circomkit.WitnessTester(`fromWords32ToLittleEndian`, { - file: "utils/array", - template: "fromWords32ToLittleEndian", - }); + it("fromWords32ToLittleEndian", async () => { + circuit = await circomkit.WitnessTester(`fromWords32ToLittleEndian`, { + file: "utils/array", + template: "fromWords32ToLittleEndian", + }); console.log("#constraints:", await circuit.getConstraintCount()); let input = [72, 84, 84, 80]; - await circuit.expectPass({words: input}, {data: [ - 0, 1, 0, 1, 0, 0, 0, 0, 0, - 1, 0, 1, 0, 1, 0, 0, 0, 1, - 0, 1, 0, 1, 0, 0, 0, 1, 0, - 0, 1, 0, 0, 0 - ]}) + await circuit.expectPass({ words: input }, { + data: [ + 0, 1, 0, 1, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0 + ] + }) }); }); diff --git a/circuits/test/utils/bits.test.ts b/circuits/test/utils/bits.test.ts new file mode 100644 index 0000000..30dfdc4 --- /dev/null +++ b/circuits/test/utils/bits.test.ts @@ -0,0 +1,25 @@ +import { circomkit, WitnessTester } from "../common"; + +describe("ASCII", () => { + let circuit: WitnessTester<["in"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`ASCII`, { + file: "utils/bits", + template: "ASCII", + params: [13], + }); + console.log("#constraints:", await circuit.getConstraintCount()); + }); + + it("(valid) witness: in = b\"Hello, world!\"", async () => { + await circuit.expectPass( + { in: [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] }, + ); + }); + + it("(invalid) witness: in = [256, ...]", async () => { + await circuit.expectFail( + { in: [256, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] } + ); + }); +}); \ No newline at end of file diff --git a/circuits/test/utils/bytes.test.ts b/circuits/test/utils/bytes.test.ts deleted file mode 100644 index dfb11db..0000000 --- a/circuits/test/utils/bytes.test.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { circomkit, WitnessTester } from "../common"; - -describe("ASCII", () => { - let circuit: WitnessTester<["in"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`ASCII`, { - file: "utils/bytes", - template: "ASCII", - params: [13], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("(valid) witness: in = b\"Hello, world!\"", async () => { - await circuit.expectPass( - { in: [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] }, - ); - }); - - it("(invalid) witness: in = [256, ...]", async () => { - await circuit.expectFail( - { in: [256, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] } - ); - }); -}); - -describe("BytePack", () => { - let circuit: WitnessTester<["lower", "upper"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`DoubleBytePackArray`, { - file: "utils/bytes", - template: "DoubleBytePackArray", - params: [1], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("witness: lower = 0, upper = 1", async () => { - await circuit.expectPass( - { lower: [0], upper: [1] }, { out: [256] } - ); - }); - - it("witness: lower = 1, upper = 1", async () => { - await circuit.expectPass( - { lower: [1], upper: [1] }, { out: [257] } - ); - }); - - it("witness: lower = 1, upper = 0", async () => { - await circuit.expectPass( - { lower: [1], upper: [0] }, { out: [1] } - ); - }); -}); - -describe("BytePack2", () => { - let circuit: WitnessTester<["lower", "upper"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`DoubleBytePackArray`, { - file: "utils/bytes", - template: "DoubleBytePackArray", - params: [2], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - it("witness: lower = [1,0], upper = [0,1]", async () => { - await circuit.expectPass( - { lower: [1, 0], upper: [0, 1] }, { out: [1, 256] } - ); - }); -}); - -describe("ByteUnpack", () => { - let circuit: WitnessTester<["in"], ["lower", "upper"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`UnpackDoubleByteArray`, { - file: "utils/bytes", - template: "UnpackDoubleByteArray", - params: [1], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("witness: in = 256", async () => { - await circuit.expectPass( - { in: [256] }, { lower: [0], upper: [1] } - ); - }); - - it("witness: in = 257", async () => { - await circuit.expectPass( - { in: [257] }, { lower: [1], upper: [1] } - ); - }); - - it("witness: in = 1", async () => { - await circuit.expectPass( - { in: [1] }, { lower: [1], upper: [] } - ); - }); -}); - -describe("ByteUnpack2", () => { - let circuit: WitnessTester<["in"], ["lower", "upper"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`UnpackDoubleByteArray`, { - file: "utils/bytes", - template: "UnpackDoubleByteArray", - params: [2], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("witness: in = [1,256]", async () => { - await circuit.expectPass( - { in: [1, 256] }, { lower: [1, 0], upper: [0, 1] } - ); - }); - -}); - - - -// Generic version -describe("GenericBytePack2", () => { - let circuit: WitnessTester<["in"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`GenericBytePackArray`, { - file: "utils/bytes", - template: "GenericBytePackArray", - params: [2, 3], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - it("witness: lower = [1,0,0], upper = [0,1,0]", async () => { - await circuit.expectPass( - { in: [[1, 0, 0], [0, 1, 0]] }, { out: [1, 256] } - ); - }); - it("witness: lower = [1,0,0], upper = [0,0,1]", async () => { - await circuit.expectPass( - { in: [[1, 0, 0], [0, 0, 1]] }, { out: [1, 65536] } - ); - }); -}); - -describe("GenericByteUnpack2", () => { - let circuit: WitnessTester<["in"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`GenericByteUnpackArray`, { - file: "utils/bytes", - template: "GenericByteUnpackArray", - params: [2, 3], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("witness: in = [1,256]", async () => { - await circuit.expectPass( - { in: [1, 256] }, { out: [[1, 0, 0], [0, 1, 0]] } - ); - }); - - it("witness: in = [1,256]", async () => { - await circuit.expectPass( - { in: [1, 65536] }, { out: [[1, 0, 0], [0, 0, 1]] } - ); - }); -}); diff --git a/circuits/test/utils/search.test.ts b/circuits/test/utils/search.test.ts index f172fa1..5a7ea1e 100644 --- a/circuits/test/utils/search.test.ts +++ b/circuits/test/utils/search.test.ts @@ -1,228 +1,37 @@ import { circomkit, WitnessTester } from "../common"; - import witness from "../../../inputs/search/witness.json"; -import { PoseidonModular } from "../common/poseidon"; - -describe("search", () => { - describe("SubstringSearch", () => { - let circuit: WitnessTester<["data", "key", "random_num"], ["position"]>; - - it("key at first position", async () => { - const data = [10, 8, 9, 4, 11, 9, 1, 2]; - const key = [10, 8, 9, 4]; - const concatenatedInput = key.concat(data); - const hashResult = PoseidonModular(concatenatedInput); - - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringSearch", - params: [data.length, key.length], - }); - - await circuit.expectPass( - { data: data, key: key, random_num: hashResult }, - { position: 0 }, - ); - }); - it("key at last position", async () => { - const data = [11, 9, 1, 2, 10, 8, 9, 4]; - const key = [10, 8, 9, 4]; - const concatenatedInput = key.concat(data); - const hashResult = PoseidonModular(concatenatedInput); +describe("SubstringMatchWithIndex", () => { + let circuit: WitnessTester<["data", "key", "start"], ["out"]>; - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringSearch", - params: [data.length, key.length], - }); - - await circuit.expectPass( - { data: data, key: key, random_num: hashResult }, - { position: 4 }, - ); - }); - - /// highlights the importance of appropriate calculation of random number for linear matching. - /// `1` as used here leads to passing constraints because [1, 0] matches with [0, 1] - /// because both have equal linear combination sum. - it("(INVALID `r=1` value) random_num input passes for different position, correct key position: 2", async () => { - const data = [0, 0, 1, 0, 0]; - const key = [1, 0]; - - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringSearch", - params: [data.length, key.length], - }); - - await circuit.expectPass( - { data: data, key: key, random_num: 1 }, - { position: 1 }, - ); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(data+key)", async () => { - const concatenatedInput = witness["key"].concat(witness["data"]); - const hashResult = PoseidonModular(concatenatedInput); - - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringSearch", - params: [witness["data"].length, witness["key"].length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass( - { data: witness["data"], key: witness["key"], random_num: hashResult }, - { position: 6 } - ); + before(async () => { + circuit = await circomkit.WitnessTester(`SubstringSearch`, { + file: "utils/search", + template: "SubstringMatchWithIndex", + params: [787, 10], }); + console.log("#constraints:", await circuit.getConstraintCount()); }); - describe("SubstringMatchWithHasher", () => { - let circuit: WitnessTester<["data", "key", "r", "start"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringMatchWithHasher", - params: [787, 10], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(key+data)", async () => { - await circuit.expectPass( - { - data: witness["data"], - key: witness["key"], - r: PoseidonModular(witness["key"].concat(witness["data"])), - start: 6 - }, - { out: 1 }, - ); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(key+data), output false", async () => { - await circuit.expectPass( - { - data: witness["data"], - key: witness["key"], - r: PoseidonModular(witness["key"].concat(witness["data"])), - start: 98 - }, - { out: 0 } - ); - }); + it("data = witness.json:data, key = witness.json:key, r = hash(key+data)", async () => { + await circuit.expectPass( + { + data: witness["data"], + key: witness["key"], + start: 6 + }, + { out: 1 }, + ); }); - describe("SubstringMatchWithIndex", () => { - let circuit: WitnessTester<["data", "key", "start"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringMatchWithIndex", - params: [787, 10], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(key+data)", async () => { - await circuit.expectPass( - { - data: witness["data"], - key: witness["key"], - start: 6 - }, - { out: 1 }, - ); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(key+data), output false", async () => { - await circuit.expectPass( - { - data: witness["data"], - key: witness["key"], - start: 98 - }, - { out: 0 } - ); - }); - }); - - describe("SubstringMatchWithIndexPadded", () => { - let circuit: WitnessTester<["data", "key", "keyLen", "start"], ["out"]>; - let maxKeyLen = 30; - - before(async () => { - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringMatchWithIndexPadded", - params: [787, maxKeyLen], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(key+data)", async () => { - let key = witness["key"]; - let pad_key = key.concat(Array(maxKeyLen - key.length).fill(0)); - await circuit.expectPass( - { - data: witness["data"], - key: pad_key, - keyLen: witness["key"].length, - start: 6 - }, - { out: 1 }, - ); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(key+data), output false", async () => { - let key = witness["key"]; - let pad_key = key.concat(Array(maxKeyLen - key.length).fill(0)); - await circuit.expectPass( - { - data: witness["data"], - key: pad_key, - keyLen: witness["key"].length, - start: 98 - }, - { out: 0 } - ); - }); - }); - - describe("SubstringMatch", () => { - let circuit: WitnessTester<["data", "key"], ["position"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringMatch", - params: [787, 10], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("data = witness.json:data, key = witness.json:key", async () => { - await circuit.expectPass( - { data: witness["data"], key: witness["key"] }, - { position: 6 }, - ); - }); - - it("data = witness.json:data, key = invalid key byte", async () => { - await circuit.expectFail( - { data: witness["data"], key: witness["key"].concat(257) }, - ); - }); - - it("data = witness.json:data, key = wrong key", async () => { - await circuit.expectFail( - { data: witness["data"], key: witness["key"].concat(0) }, - ); - }); + it("data = witness.json:data, key = witness.json:key, r = hash(key+data), output false", async () => { + await circuit.expectPass( + { + data: witness["data"], + key: witness["key"], + start: 98 + }, + { out: 0 } + ); }); -}); \ No newline at end of file +}); diff --git a/circuits/utils/array.circom b/circuits/utils/array.circom index f03530b..87baf4b 100644 --- a/circuits/utils/array.circom +++ b/circuits/utils/array.circom @@ -38,28 +38,6 @@ template IsEqualArray(n) { out <== totalEqual.out; } -template IsEqualArrayPaddedLHS(n) { - signal input in[2][n]; - signal output out; - - var accum = 0; - component equalComponent[n]; - component isPaddedElement[n]; - - for(var i = 0; i < n; i++) { - isPaddedElement[i] = IsZero(); - isPaddedElement[i].in <== in[0][i]; - equalComponent[i] = IsEqual(); - equalComponent[i].in[0] <== in[0][i]; - equalComponent[i].in[1] <== in[1][i] * (1-isPaddedElement[i].out); - accum += equalComponent[i].out; - } - - component totalEqual = IsEqual(); - totalEqual.in[0] <== n; - totalEqual.in[1] <== accum; - out <== totalEqual.out; -} // TODO: There should be a way to have the below assertion come from the field itself. /* @@ -254,265 +232,6 @@ template IndexSelector(total) { out <== calcTotal.sum; } -/* -This template selects an array in a mxn matrix -# Params: - - `m`: the row dimensions - - `n`: the column dimensions - -# Inputs: - - `index`: the index to select - -# Outputs: - - `out`: the array at index -*/ -template ArraySelector(m, n) { - signal input in[m][n]; - signal input index; - signal output out[n]; - assert(index >= 0 && index < m); - - signal selector[m]; - component Equal[m]; - for (var i = 0; i < m; i++) { - selector[i] <== IsEqual()([index, i]); - } - - var sum = 0; - for (var i = 0; i < m; i++) { - sum += selector[i]; - } - sum === 1; - - signal sums[n][m+1]; - for (var j = 0; j < n; j++) { - sums[j][0] <== 0; - for (var i = 0; i < m; i++) { - sums[j][i+1] <== sums[j][i] + in[i][j] * selector[i]; - } - out[j] <== sums[j][m]; - } -} - -/* -This template is multiplexer for two arrays of length n -# Params: - - `n`: the array length - -# Inputs: - - `a`: the first array - - `b`: the second array - - `sel`: the selector (1 or 0) - -# Outputs: - - `out`: the array selected -*/ -template ArrayMux(n) { - signal input a[n]; - signal input b[n]; - signal input sel; - signal output out[n]; - - for (var i = 0; i < n; i++) { - out[i] <== (b[i] - a[i]) * sel + a[i]; - } -} - -/* -This template writes one array to a larger array of fixed size starting at an index -E.g., given an array of m=160, we want to write at `index` to the n=16 bytes at that index. -This is used to write to nivc signals that are incrementally written to on each fold. -# Params: - - `m`: the length of the array writing to - - `n`: the array be written - -# Inputs: - - `array_to_write_to`: the array we of length m we are writing to - - `array_to_write_at_index`: the array of length n we are writing to the array of length m - - `index`: the index we are writing to `array_to_write_to` - -# Outputs: - - `out`: the new array -*/ -template WriteToIndex(m, n) { - signal input array_to_write_to[m]; - signal input array_to_write_at_index[n]; - signal input index; - - signal output out[m]; - - assert(m >= n); - - // Note: this is underconstrained, we need to constrain that index + n <= m - // Need to constrain that index + n <= m -- can't be an assertion, because uses a signal - // ------------------------- // - - // Here, we get an array of ALL zeros, except at the `index` AND `index + n` - // beginning-------^^^^^ end---^^^^^^^^^ - signal indexMatched[m]; - component indexBegining[m]; - component indexEnding[m]; - for(var i = 0 ; i < m ; i++) { - indexBegining[i] = IsZero(); - indexBegining[i].in <== i - index; - indexEnding[i] = IsZero(); - indexEnding[i].in <== i - (index + n); - indexMatched[i] <== indexBegining[i].out + indexEnding[i].out; - } - - // E.g., index == 31, m == 160, n == 16 - // => indexMatch[31] == 1; - // => indexMatch[47] == 1; - // => otherwise, all 0. - - signal accum[m]; - accum[0] <== indexMatched[0]; - - component writeAt = IsZero(); - writeAt.in <== accum[0] - 1; - - component or = OR(); - or.a <== (writeAt.out * array_to_write_at_index[0]); - or.b <== (1 - writeAt.out) * array_to_write_to[0]; - out[0] <== or.out; - // IF accum == 1 then { array_to_write_at } ELSE IF accum != 1 then { array to write_to } - var accum_index = accum[0]; - - component writeSelector[m - 1]; - component indexSelector[m - 1]; - component ors[m-1]; - for(var i = 1 ; i < m ; i++) { - // accum will be 1 at all indices where we want to write the new array - accum[i] <== accum[i-1] + indexMatched[i]; - writeSelector[i-1] = IsZero(); - writeSelector[i-1].in <== accum[i] - 1; - // IsZero(accum[i] - 1); --> tells us we are in the range where we want to write the new array - - indexSelector[i-1] = IndexSelector(n); - indexSelector[i-1].index <== accum_index; - indexSelector[i-1].in <== array_to_write_at_index; - // When accum is not zero, out is array_to_write_at_index, otherwise it is array_to_write_to - - ors[i-1] = OR(); - ors[i-1].a <== (writeSelector[i-1].out * indexSelector[i-1].out); - ors[i-1].b <== (1 - writeSelector[i-1].out) * array_to_write_to[i]; - out[i] <== ors[i-1].out; - accum_index += writeSelector[i-1].out; - } -} - - -/* -Convert stream of plain text to blocks of 16 bytes -# Params: - - `l`: the length of the byte stream - -# Inputs: - - `stream`: the stream of bytes of length l - -# Outputs: - - `out`: n 4x4 blocks representing 16 bytes -*/ -template ToBlocks(l){ - signal input stream[l]; - - var n = l\16; - if(l%16 > 0){ - n = n + 1; - } - signal output blocks[n][4][4]; - - var i, j, k; - - for (var idx = 0; idx < l; idx++) { - blocks[i][k][j] <== stream[idx]; - k = k + 1; - if (k == 4){ - k = 0; - j = j + 1; - if (j == 4){ - j = 0; - i = i + 1; - } - } - } - - if (l%16 > 0){ - blocks[i][k][j] <== 1; - k = k + 1; - } -} - - -/* -convert blocks of 16 bytes to stream of bytes -# Params: - - `l`: the length of the byte stream - - `n`: the number of blocks - -# Inputs: - - `blocks`: n 4x4 blocks representing 16 bytes - -# Outputs: - - `out`: the stream of bytes of length l -*/ -template ToStream(n,l){ - signal input blocks[n][4][4]; - - signal output stream[l]; - - var i, j, k; - - while(i*16 + j*4 + k < l){ - stream[i*16 + j*4 + k] <== blocks[i][k][j]; - k = k + 1; - if (k == 4){ - k = 0; - j = j + 1; - if (j == 4){ - j = 0; - i = i + 1; - } - } - } -} - -/* -Increment a 32-bit word, represented as a 4-byte array -# Inputs: - - `in`: a 4 byte word - -# Outputs: - - `out`: an incremented 4 byte word -*/ -template IncrementWord() { - signal input in[4]; - signal output out[4]; - signal carry[4]; - carry[3] <== 1; - - component IsGreaterThan[4]; - component mux[4]; - for (var i = 3; i >= 0; i--) { - // check to carry overflow - IsGreaterThan[i] = GreaterThan(8); - IsGreaterThan[i].in[0] <== in[i] + carry[i]; - IsGreaterThan[i].in[1] <== 0xFF; - - // multiplexer to select the output - mux[i] = Mux1(); - mux[i].c[0] <== in[i] + carry[i]; - mux[i].c[1] <== 0x00; - mux[i].s <== IsGreaterThan[i].out; - out[i] <== mux[i].out; - - // propagate the carry to the next bit - if (i > 0) { - carry[i - 1] <== IsGreaterThan[i].out; - } - } -} - // // from little endian to 32 bit words // // example: // 0, 1, 0, 1, 0, 0, 0, 0, => 80 diff --git a/circuits/utils/generics-bits.circom b/circuits/utils/bits.circom similarity index 80% rename from circuits/utils/generics-bits.circom rename to circuits/utils/bits.circom index b1311e9..08f2daf 100644 --- a/circuits/utils/generics-bits.circom +++ b/circuits/utils/bits.circom @@ -1,6 +1,28 @@ +pragma circom 2.1.9; + +include "circomlib/circuits/bitify.circom"; + +/* +This template passes if a given array contains only valid ASCII values (e.g., u8 vals). + +# Params: + - `n`: the length of the array + +# Inputs: + - `in[n]`: array to check +*/ +template ASCII(n) { + signal input in[n]; + + component Byte[n]; + for(var i = 0; i < n; i++) { + Byte[i] = Num2Bits(8); + Byte[i].in <== in[i]; + } +} + // initially from https://github.com/reclaimprotocol/zk-symmetric-crypto // modified for our needs -pragma circom 2.1.9; /** * Add N bit numbers together diff --git a/circuits/utils/bytes.circom b/circuits/utils/bytes.circom deleted file mode 100644 index 93a523d..0000000 --- a/circuits/utils/bytes.circom +++ /dev/null @@ -1,258 +0,0 @@ -pragma circom 2.1.9; - -include "circomlib/circuits/bitify.circom"; -include "circomlib/circuits/gates.circom"; - -/* -This template passes if a given array contains only valid ASCII values (e.g., u8 vals). - -# Params: - - `n`: the length of the array - -# Inputs: - - `in[n]`: array to check -*/ -template ASCII(n) { - signal input in[n]; - - component Byte[n]; - for(var i = 0; i < n; i++) { - Byte[i] = Num2Bits(8); - Byte[i].in <== in[i]; - } -} - -/* -This template converts bytes to bits. -# Params: - - `n`: the number of bytes - -# Inputs: - - `in[n]`: array of bytes of length n -# Outputs: - - `out`: an array of bits of length n * 8 -*/ -template BytesToBits(n_bytes) { - signal input in[n_bytes]; - signal output out[n_bytes*8]; - component num2bits[n_bytes]; - for (var i = 0; i < n_bytes; i++) { - num2bits[i] = Num2Bits(8); - num2bits[i].in <== in[i]; - for (var j = 7; j >=0; j--) { - out[i*8 + j] <== num2bits[i].out[7 -j]; - } - } -} - -/* -This template converts bits to bytes. -# Params: - - `n`: the number of bytes you want out -# Inputs: - - `in[n]`: array of bits of length n * 8 -# Outputs: - - `out`: an array of bytes of length n -*/ -template BitsToBytes(n) { - signal input in[n*8]; - signal output out[n]; - component bits2num[n]; - for (var i = 0; i < n; i++) { - bits2num[i] = Bits2Num(8); - for (var j = 0; j < 8; j++) { - bits2num[i].in[7 - j] <== in[i*8 + j]; - } - out[i] <== bits2num[i].out; - } -} - -/* -This template XORs two bytes. -# Inputs: - - `a`: a single byte - - `b`: a single byte -# Outputs: - - `out`: a XOR b -*/ -template XorByte(){ - signal input a; - signal input b; - signal output out; - - component abits = Num2Bits(8); - abits.in <== a; - - component bbits = Num2Bits(8); - bbits.in <== b; - - component XorBits = BitwiseXor(8); - XorBits.a <== abits.out; - XorBits.b <== bbits.out; - - component num = Bits2Num(8); - num.in <== XorBits.out; - - out <== num.out; -} - -/* -This template XORs n bytes. -# Inputs: - - `a`: an array of bytes of length n - - `b`: an array of bytes of length n -# Outputs: - - `out`: a XOR b -*/ -template XORBLOCK(n_bytes){ - signal input a[n_bytes]; - signal input b[n_bytes]; - signal output out[n_bytes]; - - component xorByte[n_bytes]; - for (var i = 0; i < n_bytes; i++) { - xorByte[i] = XorByte(); - xorByte[i].a <== a[i]; - xorByte[i].b <== b[i]; - out[i] <== xorByte[i].out; - } -} - -/* -This template right shifts an n bit array by r. -# Params: - - `n`: length of bits to right shift - - `r`: number of bits to right shift by -# Inputs: - - `in`: an array of bits of length n -# Outputs: - - `out`: the bit array right shifted by r -*/ -template BitwiseRightShift(n, r) { - signal input in[n]; - signal output out[n]; - for (var i=0; i 0); - assert(keyLen > 0); - assert(dataLen >= keyLen); - - // position accumulator - signal pos[dataLen-keyLen+2]; - pos[0] <== 0; - - // total matches found so far - signal num_matches[dataLen-keyLen+2]; - num_matches[0] <== 0; - - // calculate powers of r - signal r_powers[dataLen]; - r_powers[0] <== random_num; - for (var i=1 ; i