From 6ee3eb17b9444aac2b6b6fe29b1766fa355e8a36 Mon Sep 17 00:00:00 2001 From: Nicolas Sarlin Date: Mon, 4 Nov 2024 17:57:39 +0100 Subject: [PATCH] chore(zk): add a proof compat test between x86_64 and wasm --- .github/workflows/aws_tfhe_wasm_tests.yml | 4 ++ .gitignore | 2 + Makefile | 13 ++++ tfhe/js_on_wasm_tests/package.json | 2 +- tfhe/tests/zk_wasm_x86_test.rs | 86 +++++++++++++++++++++++ tfhe/tests/zk_wasm_x86_test/index.js | 38 ++++++++++ tfhe/tests/zk_wasm_x86_test/package.json | 15 ++++ tfhe/web_wasm_parallel_tests/package.json | 2 +- 8 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 tfhe/tests/zk_wasm_x86_test.rs create mode 100644 tfhe/tests/zk_wasm_x86_test/index.js create mode 100644 tfhe/tests/zk_wasm_x86_test/package.json diff --git a/.github/workflows/aws_tfhe_wasm_tests.yml b/.github/workflows/aws_tfhe_wasm_tests.yml index b94696448e..3897cc47c8 100644 --- a/.github/workflows/aws_tfhe_wasm_tests.yml +++ b/.github/workflows/aws_tfhe_wasm_tests.yml @@ -99,6 +99,10 @@ jobs: run: | make test_web_js_api_parallel_chrome_ci + - name: Run x86_64/wasm zk compatibility tests + run: | + make test_zk_wasm_x86_compat_ci + - name: Slack Notification if: ${{ failure() }} continue-on-error: true diff --git a/.gitignore b/.gitignore index d4b540dd18..2f946dce53 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ backends/tfhe-cuda-backend/cuda/cmake-build-debug/ tfhe/web_wasm_parallel_tests/server.PID venv/ web-test-runner/ +node_modules/ +package-lock.json # Dir used for backward compatibility test data tfhe/tfhe-backward-compat-data/ diff --git a/Makefile b/Makefile index c4fc33d751..25d29271e9 100644 --- a/Makefile +++ b/Makefile @@ -833,6 +833,19 @@ test_zk_pok: install_rs_build_toolchain RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \ -p tfhe-zk-pok +.PHONY: test_zk_wasm_x86_compat_ci +test_zk_wasm_x86_compat_ci: check_nvm_installed + source ~/.nvm/nvm.sh && \ + nvm install $(NODE_VERSION) && \ + nvm use $(NODE_VERSION) && \ + $(MAKE) test_zk_wasm_x86_compat + +.PHONY: test_zk_wasm_x86_compat # Check compatibility between wasm and x86_64 proofs +test_zk_wasm_x86_compat: install_rs_build_toolchain build_node_js_api + cd tfhe/tests/zk_wasm_x86_test && npm install + RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \ + -p tfhe --test zk_wasm_x86_test --features=$(TARGET_ARCH_FEATURE),integer,zk-pok + .PHONY: test_versionable # Run tests for tfhe-versionable subcrate test_versionable: install_rs_build_toolchain RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \ diff --git a/tfhe/js_on_wasm_tests/package.json b/tfhe/js_on_wasm_tests/package.json index d5a4a2f14f..0532bcd56f 100644 --- a/tfhe/js_on_wasm_tests/package.json +++ b/tfhe/js_on_wasm_tests/package.json @@ -7,5 +7,5 @@ "test": "node --test --test-reporter=tap" }, "author": "", - "license": "ISC" + "license": "BSD-3-Clause" } diff --git a/tfhe/tests/zk_wasm_x86_test.rs b/tfhe/tests/zk_wasm_x86_test.rs new file mode 100644 index 0000000000..d82f3f218a --- /dev/null +++ b/tfhe/tests/zk_wasm_x86_test.rs @@ -0,0 +1,86 @@ +//! Test compatibility between x86_64 and wasm proofs +//! +//! - Generate a crs and public key from rust +//! - Load them in js, encrypt and prove some ciphertexts +//! - Load the proven ciphertexts in rust and verify the proof + +#![cfg(feature = "zk-pok")] +#![cfg(feature = "integer")] + +use std::fs::File; +use std::path::{Path, PathBuf}; +use std::process::Command; +use tfhe::safe_serialization::{safe_deserialize, safe_serialize}; +use tfhe::zk::{CompactPkeCrs, CompactPkePublicParams}; +use tfhe::{ClientKey, CompactPublicKey, ConfigBuilder, ProvenCompactCiphertextList}; + +const SIZE_LIMIT: u64 = 1024 * 1024 * 1024; + +fn gen_key_and_crs() -> (CompactPublicKey, CompactPkeCrs) { + println!("Generating keys"); + let config = ConfigBuilder::default().build(); + let client_key = ClientKey::generate(config); + let pub_key = CompactPublicKey::new(&client_key); + + println!("Generating crs"); + let crs = CompactPkeCrs::from_config(config, 16).unwrap(); + + (pub_key, crs) +} + +fn gen_proven_ct_in_wasm(path: &Path) { + println!("Generating proven ciphertext in wasm"); + let mut child = Command::new("node") + .arg("index.js") + .current_dir(path) + .spawn() + .expect("Failed to run node script"); + + let exit_status = child.wait().unwrap(); + if let Some(exit_code) = exit_status.code() { + if exit_code == 0 { + return; + } + } + + panic!("node script returned a non-0 code."); +} + +fn verify_proof( + public_key: &CompactPublicKey, + crs: &CompactPkePublicParams, + proven_ct: &ProvenCompactCiphertextList, +) { + println!("Verifying proof"); + match proven_ct.verify(crs, public_key, &[]) { + tfhe::zk::ZkVerificationOutCome::Valid => { + println!("proof verification succeeded"); + } + tfhe::zk::ZkVerificationOutCome::Invalid => { + panic!("proof verification failed!!!") + } + } +} + +#[test] +fn test_proof_compat_with_wasm() { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + let mut test_path = PathBuf::from(manifest_dir); + test_path.push("tests"); + test_path.push("zk_wasm_x86_test"); + + let (pub_key, crs) = gen_key_and_crs(); + + let mut f_pubkey = File::create(test_path.join("public_key.bin")).unwrap(); + safe_serialize(&pub_key, &mut f_pubkey, SIZE_LIMIT).unwrap(); + + let mut f_crs = File::create(test_path.join("crs.bin")).unwrap(); + safe_serialize(crs.public_params(), &mut f_crs, SIZE_LIMIT).unwrap(); + + gen_proven_ct_in_wasm(&test_path); + + let mut f_ct = File::open(test_path.join("proof.bin")).unwrap(); + let proven_ct: ProvenCompactCiphertextList = safe_deserialize(&mut f_ct, SIZE_LIMIT).unwrap(); + + verify_proof(&pub_key, crs.public_params(), &proven_ct); +} diff --git a/tfhe/tests/zk_wasm_x86_test/index.js b/tfhe/tests/zk_wasm_x86_test/index.js new file mode 100644 index 0000000000..ec9cb72af4 --- /dev/null +++ b/tfhe/tests/zk_wasm_x86_test/index.js @@ -0,0 +1,38 @@ +const { + TfheCompactPublicKey, + CompactCiphertextList, + CompactPkePublicParams, + ZkComputeLoad, +} = require('node-tfhe'); + +const fs = require('fs'); + +const SIZE_LIMIT = BigInt(1024) * BigInt(1024) * BigInt(1024); + +const tfhe_proof = async () => { + const publicKeyBuf = fs.readFileSync(`${__dirname}/public_key.bin`); + const publicParamsBuf = fs.readFileSync(`${__dirname}/crs.bin`); + const publicKey = TfheCompactPublicKey.safe_deserialize(publicKeyBuf, SIZE_LIMIT); + const publicParams = CompactPkePublicParams.safe_deserialize(publicParamsBuf, SIZE_LIMIT); + + const builder = CompactCiphertextList.builder(publicKey); + builder.push_u4(1); + + builder.push_u8(0xff); + + const encrypted = builder.build_with_proof_packed( + publicParams, + new Uint8Array(), + ZkComputeLoad.Proof, + ); + + const ciphertext = encrypted.safe_serialize(SIZE_LIMIT); + let ciphertext_hex = Buffer.from(ciphertext); + + + fs.writeFile('proof.bin', ciphertext_hex, (err) => { + + if (err) throw err; + }); +} +tfhe_proof(); diff --git a/tfhe/tests/zk_wasm_x86_test/package.json b/tfhe/tests/zk_wasm_x86_test/package.json new file mode 100644 index 0000000000..20923c18f5 --- /dev/null +++ b/tfhe/tests/zk_wasm_x86_test/package.json @@ -0,0 +1,15 @@ +{ + "name": "zk_wasm_x86_test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "type": "commonjs", + "author": "", + "license": "BSD-3-Clause", + "dependencies": { + "node-tfhe": "file:../../pkg" + } +} diff --git a/tfhe/web_wasm_parallel_tests/package.json b/tfhe/web_wasm_parallel_tests/package.json index a5ae8b7070..eaec66906b 100644 --- a/tfhe/web_wasm_parallel_tests/package.json +++ b/tfhe/web_wasm_parallel_tests/package.json @@ -10,7 +10,7 @@ "check-format": "prettier . --check" }, "author": "", - "license": "ISC", + "license": "BSD-3-Clause", "devDependencies": { "@babel/preset-env": "^7.25.4", "prettier": "^3.3.3",