diff --git a/.github/workflows/artifacts.yaml b/.github/workflows/artifacts.yaml index 4f6a2b6..dfcafbd 100644 --- a/.github/workflows/artifacts.yaml +++ b/.github/workflows/artifacts.yaml @@ -1,4 +1,4 @@ -name: build-circuits +name: build-artifacts concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -17,21 +17,19 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - fetch-depth: 2 # Fetch two commits to get the base branch + fetch-depth: 2 - name: Fetch main branch run: | git fetch origin main + - name: Compare package.json version with main id: version_check run: | - # Extract version from package.json in PR branch PR_VERSION=$(jq -r .version package.json) - # Extract version from package.json in main branch MAIN_VERSION=$(git show origin/main:package.json | jq -r .version) echo "PR version: $PR_VERSION" echo "Main version: $MAIN_VERSION" - # Fail if versions match if [ "$PR_VERSION" == "$MAIN_VERSION" ]; then echo "Error: package.json version has not been updated in this PR." exit 1 @@ -41,12 +39,13 @@ jobs: build: runs-on: ubuntu-latest + needs: check-version steps: - name: Checkout code uses: actions/checkout@v4 with: - fetch-depth: 0 # Need full history to compare with previous release + fetch-depth: 0 - name: Install Protocol Buffers run: | @@ -70,13 +69,6 @@ jobs: sudo mv circom /usr/local/bin/ circom --version - - name: Install circom-witnesscalc - run: | - cd .. && git clone https://github.com/pluto/circom-witnesscalc.git - cd circom-witnesscalc - cargo install --path . - echo $(which build-circuit) - - name: Install Node.js dependencies run: | npm ci @@ -87,36 +79,34 @@ jobs: VERSION=$(node -p "require('./package.json').version") echo "VERSION=$VERSION" >> $GITHUB_ENV - - name: Compile Circom circuits + - name: Build circuits using Makefile run: | - mkdir -p artifacts - for circuit in circuits/*.circom; do - if [ -f "$circuit" ]; then - filename=$(basename "$circuit" .circom) - output_dir="artifacts/$filename" - mkdir -p "$output_dir" - - echo "Processing $filename..." - - # Run circom compilation - circom "$circuit" --r1cs --wasm -o "$output_dir" -l node_modules - - # Run witness calculator build - build-circuit "$circuit" "$output_dir/$filename.bin" -l node_modules + make debug # Show what will be processed + make build # Build the circuits + + - name: Create release artifacts + run: | + # Get the list of target directories + for target_dir in builds/target_*b; do + if [ -d "$target_dir/artifacts" ]; then + # Extract the target size from the directory name + target_size=$(basename "$target_dir") + + echo "Creating archive for $target_size" + # Create zip file for this target size + ( cd "$target_dir/artifacts" && \ + zip -r "../../../circom-artifacts-${target_size}-v${{ env.VERSION }}.zip" . ) fi done - - name: Create release artifacts - run: | - cd artifacts - zip -r ../circom-artifacts-v${{ env.VERSION }}.zip ./* - cd .. + - name: Clean build artifacts + if: always() + run: make clean - # Upload artifacts for PR - - name: Upload artifacts for PR + - name: Upload artifacts if: github.event_name == 'pull_request' uses: actions/upload-artifact@v4 with: name: circom-artifacts-v${{ env.VERSION }} - path: circom-artifacts-v${{ env.VERSION }}.zip + path: circom-artifacts-*-v${{ env.VERSION }}.zip retention-days: 5 \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c62310e..f68e115 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,4 +1,3 @@ -# .github/workflows/release.yml name: Release on: @@ -50,20 +49,26 @@ jobs: uses: actions/download-artifact@v4 with: name: circom-artifacts-v${{ env.VERSION }} - path: . + path: ./artifacts github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ env.run_id }} + - name: Prepare Release Notes + run: | + echo "Automated release of compiled Circom circuits" > release_notes.md + echo "Version: ${{ env.VERSION }}" >> release_notes.md + echo "Commit: ${{ github.sha }}" >> release_notes.md + echo "\nArtifacts included:" >> release_notes.md + for zip in artifacts/circom-artifacts-*-v${{ env.VERSION }}.zip; do + basename "$zip" >> release_notes.md + done - # Add artifacts to existing release - - name: Upload Release Asset + # Create release with all artifact files + - name: Upload Release Assets uses: softprops/action-gh-release@v2 with: - files: circom-artifacts-v${{ env.VERSION }}.zip + files: artifacts/circom-artifacts-*-v${{ env.VERSION }}.zip tag_name: v${{ env.VERSION }} - body: | - Automated release of compiled Circom circuits - Version: ${{ env.VERSION }} - Commit: ${{ github.sha }} + body_path: release_notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f89936c..31e0721 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ on: branches: [ main ] jobs: - circom: + test: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 680faa2..f70f723 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ ir_log/* log_input_signals.txt *.bin *.r1cs +builds/**/*.bin +builds/**/*.r1cs \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a3a15cf --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +# Find all target directories +TARGET_DIRS := $(wildcard builds/target_*b) + +# Find all .circom files in those directories +CIRCOM_FILES := $(wildcard $(addsuffix /*_*b.circom,$(TARGET_DIRS))) + +# Create artifacts directories +$(shell mkdir -p $(addsuffix /artifacts,$(TARGET_DIRS))) + +# Default target +.PHONY: all clean +all: build + +# Build target +.PHONY: build +build: + @for circuit in $(CIRCOM_FILES); do \ + echo "Processing $${circuit}..."; \ + circom "$${circuit}" --r1cs -o "$$(dirname $${circuit})/artifacts" -l node_modules; \ + build-circuit "$${circuit}" "$$(dirname $${circuit})/artifacts/$$(basename $${circuit} .circom).bin" -l node_modules; \ + done + +# Clean target +clean: + rm -rf $(addsuffix /artifacts,$(TARGET_DIRS)) + +# Debug target to show what files were found +.PHONY: debug +debug: + @echo "Found directories:" + @echo $(TARGET_DIRS) + @echo "\nFound circom files:" + @echo $(CIRCOM_FILES) + @echo "\nArtifacts will be generated in:" + @echo $(addsuffix /artifacts,$(TARGET_DIRS)) \ No newline at end of file diff --git a/builds/target_1024b/aes_gctr_nivc_1024b.circom b/builds/target_1024b/aes_gctr_nivc_1024b.circom new file mode 100644 index 0000000..ae0ccf2 --- /dev/null +++ b/builds/target_1024b/aes_gctr_nivc_1024b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/aes-gcm/nivc/aes-gctr-nivc.circom"; + +// the circomkit tests become unhappy when there is a main. +component main { public [step_in] } = AESGCTRFOLD(1024, 10); \ No newline at end of file diff --git a/builds/target_1024b/http_body_mask_1024b.circom b/builds/target_1024b/http_body_mask_1024b.circom new file mode 100644 index 0000000..ea474a2 --- /dev/null +++ b/builds/target_1024b/http_body_mask_1024b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/body_mask.circom"; + +component main { public [step_in] } = HTTPMaskBodyNIVC(1024, 10); + diff --git a/builds/target_1024b/http_lock_header_1024b.circom b/builds/target_1024b/http_lock_header_1024b.circom new file mode 100644 index 0000000..fc3d5b3 --- /dev/null +++ b/builds/target_1024b/http_lock_header_1024b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/lock_header.circom"; + +component main { public [step_in] } = LockHeader(1024, 10, 50, 100); \ No newline at end of file diff --git a/builds/target_1024b/http_parse_and_lock_start_line_1024b.circom b/builds/target_1024b/http_parse_and_lock_start_line_1024b.circom new file mode 100644 index 0000000..c1150bc --- /dev/null +++ b/builds/target_1024b/http_parse_and_lock_start_line_1024b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/parse_and_lock_start_line.circom"; + +component main { public [step_in] } = ParseAndLockStartLine(1024, 10, 20, 20, 20); \ No newline at end of file diff --git a/builds/target_1024b/json_extract_value_1024b.circom b/builds/target_1024b/json_extract_value_1024b.circom new file mode 100644 index 0000000..7f4d122 --- /dev/null +++ b/builds/target_1024b/json_extract_value_1024b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/extractor.circom"; + +component main { public [step_in] } = MaskExtractFinal(1024, 10, 50); \ No newline at end of file diff --git a/builds/target_1024b/json_mask_array_index_1024b.circom b/builds/target_1024b/json_mask_array_index_1024b.circom new file mode 100644 index 0000000..d2793c8 --- /dev/null +++ b/builds/target_1024b/json_mask_array_index_1024b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/masker.circom"; + +component main { public [step_in] } = JsonMaskArrayIndexNIVC(1024, 10); \ No newline at end of file diff --git a/builds/target_1024b/json_mask_object_1024b.circom b/builds/target_1024b/json_mask_object_1024b.circom new file mode 100644 index 0000000..e91d812 --- /dev/null +++ b/builds/target_1024b/json_mask_object_1024b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/masker.circom"; + +component main { public [step_in] } = JsonMaskObjectNIVC(1024, 10, 10); diff --git a/builds/target_1024b/json_parse_1024b.circom b/builds/target_1024b/json_parse_1024b.circom new file mode 100644 index 0000000..4538d31 --- /dev/null +++ b/builds/target_1024b/json_parse_1024b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/parse.circom"; + +component main { public [step_in] } = JsonParseNIVC(1024, 10); + diff --git a/builds/target_256b/aes_gctr_nivc_256b.circom b/builds/target_256b/aes_gctr_nivc_256b.circom new file mode 100644 index 0000000..478c4b2 --- /dev/null +++ b/builds/target_256b/aes_gctr_nivc_256b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/aes-gcm/nivc/aes-gctr-nivc.circom"; + +// the circomkit tests become unhappy when there is a main. +component main { public [step_in] } = AESGCTRFOLD(256, 10); \ No newline at end of file diff --git a/builds/target_256b/http_body_mask_256b.circom b/builds/target_256b/http_body_mask_256b.circom new file mode 100644 index 0000000..cb65ee5 --- /dev/null +++ b/builds/target_256b/http_body_mask_256b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/body_mask.circom"; + +component main { public [step_in] } = HTTPMaskBodyNIVC(256, 10); + diff --git a/builds/target_256b/http_lock_header_256b.circom b/builds/target_256b/http_lock_header_256b.circom new file mode 100644 index 0000000..892e013 --- /dev/null +++ b/builds/target_256b/http_lock_header_256b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/lock_header.circom"; + +component main { public [step_in] } = LockHeader(256, 10, 50, 100); \ No newline at end of file diff --git a/builds/target_256b/http_parse_and_lock_start_line_256b.circom b/builds/target_256b/http_parse_and_lock_start_line_256b.circom new file mode 100644 index 0000000..708f35a --- /dev/null +++ b/builds/target_256b/http_parse_and_lock_start_line_256b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/parse_and_lock_start_line.circom"; + +component main { public [step_in] } = ParseAndLockStartLine(256, 10, 20, 20, 20); \ No newline at end of file diff --git a/builds/target_256b/json_extract_value_256b.circom b/builds/target_256b/json_extract_value_256b.circom new file mode 100644 index 0000000..da8db1f --- /dev/null +++ b/builds/target_256b/json_extract_value_256b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/extractor.circom"; + +component main { public [step_in] } = MaskExtractFinal(256, 10, 50); \ No newline at end of file diff --git a/builds/target_256b/json_mask_array_index_256b.circom b/builds/target_256b/json_mask_array_index_256b.circom new file mode 100644 index 0000000..83ebb08 --- /dev/null +++ b/builds/target_256b/json_mask_array_index_256b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/masker.circom"; + +component main { public [step_in] } = JsonMaskArrayIndexNIVC(256, 10); \ No newline at end of file diff --git a/builds/target_256b/json_mask_object_256b.circom b/builds/target_256b/json_mask_object_256b.circom new file mode 100644 index 0000000..b6bb1ef --- /dev/null +++ b/builds/target_256b/json_mask_object_256b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/masker.circom"; + +component main { public [step_in] } = JsonMaskObjectNIVC(256, 10, 10); diff --git a/builds/target_256b/json_parse_256b.circom b/builds/target_256b/json_parse_256b.circom new file mode 100644 index 0000000..c0f5e8c --- /dev/null +++ b/builds/target_256b/json_parse_256b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/parse.circom"; + +component main { public [step_in] } = JsonParseNIVC(256, 10); + diff --git a/builds/target_512b/aes_gctr_nivc_512b.circom b/builds/target_512b/aes_gctr_nivc_512b.circom new file mode 100644 index 0000000..07939ff --- /dev/null +++ b/builds/target_512b/aes_gctr_nivc_512b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/aes-gcm/nivc/aes-gctr-nivc.circom"; + +// the circomkit tests become unhappy when there is a main. +component main { public [step_in] } = AESGCTRFOLD(512, 10); \ No newline at end of file diff --git a/builds/target_512b/http_body_mask_512b.circom b/builds/target_512b/http_body_mask_512b.circom new file mode 100644 index 0000000..ffb3b7e --- /dev/null +++ b/builds/target_512b/http_body_mask_512b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/body_mask.circom"; + +component main { public [step_in] } = HTTPMaskBodyNIVC(512, 10); + diff --git a/builds/target_512b/http_lock_header_512b.circom b/builds/target_512b/http_lock_header_512b.circom new file mode 100644 index 0000000..02d9dc9 --- /dev/null +++ b/builds/target_512b/http_lock_header_512b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/lock_header.circom"; + +component main { public [step_in] } = LockHeader(512, 10, 50, 100); \ No newline at end of file diff --git a/builds/target_512b/http_parse_and_lock_start_line_512b.circom b/builds/target_512b/http_parse_and_lock_start_line_512b.circom new file mode 100644 index 0000000..92c2bc8 --- /dev/null +++ b/builds/target_512b/http_parse_and_lock_start_line_512b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/http/nivc/parse_and_lock_start_line.circom"; + +component main { public [step_in] } = ParseAndLockStartLine(512, 10, 20, 20, 20); \ No newline at end of file diff --git a/builds/target_512b/json_extract_value_512b.circom b/builds/target_512b/json_extract_value_512b.circom new file mode 100644 index 0000000..a7fa283 --- /dev/null +++ b/builds/target_512b/json_extract_value_512b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/extractor.circom"; + +component main { public [step_in] } = MaskExtractFinal(512, 10, 50); \ No newline at end of file diff --git a/builds/target_512b/json_mask_array_index_512b.circom b/builds/target_512b/json_mask_array_index_512b.circom new file mode 100644 index 0000000..ec72dc7 --- /dev/null +++ b/builds/target_512b/json_mask_array_index_512b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/masker.circom"; + +component main { public [step_in] } = JsonMaskArrayIndexNIVC(512, 10); \ No newline at end of file diff --git a/builds/target_512b/json_mask_object_512b.circom b/builds/target_512b/json_mask_object_512b.circom new file mode 100644 index 0000000..3bd0e31 --- /dev/null +++ b/builds/target_512b/json_mask_object_512b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/masker.circom"; + +component main { public [step_in] } = JsonMaskObjectNIVC(512, 10, 10); diff --git a/builds/target_512b/json_parse_512b.circom b/builds/target_512b/json_parse_512b.circom new file mode 100644 index 0000000..a48a10b --- /dev/null +++ b/builds/target_512b/json_parse_512b.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.9; + +include "../../circuits/json/nivc/parse.circom"; + +component main { public [step_in] } = JsonParseNIVC(512, 10); + diff --git a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom index 689da97..6d17213 100644 --- a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom +++ b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom @@ -5,42 +5,40 @@ include "../../utils/array.circom"; // Compute AES-GCTR -template AESGCTRFOLD(INPUT_LEN) { - assert(INPUT_LEN % 16 == 0); - var DATA_BYTES = (INPUT_LEN * 2) + 4; +template AESGCTRFOLD(DATA_BYTES, MAX_STACK_HEIGHT) { + // ------------------------------------------------------------------------------------------------------------------ // + // ~~ Set sizes at compile time ~~ + assert(DATA_BYTES % 16 == 0); + // Total number of variables in the parser for each byte of data + var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; + var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + // ------------------------------------------------------------------------------------------------------------------ // + + signal input key[16]; signal input iv[12]; signal input aad[16]; signal input plainText[16]; - // step_in[0..INPUT_LEN] => accumulate plaintext blocks - // step_in[INPUT_LEN..INPUT_LEN*2] => accumulate ciphertext blocks - // step_in[INPUT_LEN*2..INPUT_LEN*2+4] => accumulate counter - signal input step_in[DATA_BYTES]; - signal output step_out[DATA_BYTES]; - signal counter; + // step_in[0..DATA_BYTES] => accumulate plaintext blocks + // step_in[DATA_BYTES..DATA_BYTES*2] => accumulate ciphertext blocks + // step_in[DATA_BYTES_LEN*2..DATA_BYTES*2+4] => accumulate counter + signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; + signal output step_out[TOTAL_BYTES_ACROSS_NIVC]; + // We extract the number from the 4 byte word counter component last_counter_bits = BytesToBits(4); for(var i = 0; i < 4; i ++) { - last_counter_bits.in[i] <== step_in[INPUT_LEN*2 + i]; + last_counter_bits.in[i] <== step_in[DATA_BYTES * 2 + i]; } component last_counter_num = Bits2Num(32); // pass in reverse order for (var i = 0; i< 32; i++){ last_counter_num.in[i] <== last_counter_bits.out[31 - i]; } - - counter <== last_counter_num.out - 1; - - // write new plain text block. - signal plainTextAccumulator[DATA_BYTES]; - component writeToIndex = WriteToIndex(DATA_BYTES, 16); - writeToIndex.array_to_write_to <== step_in; - writeToIndex.array_to_write_at_index <== plainText; - writeToIndex.index <== counter * 16; - writeToIndex.out ==> plainTextAccumulator; - + signal index <== last_counter_num.out - 1; + // folds one block component aes = AESGCTRFOLDABLE(); aes.key <== key; @@ -49,22 +47,125 @@ template AESGCTRFOLD(INPUT_LEN) { aes.plainText <== plainText; for(var i = 0; i < 4; i++) { - aes.lastCounter[i] <== step_in[INPUT_LEN*2 + i]; + aes.lastCounter[i] <== step_in[DATA_BYTES * 2 + i]; } - // accumulate cipher text - signal cipherTextAccumulator[DATA_BYTES]; - component writeCipherText = WriteToIndex(DATA_BYTES, 16); - writeCipherText.array_to_write_to <== plainTextAccumulator; - writeCipherText.array_to_write_at_index <== aes.cipherText; - writeCipherText.index <== INPUT_LEN + counter * 16; - writeCipherText.out ==> cipherTextAccumulator; - - // get counter - signal counterAccumulator[DATA_BYTES]; - component writeCounter = WriteToIndex(DATA_BYTES, 4); - writeCounter.array_to_write_to <== cipherTextAccumulator; - writeCounter.array_to_write_at_index <== aes.counter; - writeCounter.index <== INPUT_LEN*2; - writeCounter.out ==> step_out; -} \ No newline at end of file + + // Write out the plaintext and ciphertext to our accumulation arrays, both at once. + signal prevAccumulatedPlaintext[DATA_BYTES]; + for(var i = 0 ; i < DATA_BYTES ; i++) { + prevAccumulatedPlaintext[i] <== step_in[i]; + } + signal prevAccumulatedCiphertext[DATA_BYTES]; + for(var i = 0 ; i < DATA_BYTES ; i++) { + prevAccumulatedCiphertext[i] <== step_in[DATA_BYTES + i]; + } + component nextTexts = WriteToIndexForTwoArrays(DATA_BYTES, 16); + nextTexts.first_array_to_write_to <== prevAccumulatedPlaintext; + nextTexts.second_array_to_write_to <== prevAccumulatedCiphertext; + nextTexts.first_array_to_write_at_index <== plainText; + nextTexts.second_array_to_write_at_index <== aes.cipherText; + nextTexts.index <== index * 16; + + + for(var i = 0 ; i < TOTAL_BYTES_ACROSS_NIVC ; i++) { + if(i < DATA_BYTES) { + step_out[i] <== nextTexts.outFirst[i]; + } else if(i < 2 * DATA_BYTES) { + step_out[i] <== nextTexts.outSecond[i - DATA_BYTES]; + } else if(i < 2 * DATA_BYTES + 4) { + step_out[i] <== aes.counter[i - (2 * DATA_BYTES)]; + } else { + step_out[i] <== 0; + } + } +} + + + +template WriteToIndexForTwoArrays(m, n) { + signal input first_array_to_write_to[m]; + signal input second_array_to_write_to[m]; + signal input first_array_to_write_at_index[n]; + signal input second_array_to_write_at_index[n]; + signal input index; + + signal output outFirst[m]; + signal output outSecond[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 orFirst = OR(); + orFirst.a <== (writeAt.out * first_array_to_write_at_index[0]); + orFirst.b <== (1 - writeAt.out) * first_array_to_write_to[0]; + outFirst[0] <== orFirst.out; + + component orSecond = OR(); + orSecond.a <== (writeAt.out * second_array_to_write_at_index[0]); + orSecond.b <== (1 - writeAt.out) * second_array_to_write_to[0]; + outSecond[0] <== orSecond.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 indexSelectorFirst[m - 1]; + component indexSelectorSecond[m - 1]; + component orsFirst[m-1]; + component orsSecond[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 + + indexSelectorFirst[i-1] = IndexSelector(n); + indexSelectorFirst[i-1].index <== accum_index; + indexSelectorFirst[i-1].in <== first_array_to_write_at_index; + + indexSelectorSecond[i-1] = IndexSelector(n); + indexSelectorSecond[i-1].index <== accum_index; + indexSelectorSecond[i-1].in <== second_array_to_write_at_index; + // When accum is not zero, out is array_to_write_at_index, otherwise it is array_to_write_to + + orsFirst[i-1] = OR(); + orsFirst[i-1].a <== (writeSelector[i-1].out * indexSelectorFirst[i-1].out); + orsFirst[i-1].b <== (1 - writeSelector[i-1].out) * first_array_to_write_to[i]; + outFirst[i] <== orsFirst[i-1].out; + + orsSecond[i-1] = OR(); + orsSecond[i-1].a <== (writeSelector[i-1].out * indexSelectorSecond[i-1].out); + orsSecond[i-1].b <== (1 - writeSelector[i-1].out) * second_array_to_write_to[i]; + outSecond[i] <== orsSecond[i-1].out; + + accum_index += writeSelector[i-1].out; + } +} diff --git a/circuits/aes-gctr-nivc.circom b/circuits/aes-gctr-nivc.circom deleted file mode 100644 index 7886f37..0000000 --- a/circuits/aes-gctr-nivc.circom +++ /dev/null @@ -1,7 +0,0 @@ -pragma circom 2.1.9; - -include "aes-gcm/nivc/aes-gctr-nivc.circom"; - -// Note(WJ 2024-10-31): I put this here like this because i have tests i wanted to include for this component -// the circomkit tests become unhappy when there is a main. -component main { public [step_in] } = AESGCTRFOLD(48); \ No newline at end of file diff --git a/circuits/extract_value.circom b/circuits/extract_value.circom deleted file mode 100644 index 3a492ab..0000000 --- a/circuits/extract_value.circom +++ /dev/null @@ -1,35 +0,0 @@ -pragma circom 2.1.9; - -include "circomlib/circuits/gates.circom"; -include "@zk-email/circuits/utils/array.circom"; - -template MaskExtractFinal(TOTAL_BYTES, maxValueLen) { - signal input step_in[TOTAL_BYTES]; - signal output step_out[TOTAL_BYTES]; - - signal is_zero_mask[TOTAL_BYTES]; - signal is_prev_starting_index[TOTAL_BYTES]; - signal value_starting_index[TOTAL_BYTES]; - - value_starting_index[0] <== 0; - is_prev_starting_index[0] <== 0; - is_zero_mask[0] <== IsZero()(step_in[0]); - for (var i=1 ; i var TOTAL_BYTES = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1); // data + parser vars - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (HttpParseAndLockStartLine or HTTPLockHeader) - signal input step_in[TOTAL_BYTES]; - - signal data[DATA_BYTES]; - signal parsing_body[DATA_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - data[i] <== step_in[i]; - parsing_body[i] <== step_in[DATA_BYTES + i * 5 + 4]; - } - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Write out to next NIVC step - signal output step_out[TOTAL_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - step_out[i] <== data[i] * parsing_body[i]; - } - // Write out padded with zeros - for (var i = DATA_BYTES ; i < TOTAL_BYTES ; i++) { - step_out[i] <== 0; - } -} - -component main { public [step_in] } = HTTPMaskBodyNIVC(4160, 320); - diff --git a/circuits/http_lock_header.circom b/circuits/http_lock_header.circom deleted file mode 100644 index 46a55f0..0000000 --- a/circuits/http_lock_header.circom +++ /dev/null @@ -1,87 +0,0 @@ -pragma circom 2.1.9; - -include "parser-attestor/circuits/http/interpreter.circom"; -include "parser-attestor/circuits/utils/array.circom"; - -template LockHeader(TOTAL_BYTES, DATA_BYTES, headerNameLen, headerValueLen) { - // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - var PER_ITERATION_DATA_LENGTH = 5; - var TOTAL_BYTES_USED = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1); // data + parser vars - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (HttpParseAndLockStartLine or HTTPLockHeader) - signal input step_in[TOTAL_BYTES]; - - signal data[DATA_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - data[i] <== step_in[i]; - } - - signal input header[headerNameLen]; - signal input value[headerValueLen]; - - component headerNameLocation = FirstStringMatch(DATA_BYTES, headerNameLen); - headerNameLocation.data <== data; - headerNameLocation.key <== header; - - component headerFieldNameValueMatch; - headerFieldNameValueMatch = HeaderFieldNameValueMatch(DATA_BYTES, headerNameLen, headerValueLen); - headerFieldNameValueMatch.data <== data; - headerFieldNameValueMatch.headerName <== header; - headerFieldNameValueMatch.headerValue <== value; - headerFieldNameValueMatch.index <== headerNameLocation.position; - - // TODO: Make this assert we are parsing header!!! - // This is the assertion that we have locked down the correct header - headerFieldNameValueMatch.out === 1; - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Write out to next NIVC step - signal output step_out[TOTAL_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - // add plaintext http input to step_out - step_out[i] <== step_in[i]; - - // add parser state - step_out[DATA_BYTES + i * 5] <== step_in[DATA_BYTES + i * 5]; - step_out[DATA_BYTES + i * 5 + 1] <== step_in[DATA_BYTES + i * 5 + 1]; - step_out[DATA_BYTES + i * 5 + 2] <== step_in[DATA_BYTES + i * 5 + 2]; - step_out[DATA_BYTES + i * 5 + 3] <== step_in[DATA_BYTES + i * 5 + 3]; - step_out[DATA_BYTES + i * 5 + 4] <== step_in[DATA_BYTES + i * 5 + 4]; - } - // Pad remaining with zeros - for (var i = TOTAL_BYTES_USED ; i < TOTAL_BYTES ; i++ ) { - step_out[i] <== 0; - } -} - -// TODO: Handrolled template that I haven't tested YOLO. -template FirstStringMatch(dataLen, keyLen) { - signal input data[dataLen]; - signal input key[keyLen]; - signal output position; - - var matched = 0; - var counter = 0; - component stringMatch[dataLen - keyLen]; - component hasMatched[dataLen - keyLen]; - for (var idx = 0 ; idx < dataLen - keyLen ; idx++) { - stringMatch[idx] = IsEqualArray(keyLen); - stringMatch[idx].in[0] <== key; - for (var key_idx = 0 ; key_idx < keyLen ; key_idx++) { - stringMatch[idx].in[1][key_idx] <== data[idx + key_idx] * (1 - matched); - } - hasMatched[idx] = IsEqual(); - hasMatched[idx].in <== [stringMatch[idx].out, 1]; - matched += hasMatched[idx].out; - counter += (1 - matched); // TODO: Off by one? Move before? - } - position <== counter; -} - -component main { public [step_in] } = LockHeader(4160, 320, 12, 31); - diff --git a/circuits/http_parse_and_lock_start_line.circom b/circuits/http_parse_and_lock_start_line.circom deleted file mode 100644 index d47d50b..0000000 --- a/circuits/http_parse_and_lock_start_line.circom +++ /dev/null @@ -1,126 +0,0 @@ -pragma circom 2.1.9; - -include "parser-attestor/circuits/http/parser/machine.circom"; -include "parser-attestor/circuits/http/interpreter.circom"; -include "parser-attestor/circuits/utils/bytes.circom"; - -// TODO: Note that TOTAL_BYTES will match what we have for AESGCMFOLD step_out -// I have not gone through to double check the sizes of everything yet. -template LockStartLine(TOTAL_BYTES, DATA_BYTES, beginningLen, middleLen, finalLen) { - // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - var AES_BYTES = DATA_BYTES + 50; // TODO: Might be wrong, but good enough for now - var PER_ITERATION_DATA_LENGTH = 5; - var TOTAL_BYTES_USED = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1); // data + parser vars - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (JsonParseNIVC) - signal input step_in[TOTAL_BYTES]; - - signal data[DATA_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - data[i] <== step_in[50 + i]; - } - - // // TODO: check if these needs to here or not - // component dataASCII = ASCII(DATA_BYTES); - // dataASCII.in <== data; - - signal input beginning[beginningLen]; - signal input middle[middleLen]; - signal input final[finalLen]; - - // 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; - } - - // 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 - 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; - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Write out to next NIVC step (Lock Header) - signal output step_out[TOTAL_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - // add plaintext http input to step_out - step_out[i] <== step_in[50 + i]; - - // add parser state - step_out[DATA_BYTES + i * 5] <== State[i].next_parsing_start; - step_out[DATA_BYTES + i * 5 + 1] <== State[i].next_parsing_header; - step_out[DATA_BYTES + i * 5 + 2] <== State[i].next_parsing_field_name; - step_out[DATA_BYTES + i * 5 + 3] <== State[i].next_parsing_field_value; - step_out[DATA_BYTES + i * 5 + 4] <== State[i].next_parsing_body; - } - // Pad remaining with zeros - for (var i = TOTAL_BYTES_USED ; i < TOTAL_BYTES ; i++ ) { - step_out[i] <== 0; - } -} - -component main { public [step_in] } = LockStartLine(4160, 320, 8, 3, 2); \ No newline at end of file diff --git a/circuits/json/nivc/extractor.circom b/circuits/json/nivc/extractor.circom index aadb436..f3d48eb 100644 --- a/circuits/json/nivc/extractor.circom +++ b/circuits/json/nivc/extractor.circom @@ -42,6 +42,4 @@ template MaskExtractFinal(DATA_BYTES, MAX_STACK_HEIGHT, MAX_VALUE_LENGTH) { } // TODO: Do anything with last depth? // step_out[TOTAL_BYTES_ACROSS_NIVC - 1] <== 0; -} - -// component main { public [step_in] } = MaskExtractFinal(4160, 320, 200); \ No newline at end of file +} \ No newline at end of file diff --git a/circuits/json_mask_array_index.circom b/circuits/json_mask_array_index.circom deleted file mode 100644 index 5cf36c7..0000000 --- a/circuits/json_mask_array_index.circom +++ /dev/null @@ -1,71 +0,0 @@ -pragma circom 2.1.9; - -include "parser-attestor/circuits/json/interpreter.circom"; - -template JsonMaskArrayIndexNIVC(TOTAL_BYTES, DATA_BYTES, MAX_STACK_HEIGHT) { - // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - assert(MAX_STACK_HEIGHT >= 2); - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_USED = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1); - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (JsonParseNIVC) - signal input step_in[TOTAL_BYTES]; - - // Grab the raw data bytes from the `step_in` variable - signal data[DATA_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - data[i] <== step_in[i]; - } - - // Decode the encoded data in `step_in` back into parser variables - signal stack[DATA_BYTES][MAX_STACK_HEIGHT][2]; - signal parsingData[DATA_BYTES][2]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - for (var j = 0 ; j < MAX_STACK_HEIGHT ; j++) { - stack[i][j][0] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2]; - stack[i][j][1] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2 + 1]; - } - parsingData[i][0] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2]; - parsingData[i][1] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2 + 1]; - } - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Array index masking ~ - signal input index; - - // value starting index in `data` - signal value_starting_index[DATA_BYTES]; - signal mask[DATA_BYTES]; - - signal parsing_array[DATA_BYTES]; - signal or[DATA_BYTES]; - - parsing_array[0] <== InsideArrayIndexObject()(stack[0][0], stack[0][1], parsingData[0][0], parsingData[0][1], index); - mask[0] <== data[0] * parsing_array[0]; - - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - parsing_array[data_idx] <== InsideArrayIndexObject()(stack[data_idx][0], stack[data_idx][1], parsingData[data_idx][0], parsingData[data_idx][1], index); - - or[data_idx] <== OR()(parsing_array[data_idx], parsing_array[data_idx - 1]); - mask[data_idx] <== data[data_idx] * or[data_idx]; - } - - // Write the `step_out` with masked data - signal output step_out[TOTAL_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - step_out[i] <== mask[i]; - } - // Append the parser state back on `step_out` - for (var i = DATA_BYTES ; i < TOTAL_BYTES ; i++) { - step_out[i] <== step_in[i]; - } - // No need to pad as this is currently when TOTAL_BYTES == TOTAL_BYTES_USED -} - -component main { public [step_in] } = JsonMaskArrayIndexNIVC(4160, 320, 5); \ No newline at end of file diff --git a/circuits/json_mask_object.circom b/circuits/json_mask_object.circom deleted file mode 100644 index 89b7135..0000000 --- a/circuits/json_mask_object.circom +++ /dev/null @@ -1,110 +0,0 @@ -pragma circom 2.1.9; - -include "parser-attestor/circuits/json/interpreter.circom"; - -template JsonMaskObjectNIVC(TOTAL_BYTES, DATA_BYTES, MAX_STACK_HEIGHT, maxKeyLen) { - // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - assert(MAX_STACK_HEIGHT >= 2); - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_USED = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1); // data + parser vars - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (JsonParseNIVC) - signal input step_in[TOTAL_BYTES]; - - // Grab the raw data bytes from the `step_in` variable - signal data[DATA_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - data[i] <== step_in[i]; - } - - // Decode the encoded data in `step_in` back into parser variables - signal stack[DATA_BYTES][MAX_STACK_HEIGHT][2]; - signal parsingData[DATA_BYTES][2]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - for (var j = 0 ; j < MAX_STACK_HEIGHT ; j++) { - stack[i][j][0] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2]; - stack[i][j][1] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2 + 1]; - } - parsingData[i][0] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2]; - parsingData[i][1] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2 + 1]; - } - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Object masking ~ - // Key data to use to point to which object to extract - signal input key[maxKeyLen]; - signal input keyLen; - - // flag determining whether this byte is matched value - signal is_value_match[DATA_BYTES - maxKeyLen]; - // final mask - signal mask[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]; - - // Signals to detect if we are parsing a key or value with initial setup - signal parsing_key[DATA_BYTES - maxKeyLen]; - signal parsing_value[DATA_BYTES - maxKeyLen]; - // TODO: Can't these just be 0 since the start of object can't be either of these? - // parsing_key[0] <== InsideKey()(stack[0][0], parsingData[0][0], parsingData[0][1]); - // parsing_value[0] <== InsideValueObject()(stack[0][0], stack[0][1], parsingData[0][0], parsingData[0][1]); - - // Initialize values knowing 0th bit of data will never be a key/value - parsing_key[0] <== 0; - parsing_value[0] <== 0; - is_key_match[0] <== 0; - - is_next_pair_at_depth[0] <== NextKVPairAtDepth(MAX_STACK_HEIGHT, 0)(stack[0], data[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++) { - parsing_key[data_idx] <== InsideKey()(stack[data_idx][0], parsingData[data_idx][0], parsingData[data_idx][1]); - parsing_value[data_idx] <== InsideValueObject()(stack[data_idx][0], stack[data_idx][1], parsingData[data_idx][0], parsingData[data_idx][1]); - - // 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, 0)(stack[data_idx], data[data_idx]); - 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]; - - } - - // Write the `step_out` with masked data - signal output step_out[TOTAL_BYTES]; - for (var i = 0 ; i < DATA_BYTES - maxKeyLen ; i++) { - step_out[i] <== mask[i]; - } - for (var i = 0 ; i < maxKeyLen ; i++) { - step_out[DATA_BYTES - maxKeyLen + i] <== 0; - } - // Append the parser state back on `step_out` - for (var i = DATA_BYTES ; i < TOTAL_BYTES ; i++) { - step_out[i] <== step_in[i]; - } - // No need to pad as this is currently when TOTAL_BYTES == TOTAL_BYTES_USED -} - -component main { public [step_in] } = JsonMaskObjectNIVC(4160, 320, 5, 10); diff --git a/circuits/json_parse.circom b/circuits/json_parse.circom deleted file mode 100644 index db2e154..0000000 --- a/circuits/json_parse.circom +++ /dev/null @@ -1,60 +0,0 @@ -pragma circom 2.1.9; - -include "parser-attestor/circuits/json/parser/parser.circom"; - -template JsonParseNIVC(TOTAL_BYTES, DATA_BYTES, MAX_STACK_HEIGHT) { - // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_USED = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1); - // ------------------------------------------------------------------------------------------------------------------ // - - // Read in from previous NIVC step (AESNIVC) - signal input step_in[TOTAL_BYTES]; - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Parse JSON ~ - // Initialize the parser - component State[DATA_BYTES]; - State[0] = StateUpdate(MAX_STACK_HEIGHT); - 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; - State[0].byte <== step_in[0]; - - // Parse all the data to generate the complete parser state - for(var i = 1; i < DATA_BYTES; i++) { - State[i] = StateUpdate(MAX_STACK_HEIGHT); - State[i].byte <== step_in[i]; - State[i].stack <== State[i - 1].next_stack; - State[i].parsing_string <== State[i - 1].next_parsing_string; - State[i].parsing_number <== State[i - 1].next_parsing_number; - } - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Write to `step_out` for next NIVC step - // Pass the data bytes back out in the first `step_out` signals - signal output step_out[TOTAL_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - step_out[i] <== step_in[i]; - } - - // Decode the parser state into the `step_out` remaining signals - for (var i = 0 ; i < DATA_BYTES ; i++) { - for (var j = 0 ; j < MAX_STACK_HEIGHT ; j++) { - step_out[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2] <== State[i].next_stack[j][0]; - step_out[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2 + 1] <== State[i].next_stack[j][1]; - } - step_out[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2] <== State[i].next_parsing_string; - step_out[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2 + 1] <== State[i].next_parsing_number; - } - // No need to pad as this is currently when TOTAL_BYTES == TOTAL_BYTES_USED - // ------------------------------------------------------------------------------------------------------------------ // -} - -component main { public [step_in] } = JsonParseNIVC(4160, 320, 5); - diff --git a/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts b/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts index 4b63918..6ebd2bb 100644 --- a/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts +++ b/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts @@ -2,26 +2,36 @@ import { assert } from "chai"; import { WitnessTester } from "circomkit"; import { circomkit } from "../../common"; +const MAX_STACK_HEIGHT = 0; + describe("aes-gctr-nivc", () => { let circuit_one_block: WitnessTester<["key", "iv", "plainText", "aad", "step_in"], ["step_out"]>; + + const DATA_BYTES_0 = 16; + const TOTAL_BYTES_ACROSS_NIVC_0 = DATA_BYTES_0 * (MAX_STACK_HEIGHT + 2 + 1) + 1; + 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: [16], // input len is 16 bytes + params: [DATA_BYTES_0, MAX_STACK_HEIGHT], // input len is 16 bytes }); - let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + 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]; + 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 counter = [0x00, 0x00, 0x00, 0x01]; - const step_in = new Array(32).fill(0x00).concat(counter); + const counter = [0x00, 0x00, 0x00, 0x01]; + const step_in = new Array(TOTAL_BYTES_ACROSS_NIVC_0).fill(0x00); + counter.forEach((value, index) => { + step_in[2 * DATA_BYTES_0 + index] = value; + }); let expected = plainText.concat(ct).concat([0x00, 0x00, 0x00, 0x02]); + expected = expected.concat(new Array(TOTAL_BYTES_ACROSS_NIVC_0 - expected.length).fill(0)); const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText, aad: aad, step_in: step_in }, ["step_out"]) assert.deepEqual(witness.step_out, expected.map(BigInt)); }); @@ -30,45 +40,55 @@ describe("aes-gctr-nivc", () => { circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { file: "aes-gcm/nivc/aes-gctr-nivc", template: "AESGCTRFOLD", - params: [16], // input len is 16 bytes + params: [DATA_BYTES_0, MAX_STACK_HEIGHT], // input len is 16 bytes }); - - let key = [0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31]; + + 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]; + 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 counter = [0x00, 0x00, 0x00, 0x01]; - const step_in = new Array(32).fill(0x00).concat(counter); + const step_in = new Array(TOTAL_BYTES_ACROSS_NIVC_0).fill(0x00); + counter.forEach((value, index) => { + step_in[2 * DATA_BYTES_0 + index] = value; + }); let expected = plainText.concat(ct).concat([0x00, 0x00, 0x00, 0x02]); + expected = expected.concat(new Array(TOTAL_BYTES_ACROSS_NIVC_0 - expected.length).fill(0)); const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText, aad: aad, step_in: step_in }, ["step_out"]) assert.deepEqual(witness.step_out, expected.map(BigInt)); }); + const DATA_BYTES_1 = 32; + const TOTAL_BYTES_ACROSS_NIVC_1 = DATA_BYTES_1 * (MAX_STACK_HEIGHT + 2 + 1) + 1; + + let zero_block = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + 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]; 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: [32], // input len is 32 bytes + params: [DATA_BYTES_1, MAX_STACK_HEIGHT], // input len is 32 bytes }); - let zero_block = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - 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]; - const counter = [0x00, 0x00, 0x00, 0x01]; - const step_in = new Array(64).fill(0x00).concat(counter); + const step_in = new Array(TOTAL_BYTES_ACROSS_NIVC_1).fill(0x00); + counter.forEach((value, index) => { + step_in[2 * DATA_BYTES_1 + index] = value; + }); let expected = plainText1.concat(zero_block).concat(ct_part1).concat(zero_block).concat([0x00, 0x00, 0x00, 0x02]); + expected = expected.concat(new Array(TOTAL_BYTES_ACROSS_NIVC_1 - expected.length).fill(0)); const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText1, aad: aad, step_in: step_in }, ["step_out"]) assert.deepEqual(witness.step_out, expected.map(BigInt)); @@ -78,21 +98,15 @@ describe("aes-gctr-nivc", () => { circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { file: "aes-gcm/nivc/aes-gctr-nivc", template: "AESGCTRFOLD", - params: [32], // input len is 32 bytes + params: [DATA_BYTES_1, MAX_STACK_HEIGHT], // input len is 32 bytes }); - let zero_block = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - 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]; - const counter = [0x00, 0x00, 0x00, 0x02]; - const step_in = plainText1.concat(zero_block).concat(ct_part1).concat(zero_block).concat(counter); + let step_in = plainText1.concat(zero_block).concat(ct_part1).concat(zero_block).concat(counter); + step_in = step_in.concat(new Array(TOTAL_BYTES_ACROSS_NIVC_1 - step_in.length).fill(0)); + let expected = plainText1.concat(plainText2).concat(ct_part1).concat(ct_part2).concat([0x00, 0x00, 0x00, 0x03]); + expected = expected.concat(new Array(TOTAL_BYTES_ACROSS_NIVC_1 - expected.length).fill(0)); const witness = await circuit_one_block.compute({ key: key, iv: iv, plainText: plainText2, aad: aad, step_in: step_in }, ["step_out"]) assert.deepEqual(witness.step_out, expected.map(BigInt)); diff --git a/circuits/test/full/full.test.ts b/circuits/test/full/full.test.ts new file mode 100644 index 0000000..cde3d60 --- /dev/null +++ b/circuits/test/full/full.test.ts @@ -0,0 +1,132 @@ +import { CircuitSignals } from "circomkit"; +import { circomkit, WitnessTester, toByte } from "../common"; + +// 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]; + +describe("NIVC_FULL", async () => { + let aesCircuit: WitnessTester<["key", "iv", "plainText", "aad", "step_in"], ["step_out"]>; + let httpParseAndLockStartLineCircuit: WitnessTester<["step_in", "beginning", "beginning_length", "middle", "middle_length", "final", "final_length"], ["step_out"]>; + let lockHeaderCircuit: WitnessTester<["step_in", "header", "headerNameLength", "value", "headerValueLength"], ["step_out"]>; + let bodyMaskCircuit: WitnessTester<["step_in"], ["step_out"]>; + + const DATA_BYTES = 320; + const MAX_STACK_HEIGHT = 5; + const PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; + const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 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 () => { + aesCircuit = await circomkit.WitnessTester("AESGCTRFOLD", { + file: "aes-gcm/nivc/aes-gctr-nivc", + template: "AESGCTRFOLD", + params: [DATA_BYTES, MAX_STACK_HEIGHT], + }); + console.log("#constraints (AES-GCTR):", await aesCircuit.getConstraintCount()); + httpParseAndLockStartLineCircuit = await circomkit.WitnessTester(`ParseAndLockStartLine`, { + file: "http/nivc/parse_and_lock_start_line", + template: "ParseAndLockStartLine", + params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], + }); + console.log("#constraints (HTTP-PARSE-AND-LOCK-START-LINE):", await httpParseAndLockStartLineCircuit.getConstraintCount()); + + lockHeaderCircuit = await circomkit.WitnessTester(`LockHeader`, { + file: "http/nivc/lock_header", + template: "LockHeader", + params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], + }); + console.log("#constraints (HTTP-LOCK-HEADER):", await lockHeaderCircuit.getConstraintCount()); + + bodyMaskCircuit = await circomkit.WitnessTester(`BodyMask`, { + file: "http/nivc/body_mask", + template: "HTTPMaskBodyNIVC", + params: [DATA_BYTES, MAX_STACK_HEIGHT], + }); + console.log("#constraints (HTTP-BODY-MASK):", await bodyMaskCircuit.getConstraintCount()); + }); + + + 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("NIVC_CHAIN", async () => { + // fold 16 bytes at a time + let aes_gcm: CircuitSignals = { step_out: [] }; + // console.log("DATA_BYTES", DATA_BYTES); + + // Run the 0th chunk of plaintext + const counter = [0x00, 0x00, 0x00, 0x01]; + const init_nivc_input = new Array(TOTAL_BYTES_ACROSS_NIVC).fill(0x00); + counter.forEach((value, index) => { + init_nivc_input[2 * DATA_BYTES + index] = value; + }); + let pt = http_response_plaintext.slice(0, 16); + aes_gcm = await aesCircuit.compute({ key: Array(16).fill(0), iv: Array(12).fill(0), plainText: pt, aad: Array(16).fill(0), step_in: init_nivc_input }, ["step_out"]); + for (let i = 1; i < (DATA_BYTES / 16); i++) { + let pt = http_response_plaintext.slice(i * 16, i * 16 + 16); + aes_gcm = await aesCircuit.compute({ key: Array(16).fill(0), iv: Array(12).fill(0), plainText: pt, aad: Array(16).fill(0), step_in: aes_gcm.step_out }, ["step_out"]); + } + let out = aes_gcm.step_out as number[]; + let extendedJsonInput = out.slice(0, DATA_BYTES).concat(Array(Math.max(0, TOTAL_BYTES_ACROSS_NIVC - http_response_plaintext.length)).fill(0)); + let parseAndLockStartLine = await httpParseAndLockStartLineCircuit.compute({ step_in: extendedJsonInput, 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, header: headerNamePadded, headerNameLength: headerName.length, value: headerValuePadded, headerValueLength: headerValue.length }, ["step_out"]); + + let bodyMask = await bodyMaskCircuit.compute({ step_in: lockHeader.step_out }, ["step_out"]); + + let bodyMaskOut = bodyMask.step_out as number[]; + let idx = bodyMaskOut.indexOf('{'.charCodeAt(0)); + + let maskedInput = extendedJsonInput.fill(0, 0, idx); + maskedInput = maskedInput.fill(0, 320); + + bodyMaskOut === maskedInput; + }); +}); \ No newline at end of file diff --git a/circuits/test/http/locker.test.ts b/circuits/test/http/locker.test.ts new file mode 100644 index 0000000..34f32be --- /dev/null +++ b/circuits/test/http/locker.test.ts @@ -0,0 +1,136 @@ +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/package-lock.json b/package-lock.json index acf451a..b4e8631 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,16 @@ { "name": "web-prover-circuits", - "version": "0.2.4", + "version": "0.2.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "web-prover-circuits", - "version": "0.2.4", + "version": "0.2.5", "license": "Apache-2.0", "dependencies": { "@zk-email/circuits": "^6.1.1", - "aes-proof": "github:pluto/aes-proof#1d08e13ea4f381649cdff83f56d93444008b6548", - "circomlib": "^2.0.5", - "parser-attestor": "github:pluto/parser-attestor#b9feeeb240ddf867da85198de7d59e73cba4b008" + "circomlib": "^2.0.5" }, "devDependencies": { "@semantic-release/commit-analyzer": "^11.1.0", @@ -91,6 +89,7 @@ "version": "0.0.11", "resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.11.tgz", "integrity": "sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==", + "dev": true, "license": "GPL-3.0", "dependencies": { "fastfile": "0.0.20", @@ -917,6 +916,7 @@ "version": "0.7.8", "resolved": "https://registry.npmjs.org/@types/snarkjs/-/snarkjs-0.7.8.tgz", "integrity": "sha512-x37Jsv1vx6I6RMJdfvYEmDUOLYgzYMecwlk13gniDOcN20xLVe9hy9DlQxWeCPirqpDY/jwugQSqCi2RxehU3g==", + "dev": true, "license": "MIT", "peer": true }, @@ -976,37 +976,6 @@ "node": ">=0.4.0" } }, - "node_modules/aes-proof": { - "version": "0.1.0", - "resolved": "git+ssh://git@github.com/pluto/aes-proof.git#1d08e13ea4f381649cdff83f56d93444008b6548", - "integrity": "sha512-e/wiJJgISYDBE47vddzI3nyM1odtYqvH55AOYHQQWu5otp7KUuwHI+oO6XVsbQuPr992jo1+CQbqs19Jb1I+UQ==", - "license": "Apache-2.0", - "dependencies": { - "circomkit": "^0.2.1", - "circomlib": "^2.0.5" - } - }, - "node_modules/aes-proof/node_modules/circomkit": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/circomkit/-/circomkit-0.2.1.tgz", - "integrity": "sha512-7O8QsOLUq2QvwGMimvWxwdg7OgV33OT7ZBND+81dv3JrVp8ove93yV16jF3TW6XBncSY92/Aka8F4CAi/H9VQw==", - "license": "MIT", - "dependencies": { - "circom_tester": "^0.0.19", - "commander": "^12.0.0", - "loglevel": "^1.8.1" - }, - "bin": { - "circomkit": "dist/cli.js" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/snarkjs": "^0.7.x", - "snarkjs": "^0.7.x" - } - }, "node_modules/agent-base": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", @@ -1138,6 +1107,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -1153,6 +1123,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -1269,6 +1240,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -1311,6 +1283,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, "license": "MIT", "dependencies": { "assertion-error": "^1.1.0", @@ -1355,6 +1328,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, "license": "MIT", "dependencies": { "get-func-name": "^2.0.2" @@ -1373,6 +1347,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", "integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==", + "dev": true, "license": "ISC" }, "node_modules/chokidar": { @@ -1427,6 +1402,7 @@ "version": "0.0.19", "resolved": "https://registry.npmjs.org/circom_tester/-/circom_tester-0.0.19.tgz", "integrity": "sha512-SNHaBsGxcBH6XsVWfsRbRPA7NF8m8AMKJI9dtJJCFGUtOTT2+zsoIqAwi50z6XCnO4TtjyXq7AeXa1PLHqT0tw==", + "dev": true, "license": "GPL-3.0", "dependencies": { "chai": "^4.3.6", @@ -1443,6 +1419,7 @@ "version": "0.1.21", "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.21.tgz", "integrity": "sha512-qTkud630B/GK8y76hnOaaS1aNuF6prfV0dTrkeRsiJKnlP1ryQbP2FWLgDOPqn6aKyaPlam+Z+DTbBhkEzh8dA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "ffjavascript": "0.2.56" @@ -1455,6 +1432,7 @@ "version": "0.2.56", "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.56.tgz", "integrity": "sha512-em6G5Lrj7ucIqj4TYEgyoHs/j99Urwwqa4+YxEVY2hggnpRimVj+noX5pZQTxI1pvtiekZI4rG65JBf0xraXrg==", + "dev": true, "license": "GPL-3.0", "dependencies": { "wasmbuilder": "0.0.16", @@ -1466,6 +1444,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.5.0.tgz", "integrity": "sha512-KWz8mZ2Y+6wvn6GGkQo6/ZlKwETdAGohd40Lzpwp5TUZCn6N6O4Az1SuX1rw/qREGL6Im+ycb19suCFE8/xaKA==", + "dev": true, "license": "GPL-3.0", "dependencies": { "@iden3/binfileutils": "0.0.11", @@ -1487,6 +1466,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.0.tgz", "integrity": "sha512-3e2rbxdujOwaod657gxgmdhZNn+i1qKdHO3Y/bK+8E7bV8ttV/fu5FO4/WLBACF375cK0QDLOP+65Na63qYuWA==", + "dev": true, "license": "GPL-3.0", "dependencies": { "wasmbuilder": "0.0.16" @@ -1646,6 +1626,7 @@ "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -1894,6 +1875,7 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, "license": "MIT", "dependencies": { "type-detect": "^4.0.0" @@ -1922,6 +1904,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -2212,6 +2195,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" @@ -2224,6 +2208,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2397,6 +2382,7 @@ "version": "0.2.63", "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.63.tgz", "integrity": "sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==", + "dev": true, "license": "GPL-3.0", "dependencies": { "wasmbuilder": "0.0.16", @@ -2520,12 +2506,14 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/fnv-plus/-/fnv-plus-1.3.1.tgz", "integrity": "sha512-Gz1EvfOneuFfk4yG458dJ3TLJ7gV19q3OM/vVvvHf7eT02Hm1DleB4edsia6ahbKgAYxO9gvyQ1ioWZR+a00Yw==", + "dev": true, "license": "MIT" }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.1.3" @@ -2583,6 +2571,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2615,6 +2604,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -2624,6 +2614,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2772,6 +2763,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -2822,6 +2814,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -2834,6 +2827,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2846,6 +2840,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2858,6 +2853,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -2873,6 +2869,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -3075,6 +3072,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, "license": "ISC" }, "node_modules/ini": { @@ -3105,6 +3103,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -3141,6 +3140,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3173,6 +3173,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" @@ -3260,6 +3261,7 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, "license": "MIT", "dependencies": { "which-typed-array": "^1.1.14" @@ -3588,6 +3590,7 @@ "version": "1.9.2", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6.0" @@ -3607,6 +3610,7 @@ "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, "license": "MIT", "dependencies": { "get-func-name": "^2.0.1" @@ -7442,16 +7446,6 @@ "dev": true, "license": "MIT" }, - "node_modules/parser-attestor": { - "version": "0.1.0", - "resolved": "git+ssh://git@github.com/pluto/parser-attestor.git#b9feeeb240ddf867da85198de7d59e73cba4b008", - "integrity": "sha512-8yldptobgJKXHzSpb1/xdtEQLHqzGb55bqrdyTbapyZ1zR482FKiS4RXw8gXKwKGLQK0WNSumYDbh8BBqlJGgw==", - "license": "Apache-2.0", - "dependencies": { - "@zk-email/circuits": "^6.1.1", - "circomlib": "^2.0.5" - } - }, "node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -7486,6 +7480,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -7546,6 +7541,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -7614,6 +7610,7 @@ "version": "0.0.41", "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.41.tgz", "integrity": "sha512-Q1WDF3u1vYeAwjHo4YuddkA8Aq0TulbKjmGm99+Atn13Lf5fTsMZBnBV9T741w8iSyPFG6Uh6sapQby77sREqA==", + "dev": true, "license": "GPL-3.0", "dependencies": { "@iden3/bigarray": "0.0.2", @@ -7626,6 +7623,7 @@ "version": "0.2.56", "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.56.tgz", "integrity": "sha512-em6G5Lrj7ucIqj4TYEgyoHs/j99Urwwqa4+YxEVY2hggnpRimVj+noX5pZQTxI1pvtiekZI4rG65JBf0xraXrg==", + "dev": true, "license": "GPL-3.0", "dependencies": { "wasmbuilder": "0.0.16", @@ -7637,6 +7635,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.0.tgz", "integrity": "sha512-3e2rbxdujOwaod657gxgmdhZNn+i1qKdHO3Y/bK+8E7bV8ttV/fu5FO4/WLBACF375cK0QDLOP+65Na63qYuWA==", + "dev": true, "license": "GPL-3.0", "dependencies": { "wasmbuilder": "0.0.16" @@ -8448,6 +8447,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -9003,6 +9003,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.14" @@ -9012,6 +9013,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, "license": "MIT", "dependencies": { "tmp": "^0.2.0" @@ -9119,6 +9121,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -9248,6 +9251,7 @@ "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -9323,6 +9327,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", diff --git a/package.json b/package.json index d2e637d..4f472fc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "web-prover-circuits", "description": "ZK Circuits for WebProofs", - "version": "0.2.4", + "version": "0.2.5", "license": "Apache-2.0", "repository": { "type": "git", @@ -13,9 +13,7 @@ }, "dependencies": { "@zk-email/circuits": "^6.1.1", - "aes-proof": "github:pluto/aes-proof#1d08e13ea4f381649cdff83f56d93444008b6548", - "circomlib": "^2.0.5", - "parser-attestor": "github:pluto/parser-attestor#b9feeeb240ddf867da85198de7d59e73cba4b008" + "circomlib": "^2.0.5" }, "devDependencies": { "@semantic-release/commit-analyzer": "^11.1.0",