Skip to content

feat: add zk-inputs-wasm crate [skip-line-limit]#905

Merged
cedoor merged 4 commits into
devfrom
feat/wasm-ct-add-2
Oct 27, 2025
Merged

feat: add zk-inputs-wasm crate [skip-line-limit]#905
cedoor merged 4 commits into
devfrom
feat/wasm-ct-add-2

Conversation

@cedoor

@cedoor cedoor commented Oct 27, 2025

Copy link
Copy Markdown
Contributor

Adds a new zk-inputs-wasm crate that exposes the CRISP ZK inputs generator to JavaScript via wasm-bindgen, and updates CRISP workspace and package settings to build and consume the package.

Summary by CodeRabbit

  • New Features

    • WebAssembly bindings for zero-knowledge inputs generation, enabling JS/browser use.
    • Local deployment configuration added for full local contract testing.
  • Refactor

    • Public API moved to raw byte inputs/outputs for efficiency.
    • Build pipeline updated to include automated WASM build in the standard build process.
  • Tests

    • Tests updated to use generated keys/wasm-produced artifacts instead of filesystem fixtures.

@cedoor cedoor requested a review from ctrlc03 October 27, 2025 12:23
@vercel

vercel Bot commented Oct 27, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
crisp Skipped Skipped Oct 27, 2025 0:51am
enclave-docs Skipped Skipped Oct 27, 2025 0:51am

@github-actions

Copy link
Copy Markdown
Contributor

License Header Check Failed

Some files are missing the required SPDX license header. Please add the following header to the beginning of all .js, .jsx, .nr, .rs, .sol, .ts, and .tsx files:

// SPDX-License-Identifier: LGPL-3.0-only
//
// This file is provided WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

You can run ./scripts/check-license-headers.sh --fix locally to automatically add missing headers, then commit the changes.

Or run ./scripts/check-license-headers.sh to see which files need headers.

@coderabbitai

coderabbitai Bot commented Oct 27, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Restructures the CRISP ZK inputs generator into a core Rust crate (zk-inputs) and a WASM bindings crate (zk-inputs-wasm); converts APIs to byte-based inputs/outputs; updates workspace, build scripts, Docker, VSCode settings, and SDK/tests to consume the new crates. (50 words)

Changes

Cohort / File(s) Summary
Core ZK Inputs Refactor
examples/CRISP/crates/zk-inputs/Cargo.toml, examples/CRISP/crates/zk-inputs/src/lib.rs, examples/CRISP/crates/zk-inputs/src/serialization.rs
Renamed types (CrispZKInputsGeneratorZKInputsGenerator, CrispZKInputsZKInputs), changed constructors to new(degree, plaintext_modulus, moduli) and with_defaults(), switched APIs from hex/strings to byte-slice inputs/outputs (Vec<u8>), and updated tests/docs.
WASM Bindings
examples/CRISP/crates/zk-inputs-wasm/Cargo.toml, examples/CRISP/crates/zk-inputs-wasm/src/lib.rs
Added new wasm-bindgen crate exposing JS-friendly ZKInputsGenerator with methods: new, withDefaults, generateInputs, generatePublicKey, encryptVote, and version; includes wasm-bindgen tests.
Workspace / Manifests
Cargo.toml, examples/CRISP/Cargo.toml, pnpm-workspace.yaml, examples/CRISP/crates/zk-inputs/Cargo.toml
Replaced crates/generator with crates/zk-inputs and crates/zk-inputs-wasm in CRISP workspace; removed previously excluded path; added examples/CRISP/packages/crisp-zk-inputs to pnpm workspace; renamed package name to zk-inputs.
SDK & JS Integration
examples/CRISP/package.json, examples/CRISP/packages/crisp-sdk/package.json, examples/CRISP/packages/crisp-sdk/vite.config.ts
Added build:wasm scripts and chained wasm build into SDK build; added dependency @enclave/crisp-zk-inputs (workspace:*); added devDeps vite and vite-plugin-wasm; added Vite config with wasm plugin.
Tests Update
examples/CRISP/packages/crisp-sdk/tests/vote.test.ts
Replaced FS-based pubkey read with ZKInputsGenerator.withDefaults() and generatePublicKey(); removed beforeAll pubkey fixture.
Docker & Compose
examples/CRISP/docker-compose.yaml, examples/CRISP/server/Dockerfile
Replaced generator-target volume with zk-inputs-target; adjusted Dockerfile COPY steps to reference zk-inputs crate.
Contracts Deployment Data
examples/CRISP/packages/crisp-contracts/deployed_contracts.json
Added a localhost deployment block with multiple contract entries and constructorArgs for local development.
Editor Settings
.vscode/settings.json
Reformatted arrays to single-line and updated rust-analyzer.linkedProjects entries to reference new zk-inputs paths (removed old wasm-crypto path).

