diff --git a/crates/bfv-helpers/src/client.rs b/crates/bfv-helpers/src/client.rs index a8ff7a93b4..68ea4c485a 100644 --- a/crates/bfv-helpers/src/client.rs +++ b/crates/bfv-helpers/src/client.rs @@ -55,9 +55,50 @@ pub fn bfv_encrypt_u64( Ok(encrypted_data) } +/// Encrypt a Vec using BFV homomorphic encryption +/// +/// # Arguments +/// * `data` - The value to encrypt (Vec) +/// * `public_key` - Serialized BFV public key bytes +/// # `degree` - Polynomial degree for BFV parameters +/// # `plaintext_modulus` - Plaintext modulus for BFV parameters +/// * `moduli` - Vector of moduli for BFV parameters +/// +/// # Returns +/// * `Result>` - Serialized BFV ciphertext bytes +/// +/// # Errors +/// Returns error string if: +/// - Public key deserialization fails +/// - Plaintext encoding fails +/// - Encryption fails +/// - Input validation vector computation fails +pub fn bfv_encrypt_v64( + data: Vec, + public_key: Vec, + degree: usize, + plaintext_modulus: u64, + moduli: [u64; 1], +) -> Result> { + let params = build_bfv_params_arc(degree, plaintext_modulus, &moduli); + + let pk = PublicKey::from_bytes(&public_key, ¶ms) + .map_err(|e| anyhow!("Error deserializing public key:{e}"))?; + + let pt = Plaintext::try_encode(&data, Encoding::poly(), ¶ms) + .map_err(|e| anyhow!("Error encoding plaintext: {e}"))?; + + let ct = pk + .try_encrypt(&pt, &mut thread_rng()) + .map_err(|e| anyhow!("Error encrypting data: {e}"))?; + + let encrypted_data = ct.to_bytes(); + Ok(encrypted_data) +} + #[derive(Debug, Clone)] pub struct VerifiableEncryptionResult { - pub encrypted_vote: Vec, + pub encrypted_data: Vec, pub circuit_inputs: String, } @@ -81,7 +122,7 @@ pub struct VerifiableEncryptionResult { /// - Encryption fails /// - Input validation vector computation fails pub fn bfv_verifiable_encrypt_u64( - vote: u64, + data: u64, public_key: Vec, degree: usize, plaintext_modulus: u64, @@ -92,14 +133,78 @@ pub fn bfv_verifiable_encrypt_u64( let pk = PublicKey::from_bytes(&public_key, ¶ms) .map_err(|e| anyhow!("Error deserializing public key: {}", e))?; - let vote_vector = vec![vote]; + let data_vector = vec![data]; + + let plaintext = Plaintext::try_encode(&data_vector, Encoding::poly(), ¶ms) + .map_err(|e| anyhow!("Error encoding plaintext: {}", e))?; + + let (cipher_text, u_rns, e0_rns, e1_rns) = pk + .try_encrypt_extended(&plaintext, &mut thread_rng()) + .map_err(|e| anyhow!("Error encrypting data: {}", e))?; + + // Create Greco input validation ZK proof + let input_val_vectors = InputValidationVectors::compute( + &plaintext, + &u_rns, + &e0_rns, + &e1_rns, + &cipher_text, + &pk, + ¶ms, + ) + .map_err(|e| anyhow!("Error computing input validation vectors: {}", e))?; + + let zkp_modulus = BigInt::from_str_radix( + "21888242871839275222246405745257275088548364400416034343698204186575808495617", + 10, + ) + .unwrap(); + + let standard_input_val = input_val_vectors.standard_form(&zkp_modulus); + + Ok(VerifiableEncryptionResult { + encrypted_data: cipher_text.to_bytes(), + circuit_inputs: standard_input_val.to_json().to_string(), + }) +} + +/// Verifiably encrypt a u64 using BFV homomorphic encryption and generate circuit inputs +/// to pass into Greco to prove the validity of the ciphertext +/// +/// # Arguments +/// * `data` - The value to encrypt (u64) +/// * `public_key` - Serialized BFV public key bytes +/// # `degree` - Polynomial degree for BFV parameters +/// # `plaintext_modulus` - Plaintext modulus for BFV parameters +/// * `moduli` - Vector of moduli for BFV parameters +/// +/// # Returns +/// * `Result` - Contains encrypted u64 and circuit inputs for ZKP +/// +/// # Errors +/// Returns error string if: +/// - Public key deserialization fails +/// - Plaintext encoding fails +/// - Encryption fails +/// - Input validation vector computation fails +pub fn bfv_verifiable_encrypt_v64( + data: Vec, + public_key: Vec, + degree: usize, + plaintext_modulus: u64, + moduli: [u64; 1], +) -> Result { + let params = build_bfv_params_arc(degree, plaintext_modulus, &moduli); - let plaintext = Plaintext::try_encode(&vote_vector, Encoding::poly(), ¶ms) + let pk = PublicKey::from_bytes(&public_key, ¶ms) + .map_err(|e| anyhow!("Error deserializing public key: {}", e))?; + + let plaintext = Plaintext::try_encode(&data, Encoding::poly(), ¶ms) .map_err(|e| anyhow!("Error encoding plaintext: {}", e))?; let (cipher_text, u_rns, e0_rns, e1_rns) = pk .try_encrypt_extended(&plaintext, &mut thread_rng()) - .map_err(|e| anyhow!("Error encrypting vote: {}", e))?; + .map_err(|e| anyhow!("Error encrypting data: {}", e))?; // Create Greco input validation ZK proof let input_val_vectors = InputValidationVectors::compute( @@ -122,7 +227,7 @@ pub fn bfv_verifiable_encrypt_u64( let standard_input_val = input_val_vectors.standard_form(&zkp_modulus); Ok(VerifiableEncryptionResult { - encrypted_vote: cipher_text.to_bytes(), + encrypted_data: cipher_text.to_bytes(), circuit_inputs: standard_input_val.to_json().to_string(), }) } @@ -145,15 +250,43 @@ mod tests { let pk = PublicKey::new(&sk, &mut rng); let num = 1; - let encrypted_vote = + let encrypted_data = bfv_encrypt_u64(num, pk.to_bytes(), degree, plaintext_modulus, moduli).unwrap(); - let ct = Ciphertext::from_bytes(&encrypted_vote, ¶ms).unwrap(); + let ct = Ciphertext::from_bytes(&encrypted_data, ¶ms).unwrap(); let pt = sk.try_decrypt(&ct).unwrap(); assert_eq!(pt.value[0], num); } + #[test] + fn test_bfv_encrypt_v64() { + use fhe::bfv::{Ciphertext, PublicKey, SecretKey}; + use fhe_traits::{DeserializeParametrized, FheDecrypter, Serialize}; + + let (degree, plaintext_modulus, moduli) = SET_2048_1032193_1; + let params = build_bfv_params_arc(degree, plaintext_modulus, &moduli); + let mut rng = thread_rng(); + let sk = SecretKey::random(¶ms, &mut rng); + let pk = PublicKey::new(&sk, &mut rng); + + let num = vec![1, 2]; + let encrypted_data = bfv_encrypt_v64( + num.clone(), + pk.to_bytes(), + degree, + plaintext_modulus, + moduli, + ) + .unwrap(); + + let ct = Ciphertext::from_bytes(&encrypted_data, ¶ms).unwrap(); + let pt = sk.try_decrypt(&ct).unwrap(); + + assert_eq!(pt.value[0], num[0]); + assert_eq!(pt.value[1], num[1]); + } + #[test] fn test_bfv_verifiable_encrypt_u64() { use fhe::bfv::{Ciphertext, PublicKey, SecretKey}; @@ -166,13 +299,41 @@ mod tests { let pk = PublicKey::new(&sk, &mut rng); let num = 1; - let encrypted_vote = + let encrypted_data = bfv_verifiable_encrypt_u64(num, pk.to_bytes(), degree, plaintext_modulus, moduli) .unwrap(); - let ct = Ciphertext::from_bytes(&encrypted_vote.encrypted_vote, ¶ms).unwrap(); + let ct = Ciphertext::from_bytes(&encrypted_data.encrypted_data, ¶ms).unwrap(); let pt = sk.try_decrypt(&ct).unwrap(); assert_eq!(pt.value[0], num); } + + #[test] + fn test_bfv_verifiable_encrypt_v64() { + use fhe::bfv::{Ciphertext, PublicKey, SecretKey}; + use fhe_traits::{DeserializeParametrized, FheDecrypter, Serialize}; + + let (degree, plaintext_modulus, moduli) = SET_2048_1032193_1; + let params = build_bfv_params_arc(degree, plaintext_modulus, &moduli); + let mut rng = thread_rng(); + let sk = SecretKey::random(¶ms, &mut rng); + let pk = PublicKey::new(&sk, &mut rng); + + let num = vec![1, 2]; + let encrypted_data = bfv_verifiable_encrypt_v64( + num.clone(), + pk.to_bytes(), + degree, + plaintext_modulus, + moduli, + ) + .unwrap(); + + let ct = Ciphertext::from_bytes(&encrypted_data.encrypted_data, ¶ms).unwrap(); + let pt = sk.try_decrypt(&ct).unwrap(); + + assert_eq!(pt.value[0], num[0]); + assert_eq!(pt.value[1], num[1]); + } } diff --git a/crates/wasm/src/lib.rs b/crates/wasm/src/lib.rs index ecb66833a3..765cce2581 100644 --- a/crates/wasm/src/lib.rs +++ b/crates/wasm/src/lib.rs @@ -4,7 +4,9 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use e3_bfv_helpers::client::{bfv_encrypt_u64, bfv_verifiable_encrypt_u64}; +use e3_bfv_helpers::client::{ + bfv_encrypt_u64, bfv_encrypt_v64, bfv_verifiable_encrypt_u64, bfv_verifiable_encrypt_v64, +}; use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -37,6 +39,36 @@ pub fn bfv_encrypt_number( Ok(encrypted_data) } +#[wasm_bindgen] +/// A function to encrypt a Vec value using BFV and default params. +/// +/// # Arguments +/// +/// * `data` - The data to encrypt - must be a Vec +/// * `public_key` - The public key to be used for encryption +/// * `degree` - Polynomial degree for BFV parameters +/// * `plaintext_modulus` - Plaintext modulus for BFV parameters +/// * `moduli` - Modulus for BFV parameters +/// +/// # Returns +/// +/// Returns a `Result, JsValue>` containing the encrypted data and any errors. +/// +/// # Panics +/// +/// Panics if the data cannot be encrypted +pub fn bfv_encrypt_vector( + data: Vec, + public_key: Vec, + degree: usize, + plaintext_modulus: u64, + moduli: u64, +) -> Result, JsValue> { + let encrypted_data = bfv_encrypt_v64(data, public_key, degree, plaintext_modulus, [moduli]) + .map_err(|e| JsValue::from_str(&format!("{}", e)))?; + Ok(encrypted_data) +} + #[wasm_bindgen] /// A function to encrypt a u64 value using BFV and default params and /// generate circuit inputs for Greco @@ -68,7 +100,43 @@ pub fn bfv_verifiable_encrypt_number( // Return as a vector of JsValues Ok(vec![ - JsValue::from(result.encrypted_vote), + JsValue::from(result.encrypted_data), + JsValue::from(result.circuit_inputs), + ]) +} + +#[wasm_bindgen] +/// A function to encrypt a Vec value using BFV and default params and +/// generate circuit inputs for Greco +/// +/// # Arguments +/// +/// * `data` - The data to encrypt - must be a Vec +/// * `public_key` - The public key to be used for encryption +/// * `degree` - Polynomial degree for BFV parameters +/// * `plaintext_modulus` - Plaintext modulus for BFV parameters +/// * `moduli` - Modulus for BFV parameters +/// +/// # Returns +/// +/// Returns a `Result, JsValue>` containing the encrypted data, circuit inputs and any errors. +/// +/// # Panics +/// +/// Panics if the data cannot be encrypted +pub fn bfv_verifiable_encrypt_vector( + data: Vec, + public_key: Vec, + degree: usize, + plaintext_modulus: u64, + moduli: u64, +) -> Result, JsValue> { + let result = bfv_verifiable_encrypt_v64(data, public_key, degree, plaintext_modulus, [moduli]) + .map_err(|e| JsValue::from_str(&format!("{}", e)))?; + + // Return as a vector of JsValues + Ok(vec![ + JsValue::from(result.encrypted_data), JsValue::from(result.circuit_inputs), ]) } diff --git a/examples/CRISP/sdk/package.json b/examples/CRISP/sdk/package.json index be5e2f8ddc..9cfb3728a8 100644 --- a/examples/CRISP/sdk/package.json +++ b/examples/CRISP/sdk/package.json @@ -38,7 +38,7 @@ }, "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808", "dependencies": { - "@enclave-e3/sdk": "^0.1.5", + "@enclave-e3/sdk": "workspace:*", "@zk-kit/lean-imt": "^2.2.4", "poseidon-lite": "^0.3.0", "viem": "2.30.6" diff --git a/packages/enclave-sdk/src/enclave-sdk.ts b/packages/enclave-sdk/src/enclave-sdk.ts index dc887b38ff..5a6a83c8d5 100644 --- a/packages/enclave-sdk/src/enclave-sdk.ts +++ b/packages/enclave-sdk/src/enclave-sdk.ts @@ -34,10 +34,13 @@ import type { SDKConfig, ProtocolParams, VerifiableEncryptionResult, + EncryptedValueAndPublicInputs, } from "./types"; import { bfv_encrypt_number, + bfv_encrypt_vector, bfv_verifiable_encrypt_number, + bfv_verifiable_encrypt_vector, } from "@enclave-e3/wasm"; import { CircuitInputs, generateProof } from "./greco"; import { CompiledCircuit } from "@noir-lang/noir_js"; @@ -137,6 +140,31 @@ export class EnclaveSDK { } } + /** + * Encrypt a vector using the configured protocol + * @param data - The vector to encrypt + * @param publicKey - The public key to use for encryption + * @returns The ciphertext + */ + public async encryptVector( + data: BigUint64Array, + publicKey: Uint8Array + ): Promise { + await initializeWasm(); + switch (this.protocol) { + case FheProtocol.BFV: + return bfv_encrypt_vector( + data, + publicKey, + this.protocolParams.degree, + this.protocolParams.plaintextModulus, + this.protocolParams.moduli + ); + default: + throw new Error("Protocol not supported"); + } + } + /** * Encrypt a number using the configured protocol and generate a zk-SNARK proof using Greco * @param data - The number to encrypt @@ -152,7 +180,7 @@ export class EnclaveSDK { await initializeWasm(); switch (this.protocol) { case FheProtocol.BFV: - const [encryptedVote, circuitInputs] = bfv_verifiable_encrypt_number( + const [encryptedData, circuitInputs] = bfv_verifiable_encrypt_number( data, publicKey, this.protocolParams.degree, @@ -165,7 +193,7 @@ export class EnclaveSDK { const proof = await generateProof(inputs, circuit); return { - encryptedVote, + encryptedData, proof, }; default: @@ -173,6 +201,73 @@ export class EnclaveSDK { } } + /** + * Encrypt a vector using the configured protocol and generate a zk-SNARK proof using Greco + * @param data - The vector to encrypt + * @param publicKey - The public key to use for encryption + * @param circuit - The circuit to use for proof generation + * @returns The encrypted vector and the proof + */ + public async encryptVectorAndGenProof( + data: BigUint64Array, + publicKey: Uint8Array, + circuit: CompiledCircuit + ): Promise { + await initializeWasm(); + switch (this.protocol) { + case FheProtocol.BFV: + const [encryptedVector, circuitInputs] = bfv_verifiable_encrypt_vector( + data, + publicKey, + this.protocolParams.degree, + this.protocolParams.plaintextModulus, + this.protocolParams.moduli + ); + + const inputs = JSON.parse(circuitInputs) as CircuitInputs; + // inputs.params = defaultParams; + const proof = await generateProof(inputs, circuit); + + return { + encryptedData: encryptedVector, + proof, + }; + default: + throw new Error("Protocol not supported"); + } + } + + /** + * Encrypt a vector and generate inputs for an E3 computation + * @param data - The vector to encrypt + * @param publicKey - The public key to use for encryption + * @returns The encrypted vector and the inputs for the E3 computation + */ + public async encryptVectorAndGenerateInputs( + data: BigUint64Array, + publicKey: Uint8Array, + ): Promise { + await initializeWasm(); + switch (this.protocol) { + case FheProtocol.BFV: + const [encryptedVector, circuitInputs] = bfv_verifiable_encrypt_vector( + data, + publicKey, + this.protocolParams.degree, + this.protocolParams.plaintextModulus, + this.protocolParams.moduli + ); + + const inputs = JSON.parse(circuitInputs); + return { + encryptedVector, + publicInputs: inputs + }; + default: + throw new Error("Protocol not supported"); + } + } + /** * Request a new E3 computation */ diff --git a/packages/enclave-sdk/src/types.ts b/packages/enclave-sdk/src/types.ts index c1e301873e..17f7e30e63 100644 --- a/packages/enclave-sdk/src/types.ts +++ b/packages/enclave-sdk/src/types.ts @@ -256,9 +256,9 @@ export interface SDKEventEmitter { */ export interface VerifiableEncryptionResult { /** - * The encrypted vote + * The encrypted data */ - encryptedVote: Uint8Array; + encryptedData: Uint8Array; /** * The proof generated by Greco */ @@ -313,3 +313,18 @@ export const BfvProtocolParams = { moduli: 0x3FFFFFFF000001n, } as const satisfies ProtocolParams, } + +/** + * The result of encrypting a value and generating a proof + */ +export interface EncryptedValueAndPublicInputs { + /** + * The encrypted vector + */ + encryptedVector: Uint8Array; + + /** + * The public inputs for the proof + */ + publicInputs: Object; +} diff --git a/packages/enclave-sdk/tests/sdk.test.ts b/packages/enclave-sdk/tests/sdk.test.ts index d2e59988e9..af7f614125 100644 --- a/packages/enclave-sdk/tests/sdk.test.ts +++ b/packages/enclave-sdk/tests/sdk.test.ts @@ -46,7 +46,28 @@ describe("encryptNumber", () => { const value = await sdk.encryptNumberAndGenProof(1n, Uint8Array.from(buffer), demoCircuit as unknown as CompiledCircuit); expect(value).to.be.an.instanceof(Object); - expect(value.encryptedVote).to.be.an.instanceof(Uint8Array); + expect(value.encryptedData).to.be.an.instanceof(Uint8Array); + expect(value.proof).to.be.an.instanceOf(Object) + }, 9999999); + + it("should encrypt a vecor of numbers without crashing in a node environent", async () => { + const buffer = await fs.readFile( + path.resolve(__dirname, "./fixtures/pubkey.bin"), + ); + const value = await sdk.encryptVector(new BigUint64Array([1n, 2n]), Uint8Array.from(buffer)); + expect(value).to.be.an.instanceof(Uint8Array); + expect(value.length).to.equal(27_674); + }); + + it("should encrypt a vector and generate a proof without crashing in a node environent", async () => { + const buffer = await fs.readFile( + path.resolve(__dirname, "./fixtures/pubkey.bin"), + ); + + const value = await sdk.encryptVectorAndGenProof(new BigUint64Array([1n, 2n]), Uint8Array.from(buffer), demoCircuit as unknown as CompiledCircuit); + + expect(value).to.be.an.instanceof(Object); + expect(value.encryptedData).to.be.an.instanceof(Uint8Array); expect(value.proof).to.be.an.instanceOf(Object) }, 9999999); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 742e4870fe..af9f2c4b1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -319,8 +319,8 @@ importers: examples/CRISP/sdk: dependencies: '@enclave-e3/sdk': - specifier: ^0.1.5 - version: 0.1.5(@openzeppelin/contracts@5.3.0)(@types/node@22.7.5)(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@6.3.5(@types/node@22.7.5)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.1))(zod@3.25.76) + specifier: workspace:* + version: link:../../../packages/enclave-sdk '@zk-kit/lean-imt': specifier: ^2.2.4 version: 2.2.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -1530,21 +1530,12 @@ packages: '@enclave-e3/contracts@0.1.3': resolution: {integrity: sha512-A1EPfAX2fcZzqHZ6v02P/c6OJStyMrCsEZURSOlKHUOBUnCS/o0o67TcJ0/LNoi/yamI4UH+cGAzS/kW2i4QfQ==} - '@enclave-e3/contracts@0.1.5': - resolution: {integrity: sha512-C1Mo9z2JG6netDhpOsk0kZV8DBjVd4ftE5oqhpXDDbK+HHD4XHozjKMqmlUYTooSzzT3INGYNS/IEDUHxYOqTA==} - '@enclave-e3/sdk@0.1.3': resolution: {integrity: sha512-MtCP2HX/GVMR8efiunKqYOeTkfKV/0biwb3dTJ2gylJfqV1Z8c9cHymj+Ivd1ZI+tbYPHvLoSs4PUMsdA/cLZA==} - '@enclave-e3/sdk@0.1.5': - resolution: {integrity: sha512-AZGIYrlJZ6FeK6DIQWqNKZDwvDpw+l1zCd7hc97giFX2LrNbSAzf/UJmNewAXFfaGtlnOePSVsuixk/ZQd1TVw==} - '@enclave-e3/wasm@0.1.3': resolution: {integrity: sha512-pKssAhrIjZJPF6N32JMA44MMOUU2Xrxxh4zx0/+qGx7MsSOFNXEg67or45C1OOewCzWrsuYdMWfyR7UibddiGA==} - '@enclave-e3/wasm@0.1.5': - resolution: {integrity: sha512-PZ/TpABK/PAAzO0d2+q17i3plzCs/E3chihc4yOi9DqCxdGFhm76hTueY/lDXusDnM+LUrEuaD11YR/2kBRvTg==} - '@esbuild/aix-ppc64@0.20.0': resolution: {integrity: sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==} engines: {node: '>=12'} @@ -10593,14 +10584,6 @@ snapshots: transitivePeerDependencies: - '@openzeppelin/contracts' - '@enclave-e3/contracts@0.1.5(@openzeppelin/contracts@5.3.0)': - dependencies: - '@openzeppelin/contracts-upgradeable': 5.4.0(@openzeppelin/contracts@5.3.0) - '@zk-kit/lean-imt.sol': 2.0.1 - poseidon-solidity: 0.0.5 - transitivePeerDependencies: - - '@openzeppelin/contracts' - '@enclave-e3/sdk@0.1.3(@openzeppelin/contracts@5.3.0)(@types/node@22.7.5)(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@6.3.5(@types/node@22.7.5)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.1))(zod@3.25.76)': dependencies: '@aztec/bb.js': 0.82.3 @@ -10673,46 +10656,8 @@ snapshots: - vite - zod - '@enclave-e3/sdk@0.1.5(@openzeppelin/contracts@5.3.0)(@types/node@22.7.5)(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@6.3.5(@types/node@22.7.5)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.1))(zod@3.25.76)': - dependencies: - '@aztec/bb.js': 0.82.3 - '@enclave-e3/contracts': 0.1.5(@openzeppelin/contracts@5.3.0) - '@enclave-e3/wasm': 0.1.5 - '@noir-lang/noir_js': 1.0.0-beta.3 - comlink: 4.4.2 - viem: 2.30.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - vite-plugin-top-level-await: 1.6.0(rollup@4.49.0)(vite@6.3.5(@types/node@22.7.5)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.1)) - vite-plugin-wasm: 3.5.0(vite@6.3.5(@types/node@22.7.5)(jiti@1.21.7)(tsx@4.20.5)(yaml@2.8.1)) - vitest: 1.6.1(@types/node@22.7.5) - web-worker: 1.5.0 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@openzeppelin/contracts' - - '@swc/helpers' - - '@types/node' - - '@vitest/browser' - - '@vitest/ui' - - bufferutil - - happy-dom - - jsdom - - less - - lightningcss - - rollup - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - typescript - - utf-8-validate - - vite - - zod - '@enclave-e3/wasm@0.1.3': {} - '@enclave-e3/wasm@0.1.5': {} - '@esbuild/aix-ppc64@0.20.0': optional: true