Sequence Diagram(s)

sequenceDiagram
    participant JS as JavaScript/Test
    participant WASM as zk-inputs-wasm
    participant Core as zk-inputs (Rust)
    participant Crypto as BFV Engine

    JS->>WASM: withDefaults() or new(...)
    WASM->>Core: new(degree, plaintext_modulus, moduli)
    Core-->>WASM: ZKInputsGenerator (core)

    rect rgb(220,240,250)
      note right of JS: Generate public key
      JS->>WASM: generatePublicKey()
      WASM->>Core: generate_public_key()
      Core->>Crypto: BFV keygen
      Crypto-->>Core: Vec<u8>
      Core-->>WASM: Result<Vec<u8>>
      WASM-->>JS: Result<Vec<u8>>
    end

    rect rgb(240,230,220)
      note right of JS: Generate inputs / encrypt
      JS->>WASM: generateInputs(prev_ct, pubkey, vote)
      WASM->>Core: generate_inputs(&[u8], &[u8], u8)
      Core->>Crypto: process bytes -> inputs JSON
      Crypto-->>Core: String (JSON)
      Core-->>WASM: Result<String>
      WASM->>JS: Result<JsValue>
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • examples/CRISP/crates/zk-inputs/src/lib.rs — API signature and byte/hex handling changes.
    • examples/CRISP/crates/zk-inputs-wasm/src/lib.rs — wasm-bindgen error mapping and JS value conversions.
    • Workspace and package paths (Cargo/pnpm) — ensure references and build ordering are consistent.
    • Dockerfile/CICD changes — confirm build artifacts and volume names.

Possibly related issues

Possibly related PRs

Suggested reviewers

  • ctrlc03

Poem

🐰 Hop, I split the generator in two,

Core Rust heart and tiny WASM shoe,
Bytes now dance where hex once flew,
JS calls, WASM answers — a crunchy new chew! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "feat: add zk-inputs-wasm crate [skip-line-limit]" accurately captures the primary objective of the pull request. The changeset's main focus is the introduction of a new zk-inputs-wasm crate that provides JavaScript-compatible WASM bindings for the CRISP ZK inputs generator via wasm-bindgen. While the PR includes supporting changes—such as refactoring the core zk-inputs crate (renaming structs, updating method signatures, changing from hex strings to bytes), updating build scripts, and modifying workspace configuration—these are secondary to the core feature. The title is specific, uses clear conventional commit format, avoids generic terminology, and would allow a developer scanning the history to understand the primary change at a glance.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/wasm-ct-add-2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cedoor cedoor changed the title feat: add zk-inputs-wasm crate feat: add zk-inputs-wasm crate [skip-line-limit] Oct 27, 2025
@vercel vercel Bot temporarily deployed to Preview – enclave-docs October 27, 2025 12:26 Inactive
@vercel vercel Bot temporarily deployed to Preview – crisp October 27, 2025 12:26 Inactive
@cedoor cedoor linked an issue Oct 27, 2025 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
examples/CRISP/crates/zk-inputs/src/lib.rs (2)

38-48: Avoid panic on invalid BFV parameters (public API) — provide a fallible constructor

build_arc().unwrap() will panic on invalid params. From JS this aborts the WASM module. Expose a non‑panicking constructor and keep new() as a thin wrapper if you want a convenience API.

Apply:

 pub struct ZKInputsGenerator {
     bfv_params: Arc<BfvParameters>,
 }
 
-impl ZKInputsGenerator {
-    /// Creates a new generator with the specified BFV parameters.
-    pub fn new(degree: usize, plaintext_modulus: u64, moduli: &[u64]) -> Self {
-        let bfv_params = BfvParametersBuilder::new()
-            .set_degree(degree)
-            .set_plaintext_modulus(plaintext_modulus)
-            .set_moduli(moduli)
-            .build_arc()
-            .unwrap();
-        Self { bfv_params }
-    }
+impl ZKInputsGenerator {
+    /// Non-panicking constructor.
+    pub fn try_new(degree: usize, plaintext_modulus: u64, moduli: &[u64]) -> Result<Self> {
+        let bfv_params = BfvParametersBuilder::new()
+            .set_degree(degree)
+            .set_plaintext_modulus(plaintext_modulus)
+            .set_moduli(moduli)
+            .build_arc()
+            .with_context(|| "Invalid BFV parameters")?;
+        Ok(Self { bfv_params })
+    }
+
+    /// Convenience constructor that panics on invalid parameters (kept for back-compat).
+    pub fn new(degree: usize, plaintext_modulus: u64, moduli: &[u64]) -> Self {
+        Self::try_new(degree, plaintext_modulus, moduli).expect("Invalid BFV parameters")
+    }

74-82: Validate vote ∈ {0,1} instead of silently coercing

Silently mapping any non‑1 to 0 can hide caller bugs. Return an error for invalid values.

 pub fn generate_inputs(
@@
-    // Set vote value (0 or 1) in the first coefficient.
-    message_data[0] = if vote == 1 { 1 } else { 0 };
+    // Enforce {0,1} vote domain.
+    if vote > 1 {
+        eyre::bail!("vote must be 0 or 1");
+    }
+    message_data[0] = vote as u64;
@@
 pub fn encrypt_vote(&self, public_key: &[u8], vote: u8) -> Result<Vec<u8>> {
@@
-    // Set vote value (0 or 1) in the first coefficient.
-    message_data[0] = if vote == 1 { 1 } else { 0 };
+    if vote > 1 {
+        eyre::bail!("vote must be 0 or 1");
+    }
+    message_data[0] = vote as u64;

Consider adding a small negative test asserting error on vote=2. Based on learnings

Also applies to: 124-131

🧹 Nitpick comments (8)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (2)

47-67: Use JsError and preserve JSON parse context for better JS ergonomics

Map Rust errors to JsError so callers get proper stack/name, and include parse error details. Functionally identical, but improves DX.

Apply:

-    pub fn generate_inputs(
+    pub fn generate_inputs(
         &self,
         prev_ciphertext: &[u8],
         public_key: &[u8],
         vote: u8,
     ) -> Result<JsValue, JsValue> {
-        match self
-            .generator
-            .generate_inputs(prev_ciphertext, public_key, vote)
-        {
-            Ok(inputs_json) => {
-                // Parse the JSON string and return as JsValue.
-                match js_sys::JSON::parse(&inputs_json) {
-                    Ok(js_value) => Ok(js_value),
-                    Err(_) => Err(JsValue::from_str("Failed to parse inputs JSON")),
-                }
-            }
-            Err(e) => Err(JsValue::from_str(&e.to_string())),
-        }
+        use wasm_bindgen::JsError;
+        let inputs_json = self
+            .generator
+            .generate_inputs(prev_ciphertext, public_key, vote)
+            .map_err(|e| JsError::new(&e.to_string()))?;
+        js_sys::JSON::parse(&inputs_json)
+            .map_err(|e| JsError::new(&format!("Failed to parse inputs JSON: {e:?}")).into())
     }

69-76: Consistent error mapping across bindings

Return JsError instead of stringly JsValue for generatePublicKey and encryptVote.

-    pub fn generate_public_key(&self) -> Result<Vec<u8>, JsValue> {
-        match self.generator.generate_public_key() {
-            Ok(public_key_bytes) => Ok(public_key_bytes),
-            Err(e) => Err(JsValue::from_str(&e.to_string())),
-        }
-    }
+    pub fn generate_public_key(&self) -> Result<Vec<u8>, JsValue> {
+        use wasm_bindgen::JsError;
+        self.generator
+            .generate_public_key()
+            .map_err(|e| JsError::new(&e.to_string()).into())
+    }
@@
-    pub fn encrypt_vote(&self, public_key: &[u8], vote: u8) -> Result<Vec<u8>, JsValue> {
-        match self.generator.encrypt_vote(public_key, vote) {
-            Ok(ciphertext_bytes) => Ok(ciphertext_bytes),
-            Err(e) => Err(JsValue::from_str(&e.to_string())),
-        }
-    }
+    pub fn encrypt_vote(&self, public_key: &[u8], vote: u8) -> Result<Vec<u8>, JsValue> {
+        use wasm_bindgen::JsError;
+        self.generator
+            .encrypt_vote(public_key, vote)
+            .map_err(|e| JsError::new(&e.to_string()).into())
+    }

Also applies to: 79-85

examples/CRISP/crates/zk-inputs/src/lib.rs (2)

50-53: Mirror fallible ctor for defaults or guarantee non‑panic

with_defaults() relies on new(). If defaults can never fail, fine; otherwise prefer the fallible variant.

Option A (safe):

-    pub fn with_defaults() -> Self {
-        Self::new(DEFAULT_DEGREE, DEFAULT_PLAINTEXT_MODULUS, &DEFAULT_MODULI)
-    }
+    pub fn try_with_defaults() -> Result<Self> {
+        Self::try_new(DEFAULT_DEGREE, DEFAULT_PLAINTEXT_MODULUS, &DEFAULT_MODULI)
+    }

Option B (documented guarantee): keep as-is but add a /// # Panics doc note stating defaults are known-valid.


166-207: Tests look solid; consider one negative case for invalid vote

Add a test that generate_inputs(..., 2) and encrypt_vote(..., 2) return Err after the validation above. Keeps behavior explicit.

examples/CRISP/crates/zk-inputs-wasm/Cargo.toml (2)

9-11: Add rlib for tests and publish = false to prevent accidental release (example crate)

Not required, but improves DX and safety.

 [lib]
-crate-type = ["cdylib"]
+crate-type = ["cdylib", "rlib"]
+
+[package]
+# ...
+publish = false

Optional (if using wasm-pack): add

[package.metadata.wasm-pack.profile.release]
wasm-opt = ['-Os']

12-18: Version alignment tip

Keep wasm-bindgen, wasm-bindgen-test, js-sys, and web-sys on compatible minor versions to avoid linker mismatches. Current specs look fine; pinning exact minors can reduce CI flakes.

examples/CRISP/packages/crisp-sdk/tests/vote.test.ts (2)

7-12: Remove unused imports

fs, path, and beforeAll are unused after the change.

-import fs from 'fs/promises'
-import path from 'path'
-import { describe, it, expect, beforeAll } from 'vitest'
+import { describe, it, expect } from 'vitest'

122-124: Initialize WASM-backed generator in a setup hook to avoid early evaluation

Creating the generator at describe scope can run before WASM is fully initialized in some runners. Initialize once in a setup hook.

-    let zkInputsGenerator = ZKInputsGenerator.withDefaults()
-    let publicKey = zkInputsGenerator.generatePublicKey()
+    let zkInputsGenerator: ZKInputsGenerator
+    let publicKey: Uint8Array
+
+    // If your package requires explicit async init, call it here and await.
+    // e.g., const init = (await import('@enclave/crisp-zk-inputs/init.js')).default; await init();
+    beforeAll(() => {
+      zkInputsGenerator = ZKInputsGenerator.withDefaults()
+      publicKey = zkInputsGenerator.generatePublicKey()
+    })

Please run the test once with --runInBand to confirm no flakiness due to WASM init order.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c316a53 and 7f6ad2d.

⛔ Files ignored due to path filters (3)
  • examples/CRISP/Cargo.lock is excluded by !**/*.lock
  • examples/CRISP/packages/crisp-sdk/tests/fixtures/pubkey.bin is excluded by !**/*.bin
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • .vscode/settings.json (1 hunks)
  • Cargo.toml (0 hunks)
  • examples/CRISP/Cargo.toml (1 hunks)
  • examples/CRISP/crates/zk-inputs-wasm/Cargo.toml (1 hunks)
  • examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1 hunks)
  • examples/CRISP/crates/zk-inputs/Cargo.toml (1 hunks)
  • examples/CRISP/crates/zk-inputs/src/lib.rs (16 hunks)
  • examples/CRISP/crates/zk-inputs/src/serialization.rs (6 hunks)
  • examples/CRISP/docker-compose.yaml (2 hunks)
  • examples/CRISP/package.json (1 hunks)
  • examples/CRISP/packages/crisp-contracts/deployed_contracts.json (1 hunks)
  • examples/CRISP/packages/crisp-sdk/package.json (2 hunks)
  • examples/CRISP/packages/crisp-sdk/tests/vote.test.ts (2 hunks)
  • examples/CRISP/packages/crisp-sdk/vite.config.ts (1 hunks)
  • examples/CRISP/server/Dockerfile (2 hunks)
  • pnpm-workspace.yaml (1 hunks)
💤 Files with no reviewable changes (1)
  • Cargo.toml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-25T10:28:56.174Z
Learnt from: ctrlc03
PR: gnosisguild/enclave#657
File: Cargo.toml:32-34
Timestamp: 2025-08-25T10:28:56.174Z
Learning: The examples/CRISP directory has its own Cargo.toml workspace configuration with members like "server", "wasm-crypto", "program/core", "program/client", etc. The root workspace intentionally excludes "examples/CRISP/server", "examples/CRISP/program", and "examples/CRISP/wasm-crypto" to prevent double workspace membership, which is the correct approach for self-contained example workspaces.

Applied to files:

  • examples/CRISP/Cargo.toml
  • examples/CRISP/crates/zk-inputs-wasm/Cargo.toml
  • examples/CRISP/docker-compose.yaml
  • examples/CRISP/server/Dockerfile
  • pnpm-workspace.yaml
📚 Learning: 2024-10-03T23:02:41.732Z
Learnt from: ryardley
PR: gnosisguild/enclave#133
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:137-139
Timestamp: 2024-10-03T23:02:41.732Z
Learning: In `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, using the same RNG instance `rng_test` for generating multiple key shares without advancing its state is acceptable.

Applied to files:

  • examples/CRISP/crates/zk-inputs/src/lib.rs
🧬 Code graph analysis (2)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1)
examples/CRISP/crates/zk-inputs/src/lib.rs (5)
  • new (40-48)
  • with_defaults (51-53)
  • generate_inputs (64-119)
  • generate_public_key (151-158)
  • encrypt_vote (129-145)
examples/CRISP/crates/zk-inputs/src/lib.rs (2)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (5)
  • new (30-37)
  • with_defaults (41-44)
  • generate_inputs (48-67)
  • encrypt_vote (80-85)
  • generate_public_key (71-76)
examples/CRISP/crates/zk-inputs/src/ciphertext_addition.rs (1)
  • new (42-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: build_sdk
  • GitHub Check: test_net
  • GitHub Check: integration_prebuild
  • GitHub Check: rust_unit
  • GitHub Check: test_contracts
  • GitHub Check: build_enclave_cli
  • GitHub Check: build_e3_support_risc0
  • GitHub Check: rust_integration
  • GitHub Check: Build & Push Image
  • GitHub Check: Build & Push Image
🔇 Additional comments (13)
examples/CRISP/packages/crisp-contracts/deployed_contracts.json (1)

85-162: Remove the imageId verification request; clarify that localhost addresses require fresh deployment scripts.

The imageId is a cryptographic hash of the ELF file required for verification, and containerized builds ensure the same ImageID across all environments. This is correct and intentional—no changes needed.

However, local blockchains do not persist state across runs; you must re-deploy contracts after restarting. The stored localhost addresses in this file will become stale each time the local blockchain is restarted. Ensure your deployment scripts regenerate these addresses dynamically rather than relying on static values from this config file.

examples/CRISP/docker-compose.yaml (1)

16-16: LGTM! Volume rename aligns with crate restructuring.

The volume name change from generator-target to zk-inputs-target is correct and consistent between the volume mount and declaration.

Also applies to: 44-44

examples/CRISP/server/Dockerfile (1)

34-34: LGTM! Dockerfile paths updated correctly.

The COPY commands in both the chef and planner stages now correctly reference the new zk-inputs crate path, aligning with the workspace restructuring.

Also applies to: 55-55

examples/CRISP/package.json (1)

23-24: LGTM! WASM build script properly configured.

The new build:wasm script correctly configures wasm-pack to build the zk-inputs-wasm crate with the appropriate scope and output directory that aligns with the workspace structure.

pnpm-workspace.yaml (1)

8-8: LGTM! Workspace package added correctly.

The new workspace path for crisp-zk-inputs aligns with the wasm-pack output directory configured in the build script.

examples/CRISP/crates/zk-inputs/Cargo.toml (1)

2-2: LGTM! Package name simplified appropriately.

The package name change from crisp-zk-inputs to zk-inputs is consistent with the crate restructuring and simplifies the naming convention.

.vscode/settings.json (1)

4-4: LGTM! VSCode settings updated for new crate structure.

The rust-analyzer linked projects correctly reference the new zk-inputs and zk-inputs-wasm crates, replacing the old wasm-crypto reference. The array formatting changes are also appropriate.

Also applies to: 7-7, 13-14

examples/CRISP/packages/crisp-sdk/vite.config.ts (1)

1-15: LGTM! Vite configuration properly set up for WASM support.

The new configuration correctly enables WASM support through the vite-plugin-wasm and sets the test environment to 'node', which is appropriate for the SDK testing workflow.

examples/CRISP/crates/zk-inputs/src/serialization.rs (1)

20-20: LGTM! Type rename applied consistently.

The rename from CrispZKInputs to ZKInputs is applied consistently throughout the struct definition, function signatures, and documentation. The refactoring is clean with no logic changes.

Also applies to: 57-57, 161-161, 258-258

examples/CRISP/Cargo.toml (1)

6-7: No workspace membership issues detected

Verified: crates/zk-inputs and crates/zk-inputs-wasm are only listed in the examples/CRISP/Cargo.toml workspace and are not duplicated in the root workspace. These crates remain properly isolated with no double membership or feature unification conflicts.

examples/CRISP/packages/crisp-sdk/package.json (3)

22-23: Verify build script integration and WASM output location.

The build script now chains build:wasm && tsc, which assumes the WASM build output from ../../ is accessible to TypeScript compilation. Clarify:

  1. Where does pnpm -C ../../ build:wasm place the generated WASM and binding files?
  2. Are they configured to be importable from this package's source code (e.g., via paths in tsconfig.json or vite configuration)?
  3. Does the build process clean stale WASM artifacts before regenerating?

38-39: Verify Vite configuration for WASM support.

vite and vite-plugin-wasm are added as dev dependencies, suggesting this package uses Vite for bundling. However, the provided context does not include a vite.config.ts (or vite.config.js) file. Verify:

  1. Does a Vite configuration file exist in this package? If so, does it reference vite-plugin-wasm?
  2. If not, is the Vite config inherited from a parent workspace configuration?
  3. Are TypeScript paths configured to resolve WASM imports correctly?

43-43: Verify the new dependency is actually used.

@enclave/crisp-zk-inputs is declared as a dependency, but it's unclear from this file whether it's actually imported and used in the source code. Verify:

  1. Is this package imported in any source files (e.g., src/index.ts)?
  2. If so, confirm that the API (e.g., ZKInputsGenerator, methods like generatePublicKey) matches the new WASM bindings exposed by the crate.
  3. Check for any circular dependencies or import path issues between this package and @enclave/crisp-zk-inputs.

Comment thread examples/CRISP/crates/zk-inputs-wasm/src/lib.rs
ctrlc03
ctrlc03 previously approved these changes Oct 27, 2025

@ctrlc03 ctrlc03 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

@vercel vercel Bot temporarily deployed to Preview – enclave-docs October 27, 2025 12:51 Inactive
@cedoor cedoor enabled auto-merge (squash) October 27, 2025 12:51
@vercel vercel Bot temporarily deployed to Preview – crisp October 27, 2025 12:51 Inactive
@cedoor cedoor requested a review from ctrlc03 October 27, 2025 12:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
examples/CRISP/crates/zk-inputs/src/lib.rs (2)

76-83: Reject invalid vote values instead of coercing

Currently, any non‑1 becomes 0. This is silent data corruption for out‑of‑range inputs.

-        // Set vote value (0 or 1) in the first coefficient.
-        message_data[0] = if vote == 1 { 1 } else { 0 };
+        // Validate vote ∈ {0,1}.
+        if vote > 1 {
+            return Err(eyre::eyre!("vote must be 0 or 1"));
+        }
+        // Set vote value (0 or 1) in the first coefficient.
+        message_data[0] = if vote == 1 { 1 } else { 0 };

Apply the same check in encrypt_vote:

-        // Set vote value (0 or 1) in the first coefficient.
-        message_data[0] = if vote == 1 { 1 } else { 0 };
+        if vote > 1 {
+            return Err(eyre::eyre!("vote must be 0 or 1"));
+        }
+        message_data[0] = if vote == 1 { 1 } else { 0 };

Also applies to: 133-139


20-20: Use OsRng for cryptographic randomness

Prefer OsRng for keygen and encryption to align with cryptographic best practices across targets (including WASM via Web Crypto).

-use rand::thread_rng;
+use rand::rngs::OsRng;
...
-        let (ct, u_rns, e0_rns, e1_rns) = pk
-            .try_encrypt_extended(&pt, &mut thread_rng())
+        let (ct, u_rns, e0_rns, e1_rns) = pk
+            .try_encrypt_extended(&pt, &mut OsRng)
             .with_context(|| "Failed to encrypt plaintext")?;
...
-        let (ct, _u_rns, _e0_rns, _e1_rns) = pk
-            .try_encrypt_extended(&pt, &mut thread_rng())
+        let (ct, _u_rns, _e0_rns, _e1_rns) = pk
+            .try_encrypt_extended(&pt, &mut OsRng)
             .with_context(|| "Failed to encrypt plaintext")?;
...
-        let mut rng = thread_rng();
+        let mut rng = OsRng;
         let sk = SecretKey::random(&self.bfv_params, &mut rng);
         let pk = PublicKey::new(&sk, &mut rng);

Also applies to: 85-87, 140-142, 153-156

♻️ Duplicate comments (1)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1)

29-38: Resolved: ctor no longer panics (now returns Result) — good change

Switching to core’s Result-returning constructor prevents WASM aborts on invalid params. This addresses the earlier concern.

🧹 Nitpick comments (5)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (4)

35-37: Return JsError for proper JS exceptions

Map errors to JsError so callers get real Error objects (message/stack) instead of raw strings.

-        let generator = CoreZKInputsGenerator::new(degree, plaintext_modulus, &moduli)
-            .map_err(|e| JsValue::from_str(&e.to_string()))?;
+        use wasm_bindgen::JsError;
+        let generator = CoreZKInputsGenerator::new(degree, plaintext_modulus, &moduli)
+            .map_err(|e| JsError::new(&e.to_string()))?;
...
-        let generator = CoreZKInputsGenerator::with_defaults()
-            .map_err(|e| JsValue::from_str(&e.to_string()))?;
+        let generator = CoreZKInputsGenerator::with_defaults()
+            .map_err(|e| JsError::new(&e.to_string()))?;
...
-            Err(e) => Err(JsValue::from_str(&e.to_string())),
+            Err(e) => Err(JsError::new(&e.to_string()).into()),
...
-            Err(e) => Err(JsValue::from_str(&e.to_string())),
+            Err(e) => Err(JsError::new(&e.to_string()).into()),
...
-            Err(e) => Err(JsValue::from_str(&e.to_string())),
+            Err(e) => Err(JsError::new(&e.to_string()).into()),

Also applies to: 42-46, 67-68, 74-77, 83-86


31-34: Beware: Vec from JS requires BigInt/BigUint64Array

JS must pass bigint[] (or BigUint64Array). Many apps still pass number[]. Consider:

  • Documenting bigint[] requirement in JSDoc/README, or
  • Providing an alt ctor accepting string[] (hex/dec) or Uint32Array[] pairs, or
  • Accepting js_sys::BigUint64Array and converting internally.

Do your TS consumers already pass bigint[]? If not, I can draft a newWithModuliStrings(moduli: string[]) helper.


11-11: Remove unnecessary crate import

use js_sys; is redundant since you reference js_sys::JSON with a fully-qualified path.

-use js_sys;

61-65: Preserve JSON parse error details

Surface the underlying parse error to aid debugging.

-                    Err(_) => Err(JsValue::from_str("Failed to parse inputs JSON")),
+                    Err(e) => {
+                        let msg = js_sys::JSON::stringify(&e)
+                            .ok()
+                            .and_then(|s| s.as_string())
+                            .unwrap_or_else(|| "Failed to parse inputs JSON".to_string());
+                        Err(wasm_bindgen::JsError::new(&msg).into())
+                    },
examples/CRISP/crates/zk-inputs/src/lib.rs (1)

63-69: Consider returning structured JSON instead of String

If consumers are primarily JS/WASM, returning serde_json::Value avoids stringify→parse roundtrips and preserves types. The WASM layer can pass it directly via serde_wasm_bindgen.

If acceptable, I can provide a follow‑up patch switching generate_inputs to Result<serde_json::Value> and updating the WASM binding accordingly.

Also applies to: 118-119

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f6ad2d and b9be10f.

📒 Files selected for processing (2)
  • examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1 hunks)
  • examples/CRISP/crates/zk-inputs/src/lib.rs (15 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
examples/CRISP/crates/zk-inputs/src/lib.rs (2)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (5)
  • new (30-38)
  • with_defaults (42-46)
  • generate_inputs (50-69)
  • encrypt_vote (82-87)
  • generate_public_key (73-78)
templates/default/program/src/lib.rs (1)
  • test (37-72)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1)
examples/CRISP/crates/zk-inputs/src/lib.rs (5)
  • new (40-48)
  • with_defaults (51-53)
  • generate_inputs (64-119)
  • generate_public_key (151-158)
  • encrypt_vote (129-145)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: build_sdk
  • GitHub Check: build_enclave_cli
  • GitHub Check: rust_unit
  • GitHub Check: integration_prebuild
  • GitHub Check: test_net
  • GitHub Check: rust_integration
  • GitHub Check: test_contracts
  • GitHub Check: build_e3_support_risc0
  • GitHub Check: Build & Push Image
  • GitHub Check: Build & Push Image
🔇 Additional comments (1)
examples/CRISP/crates/zk-inputs/src/lib.rs (1)

170-187: Tests: great coverage; add a negative test for vote > 1 once validation lands

After adding vote validation, assert errors for vote=2 in both generate_inputs and encrypt_vote.

Would you like me to append those two negative tests now?

Also applies to: 189-207, 210-226, 262-277, 281-297, 299-308, 311-335, 339-364

Comment thread examples/CRISP/crates/zk-inputs-wasm/src/lib.rs
@cedoor cedoor merged commit f2463fa into dev Oct 27, 2025
25 checks passed
@github-actions github-actions Bot deleted the feat/wasm-ct-add-2 branch November 4, 2025 03:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create JS library with WASM bindings for ZK inputs generator

2 participants