From 6aa05b1b8377c0889fb6828fceef00eb3fcbee8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Thu, 11 Sep 2025 11:57:20 +0200 Subject: [PATCH 01/75] cargo: add comment about cdylib --- plonk-napi/Cargo.toml | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 plonk-napi/Cargo.toml diff --git a/plonk-napi/Cargo.toml b/plonk-napi/Cargo.toml new file mode 100644 index 0000000000..50f443b10c --- /dev/null +++ b/plonk-napi/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "plonk-napi" +version = "0.1.0" +authors = ["opensource@o1labs.org"] +description = "Node-API bindings for plonk proof systems" +repository = "https://github.com/MinaProtocol/mina" +license = "MIT/Apache-2.0" +edition = "2021" + +[lib] +name = "plonk_napi" +crate-type = ["cdylib"] # to generate a dynamic library that is loadable by Node + +[dependencies] +napi = { workspace = true, features = ["napi7"] } +napi-derive.workspace = true + +# arkworks +ark-ec.workspace = true +ark-ff.workspace = true +ark-poly.workspace = true +ark-serialize.workspace = true +arkworks.workspace = true + +# proof-systems +mina-curves = { path = "../curves" } +mina-poseidon = { path = "../poseidon" } +o1-utils = { path = "../utils" } +poly-commitment = { path = "../poly-commitment" } +kimchi = { path = "../kimchi" } + +getrandom.workspace = true +libc.workspace = true +num-bigint.workspace = true +once_cell.workspace = true +paste.workspace = true +rand.workspace = true +rayon.workspace = true +rmp-serde.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +wasm-types.workspace = true + +[build-dependencies] +napi-build.workspace = true From d02ec8301ceac456ff5ff02121779e0564829ca5 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 22 Sep 2025 20:01:32 +0200 Subject: [PATCH 02/75] napi: poseidon ffi --- Cargo.lock | 85 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 ++ plonk-napi/Cargo.toml | 3 -- plonk-napi/build.rs | 3 ++ plonk-napi/src/lib.rs | 6 +++ plonk-napi/src/poseidon.rs | 52 +++++++++++++++++++++++ 6 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 plonk-napi/build.rs create mode 100644 plonk-napi/src/lib.rs create mode 100644 plonk-napi/src/poseidon.rs diff --git a/Cargo.lock b/Cargo.lock index 62d96b5876..cccd069127 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2386,6 +2386,63 @@ dependencies = [ "rand", ] +[[package]] +name = "napi" +version = "2.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55740c4ae1d8696773c78fdafd5d0e5fe9bc9f1b071c7ba493ba5c413a9184f3" +dependencies = [ + "bitflags 2.4.2", + "ctor", + "napi-derive", + "napi-sys", + "once_cell", +] + +[[package]] +name = "napi-build" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcae8ad5609d14afb3a3b91dee88c757016261b151e9dcecabf1b2a31a6cab14" + +[[package]] +name = "napi-derive" +version = "2.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c" +dependencies = [ + "cfg-if 1.0.0", + "convert_case", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "napi-derive-backend" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf" +dependencies = [ + "convert_case", + "once_cell", + "proc-macro2", + "quote", + "regex", + "semver", + "syn 2.0.100", +] + +[[package]] +name = "napi-sys" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" +dependencies = [ + "libloading", +] + [[package]] name = "neon" version = "1.0.0" @@ -2867,6 +2924,34 @@ dependencies = [ "time", ] +[[package]] +name = "plonk-napi" +version = "0.1.0" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "arkworks", + "getrandom 0.2.15", + "libc", + "mina-curves", + "mina-poseidon", + "napi", + "napi-build", + "napi-derive", + "num-bigint", + "o1-utils", + "once_cell", + "paste", + "rand", + "rayon", + "rmp-serde", + "serde", + "serde_with", + "wasm-types", +] + [[package]] name = "plonk_neon" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a4303d9237..cbb7773e07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "mvpoly", "o1vm", "plonk-neon", + "plonk-napi", "plonk-wasm", "poly-commitment", "poseidon", @@ -61,6 +62,9 @@ libflate = "2" log = "0.4.20" num-bigint = { version = "0.4.4", features = ["rand", "serde"] } num-integer = "0.1.45" +napi = { version = "2.16.8", default-features = false, features = ["napi7"] } +napi-derive = "2.16.8" +napi-build = "2.1.0" ocaml = { version = "0.22.2" } ocaml-gen = { version = "1.0.0" } once_cell = "=1.21.3" diff --git a/plonk-napi/Cargo.toml b/plonk-napi/Cargo.toml index 50f443b10c..87dfbbd0da 100644 --- a/plonk-napi/Cargo.toml +++ b/plonk-napi/Cargo.toml @@ -26,8 +26,6 @@ arkworks.workspace = true mina-curves = { path = "../curves" } mina-poseidon = { path = "../poseidon" } o1-utils = { path = "../utils" } -poly-commitment = { path = "../poly-commitment" } -kimchi = { path = "../kimchi" } getrandom.workspace = true libc.workspace = true @@ -38,7 +36,6 @@ rand.workspace = true rayon.workspace = true rmp-serde.workspace = true serde.workspace = true -serde_json.workspace = true serde_with.workspace = true wasm-types.workspace = true diff --git a/plonk-napi/build.rs b/plonk-napi/build.rs new file mode 100644 index 0000000000..0f1b01002b --- /dev/null +++ b/plonk-napi/build.rs @@ -0,0 +1,3 @@ +fn main() { + napi_build::setup(); +} diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs new file mode 100644 index 0000000000..ce7da054aa --- /dev/null +++ b/plonk-napi/src/lib.rs @@ -0,0 +1,6 @@ +mod poseidon; + +pub use poseidon::{ + caml_pasta_fp_poseidon_block_cipher, + caml_pasta_fq_poseidon_block_cipher, +}; diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs new file mode 100644 index 0000000000..c44d9921bd --- /dev/null +++ b/plonk-napi/src/poseidon.rs @@ -0,0 +1,52 @@ +use arkworks::{WasmPastaFp, WasmPastaFq}; +use mina_curves::pasta::{Fp, Fq}; +use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, permutation::poseidon_block_cipher}; +use napi::bindgen_prelude::*; +use napi_derive::napi; +use wasm_types::{FlatVector, FlatVectorElem}; + +// fp + +#[napi] +pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result> { + let mut state: Vec = FlatVector::::from_bytes(state.to_vec()) + .into_iter() + .map(Into::into) + .collect(); + + poseidon_block_cipher::( + mina_poseidon::pasta::fp_kimchi::static_params(), + &mut state, + ); + + let res = state + .into_iter() + .map(WasmPastaFp) + .flat_map(FlatVectorElem::flatten) + .collect(); + + Ok(res) +} + +// fq + +#[napi] +pub fn caml_pasta_fq_poseidon_block_cipher(state: Uint8Array) -> Result> { + let mut state: Vec = FlatVector::::from_bytes(state.to_vec()) + .into_iter() + .map(Into::into) + .collect(); + + poseidon_block_cipher::( + mina_poseidon::pasta::fq_kimchi::static_params(), + &mut state, + ); + + let res = state + .into_iter() + .map(WasmPastaFq) + .flat_map(FlatVectorElem::flatten) + .collect(); + + Ok(res) +} From 18a237054ce5bc9426b83a6e6fbe088649132319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Mon, 29 Sep 2025 20:14:23 +0200 Subject: [PATCH 03/75] minor: rename variable to avoid confusion --- plonk-napi/src/poseidon.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index c44d9921bd..337e771071 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -9,17 +9,17 @@ use wasm_types::{FlatVector, FlatVectorElem}; #[napi] pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result> { - let mut state: Vec = FlatVector::::from_bytes(state.to_vec()) + let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) .collect(); poseidon_block_cipher::( mina_poseidon::pasta::fp_kimchi::static_params(), - &mut state, + &mut state_vec, ); - let res = state + let res = state_vec .into_iter() .map(WasmPastaFp) .flat_map(FlatVectorElem::flatten) @@ -32,17 +32,17 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result> #[napi] pub fn caml_pasta_fq_poseidon_block_cipher(state: Uint8Array) -> Result> { - let mut state: Vec = FlatVector::::from_bytes(state.to_vec()) + let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) .collect(); poseidon_block_cipher::( mina_poseidon::pasta::fq_kimchi::static_params(), - &mut state, + &mut state_vec, ); - let res = state + let res = state_vec .into_iter() .map(WasmPastaFq) .flat_map(FlatVectorElem::flatten) From cd24f576fc09b8e13300a165fe2bd63ded81b56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Tue, 30 Sep 2025 13:30:11 +0200 Subject: [PATCH 04/75] types: change output types of poseidon ffi to fix o1js tests --- plonk-napi/src/poseidon.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index 337e771071..fc612e21bf 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -8,7 +8,7 @@ use wasm_types::{FlatVector, FlatVectorElem}; // fp #[napi] -pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result> { +pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result { let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) @@ -19,19 +19,19 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result> &mut state_vec, ); - let res = state_vec + let res: Vec = state_vec .into_iter() .map(WasmPastaFp) .flat_map(FlatVectorElem::flatten) .collect(); - Ok(res) + Ok(Uint8Array::from(res)) } // fq #[napi] -pub fn caml_pasta_fq_poseidon_block_cipher(state: Uint8Array) -> Result> { +pub fn caml_pasta_fq_poseidon_block_cipher(state: Uint8Array) -> Result { let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) @@ -42,11 +42,11 @@ pub fn caml_pasta_fq_poseidon_block_cipher(state: Uint8Array) -> Result> &mut state_vec, ); - let res = state_vec + let res: Vec = state_vec .into_iter() .map(WasmPastaFq) .flat_map(FlatVectorElem::flatten) .collect(); - Ok(res) + Ok(Uint8Array::from(res)) } From 2a07e99eb6cbef041a5fa918e3c4638659ac5734 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 8 Oct 2025 15:51:37 +0700 Subject: [PATCH 05/75] dummy logs --- plonk-napi/src/poseidon.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index fc612e21bf..dc7c9f108d 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -9,6 +9,8 @@ use wasm_types::{FlatVector, FlatVectorElem}; #[napi] pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result { + println!("from native rust"); + let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) @@ -32,6 +34,8 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result Result { + println!("from native rust"); + let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) From 9286836d14d030ee7b669bf0a8a29125e7ad1ab4 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 18:42:52 +0700 Subject: [PATCH 06/75] re-implement `circuit.rs ` --- Cargo.lock | 3 +++ plonk-napi/Cargo.toml | 3 +++ plonk-napi/src/circuit.rs | 36 ++++++++++++++++++++++++++++++++++++ plonk-napi/src/lib.rs | 10 ++++++---- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 plonk-napi/src/circuit.rs diff --git a/Cargo.lock b/Cargo.lock index cccd069127..d7aaf3c947 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2934,6 +2934,7 @@ dependencies = [ "ark-serialize", "arkworks", "getrandom 0.2.15", + "kimchi", "libc", "mina-curves", "mina-poseidon", @@ -2944,10 +2945,12 @@ dependencies = [ "o1-utils", "once_cell", "paste", + "poly-commitment", "rand", "rayon", "rmp-serde", "serde", + "serde_json", "serde_with", "wasm-types", ] diff --git a/plonk-napi/Cargo.toml b/plonk-napi/Cargo.toml index 87dfbbd0da..6cfa08e0e6 100644 --- a/plonk-napi/Cargo.toml +++ b/plonk-napi/Cargo.toml @@ -23,9 +23,11 @@ ark-serialize.workspace = true arkworks.workspace = true # proof-systems +kimchi.workspace = true mina-curves = { path = "../curves" } mina-poseidon = { path = "../poseidon" } o1-utils = { path = "../utils" } +poly-commitment = { path = "../poly-commitment" } getrandom.workspace = true libc.workspace = true @@ -36,6 +38,7 @@ rand.workspace = true rayon.workspace = true rmp-serde.workspace = true serde.workspace = true +serde_json.workspace = true serde_with.workspace = true wasm-types.workspace = true diff --git a/plonk-napi/src/circuit.rs b/plonk-napi/src/circuit.rs new file mode 100644 index 0000000000..0c2a850228 --- /dev/null +++ b/plonk-napi/src/circuit.rs @@ -0,0 +1,36 @@ +use ark_ff::PrimeField; +use kimchi::circuits::{constraints::ConstraintSystem, gate::CircuitGate}; +use mina_curves::pasta::Fp; +use napi::bindgen_prelude::*; +use napi_derive::napi; +use serde::Serialize; + +use crate::types::WasmPastaFpPlonkIndex; + +#[derive(Serialize)] +struct Circuit +where + F: PrimeField, +{ + public_input_size: usize, + #[serde(bound = "CircuitGate: Serialize")] + gates: Vec>, +} + +impl From<&ConstraintSystem> for Circuit +where + F: PrimeField, +{ + fn from(cs: &ConstraintSystem) -> Self { + Self { + public_input_size: cs.public, + gates: cs.gates.to_vec(), + } + } +} + +#[napi] +pub fn prover_to_json(prover_index: External) -> String { + let circuit: Circuit = prover_index.0.cs.as_ref().into(); + serde_json::to_string(&circuit).expect("couldn't serialize constraints") +} diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index ce7da054aa..f0c304a7b9 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,6 +1,8 @@ +mod circuit; mod poseidon; +mod types; -pub use poseidon::{ - caml_pasta_fp_poseidon_block_cipher, - caml_pasta_fq_poseidon_block_cipher, -}; +pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; + +pub use circuit::prover_to_json; +pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; From cf6b541b0e6637cf2ca00552b60b6a32b48a9754 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 18:42:58 +0700 Subject: [PATCH 07/75] hack serialisation for now --- plonk-napi/src/types.rs | 79 ++++++++++++++++++++++++++ plonk-wasm/src/pasta_fp_plonk_index.rs | 68 +++++++++++++++++++++- 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 plonk-napi/src/types.rs diff --git a/plonk-napi/src/types.rs b/plonk-napi/src/types.rs new file mode 100644 index 0000000000..985bf50d35 --- /dev/null +++ b/plonk-napi/src/types.rs @@ -0,0 +1,79 @@ +use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; +use mina_curves::pasta::{Vesta as GAffine, VestaParameters}; +use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; +use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi_derive::napi; +use poly_commitment::ipa::{OpeningProof, SRS}; +use serde::{Deserialize, Serialize}; +use std::{io::Cursor, sync::Arc}; + +pub struct WasmPastaFpPlonkIndex(pub Box>>); + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[derive(Serialize, Deserialize)] +struct SerializedProverIndex { + prover_index: Vec, + srs: Vec, +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +impl WasmPastaFpPlonkIndex { + fn serialize_inner(&self) -> Result, String> { + let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; + + let mut srs = Vec::new(); + self.0 + .srs + .serialize(&mut rmp_serde::Serializer::new(&mut srs)) + .map_err(|e| e.to_string())?; + + let serialized = SerializedProverIndex { prover_index, srs }; + + rmp_serde::to_vec(&serialized).map_err(|e| e.to_string()) + } + + fn deserialize_inner(bytes: &[u8]) -> Result { + let serialized: SerializedProverIndex = + rmp_serde::from_slice(bytes).map_err(|e| e.to_string())?; + + let mut index: ProverIndex> = ProverIndex::deserialize( + &mut rmp_serde::Deserializer::new(Cursor::new(serialized.prover_index)), + ) + .map_err(|e| e.to_string())?; + + let srs = SRS::::deserialize(&mut rmp_serde::Deserializer::new(Cursor::new( + serialized.srs, + ))) + .map_err(|e| e.to_string())?; + + index.srs = Arc::new(srs); + + let (linearization, powers_of_alpha) = + expr_linearization(Some(&index.cs.feature_flags), true); + index.linearization = linearization; + index.powers_of_alpha = powers_of_alpha; + + index.compute_verifier_index_digest::< + DefaultFqSponge, + >(); + + Ok(WasmPastaFpPlonkIndex(Box::new(index))) + } +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[napi] +pub fn prover_index_from_bytes(bytes: Uint8Array) -> NapiResult> { + let index = WasmPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) + .map_err(|e| Error::new(Status::InvalidArg, e))?; + Ok(External::new(index)) +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[napi] +pub fn prover_index_to_bytes(index: External) -> NapiResult { + let bytes = index + .serialize_inner() + .map_err(|e| Error::new(Status::GenericFailure, e))?; + Ok(Uint8Array::from(bytes)) +} diff --git a/plonk-wasm/src/pasta_fp_plonk_index.rs b/plonk-wasm/src/pasta_fp_plonk_index.rs index b56347c23f..5af8cdf550 100644 --- a/plonk-wasm/src/pasta_fp_plonk_index.rs +++ b/plonk-wasm/src/pasta_fp_plonk_index.rs @@ -20,7 +20,8 @@ use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSpon use serde::{Deserialize, Serialize}; use std::{ fs::{File, OpenOptions}, - io::{BufReader, BufWriter, Seek, SeekFrom::Start}, + io::{BufReader, BufWriter, Cursor, Seek, SeekFrom::Start}, + sync::Arc, }; use wasm_bindgen::prelude::*; use wasm_types::FlatVector as WasmFlatVector; @@ -35,6 +36,71 @@ pub struct WasmPastaFpPlonkIndex( #[wasm_bindgen(skip)] pub Box>>, ); +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[derive(Serialize, Deserialize)] +struct SerializedProverIndex { + prover_index: Vec, + srs: Vec, +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[wasm_bindgen] +impl WasmPastaFpPlonkIndex { + #[wasm_bindgen(js_name = "serialize")] + pub fn serialize(&self) -> Result, JsError> { + serialize_prover_index(self.0.as_ref()) + .map_err(|e| JsError::new(&format!("WasmPastaFpPlonkIndex::serialize: {e}"))) + } + + #[wasm_bindgen(js_name = "deserialize")] + pub fn deserialize(bytes: &[u8]) -> Result { + deserialize_prover_index(bytes) + .map(WasmPastaFpPlonkIndex) + .map_err(|e| JsError::new(&format!("WasmPastaFpPlonkIndex::deserialize: {e}"))) + } +} + +fn serialize_prover_index( + index: &ProverIndex>, +) -> Result, String> { + let prover_index = rmp_serde::to_vec(index).map_err(|e| e.to_string())?; + + let mut srs = Vec::new(); + index + .srs + .serialize(&mut rmp_serde::Serializer::new(&mut srs)) + .map_err(|e| e.to_string())?; + + let serialized = SerializedProverIndex { prover_index, srs }; + + rmp_serde::to_vec(&serialized).map_err(|e| e.to_string()) +} + +fn deserialize_prover_index( + bytes: &[u8], +) -> Result>>, String> { + let serialized: SerializedProverIndex = + rmp_serde::from_slice(bytes).map_err(|e| e.to_string())?; + + let mut index: ProverIndex> = ProverIndex::deserialize( + &mut rmp_serde::Deserializer::new(Cursor::new(serialized.prover_index)), + ) + .map_err(|e| e.to_string())?; + + let srs = poly_commitment::ipa::SRS::::deserialize(&mut rmp_serde::Deserializer::new( + Cursor::new(serialized.srs), + )) + .map_err(|e| e.to_string())?; + + index.srs = Arc::new(srs); + + let (linearization, powers_of_alpha) = expr_linearization(Some(&index.cs.feature_flags), true); + index.linearization = linearization; + index.powers_of_alpha = powers_of_alpha; + + Ok(Box::new(index)) +} + // This should mimic LookupTable structure #[wasm_bindgen] pub struct WasmPastaFpLookupTable { From e25e75de7b9ca1835e7c3b3fa8c741bbc9459986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Tue, 30 Sep 2025 20:12:10 +0200 Subject: [PATCH 08/75] napi: wrapper for field types --- plonk-napi/src/lib.rs | 3 +- plonk-napi/src/poseidon.rs | 2 +- plonk-napi/src/wrappers/field.rs | 99 ++++++++++++++++++++++++++++++++ plonk-napi/src/wrappers/mod.rs | 1 + 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 plonk-napi/src/wrappers/field.rs create mode 100644 plonk-napi/src/wrappers/mod.rs diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index f0c304a7b9..c46288a072 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,8 +1,9 @@ mod circuit; mod poseidon; mod types; +mod wrappers; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; - +pub use wrappers::field::{WasmPastaFp, WasmPastaFq}; pub use circuit::prover_to_json; pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index dc7c9f108d..4f910b5b54 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -1,4 +1,4 @@ -use arkworks::{WasmPastaFp, WasmPastaFq}; +use crate::wrappers::field::{WasmPastaFp, WasmPastaFq}; use mina_curves::pasta::{Fp, Fq}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, permutation::poseidon_block_cipher}; use napi::bindgen_prelude::*; diff --git a/plonk-napi/src/wrappers/field.rs b/plonk-napi/src/wrappers/field.rs new file mode 100644 index 0000000000..8f396ab97e --- /dev/null +++ b/plonk-napi/src/wrappers/field.rs @@ -0,0 +1,99 @@ +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use mina_curves::pasta::{Fp, Fq}; +use napi::bindgen_prelude::*; +use wasm_types::FlatVectorElem; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct WasmPastaFp(pub Fp); + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct WasmPastaFq(pub Fq); + +macro_rules! impl_field_wrapper { + ($name:ident, $field:ty) => { + impl $name { + fn serialize(&self) -> Vec { + let mut bytes = Vec::with_capacity(core::mem::size_of::<$field>()); + self.0 + .serialize_compressed(&mut bytes) + .expect("serialization failure"); + bytes + } + + fn deserialize(bytes: &[u8]) -> Self { + let value = + <$field>::deserialize_compressed(bytes).expect("deserialization failure"); + Self(value) + } + } + + impl From<$field> for $name { + fn from(value: $field) -> Self { + Self(value) + } + } + + impl From<$name> for $field { + fn from(value: $name) -> Self { + value.0 + } + } + + impl<'a> From<&'a $name> for &'a $field { + fn from(value: &'a $name) -> Self { + &value.0 + } + } + + impl FlatVectorElem for $name { + const FLATTENED_SIZE: usize = core::mem::size_of::<$field>(); + + fn flatten(self) -> Vec { + self.serialize() + } + + fn unflatten(flat: Vec) -> Self { + Self::deserialize(&flat) + } + } + + impl TypeName for $name { + fn type_name() -> &'static str { + ::type_name() + } + + fn value_type() -> ValueType { + ::value_type() + } + } + + impl ValidateNapiValue for $name { + unsafe fn validate( + env: sys::napi_env, + napi_val: sys::napi_value, + ) -> Result { + ::validate(env, napi_val) + } + } + + impl FromNapiValue for $name { + unsafe fn from_napi_value( + env: sys::napi_env, + napi_val: sys::napi_value, + ) -> Result { + let buffer = ::from_napi_value(env, napi_val)?; + Ok(Self::deserialize(buffer.as_ref())) + } + } + + impl ToNapiValue for $name { + unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { + let buffer = Buffer::from(val.serialize()); + ::to_napi_value(env, buffer) + } + } + }; +} + +impl_field_wrapper!(WasmPastaFp, Fp); +impl_field_wrapper!(WasmPastaFq, Fq); \ No newline at end of file diff --git a/plonk-napi/src/wrappers/mod.rs b/plonk-napi/src/wrappers/mod.rs new file mode 100644 index 0000000000..70f3d34a62 --- /dev/null +++ b/plonk-napi/src/wrappers/mod.rs @@ -0,0 +1 @@ +pub(crate) mod field; \ No newline at end of file From a5d32fee40f2f30d51fbfbe5ee788c9aa220a772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Tue, 30 Sep 2025 20:14:53 +0200 Subject: [PATCH 09/75] napi: wrapper for group types --- plonk-napi/src/lib.rs | 1 + plonk-napi/src/wrappers/group.rs | 123 +++++++++++++++++++++++++++++++ plonk-napi/src/wrappers/mod.rs | 3 +- 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 plonk-napi/src/wrappers/group.rs diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index c46288a072..4321ee6911 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -7,3 +7,4 @@ pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_b pub use wrappers::field::{WasmPastaFp, WasmPastaFq}; pub use circuit::prover_to_json; pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; +pub use wrappers::group::{WasmGPallas, WasmGVesta}; diff --git a/plonk-napi/src/wrappers/group.rs b/plonk-napi/src/wrappers/group.rs new file mode 100644 index 0000000000..be8cbff4a0 --- /dev/null +++ b/plonk-napi/src/wrappers/group.rs @@ -0,0 +1,123 @@ +use crate::wrappers::field::{WasmPastaFp, WasmPastaFq}; +use mina_curves::pasta::{ + curves::{ + pallas::{G_GENERATOR_X as GeneratorPallasX, G_GENERATOR_Y as GeneratorPallasY}, + vesta::{G_GENERATOR_X as GeneratorVestaX, G_GENERATOR_Y as GeneratorVestaY}, + }, + Pallas as AffinePallas, Vesta as AffineVesta, +}; +use napi_derive::napi; + +#[napi(object)] +#[derive(Clone, Debug)] +pub struct WasmGPallas { + pub x: WasmPastaFp, + pub y: WasmPastaFp, + pub infinity: bool, +} + +#[napi(object)] +#[derive(Clone, Debug)] +pub struct WasmGVesta { + pub x: WasmPastaFq, + pub y: WasmPastaFq, + pub infinity: bool, +} + +impl From for WasmGPallas { + fn from(point: AffinePallas) -> Self { + Self { + x: point.x.into(), + y: point.y.into(), + infinity: point.infinity, + } + } +} + +impl From<&AffinePallas> for WasmGPallas { + fn from(point: &AffinePallas) -> Self { + Self { + x: point.x.into(), + y: point.y.into(), + infinity: point.infinity, + } + } +} + +impl From for AffinePallas { + fn from(point: WasmGPallas) -> Self { + AffinePallas { + x: point.x.into(), + y: point.y.into(), + infinity: point.infinity, + } + } +} + +impl From<&WasmGPallas> for AffinePallas { + fn from(point: &WasmGPallas) -> Self { + AffinePallas { + x: point.x.into(), + y: point.y.into(), + infinity: point.infinity, + } + } +} + +impl From for WasmGVesta { + fn from(point: AffineVesta) -> Self { + Self { + x: point.x.into(), + y: point.y.into(), + infinity: point.infinity, + } + } +} + +impl From<&AffineVesta> for WasmGVesta { + fn from(point: &AffineVesta) -> Self { + Self { + x: point.x.into(), + y: point.y.into(), + infinity: point.infinity, + } + } +} + +impl From for AffineVesta { + fn from(point: WasmGVesta) -> Self { + AffineVesta { + x: point.x.into(), + y: point.y.into(), + infinity: point.infinity, + } + } +} + +impl From<&WasmGVesta> for AffineVesta { + fn from(point: &WasmGVesta) -> Self { + AffineVesta { + x: point.x.into(), + y: point.y.into(), + infinity: point.infinity, + } + } +} + +#[napi] +pub fn caml_pallas_affine_one() -> WasmGPallas { + WasmGPallas { + x: WasmPastaFp::from(GeneratorPallasX), + y: WasmPastaFp::from(GeneratorPallasY), + infinity: false, + } +} + +#[napi] +pub fn caml_vesta_affine_one() -> WasmGVesta { + WasmGVesta { + x: WasmPastaFq::from(GeneratorVestaX), + y: WasmPastaFq::from(GeneratorVestaY), + infinity: false, + } +} \ No newline at end of file diff --git a/plonk-napi/src/wrappers/mod.rs b/plonk-napi/src/wrappers/mod.rs index 70f3d34a62..15443ca3d8 100644 --- a/plonk-napi/src/wrappers/mod.rs +++ b/plonk-napi/src/wrappers/mod.rs @@ -1 +1,2 @@ -pub(crate) mod field; \ No newline at end of file +pub(crate) mod field; +pub(crate) mod group; \ No newline at end of file From 4b320f3832e79d61c59e63281c180cda93196894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Tue, 30 Sep 2025 20:18:59 +0200 Subject: [PATCH 10/75] napi: impls for wasm vectors --- plonk-napi/src/lib.rs | 6 +- plonk-napi/src/wasm_vector.rs | 199 ++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 plonk-napi/src/wasm_vector.rs diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 4321ee6911..22e9577972 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -2,9 +2,11 @@ mod circuit; mod poseidon; mod types; mod wrappers; +mod wasm_vector; -pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; -pub use wrappers::field::{WasmPastaFp, WasmPastaFq}; pub use circuit::prover_to_json; +pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; +pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; +pub use wrappers::field::{WasmPastaFp, WasmPastaFq}; pub use wrappers::group::{WasmGPallas, WasmGVesta}; diff --git a/plonk-napi/src/wasm_vector.rs b/plonk-napi/src/wasm_vector.rs new file mode 100644 index 0000000000..278b408a21 --- /dev/null +++ b/plonk-napi/src/wasm_vector.rs @@ -0,0 +1,199 @@ +use std::{iter::FromIterator, ops::Deref}; + +use napi::{bindgen_prelude::*, sys}; +use wasm_types::{FlatVector, FlatVectorElem}; + +#[derive(Clone, Debug, Default)] +pub struct WasmVector(pub Vec); + +impl WasmVector { + pub fn into_inner(self) -> Vec { + self.0 + } +} + +impl Deref for WasmVector { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From> for WasmVector { + fn from(value: Vec) -> Self { + WasmVector(value) + } +} + +impl From> for Vec { + fn from(value: WasmVector) -> Self { + value.0 + } +} + +impl<'a, T> From<&'a WasmVector> for &'a Vec { + fn from(value: &'a WasmVector) -> Self { + &value.0 + } +} + +impl IntoIterator for WasmVector { + type Item = T; + type IntoIter = as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a, T> IntoIterator for &'a WasmVector { + type Item = &'a T; + type IntoIter = <&'a Vec as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl FromIterator for WasmVector { + fn from_iter>(iter: I) -> Self { + WasmVector(Vec::from_iter(iter)) + } +} + +impl Extend for WasmVector { + fn extend>(&mut self, iter: I) { + self.0.extend(iter); + } +} + +impl TypeName for WasmVector +where + Vec: TypeName, +{ + fn type_name() -> &'static str { + as TypeName>::type_name() + } + + fn value_type() -> ValueType { + as TypeName>::value_type() + } +} + +impl ValidateNapiValue for WasmVector +where + Vec: ValidateNapiValue, + T: FromNapiValue, +{ + unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + as ValidateNapiValue>::validate(env, napi_val) + } +} + +impl FromNapiValue for WasmVector +where + Vec: FromNapiValue, +{ + unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + Ok(WasmVector( as FromNapiValue>::from_napi_value( + env, napi_val, + )?)) + } +} + +impl ToNapiValue for WasmVector +where + Vec: ToNapiValue, +{ + unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { + as ToNapiValue>::to_napi_value(env, val.0) + } +} + +macro_rules! impl_vec_vec_fp { + ($name:ident, $field:ty, $wasm_field:ty) => { + #[napi] + #[derive(Clone, Debug, Default)] + pub struct $name(#[napi(skip)] pub Vec>); + + #[napi] + impl $name { + #[napi(constructor)] + pub fn create(capacity: i32) -> Self { + Self(Vec::with_capacity(capacity as usize)) + } + + #[napi] + pub fn push(&mut self, vector: Uint8Array) -> Result<()> { + let flattened = vector.as_ref().to_vec(); + let values = FlatVector::<$wasm_field>::from_bytes(flattened) + .into_iter() + .map(Into::into) + .collect(); + self.0.push(values); + Ok(()) + } + + #[napi] + pub fn get(&self, index: i32) -> Result { + let slice = self.0.get(index as usize).ok_or_else(|| { + Error::new(Status::InvalidArg, "index out of bounds".to_string()) + })?; + + let bytes = slice + .iter() + .cloned() + .map(<$wasm_field>::from) + .flat_map(FlatVectorElem::flatten) + .collect::>(); + + Ok(Uint8Array::from(bytes)) + } + + #[napi] + pub fn set(&mut self, index: i32, vector: Uint8Array) -> Result<()> { + let entry = self.0.get_mut(index as usize).ok_or_else(|| { + Error::new(Status::InvalidArg, "index out of bounds".to_string()) + })?; + + let flattened = vector.as_ref().to_vec(); + *entry = FlatVector::<$wasm_field>::from_bytes(flattened) + .into_iter() + .map(Into::into) + .collect(); + Ok(()) + } + } + + impl From>> for $name { + fn from(value: Vec>) -> Self { + Self(value) + } + } + + impl From<$name> for Vec> { + fn from(value: $name) -> Self { + value.0 + } + } + }; +} + +pub mod fp { + use super::*; + use crate::wrappers::field::WasmPastaFp; + use mina_curves::pasta::Fp; + use napi_derive::napi; + + impl_vec_vec_fp!(WasmVecVecFp, Fp, WasmPastaFp); +} + +pub mod fq { + use super::*; + use crate::wrappers::field::WasmPastaFq; + use mina_curves::pasta::Fq; + use napi_derive::napi; + + impl_vec_vec_fp!(WasmVecVecFq, Fq, WasmPastaFq); +} \ No newline at end of file From 8638b153d054385d8621f4f7309e9ea9f39e47eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Wed, 1 Oct 2025 13:24:13 +0200 Subject: [PATCH 11/75] napi: impls for polycomm --- plonk-napi/src/lib.rs | 2 + plonk-napi/src/poly_comm.rs | 115 ++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 plonk-napi/src/poly_comm.rs diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 22e9577972..5e62cc5d16 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -3,8 +3,10 @@ mod poseidon; mod types; mod wrappers; mod wasm_vector; +mod poly_comm; pub use circuit::prover_to_json; +pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; diff --git a/plonk-napi/src/poly_comm.rs b/plonk-napi/src/poly_comm.rs new file mode 100644 index 0000000000..b90e9df978 --- /dev/null +++ b/plonk-napi/src/poly_comm.rs @@ -0,0 +1,115 @@ +use crate::{ + wrappers::group::{WasmGPallas, WasmGVesta}, + wasm_vector::WasmVector, +}; +use napi_derive::napi; +use paste::paste; +use poly_commitment::commitment::PolyComm; + +macro_rules! impl_poly_comm { + ( + $wasm_g:ty, + $g:ty, + $field_name:ident + ) => { + paste! { + #[napi] + #[derive(Clone)] + pub struct [] { + #[napi(skip)] + pub unshifted: WasmVector<$wasm_g>, + pub shifted: Option<$wasm_g>, + } + + #[napi] + impl [] { + #[napi(constructor)] + pub fn new(unshifted: WasmVector<$wasm_g>, shifted: Option<$wasm_g>) -> Self { + assert!( + shifted.is_none(), + "mina#14628: Shifted commitments are deprecated and must not be used", + ); + Self { unshifted, shifted } + } + + #[napi(getter)] + pub fn unshifted(&self) -> WasmVector<$wasm_g> { + self.unshifted.clone() + } + + #[napi(setter)] + pub fn set_unshifted(&mut self, value: WasmVector<$wasm_g>) { + self.unshifted = value; + } + } + + impl From> for [] { + fn from(value: PolyComm<$g>) -> Self { + let PolyComm { chunks } = value; + let unshifted: Vec<$wasm_g> = chunks.into_iter().map(Into::into).collect(); + Self { + unshifted: unshifted.into(), + shifted: None, + } + } + } + + impl From<&PolyComm<$g>> for [] { + fn from(value: &PolyComm<$g>) -> Self { + let unshifted: Vec<$wasm_g> = value.chunks.iter().map(|chunk| (*chunk).into()).collect(); + Self { + unshifted: unshifted.into(), + shifted: None, + } + } + } + + impl From<[]> for PolyComm<$g> { + fn from(value: []) -> Self { + let [] { unshifted, shifted } = value; + assert!( + shifted.is_none(), + "mina#14628: Shifted commitments are deprecated and must not be used", + ); + PolyComm { + chunks: Vec::<$wasm_g>::from(unshifted) + .into_iter() + .map(Into::into) + .collect(), + } + } + } + + impl From<&[]> for PolyComm<$g> { + fn from(value: &[]) -> Self { + assert!( + value.shifted.is_none(), + "mina#14628: Shifted commitments are deprecated and must not be used", + ); + PolyComm { + chunks: value + .unshifted + .iter() + .cloned() + .map(Into::into) + .collect(), + } + } + } + } + }; +} + +pub mod pallas { + use super::*; + use mina_curves::pasta::Pallas as GAffine; + + impl_poly_comm!(WasmGPallas, GAffine, Fq); +} + +pub mod vesta { + use super::*; + use mina_curves::pasta::Vesta as GAffine; + + impl_poly_comm!(WasmGVesta, GAffine, Fp); +} From 0d95c15db34911f5a73bc6ec4efb8817138a5739 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 16 Oct 2025 19:42:49 +0200 Subject: [PATCH 12/75] napi: uniformize format to match plonk-wasm side --- plonk-napi/src/poly_comm.rs | 43 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/plonk-napi/src/poly_comm.rs b/plonk-napi/src/poly_comm.rs index b90e9df978..b988f3e1e7 100644 --- a/plonk-napi/src/poly_comm.rs +++ b/plonk-napi/src/poly_comm.rs @@ -1,14 +1,11 @@ -use crate::{ - wrappers::group::{WasmGPallas, WasmGVesta}, - wasm_vector::WasmVector, -}; +use crate::wasm_vector::WasmVector; use napi_derive::napi; use paste::paste; use poly_commitment::commitment::PolyComm; macro_rules! impl_poly_comm { ( - $wasm_g:ty, + $WasmG:ty, $g:ty, $field_name:ident ) => { @@ -17,14 +14,14 @@ macro_rules! impl_poly_comm { #[derive(Clone)] pub struct [] { #[napi(skip)] - pub unshifted: WasmVector<$wasm_g>, - pub shifted: Option<$wasm_g>, + pub unshifted: WasmVector<$WasmG>, + pub shifted: Option<$WasmG>, } #[napi] impl [] { #[napi(constructor)] - pub fn new(unshifted: WasmVector<$wasm_g>, shifted: Option<$wasm_g>) -> Self { + pub fn new(unshifted: WasmVector<$WasmG>, shifted: Option<$WasmG>) -> Self { assert!( shifted.is_none(), "mina#14628: Shifted commitments are deprecated and must not be used", @@ -33,20 +30,20 @@ macro_rules! impl_poly_comm { } #[napi(getter)] - pub fn unshifted(&self) -> WasmVector<$wasm_g> { + pub fn unshifted(&self) -> WasmVector<$WasmG> { self.unshifted.clone() } #[napi(setter)] - pub fn set_unshifted(&mut self, value: WasmVector<$wasm_g>) { - self.unshifted = value; + pub fn set_unshifted(&mut self, x: WasmVector<$WasmG>) { + self.unshifted = x; } } impl From> for [] { - fn from(value: PolyComm<$g>) -> Self { - let PolyComm { chunks } = value; - let unshifted: Vec<$wasm_g> = chunks.into_iter().map(Into::into).collect(); + fn from(x: PolyComm<$g>) -> Self { + let PolyComm { chunks } = x; + let unshifted: Vec<$WasmG> = chunks.into_iter().map(Into::into).collect(); Self { unshifted: unshifted.into(), shifted: None, @@ -55,8 +52,8 @@ macro_rules! impl_poly_comm { } impl From<&PolyComm<$g>> for [] { - fn from(value: &PolyComm<$g>) -> Self { - let unshifted: Vec<$wasm_g> = value.chunks.iter().map(|chunk| (*chunk).into()).collect(); + fn from(x: &PolyComm<$g>) -> Self { + let unshifted: Vec<$WasmG> = x.chunks.iter().map(|chunk| (*chunk).into()).collect(); Self { unshifted: unshifted.into(), shifted: None, @@ -65,14 +62,14 @@ macro_rules! impl_poly_comm { } impl From<[]> for PolyComm<$g> { - fn from(value: []) -> Self { - let [] { unshifted, shifted } = value; + fn from(x: []) -> Self { + let [] { unshifted, shifted } = x; assert!( shifted.is_none(), "mina#14628: Shifted commitments are deprecated and must not be used", ); PolyComm { - chunks: Vec::<$wasm_g>::from(unshifted) + chunks: Vec::<$WasmG>::from(unshifted) .into_iter() .map(Into::into) .collect(), @@ -81,13 +78,13 @@ macro_rules! impl_poly_comm { } impl From<&[]> for PolyComm<$g> { - fn from(value: &[]) -> Self { + fn from(x: &[]) -> Self { assert!( - value.shifted.is_none(), + x.shifted.is_none(), "mina#14628: Shifted commitments are deprecated and must not be used", ); PolyComm { - chunks: value + chunks: x .unshifted .iter() .cloned() @@ -102,6 +99,7 @@ macro_rules! impl_poly_comm { pub mod pallas { use super::*; + use crate::wrappers::group::WasmGPallas; use mina_curves::pasta::Pallas as GAffine; impl_poly_comm!(WasmGPallas, GAffine, Fq); @@ -109,6 +107,7 @@ pub mod pallas { pub mod vesta { use super::*; + use crate::wrappers::group::WasmGVesta; use mina_curves::pasta::Vesta as GAffine; impl_poly_comm!(WasmGVesta, GAffine, Fp); From b7c84ab044eabc23f93923d3bfe85dbcf3d594b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Thu, 2 Oct 2025 15:42:28 +0200 Subject: [PATCH 13/75] napi: wrapper for wires --- plonk-napi/src/wrappers/mod.rs | 3 ++- plonk-napi/src/wrappers/wires.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 plonk-napi/src/wrappers/wires.rs diff --git a/plonk-napi/src/wrappers/mod.rs b/plonk-napi/src/wrappers/mod.rs index 15443ca3d8..5907213cf9 100644 --- a/plonk-napi/src/wrappers/mod.rs +++ b/plonk-napi/src/wrappers/mod.rs @@ -1,2 +1,3 @@ pub(crate) mod field; -pub(crate) mod group; \ No newline at end of file +pub(crate) mod group; +pub(crate) mod wires; \ No newline at end of file diff --git a/plonk-napi/src/wrappers/wires.rs b/plonk-napi/src/wrappers/wires.rs new file mode 100644 index 0000000000..bffcccf83d --- /dev/null +++ b/plonk-napi/src/wrappers/wires.rs @@ -0,0 +1,27 @@ +use kimchi::circuits::wires::Wire as KimchiWire; +use napi_derive::napi; + +#[napi(object)] +#[derive(Clone, Copy, Debug, Default)] +pub struct NapiWire { + pub row: u32, + pub col: u32, +} + +impl From for KimchiWire { + fn from(value: NapiWire) -> Self { + KimchiWire { + row: value.row as usize, + col: value.col as usize, + } + } +} + +impl From for NapiWire { + fn from(value: KimchiWire) -> Self { + Self { + row: value.row as u32, + col: value.col as u32, + } + } +} \ No newline at end of file From 8318af088c7d234b27d667d9cc14db3cc7693df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Thu, 2 Oct 2025 16:03:36 +0200 Subject: [PATCH 14/75] deps: use kimchi in plonk-napi --- plonk-napi/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/plonk-napi/Cargo.toml b/plonk-napi/Cargo.toml index 6cfa08e0e6..6b91ebbffb 100644 --- a/plonk-napi/Cargo.toml +++ b/plonk-napi/Cargo.toml @@ -27,6 +27,7 @@ kimchi.workspace = true mina-curves = { path = "../curves" } mina-poseidon = { path = "../poseidon" } o1-utils = { path = "../utils" } +kimchi = { path = "../kimchi" } poly-commitment = { path = "../poly-commitment" } getrandom.workspace = true From 89e829f897d327cef1f08b3c799b532570cf4630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Thu, 2 Oct 2025 16:03:51 +0200 Subject: [PATCH 15/75] napi: wrapper for feature flags --- plonk-napi/src/wrappers/feature_flags.rs | 63 ++++++++++++++++++++++++ plonk-napi/src/wrappers/mod.rs | 3 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 plonk-napi/src/wrappers/feature_flags.rs diff --git a/plonk-napi/src/wrappers/feature_flags.rs b/plonk-napi/src/wrappers/feature_flags.rs new file mode 100644 index 0000000000..6f8f7f1a3e --- /dev/null +++ b/plonk-napi/src/wrappers/feature_flags.rs @@ -0,0 +1,63 @@ +use kimchi::circuits::{ + constraints::FeatureFlags as KimchiFeatureFlags, + lookup::lookups::{LookupFeatures, LookupPatterns}, +}; +use napi_derive::napi; + +#[napi(object)] +#[derive(Clone, Copy, Debug, Default)] +pub struct NapiFeatureFlags { + pub range_check0: bool, + pub range_check1: bool, + pub foreign_field_add: bool, + pub foreign_field_mul: bool, + pub xor: bool, + pub rot: bool, + pub lookup: bool, + pub runtime_tables: bool, +} + +impl From for NapiFeatureFlags { + fn from(value: KimchiFeatureFlags) -> Self { + let LookupPatterns { + xor, + lookup, + range_check, + foreign_field_mul, + } = value.lookup_features.patterns; + + Self { + range_check0: value.range_check0, + range_check1: value.range_check1, + foreign_field_add: value.foreign_field_add, + foreign_field_mul: value.foreign_field_mul, + xor: value.xor, + rot: value.rot, + lookup: lookup || range_check || foreign_field_mul || xor, + runtime_tables: value.lookup_features.uses_runtime_tables, + } + } +} + +impl From for KimchiFeatureFlags { + fn from(value: NapiFeatureFlags) -> Self { + KimchiFeatureFlags { + range_check0: value.range_check0, + range_check1: value.range_check1, + foreign_field_add: value.foreign_field_add, + foreign_field_mul: value.foreign_field_mul, + xor: value.xor, + rot: value.rot, + lookup_features: LookupFeatures { + patterns: LookupPatterns { + xor: value.lookup && value.xor, + lookup: value.lookup, + range_check: value.lookup && (value.range_check0 || value.range_check1), + foreign_field_mul: value.lookup && value.foreign_field_mul, + }, + joint_lookup_used: value.lookup, + uses_runtime_tables: value.runtime_tables, + }, + } + } +} \ No newline at end of file diff --git a/plonk-napi/src/wrappers/mod.rs b/plonk-napi/src/wrappers/mod.rs index 5907213cf9..10d05a9dbc 100644 --- a/plonk-napi/src/wrappers/mod.rs +++ b/plonk-napi/src/wrappers/mod.rs @@ -1,3 +1,4 @@ pub(crate) mod field; pub(crate) mod group; -pub(crate) mod wires; \ No newline at end of file +pub(crate) mod wires; +pub(crate) mod feature_flags; \ No newline at end of file From 83ee190fae3887881a32d72ff8cb7f854d49225f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Thu, 2 Oct 2025 16:05:03 +0200 Subject: [PATCH 16/75] napi: wrapper for lookups --- plonk-napi/src/wrappers/lookups.rs | 296 +++++++++++++++++++++++++++++ plonk-napi/src/wrappers/mod.rs | 3 +- 2 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 plonk-napi/src/wrappers/lookups.rs diff --git a/plonk-napi/src/wrappers/lookups.rs b/plonk-napi/src/wrappers/lookups.rs new file mode 100644 index 0000000000..cd9b7a4fbe --- /dev/null +++ b/plonk-napi/src/wrappers/lookups.rs @@ -0,0 +1,296 @@ +use kimchi::circuits::lookup::{ + lookups::{ + LookupFeatures as KimchiLookupFeatures, LookupInfo as KimchiLookupInfo, + LookupPatterns as KimchiLookupPatterns, + }, + runtime_tables::{ + RuntimeTable as KimchiRuntimeTable, RuntimeTableCfg as KimchiRuntimeTableCfg, + }, + tables::LookupTable as KimchiLookupTable, +}; +use mina_curves::pasta::{Fp, Fq}; +use napi::bindgen_prelude::*; +use napi_derive::napi; +use paste::paste; +use wasm_types::{FlatVector, FlatVectorElem}; + +use crate::{ + wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}, + wrappers::field::{WasmPastaFp, WasmPastaFq}, +}; + +// ----------------- +// Lookup pattern and info wrappers +// ----------------- + +#[napi(object)] +#[derive(Clone, Copy, Debug, Default)] +pub struct NapiLookupPatterns { + pub xor: bool, + pub lookup: bool, + pub range_check: bool, + pub foreign_field_mul: bool, +} + +impl From for NapiLookupPatterns { + fn from(value: KimchiLookupPatterns) -> Self { + Self { + xor: value.xor, + lookup: value.lookup, + range_check: value.range_check, + foreign_field_mul: value.foreign_field_mul, + } + } +} + +impl From for KimchiLookupPatterns { + fn from(value: NapiLookupPatterns) -> Self { + KimchiLookupPatterns { + xor: value.xor, + lookup: value.lookup, + range_check: value.range_check, + foreign_field_mul: value.foreign_field_mul, + } + } +} + +#[napi(object)] +#[derive(Clone, Debug, Default)] +pub struct NapiLookupFeatures { + pub patterns: NapiLookupPatterns, + pub joint_lookup_used: bool, + pub uses_runtime_tables: bool, +} + +impl From for NapiLookupFeatures { + fn from(value: KimchiLookupFeatures) -> Self { + Self { + patterns: value.patterns.into(), + joint_lookup_used: value.joint_lookup_used, + uses_runtime_tables: value.uses_runtime_tables, + } + } +} + +impl From for KimchiLookupFeatures { + fn from(value: NapiLookupFeatures) -> Self { + KimchiLookupFeatures { + patterns: value.patterns.into(), + joint_lookup_used: value.joint_lookup_used, + uses_runtime_tables: value.uses_runtime_tables, + } + } +} + +#[napi(object)] +#[derive(Clone, Debug, Default)] +pub struct NapiLookupInfo { + pub max_per_row: u32, + pub max_joint_size: u32, + pub features: NapiLookupFeatures, +} + +impl From for NapiLookupInfo { + fn from(value: KimchiLookupInfo) -> Self { + Self { + max_per_row: value.max_per_row as u32, + max_joint_size: value.max_joint_size as u32, + features: value.features.into(), + } + } +} + +impl From for KimchiLookupInfo { + fn from(value: NapiLookupInfo) -> Self { + KimchiLookupInfo { + max_per_row: value.max_per_row as usize, + max_joint_size: value.max_joint_size, + features: value.features.into(), + } + } +} + +// ----------------- +// Lookup tables & runtime tables +// ----------------- + +macro_rules! impl_lookup_wrappers { + ($name:ident, $field:ty, $wasm_field:ty, $vec_vec:ty) => { + paste! { + #[napi] + #[derive(Clone)] + pub struct [] { + id: i32, + data: $vec_vec, + } + + #[napi] + impl [] { + #[napi(constructor)] + pub fn new(id: i32, data: External<$vec_vec>) -> Self { + Self { + id, + data: data.as_ref().clone(), + } + } + + #[napi(getter)] + pub fn id(&self) -> i32 { + self.id + } + + #[napi(setter)] + pub fn set_id(&mut self, id: i32) { + self.id = id; + } + + #[napi(getter)] + pub fn data(&self) -> External<$vec_vec> { + External::new(self.data.clone()) + } + + #[napi(setter)] + pub fn set_data(&mut self, data: External<$vec_vec>) { + self.data = data.as_ref().clone(); + } + } + + impl From> for [] { + fn from(value: KimchiLookupTable<$field>) -> Self { + Self { + id: value.id, + data: value.data.into(), + } + } + } + + impl From<[]> for KimchiLookupTable<$field> { + fn from(value: []) -> Self { + Self { + id: value.id, + data: value.data.into(), + } + } + } + + #[napi] + #[derive(Clone)] + pub struct [] { + id: i32, + first_column: Vec<$field>, + } + + #[napi] + impl [] { + #[napi(constructor)] + pub fn new(id: i32, first_column: Uint8Array) -> Result { + let bytes = first_column.as_ref().to_vec(); + let elements: Vec<$field> = FlatVector::<$wasm_field>::from_bytes(bytes) + .into_iter() + .map(Into::into) + .collect(); + Ok(Self { id, first_column: elements }) + } + + #[napi(getter)] + pub fn id(&self) -> i32 { + self.id + } + + #[napi(setter)] + pub fn set_id(&mut self, id: i32) { + self.id = id; + } + + #[napi(getter)] + pub fn first_column(&self) -> Result { + let mut bytes = Vec::with_capacity(self.first_column.len() * <$wasm_field>::FLATTENED_SIZE); + for value in &self.first_column { + let element = <$wasm_field>::from(*value); + bytes.extend(element.flatten()); + } + Ok(Uint8Array::from(bytes)) + } + } + + impl From> for [] { + fn from(value: KimchiRuntimeTableCfg<$field>) -> Self { + Self { + id: value.id, + first_column: value.first_column, + } + } + } + + impl From<[]> for KimchiRuntimeTableCfg<$field> { + fn from(value: []) -> Self { + Self { + id: value.id, + first_column: value.first_column, + } + } + } + + #[napi] + #[derive(Clone)] + pub struct [] { + id: i32, + data: Vec<$field>, + } + + #[napi] + impl [] { + #[napi(constructor)] + pub fn new(id: i32, data: Uint8Array) -> Result { + let bytes = data.as_ref().to_vec(); + let elements: Vec<$field> = FlatVector::<$wasm_field>::from_bytes(bytes) + .into_iter() + .map(Into::into) + .collect(); + Ok(Self { id, data: elements }) + } + + #[napi(getter)] + pub fn id(&self) -> i32 { + self.id + } + + #[napi(setter)] + pub fn set_id(&mut self, id: i32) { + self.id = id; + } + + #[napi(getter)] + pub fn data(&self) -> Result { + let mut bytes = Vec::with_capacity(self.data.len() * <$wasm_field>::FLATTENED_SIZE); + for value in &self.data { + let element = <$wasm_field>::from(*value); + bytes.extend(element.flatten()); + } + Ok(Uint8Array::from(bytes)) + } + } + + impl From> for [] { + fn from(value: KimchiRuntimeTable<$field>) -> Self { + Self { + id: value.id, + data: value.data, + } + } + } + + impl From<[]> for KimchiRuntimeTable<$field> { + fn from(value: []) -> Self { + Self { + id: value.id, + data: value.data, + } + } + } + } + }; +} + +impl_lookup_wrappers!(Fp, Fp, WasmPastaFp, WasmVecVecFp); +impl_lookup_wrappers!(Fq, Fq, WasmPastaFq, WasmVecVecFq); diff --git a/plonk-napi/src/wrappers/mod.rs b/plonk-napi/src/wrappers/mod.rs index 10d05a9dbc..36a2ce209a 100644 --- a/plonk-napi/src/wrappers/mod.rs +++ b/plonk-napi/src/wrappers/mod.rs @@ -1,4 +1,5 @@ +pub(crate) mod feature_flags; pub(crate) mod field; pub(crate) mod group; +pub(crate) mod lookups; pub(crate) mod wires; -pub(crate) mod feature_flags; \ No newline at end of file From d4e816905222073d9d1f99974e63d85120375e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Thu, 2 Oct 2025 16:13:56 +0200 Subject: [PATCH 17/75] napi: ffi for gate vector --- plonk-napi/src/gate_vector.rs | 254 ++++++++++++++++++++++++++++++++++ plonk-napi/src/lib.rs | 4 +- 2 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 plonk-napi/src/gate_vector.rs diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs new file mode 100644 index 0000000000..f614c3d3a0 --- /dev/null +++ b/plonk-napi/src/gate_vector.rs @@ -0,0 +1,254 @@ +use kimchi::circuits::{ + gate::{Circuit, CircuitGate, GateType}, + wires::{GateWires, Wire as KimchiWire}, +}; +use mina_curves::pasta::{Fp, Fq}; +use napi::bindgen_prelude::*; +use napi_derive::napi; +use o1_utils::hasher::CryptoDigest; +use paste::paste; +use wasm_types::{FlatVector as WasmFlatVector, FlatVectorElem}; + +use crate::wrappers::{ + field::{WasmPastaFp, WasmPastaFq}, + wires::NapiWire, +}; + +#[napi(object)] +#[derive(Clone, Debug, Default)] +pub struct NapiGateWires { + pub w0: NapiWire, + pub w1: NapiWire, + pub w2: NapiWire, + pub w3: NapiWire, + pub w4: NapiWire, + pub w5: NapiWire, + pub w6: NapiWire, +} + +impl NapiGateWires { + fn into_inner(self) -> GateWires { + [ + KimchiWire::from(self.w0), + KimchiWire::from(self.w1), + KimchiWire::from(self.w2), + KimchiWire::from(self.w3), + KimchiWire::from(self.w4), + KimchiWire::from(self.w5), + KimchiWire::from(self.w6), + ] + } +} + +impl From<&GateWires> for NapiGateWires { + fn from(value: &GateWires) -> Self { + Self { + w0: value[0].into(), + w1: value[1].into(), + w2: value[2].into(), + w3: value[3].into(), + w4: value[4].into(), + w5: value[5].into(), + w6: value[6].into(), + } + } +} + +fn gate_type_from_i32(value: i32) -> Result { + if value < 0 { + return Err(Error::new( + Status::InvalidArg, + format!("invalid GateType discriminant: {}", value), + )); + } + + let variants: &[GateType] = &[ + GateType::Zero, + GateType::Generic, + GateType::Poseidon, + GateType::CompleteAdd, + GateType::VarBaseMul, + GateType::EndoMul, + GateType::EndoMulScalar, + GateType::Lookup, + GateType::CairoClaim, + GateType::CairoInstruction, + GateType::CairoFlags, + GateType::CairoTransition, + GateType::RangeCheck0, + GateType::RangeCheck1, + GateType::ForeignFieldAdd, + GateType::ForeignFieldMul, + GateType::Xor16, + GateType::Rot64, + ]; + + let index = value as usize; + variants.get(index).copied().ok_or_else(|| { + Error::new( + Status::InvalidArg, + format!("invalid GateType discriminant: {}", value), + ) + }) +} + +fn gate_type_to_i32(value: GateType) -> i32 { + value as i32 +} + +macro_rules! impl_gate_support { + ($module:ident, $field:ty, $wasm_field:ty) => { + paste! { + #[napi(object)] + #[derive(Clone, Debug, Default)] + pub struct [] { + pub typ: i32, + pub wires: NapiGateWires, + pub coeffs: Vec, + } + + impl [] { + fn into_inner(self) -> Result> { + let coeffs = WasmFlatVector::<$wasm_field>::from_bytes(self.coeffs) + .into_iter() + .map(Into::into) + .collect(); + + Ok(CircuitGate { + typ: gate_type_from_i32(self.typ)?, + wires: self.wires.into_inner(), + coeffs, + }) + } + + fn from_inner(value: &CircuitGate<$field>) -> Self { + let coeffs = value + .coeffs + .iter() + .cloned() + .map($wasm_field::from) + .flat_map(|elem| elem.flatten()) + .collect(); + + Self { + typ: gate_type_to_i32(value.typ), + wires: (&value.wires).into(), + coeffs, + } + } + } + + #[napi] + #[derive(Clone, Default, Debug)] + pub struct [] { + #[napi(skip)] + pub inner: Vec>, + } + + #[napi] + impl [] { + #[napi(constructor)] + pub fn new() -> Self { + Self { inner: Vec::new() } + } + + #[napi] + pub fn add(&mut self, gate: []) -> Result<()> { + self.inner.push(gate.into_inner()?); + Ok(()) + } + + #[napi] + pub fn get(&self, index: i32) -> [] { + []::from_inner(&self.inner[index as usize]) + } + + #[napi] + pub fn len(&self) -> i32 { + self.inner.len() as i32 + } + + #[napi] + pub fn wrap(&mut self, target: NapiWire, head: NapiWire) { + let row = target.row as usize; + let col = target.col as usize; + self.inner[row].wires[col] = KimchiWire::from(head); + } + + #[napi] + pub fn digest(&self, public_input_size: i32) -> Vec { + Circuit::new(public_input_size as usize, &self.inner) + .digest() + .to_vec() + } + + #[napi] + pub fn serialize(&self, public_input_size: i32) -> Result { + let circuit = Circuit::new(public_input_size as usize, &self.inner); + serde_json::to_string(&circuit).map_err(|err| { + Error::new( + Status::GenericFailure, + format!("failed to serialize circuit: {}", err), + ) + }) + } + } + + #[napi] + pub fn []() -> [] { + []::new() + } + + #[napi] + pub fn []( + vector: &mut [], + gate: [], + ) -> Result<()> { + vector.add(gate) + } + + #[napi] + pub fn []( + vector: &[], + index: i32, + ) -> [] { + vector.get(index) + } + + #[napi] + pub fn []( + vector: &[], + ) -> i32 { + vector.len() + } + + #[napi] + pub fn []( + vector: &mut [], + target: NapiWire, + head: NapiWire, + ) { + vector.wrap(target, head); + } + + #[napi] + pub fn []( + public_input_size: i32, + vector: &[], + ) -> Vec { + vector.digest(public_input_size) + } + + #[napi] + pub fn []( + public_input_size: i32, + vector: &[], + ) -> Result { + vector.serialize(public_input_size) + } + } + }; +} + +impl_gate_support!(fp, Fp, WasmPastaFp); +impl_gate_support!(fq, Fq, WasmPastaFq); diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 5e62cc5d16..fb49a161f5 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,4 +1,5 @@ mod circuit; +mod gate_vector; mod poseidon; mod types; mod wrappers; @@ -10,5 +11,4 @@ pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; -pub use wrappers::field::{WasmPastaFp, WasmPastaFq}; -pub use wrappers::group::{WasmGPallas, WasmGVesta}; +pub use wrappers::{field::{WasmPastaFp, WasmPastaFq}, group::{WasmGPallas, WasmGVesta}}; From 02e15b8a567bd58b6addbf5395ddfc6acf69901f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Fri, 3 Oct 2025 17:44:37 +0200 Subject: [PATCH 18/75] minor: add new line at eof --- plonk-napi/src/wasm_vector.rs | 2 +- plonk-napi/src/wrappers/feature_flags.rs | 2 +- plonk-napi/src/wrappers/field.rs | 2 +- plonk-napi/src/wrappers/group.rs | 2 +- plonk-napi/src/wrappers/wires.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plonk-napi/src/wasm_vector.rs b/plonk-napi/src/wasm_vector.rs index 278b408a21..d83400a04a 100644 --- a/plonk-napi/src/wasm_vector.rs +++ b/plonk-napi/src/wasm_vector.rs @@ -196,4 +196,4 @@ pub mod fq { use napi_derive::napi; impl_vec_vec_fp!(WasmVecVecFq, Fq, WasmPastaFq); -} \ No newline at end of file +} diff --git a/plonk-napi/src/wrappers/feature_flags.rs b/plonk-napi/src/wrappers/feature_flags.rs index 6f8f7f1a3e..64f93895bf 100644 --- a/plonk-napi/src/wrappers/feature_flags.rs +++ b/plonk-napi/src/wrappers/feature_flags.rs @@ -60,4 +60,4 @@ impl From for KimchiFeatureFlags { }, } } -} \ No newline at end of file +} diff --git a/plonk-napi/src/wrappers/field.rs b/plonk-napi/src/wrappers/field.rs index 8f396ab97e..d1b0d35e0b 100644 --- a/plonk-napi/src/wrappers/field.rs +++ b/plonk-napi/src/wrappers/field.rs @@ -96,4 +96,4 @@ macro_rules! impl_field_wrapper { } impl_field_wrapper!(WasmPastaFp, Fp); -impl_field_wrapper!(WasmPastaFq, Fq); \ No newline at end of file +impl_field_wrapper!(WasmPastaFq, Fq); diff --git a/plonk-napi/src/wrappers/group.rs b/plonk-napi/src/wrappers/group.rs index be8cbff4a0..602d92e715 100644 --- a/plonk-napi/src/wrappers/group.rs +++ b/plonk-napi/src/wrappers/group.rs @@ -120,4 +120,4 @@ pub fn caml_vesta_affine_one() -> WasmGVesta { y: WasmPastaFq::from(GeneratorVestaY), infinity: false, } -} \ No newline at end of file +} diff --git a/plonk-napi/src/wrappers/wires.rs b/plonk-napi/src/wrappers/wires.rs index bffcccf83d..9a2f67ea11 100644 --- a/plonk-napi/src/wrappers/wires.rs +++ b/plonk-napi/src/wrappers/wires.rs @@ -24,4 +24,4 @@ impl From for NapiWire { col: value.col as u32, } } -} \ No newline at end of file +} From 357d735d1693ace099c452fa5836fe408a97e6eb Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 15 Oct 2025 15:26:28 +0200 Subject: [PATCH 19/75] napi: inline functions for GateVector struct --- plonk-napi/src/gate_vector.rs | 91 +++++++++++------------------------ 1 file changed, 29 insertions(+), 62 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index f614c3d3a0..1b7385da5c 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -140,63 +140,13 @@ macro_rules! impl_gate_support { #[napi] #[derive(Clone, Default, Debug)] - pub struct [] { - #[napi(skip)] - pub inner: Vec>, - } - - #[napi] - impl [] { - #[napi(constructor)] - pub fn new() -> Self { - Self { inner: Vec::new() } - } - - #[napi] - pub fn add(&mut self, gate: []) -> Result<()> { - self.inner.push(gate.into_inner()?); - Ok(()) - } - - #[napi] - pub fn get(&self, index: i32) -> [] { - []::from_inner(&self.inner[index as usize]) - } - - #[napi] - pub fn len(&self) -> i32 { - self.inner.len() as i32 - } + pub struct []( + #[napi(skip)] pub Vec>); - #[napi] - pub fn wrap(&mut self, target: NapiWire, head: NapiWire) { - let row = target.row as usize; - let col = target.col as usize; - self.inner[row].wires[col] = KimchiWire::from(head); - } - - #[napi] - pub fn digest(&self, public_input_size: i32) -> Vec { - Circuit::new(public_input_size as usize, &self.inner) - .digest() - .to_vec() - } - - #[napi] - pub fn serialize(&self, public_input_size: i32) -> Result { - let circuit = Circuit::new(public_input_size as usize, &self.inner); - serde_json::to_string(&circuit).map_err(|err| { - Error::new( - Status::GenericFailure, - format!("failed to serialize circuit: {}", err), - ) - }) - } - } #[napi] pub fn []() -> [] { - []::new() + [(Vec::new())] } #[napi] @@ -204,7 +154,8 @@ macro_rules! impl_gate_support { vector: &mut [], gate: [], ) -> Result<()> { - vector.add(gate) + vector.0.push(gate.into_inner()?); + Ok(()) } #[napi] @@ -212,14 +163,14 @@ macro_rules! impl_gate_support { vector: &[], index: i32, ) -> [] { - vector.get(index) + []::from_inner(&self.0[index as usize]) } #[napi] pub fn []( vector: &[], ) -> i32 { - vector.len() + vector.0.len() as i32 } #[napi] @@ -228,15 +179,19 @@ macro_rules! impl_gate_support { target: NapiWire, head: NapiWire, ) { - vector.wrap(target, head); - } + let row = target.row as usize; + let col = target.col as usize; + self.0[row].wires[col] = KimchiWire::from(head); + } #[napi] pub fn []( public_input_size: i32, vector: &[], ) -> Vec { - vector.digest(public_input_size) + Circuit::new(public_input_size as usize, &self.0) + .digest() + .to_vec() } #[napi] @@ -244,11 +199,23 @@ macro_rules! impl_gate_support { public_input_size: i32, vector: &[], ) -> Result { - vector.serialize(public_input_size) + let circuit = Circuit::new(public_input_size as usize, &self.inner); + serde_json::to_string(&circuit).map_err(|err| { + Error::new( + Status::GenericFailure, + format!("failed to serialize circuit: {}", err), + ) + }) } } }; } -impl_gate_support!(fp, Fp, WasmPastaFp); -impl_gate_support!(fq, Fq, WasmPastaFq); +pub mod fp { + use super::*; + impl_gate_support!(fp, Fp, WasmPastaFp); +} +pub mod fq { + use super::*; + impl_gate_support!(fq, Fq, WasmPastaFq); +} From a9e249bfcd06438f66f7f68096e35e84724b6e23 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 15 Oct 2025 17:02:51 +0200 Subject: [PATCH 20/75] napi: export contents of gate_vector module --- plonk-napi/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index fb49a161f5..33a8a4f6c0 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -7,6 +7,22 @@ mod wasm_vector; mod poly_comm; pub use circuit::prover_to_json; +pub use gate_vector::{ + fp::{ + caml_pasta_fp_plonk_circuit_digest, caml_pasta_fp_plonk_circuit_serialize, + caml_pasta_fp_plonk_gate_vector_add, caml_pasta_fp_plonk_gate_vector_create, + caml_pasta_fp_plonk_gate_vector_digest, caml_pasta_fp_plonk_gate_vector_get, + caml_pasta_fp_plonk_gate_vector_len, caml_pasta_fp_plonk_gate_vector_wrap, + NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, + }, + fq::{ + caml_pasta_fq_plonk_circuit_digest, caml_pasta_fq_plonk_circuit_serialize, + caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, + caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, + caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, + NapiFqGate as WasmFqGate, NapiFqGateVector as WasmFqGateVector, + }, +}; pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; From 923133ec57db4e8baecc8983b5bf94f4edc8b9d8 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 15 Oct 2025 17:08:49 +0200 Subject: [PATCH 21/75] napi: replace self occurances to vector in gate_vector --- plonk-napi/src/gate_vector.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index 1b7385da5c..b9adee62d2 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -163,7 +163,7 @@ macro_rules! impl_gate_support { vector: &[], index: i32, ) -> [] { - []::from_inner(&self.0[index as usize]) + []::from_inner(&vector.0[index as usize]) } #[napi] @@ -181,7 +181,7 @@ macro_rules! impl_gate_support { ) { let row = target.row as usize; let col = target.col as usize; - self.0[row].wires[col] = KimchiWire::from(head); + vector.0[row].wires[col] = KimchiWire::from(head); } #[napi] @@ -189,7 +189,7 @@ macro_rules! impl_gate_support { public_input_size: i32, vector: &[], ) -> Vec { - Circuit::new(public_input_size as usize, &self.0) + Circuit::new(public_input_size as usize, &vector.0) .digest() .to_vec() } @@ -199,7 +199,7 @@ macro_rules! impl_gate_support { public_input_size: i32, vector: &[], ) -> Result { - let circuit = Circuit::new(public_input_size as usize, &self.inner); + let circuit = Circuit::new(public_input_size as usize, &vector.0); serde_json::to_string(&circuit).map_err(|err| { Error::new( Status::GenericFailure, From 31db09d34cc3d4626fd0808dd1d4f81af2a9791e Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 15 Oct 2025 18:12:39 +0200 Subject: [PATCH 22/75] napi: fix compilation of gate_vector --- plonk-napi/src/gate_vector.rs | 23 +++++++++-------------- plonk-napi/src/lib.rs | 23 +++++++++-------------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index b9adee62d2..bf1b05031c 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -141,12 +141,12 @@ macro_rules! impl_gate_support { #[napi] #[derive(Clone, Default, Debug)] pub struct []( - #[napi(skip)] pub Vec>); - + #[napi(skip)] pub Vec>, + ); #[napi] pub fn []() -> [] { - [(Vec::new())] + [](Vec::new()) } #[napi] @@ -188,10 +188,11 @@ macro_rules! impl_gate_support { pub fn []( public_input_size: i32, vector: &[], - ) -> Vec { - Circuit::new(public_input_size as usize, &vector.0) + ) -> Uint8Array { + let bytes = Circuit::new(public_input_size as usize, &vector.0) .digest() - .to_vec() + .to_vec(); + Uint8Array::from(bytes) } #[napi] @@ -211,11 +212,5 @@ macro_rules! impl_gate_support { }; } -pub mod fp { - use super::*; - impl_gate_support!(fp, Fp, WasmPastaFp); -} -pub mod fq { - use super::*; - impl_gate_support!(fq, Fq, WasmPastaFq); -} +impl_gate_support!(fp, Fp, WasmPastaFp); +impl_gate_support!(fq, Fq, WasmPastaFq); diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 33a8a4f6c0..5edf9a98c1 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -8,20 +8,15 @@ mod poly_comm; pub use circuit::prover_to_json; pub use gate_vector::{ - fp::{ - caml_pasta_fp_plonk_circuit_digest, caml_pasta_fp_plonk_circuit_serialize, - caml_pasta_fp_plonk_gate_vector_add, caml_pasta_fp_plonk_gate_vector_create, - caml_pasta_fp_plonk_gate_vector_digest, caml_pasta_fp_plonk_gate_vector_get, - caml_pasta_fp_plonk_gate_vector_len, caml_pasta_fp_plonk_gate_vector_wrap, - NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, - }, - fq::{ - caml_pasta_fq_plonk_circuit_digest, caml_pasta_fq_plonk_circuit_serialize, - caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, - caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, - caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, - NapiFqGate as WasmFqGate, NapiFqGateVector as WasmFqGateVector, - }, + caml_pasta_fp_plonk_circuit_serialize, caml_pasta_fp_plonk_gate_vector_add, + caml_pasta_fp_plonk_gate_vector_create, caml_pasta_fp_plonk_gate_vector_digest, + caml_pasta_fp_plonk_gate_vector_get, caml_pasta_fp_plonk_gate_vector_len, + caml_pasta_fp_plonk_gate_vector_wrap, caml_pasta_fq_plonk_circuit_serialize, + caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, + caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, + caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, + NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, NapiFqGate as WasmFqGate, + NapiFqGateVector as WasmFqGateVector, }; pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; From 2bb4a8ebb236e70f3424b8bb06c0c6ca6ce0624c Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 15 Oct 2025 18:52:32 +0200 Subject: [PATCH 23/75] napi: improve naming in gate_vector --- plonk-napi/src/gate_vector.rs | 64 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index bf1b05031c..9c77299502 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -55,6 +55,7 @@ impl From<&GateWires> for NapiGateWires { } fn gate_type_from_i32(value: i32) -> Result { + // Ocaml/JS int are signed, so we use i32 here if value < 0 { return Err(Error::new( Status::InvalidArg, @@ -92,24 +93,25 @@ fn gate_type_from_i32(value: i32) -> Result { }) } +// For convenience to not expose the GateType enum to JS fn gate_type_to_i32(value: GateType) -> i32 { value as i32 } macro_rules! impl_gate_support { - ($module:ident, $field:ty, $wasm_field:ty) => { + ($field_name:ident, $F:ty, $WasmF:ty) => { paste! { #[napi(object)] #[derive(Clone, Debug, Default)] - pub struct [] { - pub typ: i32, + pub struct [] { + pub typ: i32, // for convenience, we use i32 instead of GateType pub wires: NapiGateWires, - pub coeffs: Vec, + pub coeffs: Vec, // for now, serializing fields as flat bytes, but subject to changes } - impl [] { - fn into_inner(self) -> Result> { - let coeffs = WasmFlatVector::<$wasm_field>::from_bytes(self.coeffs) + impl [] { + fn into_inner(self) -> Result> { + let coeffs = WasmFlatVector::<$WasmF>::from_bytes(self.coeffs) .into_iter() .map(Into::into) .collect(); @@ -121,12 +123,12 @@ macro_rules! impl_gate_support { }) } - fn from_inner(value: &CircuitGate<$field>) -> Self { + fn from_inner(value: &CircuitGate<$F>) -> Self { let coeffs = value .coeffs .iter() .cloned() - .map($wasm_field::from) + .map($WasmF::from) .flat_map(|elem| elem.flatten()) .collect(); @@ -140,54 +142,52 @@ macro_rules! impl_gate_support { #[napi] #[derive(Clone, Default, Debug)] - pub struct []( - #[napi(skip)] pub Vec>, + pub struct []( + #[napi(skip)] pub Vec>, ); #[napi] - pub fn []() -> [] { - [](Vec::new()) + pub fn []() -> [] { + [](Vec::new()) } #[napi] - pub fn []( - vector: &mut [], - gate: [], + pub fn []( + vector: &mut [], + gate: [], ) -> Result<()> { vector.0.push(gate.into_inner()?); Ok(()) } #[napi] - pub fn []( - vector: &[], + pub fn []( + vector: &[], index: i32, - ) -> [] { - []::from_inner(&vector.0[index as usize]) + ) -> [] { + []::from_inner(&vector.0[index as usize]) } #[napi] - pub fn []( - vector: &[], + pub fn []( + vector: &[], ) -> i32 { vector.0.len() as i32 } #[napi] - pub fn []( - vector: &mut [], + pub fn []( + vector: &mut [], target: NapiWire, head: NapiWire, ) { - let row = target.row as usize; - let col = target.col as usize; - vector.0[row].wires[col] = KimchiWire::from(head); + vector.0[target.row as usize].wires[target.col as usize] = KimchiWire::from(head); } #[napi] - pub fn []( + pub fn []( public_input_size: i32, - vector: &[], + vector: &[], ) -> Uint8Array { let bytes = Circuit::new(public_input_size as usize, &vector.0) .digest() @@ -196,15 +196,15 @@ macro_rules! impl_gate_support { } #[napi] - pub fn []( + pub fn []( public_input_size: i32, - vector: &[], + vector: &[], ) -> Result { let circuit = Circuit::new(public_input_size as usize, &vector.0); serde_json::to_string(&circuit).map_err(|err| { Error::new( Status::GenericFailure, - format!("failed to serialize circuit: {}", err), + format!("couldn't serialize constraints: {}", err), ) }) } From 482430879237dd82feab7dfe1eca5105ba570c7b Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 16 Oct 2025 13:19:18 +0200 Subject: [PATCH 24/75] napi: comment out poseidon, and include comments for gatevector --- plonk-napi/src/gate_vector.rs | 7 +++++++ plonk-napi/src/poseidon.rs | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index 9c77299502..2a4712ee26 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -148,6 +148,7 @@ macro_rules! impl_gate_support { #[napi] pub fn []() -> [] { + println!("from native rust creating gate vector"); [](Vec::new()) } @@ -156,6 +157,7 @@ macro_rules! impl_gate_support { vector: &mut [], gate: [], ) -> Result<()> { + println!("from native rust adding gate to vector"); vector.0.push(gate.into_inner()?); Ok(()) } @@ -165,6 +167,7 @@ macro_rules! impl_gate_support { vector: &[], index: i32, ) -> [] { + println!("from native rust getting gate from vector"); []::from_inner(&vector.0[index as usize]) } @@ -172,6 +175,7 @@ macro_rules! impl_gate_support { pub fn []( vector: &[], ) -> i32 { + println!("from native rust getting gate vector length"); vector.0.len() as i32 } @@ -181,6 +185,7 @@ macro_rules! impl_gate_support { target: NapiWire, head: NapiWire, ) { + println!("from native rust wrapping wire in gate vector"); vector.0[target.row as usize].wires[target.col as usize] = KimchiWire::from(head); } @@ -189,6 +194,7 @@ macro_rules! impl_gate_support { public_input_size: i32, vector: &[], ) -> Uint8Array { + println!("from native rust computing gate vector digest"); let bytes = Circuit::new(public_input_size as usize, &vector.0) .digest() .to_vec(); @@ -200,6 +206,7 @@ macro_rules! impl_gate_support { public_input_size: i32, vector: &[], ) -> Result { + println!("from native rust serializing gate vector to json"); let circuit = Circuit::new(public_input_size as usize, &vector.0); serde_json::to_string(&circuit).map_err(|err| { Error::new( diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index 4f910b5b54..fb8f7b66b4 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -9,7 +9,7 @@ use wasm_types::{FlatVector, FlatVectorElem}; #[napi] pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result { - println!("from native rust"); + //println!("from native rust fp poseidon"); let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() @@ -34,7 +34,7 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result Result { - println!("from native rust"); + //println!("from native rust fq poseidon"); let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() From bc98785865e3b0a9ab10a3ded8b785a5d2bdd36c Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 19:59:51 +0700 Subject: [PATCH 25/75] remove _plonk_index_serialize --- plonk-wasm/src/pasta_fp_plonk_index.rs | 8 -------- plonk-wasm/src/pasta_fq_plonk_index.rs | 8 -------- 2 files changed, 16 deletions(-) diff --git a/plonk-wasm/src/pasta_fp_plonk_index.rs b/plonk-wasm/src/pasta_fp_plonk_index.rs index 5af8cdf550..f79bee033f 100644 --- a/plonk-wasm/src/pasta_fp_plonk_index.rs +++ b/plonk-wasm/src/pasta_fp_plonk_index.rs @@ -342,14 +342,6 @@ pub fn caml_pasta_fp_plonk_index_write( .map_err(|e| JsValue::from_str(&format!("caml_pasta_fp_plonk_index_read: {e}"))) } -#[allow(deprecated)] -#[wasm_bindgen] -pub fn caml_pasta_fp_plonk_index_serialize(index: &WasmPastaFpPlonkIndex) -> String { - let serialized = rmp_serde::to_vec(&index.0).unwrap(); - // Deprecated used on purpose: updating this leads to a bug in o1js - base64::encode(serialized) -} - // helpers fn format_field(f: &Fp) -> String { diff --git a/plonk-wasm/src/pasta_fq_plonk_index.rs b/plonk-wasm/src/pasta_fq_plonk_index.rs index 6b46b66065..68019d8757 100644 --- a/plonk-wasm/src/pasta_fq_plonk_index.rs +++ b/plonk-wasm/src/pasta_fq_plonk_index.rs @@ -273,11 +273,3 @@ pub fn caml_pasta_fq_plonk_index_write( .serialize(&mut rmp_serde::Serializer::new(w)) .map_err(|e| JsValue::from_str(&format!("caml_pasta_fq_plonk_index_read: {e}"))) } - -#[allow(deprecated)] -#[wasm_bindgen] -pub fn caml_pasta_fq_plonk_index_serialize(index: &WasmPastaFqPlonkIndex) -> String { - let serialized = rmp_serde::to_vec(&index.0).unwrap(); - // Deprecated used on purpose: updating this leads to a bug in o1js - base64::encode(serialized) -} From 25be75a5b64c5a063965458e82718a03230d9798 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 21:05:03 +0700 Subject: [PATCH 26/75] impl. prover index degrees for fq --- plonk-napi/src/pasta_fq_plonk_index.rs | 107 +++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 plonk-napi/src/pasta_fq_plonk_index.rs diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs new file mode 100644 index 0000000000..e2f046ba04 --- /dev/null +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -0,0 +1,107 @@ +use ark_poly::EvaluationDomain; +use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; +use mina_curves::pasta::{Vesta as GAffine, VestaParameters}; +use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; +use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi_derive::napi; +use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; +use poly_commitment::SRS; +use serde::{Deserialize, Serialize}; +use std::{io::Cursor, sync::Arc}; +pub struct WasmPastaFqPlonkIndex(pub Box>>); + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[derive(Serialize, Deserialize)] +struct SerializedProverIndex { + prover_index: Vec, + srs: Vec, +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +impl WasmPastaFqPlonkIndex { + fn serialize_inner(&self) -> Result, String> { + let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; + + let mut srs = Vec::new(); + self.0 + .srs + .serialize(&mut rmp_serde::Serializer::new(&mut srs)) + .map_err(|e| e.to_string())?; + + let serialized = SerializedProverIndex { prover_index, srs }; + + rmp_serde::to_vec(&serialized).map_err(|e| e.to_string()) + } + + fn deserialize_inner(bytes: &[u8]) -> Result { + let serialized: SerializedProverIndex = + rmp_serde::from_slice(bytes).map_err(|e| e.to_string())?; + + let mut index: ProverIndex> = ProverIndex::deserialize( + &mut rmp_serde::Deserializer::new(Cursor::new(serialized.prover_index)), + ) + .map_err(|e| e.to_string())?; + + let srs = IPA_SRS::::deserialize(&mut rmp_serde::Deserializer::new(Cursor::new( + serialized.srs, + ))) + .map_err(|e| e.to_string())?; + + index.srs = Arc::new(srs); + + let (linearization, powers_of_alpha) = + expr_linearization(Some(&index.cs.feature_flags), true); + index.linearization = linearization; + index.powers_of_alpha = powers_of_alpha; + + index.compute_verifier_index_digest::< + DefaultFqSponge, + >(); + + Ok(WasmPastaFqPlonkIndex(Box::new(index))) + } +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[napi] +pub fn prover_index_fq_from_bytes( + bytes: Uint8Array, +) -> NapiResult> { + let index = WasmPastaFqPlonkIndex::deserialize_inner(bytes.as_ref()) + .map_err(|e| Error::new(Status::InvalidArg, e))?; + Ok(External::new(index)) +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[napi] +pub fn prover_index_fq_to_bytes(index: External) -> NapiResult { + let bytes = index + .serialize_inner() + .map_err(|e| Error::new(Status::GenericFailure, e))?; + Ok(Uint8Array::from(bytes)) +} + +#[napi] +pub fn caml_pasta_fq_plonk_index_max_degree(index: External) -> i32 { + index.0.srs.max_poly_size() as i32 +} + +#[napi] +pub fn caml_pasta_fq_plonk_index_public_inputs(index: External) -> i32 { + index.0.cs.public as i32 +} + +#[napi] +pub fn caml_pasta_fq_plonk_index_domain_d1_size(index: External) -> i32 { + index.0.cs.domain.d1.size() as i32 +} + +#[napi] +pub fn caml_pasta_fq_plonk_index_domain_d4_size(index: External) -> i32 { + index.0.cs.domain.d4.size() as i32 +} + +#[napi] +pub fn caml_pasta_fq_plonk_index_domain_d8_size(index: External) -> i32 { + index.0.cs.domain.d8.size() as i32 +} From e728d24e69bad98d1eede4952186cbb5bf15b59d Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 21:05:16 +0700 Subject: [PATCH 27/75] impl. prover index for fp --- plonk-napi/src/pasta_fp_plonk_index.rs | 107 +++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 plonk-napi/src/pasta_fp_plonk_index.rs diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs new file mode 100644 index 0000000000..bf24ab9ffc --- /dev/null +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -0,0 +1,107 @@ +use ark_poly::EvaluationDomain; +use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; +use mina_curves::pasta::{Vesta as GAffine, VestaParameters}; +use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; +use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi_derive::napi; +use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; +use poly_commitment::SRS; +use serde::{Deserialize, Serialize}; +use std::{io::Cursor, sync::Arc}; +pub struct WasmPastaFpPlonkIndex(pub Box>>); + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[derive(Serialize, Deserialize)] +struct SerializedProverIndex { + prover_index: Vec, + srs: Vec, +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +impl WasmPastaFpPlonkIndex { + fn serialize_inner(&self) -> Result, String> { + let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; + + let mut srs = Vec::new(); + self.0 + .srs + .serialize(&mut rmp_serde::Serializer::new(&mut srs)) + .map_err(|e| e.to_string())?; + + let serialized = SerializedProverIndex { prover_index, srs }; + + rmp_serde::to_vec(&serialized).map_err(|e| e.to_string()) + } + + fn deserialize_inner(bytes: &[u8]) -> Result { + let serialized: SerializedProverIndex = + rmp_serde::from_slice(bytes).map_err(|e| e.to_string())?; + + let mut index: ProverIndex> = ProverIndex::deserialize( + &mut rmp_serde::Deserializer::new(Cursor::new(serialized.prover_index)), + ) + .map_err(|e| e.to_string())?; + + let srs = IPA_SRS::::deserialize(&mut rmp_serde::Deserializer::new(Cursor::new( + serialized.srs, + ))) + .map_err(|e| e.to_string())?; + + index.srs = Arc::new(srs); + + let (linearization, powers_of_alpha) = + expr_linearization(Some(&index.cs.feature_flags), true); + index.linearization = linearization; + index.powers_of_alpha = powers_of_alpha; + + index.compute_verifier_index_digest::< + DefaultFqSponge, + >(); + + Ok(WasmPastaFpPlonkIndex(Box::new(index))) + } +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[napi] +pub fn prover_index_fp_from_bytes( + bytes: Uint8Array, +) -> NapiResult> { + let index = WasmPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) + .map_err(|e| Error::new(Status::InvalidArg, e))?; + Ok(External::new(index)) +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[napi] +pub fn prover_index_fp_to_bytes(index: External) -> NapiResult { + let bytes = index + .serialize_inner() + .map_err(|e| Error::new(Status::GenericFailure, e))?; + Ok(Uint8Array::from(bytes)) +} + +#[napi] +pub fn caml_pasta_fp_plonk_index_max_degree(index: External) -> i32 { + index.0.srs.max_poly_size() as i32 +} + +#[napi] +pub fn caml_pasta_fp_plonk_index_public_inputs(index: External) -> i32 { + index.0.cs.public as i32 +} + +#[napi] +pub fn caml_pasta_fp_plonk_index_domain_d1_size(index: External) -> i32 { + index.0.cs.domain.d1.size() as i32 +} + +#[napi] +pub fn caml_pasta_fp_plonk_index_domain_d4_size(index: External) -> i32 { + index.0.cs.domain.d4.size() as i32 +} + +#[napi] +pub fn caml_pasta_fp_plonk_index_domain_d8_size(index: External) -> i32 { + index.0.cs.domain.d8.size() as i32 +} From 0159d401f8bdfbe2cfa9ce2fbe598f2fb2705e23 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 21:05:24 +0700 Subject: [PATCH 28/75] get rid of told types file --- plonk-napi/src/types.rs | 79 ----------------------------------------- 1 file changed, 79 deletions(-) delete mode 100644 plonk-napi/src/types.rs diff --git a/plonk-napi/src/types.rs b/plonk-napi/src/types.rs deleted file mode 100644 index 985bf50d35..0000000000 --- a/plonk-napi/src/types.rs +++ /dev/null @@ -1,79 +0,0 @@ -use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; -use mina_curves::pasta::{Vesta as GAffine, VestaParameters}; -use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; -use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; -use napi_derive::napi; -use poly_commitment::ipa::{OpeningProof, SRS}; -use serde::{Deserialize, Serialize}; -use std::{io::Cursor, sync::Arc}; - -pub struct WasmPastaFpPlonkIndex(pub Box>>); - -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around -#[derive(Serialize, Deserialize)] -struct SerializedProverIndex { - prover_index: Vec, - srs: Vec, -} - -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around -impl WasmPastaFpPlonkIndex { - fn serialize_inner(&self) -> Result, String> { - let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; - - let mut srs = Vec::new(); - self.0 - .srs - .serialize(&mut rmp_serde::Serializer::new(&mut srs)) - .map_err(|e| e.to_string())?; - - let serialized = SerializedProverIndex { prover_index, srs }; - - rmp_serde::to_vec(&serialized).map_err(|e| e.to_string()) - } - - fn deserialize_inner(bytes: &[u8]) -> Result { - let serialized: SerializedProverIndex = - rmp_serde::from_slice(bytes).map_err(|e| e.to_string())?; - - let mut index: ProverIndex> = ProverIndex::deserialize( - &mut rmp_serde::Deserializer::new(Cursor::new(serialized.prover_index)), - ) - .map_err(|e| e.to_string())?; - - let srs = SRS::::deserialize(&mut rmp_serde::Deserializer::new(Cursor::new( - serialized.srs, - ))) - .map_err(|e| e.to_string())?; - - index.srs = Arc::new(srs); - - let (linearization, powers_of_alpha) = - expr_linearization(Some(&index.cs.feature_flags), true); - index.linearization = linearization; - index.powers_of_alpha = powers_of_alpha; - - index.compute_verifier_index_digest::< - DefaultFqSponge, - >(); - - Ok(WasmPastaFpPlonkIndex(Box::new(index))) - } -} - -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around -#[napi] -pub fn prover_index_from_bytes(bytes: Uint8Array) -> NapiResult> { - let index = WasmPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) - .map_err(|e| Error::new(Status::InvalidArg, e))?; - Ok(External::new(index)) -} - -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around -#[napi] -pub fn prover_index_to_bytes(index: External) -> NapiResult { - let bytes = index - .serialize_inner() - .map_err(|e| Error::new(Status::GenericFailure, e))?; - Ok(Uint8Array::from(bytes)) -} From c74e69a3ff70d42411ddd3ab3e5fd99dc2fa19dd Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 21:05:34 +0700 Subject: [PATCH 29/75] explose and rename modules --- plonk-napi/Cargo.toml | 1 - plonk-napi/src/circuit.rs | 2 +- plonk-napi/src/lib.rs | 11 +++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/plonk-napi/Cargo.toml b/plonk-napi/Cargo.toml index 6b91ebbffb..6cfa08e0e6 100644 --- a/plonk-napi/Cargo.toml +++ b/plonk-napi/Cargo.toml @@ -27,7 +27,6 @@ kimchi.workspace = true mina-curves = { path = "../curves" } mina-poseidon = { path = "../poseidon" } o1-utils = { path = "../utils" } -kimchi = { path = "../kimchi" } poly-commitment = { path = "../poly-commitment" } getrandom.workspace = true diff --git a/plonk-napi/src/circuit.rs b/plonk-napi/src/circuit.rs index 0c2a850228..a9fa08bda1 100644 --- a/plonk-napi/src/circuit.rs +++ b/plonk-napi/src/circuit.rs @@ -5,7 +5,7 @@ use napi::bindgen_prelude::*; use napi_derive::napi; use serde::Serialize; -use crate::types::WasmPastaFpPlonkIndex; +use crate::pasta_fp_plonk_index::WasmPastaFpPlonkIndex; #[derive(Serialize)] struct Circuit diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 5edf9a98c1..5ba0f454cb 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,10 +1,12 @@ mod circuit; mod gate_vector; +mod pasta_fp_plonk_index; +mod pasta_fq_plonk_index; +mod poly_comm; mod poseidon; mod types; mod wrappers; mod wasm_vector; -mod poly_comm; pub use circuit::prover_to_json; pub use gate_vector::{ @@ -18,8 +20,13 @@ pub use gate_vector::{ NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, NapiFqGate as WasmFqGate, NapiFqGateVector as WasmFqGateVector, }; +pub use pasta_fp_plonk_index::{ + prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, +}; +pub use pasta_fq_plonk_index::{ + prover_index_fq_from_bytes, prover_index_fq_to_bytes, WasmPastaFqPlonkIndex, +}; pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; -pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; pub use wrappers::{field::{WasmPastaFp, WasmPastaFq}, group::{WasmGPallas, WasmGVesta}}; From 4b887e9ce9ebfc02ec3fa0f9b393f612edc4099c Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 21:44:51 +0700 Subject: [PATCH 30/75] fix proper types --- plonk-napi/src/pasta_fq_plonk_index.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index e2f046ba04..1a6ebfe1b2 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -1,6 +1,6 @@ use ark_poly::EvaluationDomain; use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; -use mina_curves::pasta::{Vesta as GAffine, VestaParameters}; +use mina_curves::pasta::{Pallas as GAffine, PallasParameters}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; use napi_derive::napi; @@ -55,7 +55,7 @@ impl WasmPastaFqPlonkIndex { index.powers_of_alpha = powers_of_alpha; index.compute_verifier_index_digest::< - DefaultFqSponge, + DefaultFqSponge, >(); Ok(WasmPastaFqPlonkIndex(Box::new(index))) From 5151b2a2ee973853b7acaf25bb7f618850b19560 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 21:45:02 +0700 Subject: [PATCH 31/75] WasmPastaFqPlonkIndex seri impl (wip) --- plonk-wasm/src/pasta_fq_plonk_index.rs | 66 ++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/plonk-wasm/src/pasta_fq_plonk_index.rs b/plonk-wasm/src/pasta_fq_plonk_index.rs index 68019d8757..f379fa88c4 100644 --- a/plonk-wasm/src/pasta_fq_plonk_index.rs +++ b/plonk-wasm/src/pasta_fq_plonk_index.rs @@ -22,6 +22,7 @@ use std::{ fs::{File, OpenOptions}, io::{BufReader, BufWriter, Seek, SeekFrom::Start}, }; +use std::{io::Cursor, sync::Arc}; use wasm_bindgen::prelude::*; use wasm_types::FlatVector as WasmFlatVector; @@ -35,6 +36,71 @@ pub struct WasmPastaFqPlonkIndex( #[wasm_bindgen(skip)] pub Box>>, ); +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[derive(Serialize, Deserialize)] +struct SerializedProverIndex { + prover_index: Vec, + srs: Vec, +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[wasm_bindgen] +impl WasmPastaFqPlonkIndex { + #[wasm_bindgen(js_name = "serialize")] + pub fn serialize(&self) -> Result, JsError> { + serialize_prover_index(self.0.as_ref()) + .map_err(|e| JsError::new(&format!("WasmPastaFqPlonkIndex::serialize: {e}"))) + } + + #[wasm_bindgen(js_name = "deserialize")] + pub fn deserialize(bytes: &[u8]) -> Result { + deserialize_prover_index(bytes) + .map(WasmPastaFqPlonkIndex) + .map_err(|e| JsError::new(&format!("WasmPastaFqPlonkIndex::deserialize: {e}"))) + } +} + +fn serialize_prover_index( + index: &ProverIndex>, +) -> Result, String> { + let prover_index = rmp_serde::to_vec(index).map_err(|e| e.to_string())?; + + let mut srs = Vec::new(); + index + .srs + .serialize(&mut rmp_serde::Serializer::new(&mut srs)) + .map_err(|e| e.to_string())?; + + let serialized = SerializedProverIndex { prover_index, srs }; + + rmp_serde::to_vec(&serialized).map_err(|e| e.to_string()) +} + +fn deserialize_prover_index( + bytes: &[u8], +) -> Result>>, String> { + let serialized: SerializedProverIndex = + rmp_serde::from_slice(bytes).map_err(|e| e.to_string())?; + + let mut index: ProverIndex> = ProverIndex::deserialize( + &mut rmp_serde::Deserializer::new(Cursor::new(serialized.prover_index)), + ) + .map_err(|e| e.to_string())?; + + let srs = poly_commitment::ipa::SRS::::deserialize(&mut rmp_serde::Deserializer::new( + Cursor::new(serialized.srs), + )) + .map_err(|e| e.to_string())?; + + index.srs = Arc::new(srs); + + let (linearization, powers_of_alpha) = expr_linearization(Some(&index.cs.feature_flags), true); + index.linearization = linearization; + index.powers_of_alpha = powers_of_alpha; + + Ok(Box::new(index)) +} + #[wasm_bindgen] pub struct WasmPastaFqLookupTable { #[wasm_bindgen(skip)] From 906d083c79361100221771930b4904430c113e61 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 15 Oct 2025 21:52:32 +0700 Subject: [PATCH 32/75] remove debug logs --- plonk-napi/src/poseidon.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index fb8f7b66b4..ba96f58bfb 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -9,8 +9,6 @@ use wasm_types::{FlatVector, FlatVectorElem}; #[napi] pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result { - //println!("from native rust fp poseidon"); - let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) @@ -34,8 +32,6 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result Result { - //println!("from native rust fq poseidon"); - let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) From 81e860b0c0c036f2764d24b89fe846fe2eb262a1 Mon Sep 17 00:00:00 2001 From: Florian Date: Thu, 16 Oct 2025 00:51:02 +0700 Subject: [PATCH 33/75] testtest --- Cargo.lock | 1 + plonk-napi/Cargo.toml | 1 + plonk-napi/src/gate_vector.rs | 569 ++++++++++++++++--------- plonk-napi/src/lib.rs | 7 +- plonk-napi/src/pasta_fp_plonk_index.rs | 73 +++- plonk-napi/src/pasta_fq_plonk_index.rs | 75 +++- plonk-napi/src/tables.rs | 85 ++++ plonk-wasm/src/gate_vector.rs | 295 ++++++++++--- 8 files changed, 835 insertions(+), 271 deletions(-) create mode 100644 plonk-napi/src/tables.rs diff --git a/Cargo.lock b/Cargo.lock index d7aaf3c947..3eb5e98a41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2945,6 +2945,7 @@ dependencies = [ "o1-utils", "once_cell", "paste", + "plonk_wasm", "poly-commitment", "rand", "rayon", diff --git a/plonk-napi/Cargo.toml b/plonk-napi/Cargo.toml index 6cfa08e0e6..ffb376a774 100644 --- a/plonk-napi/Cargo.toml +++ b/plonk-napi/Cargo.toml @@ -28,6 +28,7 @@ mina-curves = { path = "../curves" } mina-poseidon = { path = "../poseidon" } o1-utils = { path = "../utils" } poly-commitment = { path = "../poly-commitment" } +plonk_wasm.workspace = true getrandom.workspace = true libc.workspace = true diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index 2a4712ee26..6c6ca0cc2b 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -1,223 +1,384 @@ -use kimchi::circuits::{ - gate::{Circuit, CircuitGate, GateType}, - wires::{GateWires, Wire as KimchiWire}, -}; +use std::convert::TryFrom; + +use arkworks::{WasmPastaFp, WasmPastaFq}; +use kimchi::circuits::{gate::GateType, wires::Wire}; use mina_curves::pasta::{Fp, Fq}; -use napi::bindgen_prelude::*; +use napi::bindgen_prelude::{Error, External, Status, Uint8Array}; use napi_derive::napi; -use o1_utils::hasher::CryptoDigest; -use paste::paste; -use wasm_types::{FlatVector as WasmFlatVector, FlatVectorElem}; - -use crate::wrappers::{ - field::{WasmPastaFp, WasmPastaFq}, - wires::NapiWire, +use plonk_wasm::gate_vector::{ + CoreGate as Gate, CoreGateVector as GateVector, CoreGateWires as GateWires, }; +use wasm_types::{FlatVector, FlatVectorElem}; -#[napi(object)] -#[derive(Clone, Debug, Default)] -pub struct NapiGateWires { - pub w0: NapiWire, - pub w1: NapiWire, - pub w2: NapiWire, - pub w3: NapiWire, - pub w4: NapiWire, - pub w5: NapiWire, - pub w6: NapiWire, -} - -impl NapiGateWires { - fn into_inner(self) -> GateWires { - [ - KimchiWire::from(self.w0), - KimchiWire::from(self.w1), - KimchiWire::from(self.w2), - KimchiWire::from(self.w3), - KimchiWire::from(self.w4), - KimchiWire::from(self.w5), - KimchiWire::from(self.w6), - ] +pub struct GateVectorHandleFp(pub GateVector); +pub struct GateVectorHandleFq(pub GateVector); + +impl GateVectorHandleFp { + fn new() -> Self { + Self(GateVector::new()) + } + pub(crate) fn inner(&self) -> &GateVector { + &self.0 + } + pub(crate) fn inner_mut(&mut self) -> &mut GateVector { + &mut self.0 } } -impl From<&GateWires> for NapiGateWires { - fn from(value: &GateWires) -> Self { - Self { - w0: value[0].into(), - w1: value[1].into(), - w2: value[2].into(), - w3: value[3].into(), - w4: value[4].into(), - w5: value[5].into(), - w6: value[6].into(), - } +impl GateVectorHandleFq { + fn new() -> Self { + Self(GateVector::new()) + } + pub(crate) fn inner(&self) -> &GateVector { + &self.0 + } + pub(crate) fn inner_mut(&mut self) -> &mut GateVector { + &mut self.0 } } -fn gate_type_from_i32(value: i32) -> Result { - // Ocaml/JS int are signed, so we use i32 here - if value < 0 { - return Err(Error::new( +unsafe impl Send for GateVectorHandleFp {} +unsafe impl Sync for GateVectorHandleFp {} +unsafe impl Send for GateVectorHandleFq {} +unsafe impl Sync for GateVectorHandleFq {} + +#[napi(object)] +pub struct JsWire { + pub row: u32, + pub col: u32, +} + +#[napi(object)] +pub struct JsGateWires { + pub w0: JsWire, + pub w1: JsWire, + pub w2: JsWire, + pub w3: JsWire, + pub w4: JsWire, + pub w5: JsWire, + pub w6: JsWire, +} + +#[napi(object)] +pub struct JsGateFp { + pub typ: i32, + pub wires: JsGateWires, + pub coeffs: Uint8Array, +} + +#[napi(object)] +pub struct JsGateFq { + pub typ: i32, + pub wires: JsGateWires, + pub coeffs: Uint8Array, +} + +fn gate_type_from_i32(value: i32) -> napi::Result { + match value { + 0 => Ok(GateType::Zero), + 1 => Ok(GateType::Generic), + 2 => Ok(GateType::Poseidon), + 3 => Ok(GateType::CompleteAdd), + 4 => Ok(GateType::VarBaseMul), + 5 => Ok(GateType::EndoMul), + 6 => Ok(GateType::EndoMulScalar), + 7 => Ok(GateType::Lookup), + 8 => Ok(GateType::CairoClaim), + 9 => Ok(GateType::CairoInstruction), + 10 => Ok(GateType::CairoFlags), + 11 => Ok(GateType::CairoTransition), + 12 => Ok(GateType::RangeCheck0), + 13 => Ok(GateType::RangeCheck1), + 14 => Ok(GateType::ForeignFieldAdd), + 15 => Ok(GateType::ForeignFieldMul), + 16 => Ok(GateType::Xor16), + 17 => Ok(GateType::Rot64), + _ => Err(Error::new( Status::InvalidArg, - format!("invalid GateType discriminant: {}", value), - )); + format!("unknown gate type discriminant {value}"), + )), } +} + +fn gate_type_to_i32(value: GateType) -> i32 { + value as i32 +} + +fn js_wire_to_wire(wire: &JsWire) -> napi::Result { + Ok(Wire { + row: wire.row as usize, + col: wire.col as usize, + }) +} + +fn wire_to_js(wire: Wire) -> napi::Result { + Ok(JsWire { + row: u32::try_from(wire.row).map_err(|_| { + Error::new( + Status::InvalidArg, + format!("wire row {row} does not fit in u32", row = wire.row), + ) + })?, + col: u32::try_from(wire.col).map_err(|_| { + Error::new( + Status::InvalidArg, + format!("wire col {col} does not fit in u32", col = wire.col), + ) + })?, + }) +} + +fn js_wires_to_core(wires: &JsGateWires) -> napi::Result { + Ok(GateWires::new([ + js_wire_to_wire(&wires.w0)?, + js_wire_to_wire(&wires.w1)?, + js_wire_to_wire(&wires.w2)?, + js_wire_to_wire(&wires.w3)?, + js_wire_to_wire(&wires.w4)?, + js_wire_to_wire(&wires.w5)?, + js_wire_to_wire(&wires.w6)?, + ])) +} + +fn core_wires_to_js(wires: &GateWires) -> napi::Result { + let arr = wires.as_array(); + Ok(JsGateWires { + w0: wire_to_js(arr[0])?, + w1: wire_to_js(arr[1])?, + w2: wire_to_js(arr[2])?, + w3: wire_to_js(arr[3])?, + w4: wire_to_js(arr[4])?, + w5: wire_to_js(arr[5])?, + w6: wire_to_js(arr[6])?, + }) +} + +fn coeffs_from_bytes_fp(bytes: Vec) -> Vec { + FlatVector::::from_bytes(bytes) + .into_iter() + .map(Into::into) + .collect() +} + +fn coeffs_from_bytes_fq(bytes: Vec) -> Vec { + FlatVector::::from_bytes(bytes) + .into_iter() + .map(Into::into) + .collect() +} + +fn coeffs_to_bytes_fp(coeffs: &[Fp]) -> Vec { + coeffs + .iter() + .cloned() + .map(WasmPastaFp) + .flat_map(FlatVectorElem::flatten) + .collect() +} - let variants: &[GateType] = &[ - GateType::Zero, - GateType::Generic, - GateType::Poseidon, - GateType::CompleteAdd, - GateType::VarBaseMul, - GateType::EndoMul, - GateType::EndoMulScalar, - GateType::Lookup, - GateType::CairoClaim, - GateType::CairoInstruction, - GateType::CairoFlags, - GateType::CairoTransition, - GateType::RangeCheck0, - GateType::RangeCheck1, - GateType::ForeignFieldAdd, - GateType::ForeignFieldMul, - GateType::Xor16, - GateType::Rot64, - ]; - - let index = value as usize; - variants.get(index).copied().ok_or_else(|| { +fn coeffs_to_bytes_fq(coeffs: &[Fq]) -> Vec { + coeffs + .iter() + .cloned() + .map(WasmPastaFq) + .flat_map(FlatVectorElem::flatten) + .collect() +} + +fn js_gate_fp_to_core(gate: JsGateFp) -> napi::Result> { + let typ = gate_type_from_i32(gate.typ)?; + let wires = js_wires_to_core(&gate.wires)?; + let coeff_bytes = gate.coeffs.to_vec(); + Ok(Gate { + typ, + wires, + coeffs: coeffs_from_bytes_fp(coeff_bytes), + }) +} + +fn js_gate_fq_to_core(gate: JsGateFq) -> napi::Result> { + let typ = gate_type_from_i32(gate.typ)?; + let wires = js_wires_to_core(&gate.wires)?; + let coeff_bytes = gate.coeffs.to_vec(); + Ok(Gate { + typ, + wires, + coeffs: coeffs_from_bytes_fq(coeff_bytes), + }) +} + +fn core_gate_fp_to_js(gate: Gate) -> napi::Result { + let coeff_bytes = coeffs_to_bytes_fp(&gate.coeffs); + Ok(JsGateFp { + typ: gate_type_to_i32(gate.typ), + wires: core_wires_to_js(&gate.wires)?, + coeffs: Uint8Array::from(coeff_bytes), + }) +} + +fn core_gate_fq_to_js(gate: Gate) -> napi::Result { + let coeff_bytes = coeffs_to_bytes_fq(&gate.coeffs); + Ok(JsGateFq { + typ: gate_type_to_i32(gate.typ), + wires: core_wires_to_js(&gate.wires)?, + coeffs: Uint8Array::from(coeff_bytes), + }) +} + +#[napi] +pub fn caml_pasta_fp_plonk_gate_vector_create() -> napi::Result> { + Ok(External::new(GateVectorHandleFp::new())) +} + +#[napi] +pub fn caml_pasta_fp_plonk_gate_vector_add( + mut gates: External, + gate: JsGateFp, +) -> napi::Result<()> { + let gate = js_gate_fp_to_core(gate)?; + gates.as_mut().inner_mut().push_gate(gate.into()); + Ok(()) +} + +#[napi] +pub fn caml_pasta_fp_plonk_gate_vector_get( + gates: External, + i: i32, +) -> napi::Result { + let gate = gates + .as_ref() + .inner() + .get_gate(i as usize) + .map(core_gate_fp_to_js) + .unwrap_or_else(|| { + Err(Error::new( + Status::InvalidArg, + format!("gate index {i} out of bounds"), + )) + })?; + Ok(gate) +} + +#[napi] +pub fn caml_pasta_fp_plonk_gate_vector_len( + gates: External, +) -> napi::Result { + let len = gates.as_ref().inner().len(); + Ok(u32::try_from(len).map_err(|_| { Error::new( - Status::InvalidArg, - format!("invalid GateType discriminant: {}", value), + Status::GenericFailure, + "gate vector length exceeds u32".to_string(), ) - }) + })?) } -// For convenience to not expose the GateType enum to JS -fn gate_type_to_i32(value: GateType) -> i32 { - value as i32 +#[napi] +pub fn caml_pasta_fp_plonk_gate_vector_wrap( + mut gates: External, + t: JsWire, + h: JsWire, +) -> napi::Result<()> { + let target = js_wire_to_wire(&t)?; + let replacement = js_wire_to_wire(&h)?; + gates.as_mut().inner_mut().wrap_wire(target, replacement); + Ok(()) +} + +#[napi] +pub fn caml_pasta_fp_plonk_gate_vector_digest( + gates: External, + public_input_size: u32, +) -> Uint8Array { + Uint8Array::from(gates.as_ref().inner().digest(public_input_size as usize)) +} + +#[napi] +pub fn caml_pasta_fp_plonk_circuit_serialize( + gates: External, + public_input_size: u32, +) -> napi::Result { + gates + .as_ref() + .inner() + .serialize(public_input_size as usize) + .map_err(|e| Error::new(Status::GenericFailure, e.to_string())) } -macro_rules! impl_gate_support { - ($field_name:ident, $F:ty, $WasmF:ty) => { - paste! { - #[napi(object)] - #[derive(Clone, Debug, Default)] - pub struct [] { - pub typ: i32, // for convenience, we use i32 instead of GateType - pub wires: NapiGateWires, - pub coeffs: Vec, // for now, serializing fields as flat bytes, but subject to changes - } - - impl [] { - fn into_inner(self) -> Result> { - let coeffs = WasmFlatVector::<$WasmF>::from_bytes(self.coeffs) - .into_iter() - .map(Into::into) - .collect(); - - Ok(CircuitGate { - typ: gate_type_from_i32(self.typ)?, - wires: self.wires.into_inner(), - coeffs, - }) - } - - fn from_inner(value: &CircuitGate<$F>) -> Self { - let coeffs = value - .coeffs - .iter() - .cloned() - .map($WasmF::from) - .flat_map(|elem| elem.flatten()) - .collect(); - - Self { - typ: gate_type_to_i32(value.typ), - wires: (&value.wires).into(), - coeffs, - } - } - } - - #[napi] - #[derive(Clone, Default, Debug)] - pub struct []( - #[napi(skip)] pub Vec>, - ); - - #[napi] - pub fn []() -> [] { - println!("from native rust creating gate vector"); - [](Vec::new()) - } - - #[napi] - pub fn []( - vector: &mut [], - gate: [], - ) -> Result<()> { - println!("from native rust adding gate to vector"); - vector.0.push(gate.into_inner()?); - Ok(()) - } - - #[napi] - pub fn []( - vector: &[], - index: i32, - ) -> [] { - println!("from native rust getting gate from vector"); - []::from_inner(&vector.0[index as usize]) - } - - #[napi] - pub fn []( - vector: &[], - ) -> i32 { - println!("from native rust getting gate vector length"); - vector.0.len() as i32 - } - - #[napi] - pub fn []( - vector: &mut [], - target: NapiWire, - head: NapiWire, - ) { - println!("from native rust wrapping wire in gate vector"); - vector.0[target.row as usize].wires[target.col as usize] = KimchiWire::from(head); - } - - #[napi] - pub fn []( - public_input_size: i32, - vector: &[], - ) -> Uint8Array { - println!("from native rust computing gate vector digest"); - let bytes = Circuit::new(public_input_size as usize, &vector.0) - .digest() - .to_vec(); - Uint8Array::from(bytes) - } - - #[napi] - pub fn []( - public_input_size: i32, - vector: &[], - ) -> Result { - println!("from native rust serializing gate vector to json"); - let circuit = Circuit::new(public_input_size as usize, &vector.0); - serde_json::to_string(&circuit).map_err(|err| { - Error::new( - Status::GenericFailure, - format!("couldn't serialize constraints: {}", err), - ) - }) - } - } - }; -} - -impl_gate_support!(fp, Fp, WasmPastaFp); -impl_gate_support!(fq, Fq, WasmPastaFq); +#[napi] +pub fn caml_pasta_fq_plonk_gate_vector_create() -> napi::Result> { + Ok(External::new(GateVectorHandleFq::new())) +} + +#[napi] +pub fn caml_pasta_fq_plonk_gate_vector_add( + mut gates: External, + gate: JsGateFq, +) -> napi::Result<()> { + let gate = js_gate_fq_to_core(gate)?; + gates.as_mut().inner_mut().push_gate(gate.into()); + Ok(()) +} + +#[napi] +pub fn caml_pasta_fq_plonk_gate_vector_get( + gates: External, + i: i32, +) -> napi::Result { + let gate = gates + .as_ref() + .inner() + .get_gate(i as usize) + .map(core_gate_fq_to_js) + .unwrap_or_else(|| { + Err(Error::new( + Status::InvalidArg, + format!("gate index {i} out of bounds"), + )) + })?; + Ok(gate) +} + +#[napi] +pub fn caml_pasta_fq_plonk_gate_vector_len( + gates: External, +) -> napi::Result { + let len = gates.as_ref().inner().len(); + Ok(u32::try_from(len).map_err(|_| { + Error::new( + Status::GenericFailure, + "gate vector length exceeds u32".to_string(), + ) + })?) +} + +#[napi] +pub fn caml_pasta_fq_plonk_gate_vector_wrap( + mut gates: External, + t: JsWire, + h: JsWire, +) -> napi::Result<()> { + let target = js_wire_to_wire(&t)?; + let replacement = js_wire_to_wire(&h)?; + gates.as_mut().inner_mut().wrap_wire(target, replacement); + Ok(()) +} + +#[napi] +pub fn caml_pasta_fq_plonk_gate_vector_digest( + gates: External, + public_input_size: u32, +) -> Uint8Array { + Uint8Array::from(gates.as_ref().inner().digest(public_input_size as usize)) +} + +#[napi] +pub fn caml_pasta_fq_plonk_circuit_serialize( + gates: External, + public_input_size: u32, +) -> napi::Result { + gates + .as_ref() + .inner() + .serialize(public_input_size as usize) + .map_err(|e| Error::new(Status::GenericFailure, e.to_string())) +} diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 5ba0f454cb..d65b31d70b 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -4,6 +4,7 @@ mod pasta_fp_plonk_index; mod pasta_fq_plonk_index; mod poly_comm; mod poseidon; +mod tables; mod types; mod wrappers; mod wasm_vector; @@ -16,9 +17,8 @@ pub use gate_vector::{ caml_pasta_fp_plonk_gate_vector_wrap, caml_pasta_fq_plonk_circuit_serialize, caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, - caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, - NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, NapiFqGate as WasmFqGate, - NapiFqGateVector as WasmFqGateVector, + caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, GateVectorHandleFp, + GateVectorHandleFq, JsGateFp, JsGateFq, JsGateWires, JsWire, }; pub use pasta_fp_plonk_index::{ prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, @@ -28,5 +28,6 @@ pub use pasta_fq_plonk_index::{ }; pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; +pub use tables::{JsLookupTableFp, JsLookupTableFq, JsRuntimeTableCfgFp, JsRuntimeTableCfgFq}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; pub use wrappers::{field::{WasmPastaFp, WasmPastaFq}, group::{WasmGPallas, WasmGVesta}}; diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index bf24ab9ffc..5a38c42616 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -1,6 +1,9 @@ use ark_poly::EvaluationDomain; +use kimchi::circuits::constraints::ConstraintSystem; +use kimchi::circuits::lookup::runtime_tables::RuntimeTableCfg; +use kimchi::circuits::lookup::tables::LookupTable; use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; -use mina_curves::pasta::{Vesta as GAffine, VestaParameters}; +use mina_curves::pasta::{Fp, Pallas as GAffineOther, Vesta as GAffine, VestaParameters}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; use napi_derive::napi; @@ -8,16 +11,20 @@ use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; use std::{io::Cursor, sync::Arc}; + +use crate::gate_vector::GateVectorHandleFp; +use crate::tables::{ + lookup_table_fp_from_js, runtime_table_cfg_fp_from_js, JsLookupTableFp, JsRuntimeTableCfgFp, +}; +use plonk_wasm::srs::fp::WasmFpSrs as WasmSrs; pub struct WasmPastaFpPlonkIndex(pub Box>>); -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around #[derive(Serialize, Deserialize)] struct SerializedProverIndex { prover_index: Vec, srs: Vec, } -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around impl WasmPastaFpPlonkIndex { fn serialize_inner(&self) -> Result, String> { let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; @@ -62,7 +69,6 @@ impl WasmPastaFpPlonkIndex { } } -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around #[napi] pub fn prover_index_fp_from_bytes( bytes: Uint8Array, @@ -72,7 +78,6 @@ pub fn prover_index_fp_from_bytes( Ok(External::new(index)) } -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around #[napi] pub fn prover_index_fp_to_bytes(index: External) -> NapiResult { let bytes = index @@ -105,3 +110,61 @@ pub fn caml_pasta_fp_plonk_index_domain_d4_size(index: External) -> i32 { index.0.cs.domain.d8.size() as i32 } + +#[napi] +pub fn caml_pasta_fp_plonk_index_create( + gates: External, + public_: i32, + lookup_tables: Vec, + runtime_table_cfgs: Vec, + prev_challenges: i32, + srs: External, + lazy_mode: bool, +) -> Result, Error> { + let gates: Vec<_> = gates.as_ref().inner().as_slice().to_vec(); + + let runtime_cfgs: Vec> = runtime_table_cfgs + .into_iter() + .map(runtime_table_cfg_fp_from_js) + .collect::>()?; + + let lookup_tables: Vec> = lookup_tables + .into_iter() + .map(lookup_table_fp_from_js) + .collect::>()?; + + let srs_ref = srs.as_ref(); + + let cs = ConstraintSystem::::create(gates) + .public(public_ as usize) + .prev_challenges(prev_challenges as usize) + .lookup(lookup_tables) + .max_poly_size(Some(srs_ref.0.max_poly_size())) + .runtime(if runtime_cfgs.is_empty() { + None + } else { + Some(runtime_cfgs) + }) + .lazy_mode(lazy_mode) + .build() + .map_err(|_| { + Error::new( + Status::InvalidArg, + "caml_pasta_fp_plonk_index_create: could not create constraint system", + ) + })?; + + let (endo_q, _endo_r) = poly_commitment::ipa::endos::(); + + srs_ref.0.get_lagrange_basis(cs.domain.d1); + + let mut index = ProverIndex::>::create( + cs, + endo_q, + srs_ref.0.clone(), + lazy_mode, + ); + index.compute_verifier_index_digest::>(); + + Ok(External::new(WasmPastaFpPlonkIndex(Box::new(index)))) +} diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index 1a6ebfe1b2..5bf3485920 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -1,6 +1,7 @@ use ark_poly::EvaluationDomain; +use kimchi::circuits::constraints::ConstraintSystem; use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; -use mina_curves::pasta::{Pallas as GAffine, PallasParameters}; +use mina_curves::pasta::{Fq, Pallas as GAffine, PallasParameters, Vesta as GAffineOther}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; use napi_derive::napi; @@ -8,16 +9,23 @@ use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; use std::{io::Cursor, sync::Arc}; + +use crate::gate_vector::GateVectorHandleFq; +use crate::tables::{ + lookup_table_fq_from_js, + runtime_table_cfg_fq_from_js, + JsLookupTableFq, + JsRuntimeTableCfgFq, +}; +use plonk_wasm::srs::fq::WasmFqSrs as WasmSrs; pub struct WasmPastaFqPlonkIndex(pub Box>>); -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around #[derive(Serialize, Deserialize)] struct SerializedProverIndex { prover_index: Vec, srs: Vec, } -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around impl WasmPastaFqPlonkIndex { fn serialize_inner(&self) -> Result, String> { let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; @@ -62,7 +70,6 @@ impl WasmPastaFqPlonkIndex { } } -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around #[napi] pub fn prover_index_fq_from_bytes( bytes: Uint8Array, @@ -72,7 +79,6 @@ pub fn prover_index_fq_from_bytes( Ok(External::new(index)) } -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around #[napi] pub fn prover_index_fq_to_bytes(index: External) -> NapiResult { let bytes = index @@ -105,3 +111,62 @@ pub fn caml_pasta_fq_plonk_index_domain_d4_size(index: External) -> i32 { index.0.cs.domain.d8.size() as i32 } + +#[napi] +pub fn caml_pasta_fq_plonk_index_create( + gates: External, + public_: i32, + lookup_tables: Vec, + runtime_table_cfgs: Vec, + prev_challenges: i32, + srs: External, + lazy_mode: bool, +) -> Result, Error> { + let gates: Vec<_> = gates.as_ref().inner().as_slice().to_vec(); + + let runtime_cfgs = runtime_table_cfgs + .into_iter() + .map(runtime_table_cfg_fq_from_js) + .collect::, _>>()?; + + let lookup_tables = lookup_tables + .into_iter() + .map(lookup_table_fq_from_js) + .collect::, _>>()?; + + let srs_ref = srs.as_ref(); + + let cs = ConstraintSystem::::create(gates) + .public(public_ as usize) + .prev_challenges(prev_challenges as usize) + .lookup(lookup_tables) + .max_poly_size(Some(srs_ref.0.max_poly_size())) + .runtime(if runtime_cfgs.is_empty() { + None + } else { + Some(runtime_cfgs) + }) + .lazy_mode(lazy_mode) + .build() + .map_err(|_| { + Error::new( + Status::InvalidArg, + "caml_pasta_fq_plonk_index_create: could not create constraint system", + ) + })?; + + let (endo_q, _endo_r) = poly_commitment::ipa::endos::(); + + srs_ref.0.get_lagrange_basis(cs.domain.d1); + + let mut index = ProverIndex::>::create( + cs, + endo_q, + srs_ref.0.clone(), + lazy_mode, + ); + index.compute_verifier_index_digest::>(); + + Ok(External::new(WasmPastaFqPlonkIndex(Box::new(index)))) +} + diff --git a/plonk-napi/src/tables.rs b/plonk-napi/src/tables.rs new file mode 100644 index 0000000000..fd00cb94ae --- /dev/null +++ b/plonk-napi/src/tables.rs @@ -0,0 +1,85 @@ +use arkworks::{WasmPastaFp, WasmPastaFq}; +use kimchi::circuits::lookup::{ + runtime_tables::RuntimeTableCfg, + tables::LookupTable, +}; +use mina_curves::pasta::{Fp, Fq}; +use napi::bindgen_prelude::Uint8Array; +use napi_derive::napi; +use wasm_types::FlatVector; + +fn bytes_to_fp_vec(bytes: Vec) -> Vec { + FlatVector::::from_bytes(bytes) + .into_iter() + .map(Into::into) + .collect() +} + +fn bytes_to_fq_vec(bytes: Vec) -> Vec { + FlatVector::::from_bytes(bytes) + .into_iter() + .map(Into::into) + .collect() +} + +fn typed_array_to_vec(array: &Uint8Array) -> Vec { + array.to_vec() +} + +#[napi(object)] +pub struct JsLookupTableFp { + pub id: i32, + pub data: Vec, +} + +#[napi(object)] +pub struct JsLookupTableFq { + pub id: i32, + pub data: Vec, +} + +#[napi(object)] +pub struct JsRuntimeTableCfgFp { + pub id: i32, + pub first_column: Uint8Array, +} + +#[napi(object)] +pub struct JsRuntimeTableCfgFq { + pub id: i32, + pub first_column: Uint8Array, +} + +pub fn lookup_table_fp_from_js(js: JsLookupTableFp) -> napi::Result> { + let mut data = Vec::with_capacity(js.data.len()); + for column in js.data { + data.push(bytes_to_fp_vec(typed_array_to_vec(&column))); + } + Ok(LookupTable { id: js.id, data }) +} + +pub fn lookup_table_fq_from_js(js: JsLookupTableFq) -> napi::Result> { + let mut data = Vec::with_capacity(js.data.len()); + for column in js.data { + data.push(bytes_to_fq_vec(typed_array_to_vec(&column))); + } + Ok(LookupTable { id: js.id, data }) +} + +pub fn runtime_table_cfg_fp_from_js( + js: JsRuntimeTableCfgFp, +) -> napi::Result> { + Ok(RuntimeTableCfg { + id: js.id, + first_column: bytes_to_fp_vec(typed_array_to_vec(&js.first_column)), + }) +} + +pub fn runtime_table_cfg_fq_from_js( + js: JsRuntimeTableCfgFq, +) -> napi::Result> { + Ok(RuntimeTableCfg { + id: js.id, + first_column: bytes_to_fq_vec(typed_array_to_vec(&js.first_column)), + }) +} diff --git a/plonk-wasm/src/gate_vector.rs b/plonk-wasm/src/gate_vector.rs index 56eb361217..17f1b38f0a 100644 --- a/plonk-wasm/src/gate_vector.rs +++ b/plonk-wasm/src/gate_vector.rs @@ -1,5 +1,6 @@ //! A GateVector: this is used to represent a list of gates. +use ark_ff::PrimeField; use kimchi::circuits::{ gate::{Circuit, CircuitGate, GateType}, wires::Wire, @@ -9,6 +10,179 @@ use paste::paste; use wasm_bindgen::prelude::*; use wasm_types::FlatVector as WasmFlatVector; +pub mod shared { + use super::*; + + /// Number of wires stored per gate. + pub const WIRE_COUNT: usize = 7; + + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub struct GateWires(pub [Wire; WIRE_COUNT]); + + impl GateWires { + pub fn new(wires: [Wire; WIRE_COUNT]) -> Self { + Self(wires) + } + + pub fn as_array(&self) -> &[Wire; WIRE_COUNT] { + &self.0 + } + + pub fn into_array(self) -> [Wire; WIRE_COUNT] { + self.0 + } + } + + impl From<[Wire; WIRE_COUNT]> for GateWires { + fn from(wires: [Wire; WIRE_COUNT]) -> Self { + GateWires::new(wires) + } + } + + impl From for [Wire; WIRE_COUNT] { + fn from(gw: GateWires) -> Self { + gw.into_array() + } + } + + #[derive(Clone, Debug)] + pub struct Gate { + pub typ: GateType, + pub wires: GateWires, + pub coeffs: Vec, + } + + impl From> for Gate + where + F: PrimeField, + { + fn from(cg: CircuitGate) -> Self { + Gate { + typ: cg.typ, + wires: GateWires::new([ + cg.wires[0], cg.wires[1], cg.wires[2], cg.wires[3], cg.wires[4], cg.wires[5], + cg.wires[6], + ]), + coeffs: cg.coeffs, + } + } + } + + impl From<&CircuitGate> for Gate + where + F: PrimeField, + { + fn from(cg: &CircuitGate) -> Self { + Gate { + typ: cg.typ, + wires: GateWires::new([ + cg.wires[0], cg.wires[1], cg.wires[2], cg.wires[3], cg.wires[4], cg.wires[5], + cg.wires[6], + ]), + coeffs: cg.coeffs.clone(), + } + } + } + + impl From> for CircuitGate + where + F: PrimeField, + { + fn from(gate: Gate) -> Self { + CircuitGate { + typ: gate.typ, + wires: gate.wires.into_array(), + coeffs: gate.coeffs, + } + } + } + + #[derive(Clone, Debug, Default)] + pub struct GateVector { + gates: Vec>, + } + + impl GateVector + where + F: PrimeField, + { + pub fn new() -> Self { + Self { gates: Vec::new() } + } + + pub fn from_vec(gates: Vec>) -> Self { + Self { gates } + } + + pub fn into_inner(self) -> Vec> { + self.gates + } + + pub fn as_slice(&self) -> &[CircuitGate] { + &self.gates + } + + pub fn iter(&self) -> core::slice::Iter<'_, CircuitGate> { + self.gates.iter() + } + + pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, CircuitGate> { + self.gates.iter_mut() + } + + pub fn push_gate(&mut self, gate: CircuitGate) { + self.gates.push(gate); + } + + pub fn len(&self) -> usize { + self.gates.len() + } + + pub fn get_gate(&self, index: usize) -> Option> { + self.gates.get(index).map(Gate::from) + } + + pub fn wrap_wire(&mut self, target: Wire, replacement: Wire) { + if let Some(gate) = self.gates.get_mut(target.row) { + if target.col < gate.wires.len() { + gate.wires[target.col] = replacement; + } + } + } + + pub fn digest(&self, public_input_size: usize) -> Vec { + Circuit::new(public_input_size, self.as_slice()) + .digest() + .to_vec() + } + + pub fn serialize(&self, public_input_size: usize) -> Result { + let circuit = Circuit::new(public_input_size, self.as_slice()); + serde_json::to_string(&circuit) + } + } + + impl From>> for GateVector + where + F: PrimeField, + { + fn from(gates: Vec>) -> Self { + GateVector::from_vec(gates) + } + } + + impl From> for Vec> + where + F: PrimeField, + { + fn from(vec: GateVector) -> Self { + vec.into_inner() + } + } +} + +pub use self::shared::{Gate as CoreGate, GateVector as CoreGateVector, GateWires as CoreGateWires}; + #[wasm_bindgen] #[derive(Clone, Copy, Debug)] pub struct WasmGateWires( @@ -21,6 +195,23 @@ pub struct WasmGateWires( pub Wire, ); +impl From for WasmGateWires { + fn from(wires: CoreGateWires) -> Self { + let array = wires.into_array(); + WasmGateWires( + array[0], array[1], array[2], array[3], array[4], array[5], array[6], + ) + } +} + +impl From for CoreGateWires { + fn from(wires: WasmGateWires) -> Self { + CoreGateWires::new([ + wires.0, wires.1, wires.2, wires.3, wires.4, wires.5, wires.6, + ]) + } +} + #[wasm_bindgen] impl WasmGateWires { #[wasm_bindgen(constructor)] @@ -37,14 +228,14 @@ macro_rules! impl_gate_vector { paste! { #[wasm_bindgen] pub struct []( - #[wasm_bindgen(skip)] pub Vec>); + #[wasm_bindgen(skip)] pub CoreGateVector<$F>); pub type WasmGateVector = []; #[wasm_bindgen] pub struct [] { - pub typ: GateType, // type of the gate - pub wires: WasmGateWires, // gate wires - #[wasm_bindgen(skip)] pub coeffs: Vec<$WasmF>, // constraints vector + pub typ: GateType, + pub wires: WasmGateWires, + #[wasm_bindgen(skip)] pub coeffs: Vec<$WasmF>, } #[wasm_bindgen] @@ -62,64 +253,60 @@ macro_rules! impl_gate_vector { } } - impl From> for [] - { - fn from(cg: CircuitGate<$F>) -> Self { + impl From> for [] { + fn from(gate: CoreGate<$F>) -> Self { Self { - typ: cg.typ, - wires: WasmGateWires( - cg.wires[0], - cg.wires[1], - cg.wires[2], - cg.wires[3], - cg.wires[4], - cg.wires[5], - cg.wires[6]), - coeffs: cg.coeffs.into_iter().map(Into::into).collect(), + typ: gate.typ, + wires: gate.wires.into(), + coeffs: gate.coeffs.into_iter().map(Into::into).collect(), } } } - impl From<&CircuitGate<$F>> for [] - { - fn from(cg: &CircuitGate<$F>) -> Self { + impl From<&CoreGate<$F>> for [] { + fn from(gate: &CoreGate<$F>) -> Self { Self { - typ: cg.typ, - wires: WasmGateWires( - cg.wires[0], - cg.wires[1], - cg.wires[2], - cg.wires[3], - cg.wires[4], - cg.wires[5], - cg.wires[6]), - coeffs: cg.coeffs.clone().into_iter().map(Into::into).collect(), + typ: gate.typ, + wires: gate.wires.into(), + coeffs: gate.coeffs.clone().into_iter().map(Into::into).collect(), } } } - impl From<[]> for CircuitGate<$F> - { + impl From> for [] { + fn from(cg: CircuitGate<$F>) -> Self { + let gate: CoreGate<$F> = cg.into(); + gate.into() + } + } + + impl From<&CircuitGate<$F>> for [] { + fn from(cg: &CircuitGate<$F>) -> Self { + let gate: CoreGate<$F> = cg.into(); + (&gate).into() + } + } + + impl From<[]> for CoreGate<$F> { fn from(ccg: []) -> Self { - Self { + CoreGate { typ: ccg.typ, - wires: [ - ccg.wires.0, - ccg.wires.1, - ccg.wires.2, - ccg.wires.3, - ccg.wires.4, - ccg.wires.5, - ccg.wires.6 - ], + wires: ccg.wires.into(), coeffs: ccg.coeffs.into_iter().map(Into::into).collect(), } } } + impl From<[]> for CircuitGate<$F> { + fn from(ccg: []) -> Self { + let gate: CoreGate<$F> = ccg.into(); + gate.into() + } + } + #[wasm_bindgen] pub fn []() -> WasmGateVector { - [](Vec::new()) + [](CoreGateVector::new()) } #[wasm_bindgen] @@ -127,8 +314,8 @@ macro_rules! impl_gate_vector { v: &mut WasmGateVector, gate: [], ) { - let gate: CircuitGate<$F> = gate.into(); - v.0.push(gate); + let gate: CoreGate<$F> = gate.into(); + v.0.push_gate(gate.into()); } #[wasm_bindgen] @@ -136,7 +323,10 @@ macro_rules! impl_gate_vector { v: &WasmGateVector, i: i32, ) -> [] { - (&(v.0)[i as usize]).into() + v.0 + .get_gate(i as usize) + .map(|gate| gate.into()) + .expect("index out of bounds") } #[wasm_bindgen] @@ -152,7 +342,7 @@ macro_rules! impl_gate_vector { t: Wire, h: Wire, ) { - (v.0)[t.row as usize].wires[t.col as usize] = h.into(); + v.0.wrap_wire(t, h); } #[wasm_bindgen] @@ -160,7 +350,7 @@ macro_rules! impl_gate_vector { public_input_size: usize, v: &WasmGateVector ) -> Box<[u8]> { - Circuit::new(public_input_size, &(v.0)).digest().to_vec().into_boxed_slice() + v.0.digest(public_input_size).into_boxed_slice() } #[wasm_bindgen] @@ -168,8 +358,9 @@ macro_rules! impl_gate_vector { public_input_size: usize, v: &WasmGateVector ) -> String { - let circuit = Circuit::new(public_input_size, &v.0); - serde_json::to_string(&circuit).expect("couldn't serialize constraints") + v.0 + .serialize(public_input_size) + .expect("couldn't serialize constraints") } } }; @@ -183,10 +374,6 @@ pub mod fp { impl_gate_vector!(fp, WasmF, F, Fp); } -// -// Fq -// - pub mod fq { use super::*; use arkworks::WasmPastaFq as WasmF; From a3b92df4b47991d1eebbd4b7e32ad88dc6110030 Mon Sep 17 00:00:00 2001 From: Florian Date: Thu, 16 Oct 2025 02:25:51 +0700 Subject: [PATCH 34/75] impl some types --- plonk-napi/src/gate_vector.rs | 36 +++++++++++++++++++++++++- plonk-napi/src/lib.rs | 12 ++++++--- plonk-napi/src/pasta_fq_plonk_index.rs | 8 +++--- plonk-napi/src/srs.rs | 30 +++++++++++++++++++++ plonk-wasm/src/gate_vector.rs | 16 ++++++++++++ plonk-wasm/src/srs.rs | 21 ++++++++++++++- 6 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 plonk-napi/src/srs.rs diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index 6c6ca0cc2b..98c37cc33e 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -1,7 +1,10 @@ use std::convert::TryFrom; use arkworks::{WasmPastaFp, WasmPastaFq}; -use kimchi::circuits::{gate::GateType, wires::Wire}; +use kimchi::circuits::{ + gate::{CircuitGate, GateType}, + wires::Wire, +}; use mina_curves::pasta::{Fp, Fq}; use napi::bindgen_prelude::{Error, External, Status, Uint8Array}; use napi_derive::napi; @@ -382,3 +385,34 @@ pub fn caml_pasta_fq_plonk_circuit_serialize( .serialize(public_input_size as usize) .map_err(|e| Error::new(Status::GenericFailure, e.to_string())) } + +#[napi] +pub fn caml_pasta_fp_plonk_gate_vector_to_bytes( + gates: External, +) -> napi::Result { + let bytes = rmp_serde::to_vec(gates.as_ref().inner().as_slice()) + .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?; + Ok(Uint8Array::from(bytes)) +} + +#[napi] +pub fn caml_pasta_fp_plonk_gate_vector_from_bytes( + bytes: Uint8Array, +) -> napi::Result> { + let gates: Vec> = rmp_serde::from_slice(bytes.as_ref()) + .map_err(|e| Error::new(Status::InvalidArg, e.to_string()))?; + Ok(External::new(GateVectorHandleFp(GateVector::from_vec( + gates, + )))) +} + +#[napi] +pub fn caml_pasta_fq_plonk_gate_vector_from_bytes( + bytes: Uint8Array, +) -> napi::Result> { + let gates: Vec> = rmp_serde::from_slice(bytes.as_ref()) + .map_err(|e| Error::new(Status::InvalidArg, e.to_string()))?; + Ok(External::new(GateVectorHandleFq(GateVector::from_vec( + gates, + )))) +} diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index d65b31d70b..b84ed0b9a1 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -4,6 +4,7 @@ mod pasta_fp_plonk_index; mod pasta_fq_plonk_index; mod poly_comm; mod poseidon; +mod srs; mod tables; mod types; mod wrappers; @@ -13,12 +14,14 @@ pub use circuit::prover_to_json; pub use gate_vector::{ caml_pasta_fp_plonk_circuit_serialize, caml_pasta_fp_plonk_gate_vector_add, caml_pasta_fp_plonk_gate_vector_create, caml_pasta_fp_plonk_gate_vector_digest, - caml_pasta_fp_plonk_gate_vector_get, caml_pasta_fp_plonk_gate_vector_len, + caml_pasta_fp_plonk_gate_vector_from_bytes, caml_pasta_fp_plonk_gate_vector_get, + caml_pasta_fp_plonk_gate_vector_len, caml_pasta_fp_plonk_gate_vector_to_bytes, caml_pasta_fp_plonk_gate_vector_wrap, caml_pasta_fq_plonk_circuit_serialize, caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, - caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, - caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, GateVectorHandleFp, - GateVectorHandleFq, JsGateFp, JsGateFq, JsGateWires, JsWire, + caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_from_bytes, + caml_pasta_fq_plonk_gate_vector_get, caml_pasta_fq_plonk_gate_vector_len, + caml_pasta_fq_plonk_gate_vector_wrap, GateVectorHandleFp, GateVectorHandleFq, JsGateFp, + JsGateFq, JsGateWires, JsWire, }; pub use pasta_fp_plonk_index::{ prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, @@ -28,6 +31,7 @@ pub use pasta_fq_plonk_index::{ }; pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; +pub use srs::{caml_fp_srs_from_bytes, caml_fp_srs_to_bytes, caml_fq_srs_from_bytes}; pub use tables::{JsLookupTableFp, JsLookupTableFq, JsRuntimeTableCfgFp, JsRuntimeTableCfgFq}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; pub use wrappers::{field::{WasmPastaFp, WasmPastaFq}, group::{WasmGPallas, WasmGVesta}}; diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index 5bf3485920..ff2099002a 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -12,10 +12,7 @@ use std::{io::Cursor, sync::Arc}; use crate::gate_vector::GateVectorHandleFq; use crate::tables::{ - lookup_table_fq_from_js, - runtime_table_cfg_fq_from_js, - JsLookupTableFq, - JsRuntimeTableCfgFq, + lookup_table_fq_from_js, runtime_table_cfg_fq_from_js, JsLookupTableFq, JsRuntimeTableCfgFq, }; use plonk_wasm::srs::fq::WasmFqSrs as WasmSrs; pub struct WasmPastaFqPlonkIndex(pub Box>>); @@ -122,6 +119,8 @@ pub fn caml_pasta_fq_plonk_index_create( srs: External, lazy_mode: bool, ) -> Result, Error> { + // TODO: check if and how we run rayon threads automatically in napi + let gates: Vec<_> = gates.as_ref().inner().as_slice().to_vec(); let runtime_cfgs = runtime_table_cfgs @@ -169,4 +168,3 @@ pub fn caml_pasta_fq_plonk_index_create( Ok(External::new(WasmPastaFqPlonkIndex(Box::new(index)))) } - diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs new file mode 100644 index 0000000000..3f66c82ddd --- /dev/null +++ b/plonk-napi/src/srs.rs @@ -0,0 +1,30 @@ +use std::sync::Arc; + +use mina_curves::pasta::{Pallas as GAffineOther, Vesta as GAffine}; +use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi_derive::napi; +use plonk_wasm::srs::fp::WasmFpSrs as WasmSrsFp; +use plonk_wasm::srs::fq::WasmFqSrs as WasmSrsFq; + +use poly_commitment::ipa::SRS; + +#[napi] +pub fn caml_fp_srs_to_bytes(srs: External) -> NapiResult { + let buffer = rmp_serde::to_vec(srs.as_ref().0.as_ref()) + .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?; + Ok(Uint8Array::from(buffer)) +} + +#[napi] +pub fn caml_fp_srs_from_bytes(bytes: Uint8Array) -> NapiResult> { + let srs: SRS = rmp_serde::from_slice(bytes.as_ref()) + .map_err(|e| Error::new(Status::InvalidArg, e.to_string()))?; + Ok(External::new(Arc::new(srs).into())) +} + +#[napi] +pub fn caml_fq_srs_from_bytes(bytes: Uint8Array) -> NapiResult> { + let srs: SRS = rmp_serde::from_slice(bytes.as_ref()) + .map_err(|e: rmp_serde::decode::Error| Error::new(Status::InvalidArg, e.to_string()))?; + Ok(External::new(Arc::new(srs).into())) +} diff --git a/plonk-wasm/src/gate_vector.rs b/plonk-wasm/src/gate_vector.rs index 17f1b38f0a..7928845af1 100644 --- a/plonk-wasm/src/gate_vector.rs +++ b/plonk-wasm/src/gate_vector.rs @@ -231,6 +231,22 @@ macro_rules! impl_gate_vector { #[wasm_bindgen(skip)] pub CoreGateVector<$F>); pub type WasmGateVector = []; + #[wasm_bindgen] + impl [] { + #[wasm_bindgen(js_name = "serialize")] + pub fn serialize(&self) -> Result, JsError> { + rmp_serde::to_vec(self.0.as_slice()) + .map_err(|e| JsError::new(&format!("gate vector serialize failed: {e}"))) + } + + #[wasm_bindgen(js_name = "deserialize")] + pub fn deserialize(bytes: &[u8]) -> Result { + let gates: Vec> = rmp_serde::from_slice(bytes) + .map_err(|e| JsError::new(&format!("gate vector deserialize failed: {e}")))?; + Ok([](CoreGateVector::from_vec(gates))) + } + } + #[wasm_bindgen] pub struct [] { pub typ: GateType, diff --git a/plonk-wasm/src/srs.rs b/plonk-wasm/src/srs.rs index 4a38717f76..6e9cfbe2da 100644 --- a/plonk-wasm/src/srs.rs +++ b/plonk-wasm/src/srs.rs @@ -8,7 +8,7 @@ use poly_commitment::{ use serde::{Deserialize, Serialize}; use std::{ fs::{File, OpenOptions}, - io::{BufReader, BufWriter, Seek, SeekFrom::Start}, + io::{BufReader, BufWriter, Cursor, Seek, SeekFrom::Start}, sync::Arc, }; use wasm_bindgen::prelude::*; @@ -29,6 +29,25 @@ macro_rules! impl_srs { #[wasm_bindgen(skip)] pub Arc>); + #[wasm_bindgen] + impl [] { + #[wasm_bindgen(js_name = "serialize")] + pub fn serialize(&self) -> Result, JsValue> { + let mut buffer = Vec::new(); + self.0 + .serialize(&mut rmp_serde::Serializer::new(&mut buffer)) + .map_err(|e| JsValue::from_str(&format!("srs serialize failed: {e}")))?; + Ok(buffer) + } + + #[wasm_bindgen(js_name = "deserialize")] + pub fn deserialize(bytes: &[u8]) -> Result<[], JsValue> { + let srs = SRS::<$G>::deserialize(&mut rmp_serde::Deserializer::new(Cursor::new(bytes))) + .map_err(|e| JsValue::from_str(&format!("srs deserialize failed: {e}")))?; + Ok(Arc::new(srs).into()) + } + } + impl Deref for [] { type Target = Arc>; From e88ac1bd402eea84f63a2e9877827a0c0ac45365 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 22 Oct 2025 15:14:21 +0700 Subject: [PATCH 35/75] finish up prover index --- plonk-napi/src/pasta_fp_plonk_index.rs | 57 ++++++++++++++++++++++++++ plonk-napi/src/pasta_fq_plonk_index.rs | 57 ++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index 5a38c42616..4b58b9c543 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -10,6 +10,8 @@ use napi_derive::napi; use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; +use std::fs::OpenOptions; +use std::io::BufWriter; use std::{io::Cursor, sync::Arc}; use crate::gate_vector::GateVectorHandleFp; @@ -168,3 +170,58 @@ pub fn caml_pasta_fp_plonk_index_create( Ok(External::new(WasmPastaFpPlonkIndex(Box::new(index)))) } + +#[napi] +pub fn caml_pasta_fp_plonk_index_decode( + bytes: &[u8], + srs: External, +) -> Result, Error> { + let mut deserializer = rmp_serde::Deserializer::new(bytes); + let mut index = + ProverIndex::>::deserialize(&mut deserializer) + .map_err(|e| Error::new(Status::InvalidArg, "caml_pasta_fp_plonk_index_decode"))?; + + index.srs = srs.0.clone(); + let (linearization, powers_of_alpha) = expr_linearization(Some(&index.cs.feature_flags), true); + index.linearization = linearization; + index.powers_of_alpha = powers_of_alpha; + + Ok(External::new(WasmPastaFpPlonkIndex(Box::new(index)))) +} + +#[napi] +pub fn caml_pasta_fp_plonk_index_encode( + index: External, +) -> Result, Error> { + let mut buffer = Vec::new(); + let mut serializer = rmp_serde::Serializer::new(&mut buffer); + index.0.serialize(&mut serializer).map_err(|e| { + Error::new( + Status::InvalidArg, + &format!("caml_pasta_fp_plonk_index_encode: {}", e), + ) + })?; + Ok(buffer) +} + +#[napi] +pub fn caml_pasta_fp_plonk_index_write( + append: Option, + index: External, + path: String, +) -> Result<(), Error> { + let file = OpenOptions::new() + .append(append.unwrap_or(true)) + .open(path) + .map_err(|_| Error::new(Status::InvalidArg, "caml_pasta_fp_plonk_index_write"))?; + let w = BufWriter::new(file); + index + .0 + .serialize(&mut rmp_serde::Serializer::new(w)) + .map_err(|e| { + Error::new( + Status::InvalidArg, + &format!("caml_pasta_fp_plonk_index_write: {e}"), + ) + }) +} diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index ff2099002a..177e449a45 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -8,6 +8,8 @@ use napi_derive::napi; use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; +use std::fs::OpenOptions; +use std::io::BufWriter; use std::{io::Cursor, sync::Arc}; use crate::gate_vector::GateVectorHandleFq; @@ -168,3 +170,58 @@ pub fn caml_pasta_fq_plonk_index_create( Ok(External::new(WasmPastaFqPlonkIndex(Box::new(index)))) } + +#[napi] +pub fn caml_pasta_fq_plonk_index_decode( + bytes: &[u8], + srs: External, +) -> Result, Error> { + let mut deserializer = rmp_serde::Deserializer::new(bytes); + let mut index = + ProverIndex::>::deserialize(&mut deserializer) + .map_err(|e| Error::new(Status::InvalidArg, "caml_pasta_fq_plonk_index_decode"))?; + + index.srs = srs.0.clone(); + let (linearization, powers_of_alpha) = expr_linearization(Some(&index.cs.feature_flags), true); + index.linearization = linearization; + index.powers_of_alpha = powers_of_alpha; + + Ok(External::new(WasmPastaFqPlonkIndex(Box::new(index)))) +} + +#[napi] +pub fn caml_pasta_fq_plonk_index_encode( + index: External, +) -> Result, Error> { + let mut buffer = Vec::new(); + let mut serializer = rmp_serde::Serializer::new(&mut buffer); + index.0.serialize(&mut serializer).map_err(|e| { + Error::new( + Status::InvalidArg, + &format!("caml_pasta_fq_plonk_index_encode: {}", e), + ) + })?; + Ok(buffer) +} + +#[napi] +pub fn caml_pasta_fq_plonk_index_write( + append: Option, + index: External, + path: String, +) -> Result<(), Error> { + let file = OpenOptions::new() + .append(append.unwrap_or(true)) + .open(path) + .map_err(|_| Error::new(Status::InvalidArg, "caml_pasta_fq_plonk_index_write"))?; + let w = BufWriter::new(file); + index + .0 + .serialize(&mut rmp_serde::Serializer::new(w)) + .map_err(|e| { + Error::new( + Status::InvalidArg, + &format!("caml_pasta_fq_plonk_index_write: {e}"), + ) + }) +} From 5604cfb71453724e10542e1b3acb2939c1b2c691 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 22 Oct 2025 15:18:30 +0700 Subject: [PATCH 36/75] impl caml_pasta_fp_plonk_index_read --- plonk-napi/src/pasta_fp_plonk_index.rs | 57 ++++++++++++++++++++++++-- plonk-napi/src/pasta_fq_plonk_index.rs | 51 ++++++++++++++++++++++- 2 files changed, 103 insertions(+), 5 deletions(-) diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index 4b58b9c543..7abdb96367 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -10,9 +10,13 @@ use napi_derive::napi; use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; -use std::fs::OpenOptions; -use std::io::BufWriter; -use std::{io::Cursor, sync::Arc}; +use std::fs::{File, OpenOptions}; +use std::io::{BufReader, BufWriter}; +use std::{ + io::Cursor, + io::{Seek, SeekFrom::Start}, + sync::Arc, +}; use crate::gate_vector::GateVectorHandleFp; use crate::tables::{ @@ -225,3 +229,50 @@ pub fn caml_pasta_fp_plonk_index_write( ) }) } + +#[napi] +pub fn caml_pasta_fp_plonk_index_read( + offset: Option, + srs: External, + path: String, +) -> Result, Error> { + // read from file + let file = match File::open(path) { + Err(_) => { + return Err(Error::new( + Status::InvalidArg, + "caml_pasta_fp_plonk_index_read", + )) + } + Ok(file) => file, + }; + let mut r = BufReader::new(file); + + // optional offset in file + if let Some(offset) = offset { + r.seek(Start(offset as u64)).map_err(|err| { + Error::new( + Status::InvalidArg, + &format!("caml_pasta_fp_plonk_index_read: {err}"), + ) + })?; + } + + // deserialize the index + let mut t = ProverIndex::>::deserialize( + &mut rmp_serde::Deserializer::new(r), + ) + .map_err(|err| { + Error::new( + Status::InvalidArg, + &format!("caml_pasta_fp_plonk_index_read: {err}"), + ) + })?; + t.srs = srs.0.clone(); + let (linearization, powers_of_alpha) = expr_linearization(Some(&t.cs.feature_flags), true); + t.linearization = linearization; + t.powers_of_alpha = powers_of_alpha; + + // + Ok(External::new(WasmPastaFpPlonkIndex(Box::new(t)))) +} diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index 177e449a45..a39ec84bd2 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -8,8 +8,8 @@ use napi_derive::napi; use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; -use std::fs::OpenOptions; -use std::io::BufWriter; +use std::fs::{File, OpenOptions}; +use std::io::{BufReader, BufWriter, Seek, SeekFrom::Start}; use std::{io::Cursor, sync::Arc}; use crate::gate_vector::GateVectorHandleFq; @@ -225,3 +225,50 @@ pub fn caml_pasta_fq_plonk_index_write( ) }) } + +#[napi] +pub fn caml_pasta_fq_plonk_index_read( + offset: Option, + srs: External, + path: String, +) -> Result, Error> { + // read from file + let file = match File::open(path) { + Err(_) => { + return Err(Error::new( + Status::InvalidArg, + "caml_pasta_fq_plonk_index_read", + )) + } + Ok(file) => file, + }; + let mut r = BufReader::new(file); + + // optional offset in file + if let Some(offset) = offset { + r.seek(Start(offset as u64)).map_err(|err| { + Error::new( + Status::InvalidArg, + &format!("caml_pasta_fq_plonk_index_read: {err}"), + ) + })?; + } + + // deserialize the index + let mut t = ProverIndex::>::deserialize( + &mut rmp_serde::Deserializer::new(r), + ) + .map_err(|err| { + Error::new( + Status::InvalidArg, + &format!("caml_pasta_fp_plonk_index_read: {err}"), + ) + })?; + t.srs = srs.0.clone(); + let (linearization, powers_of_alpha) = expr_linearization(Some(&t.cs.feature_flags), true); + t.linearization = linearization; + t.powers_of_alpha = powers_of_alpha; + + // + Ok(External::new(WasmPastaFqPlonkIndex(Box::new(t)))) +} From 75f13394cb7c8f2a49e96e59d167c37a4438d871 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 22 Oct 2025 15:40:51 +0700 Subject: [PATCH 37/75] get rid of gate vectors for now --- plonk-napi/src/gate_vector.rs | 418 ------------------------- plonk-napi/src/pasta_fp_plonk_index.rs | 10 +- plonk-napi/src/pasta_fq_plonk_index.rs | 11 +- 3 files changed, 14 insertions(+), 425 deletions(-) delete mode 100644 plonk-napi/src/gate_vector.rs diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs deleted file mode 100644 index 98c37cc33e..0000000000 --- a/plonk-napi/src/gate_vector.rs +++ /dev/null @@ -1,418 +0,0 @@ -use std::convert::TryFrom; - -use arkworks::{WasmPastaFp, WasmPastaFq}; -use kimchi::circuits::{ - gate::{CircuitGate, GateType}, - wires::Wire, -}; -use mina_curves::pasta::{Fp, Fq}; -use napi::bindgen_prelude::{Error, External, Status, Uint8Array}; -use napi_derive::napi; -use plonk_wasm::gate_vector::{ - CoreGate as Gate, CoreGateVector as GateVector, CoreGateWires as GateWires, -}; -use wasm_types::{FlatVector, FlatVectorElem}; - -pub struct GateVectorHandleFp(pub GateVector); -pub struct GateVectorHandleFq(pub GateVector); - -impl GateVectorHandleFp { - fn new() -> Self { - Self(GateVector::new()) - } - pub(crate) fn inner(&self) -> &GateVector { - &self.0 - } - pub(crate) fn inner_mut(&mut self) -> &mut GateVector { - &mut self.0 - } -} - -impl GateVectorHandleFq { - fn new() -> Self { - Self(GateVector::new()) - } - pub(crate) fn inner(&self) -> &GateVector { - &self.0 - } - pub(crate) fn inner_mut(&mut self) -> &mut GateVector { - &mut self.0 - } -} - -unsafe impl Send for GateVectorHandleFp {} -unsafe impl Sync for GateVectorHandleFp {} -unsafe impl Send for GateVectorHandleFq {} -unsafe impl Sync for GateVectorHandleFq {} - -#[napi(object)] -pub struct JsWire { - pub row: u32, - pub col: u32, -} - -#[napi(object)] -pub struct JsGateWires { - pub w0: JsWire, - pub w1: JsWire, - pub w2: JsWire, - pub w3: JsWire, - pub w4: JsWire, - pub w5: JsWire, - pub w6: JsWire, -} - -#[napi(object)] -pub struct JsGateFp { - pub typ: i32, - pub wires: JsGateWires, - pub coeffs: Uint8Array, -} - -#[napi(object)] -pub struct JsGateFq { - pub typ: i32, - pub wires: JsGateWires, - pub coeffs: Uint8Array, -} - -fn gate_type_from_i32(value: i32) -> napi::Result { - match value { - 0 => Ok(GateType::Zero), - 1 => Ok(GateType::Generic), - 2 => Ok(GateType::Poseidon), - 3 => Ok(GateType::CompleteAdd), - 4 => Ok(GateType::VarBaseMul), - 5 => Ok(GateType::EndoMul), - 6 => Ok(GateType::EndoMulScalar), - 7 => Ok(GateType::Lookup), - 8 => Ok(GateType::CairoClaim), - 9 => Ok(GateType::CairoInstruction), - 10 => Ok(GateType::CairoFlags), - 11 => Ok(GateType::CairoTransition), - 12 => Ok(GateType::RangeCheck0), - 13 => Ok(GateType::RangeCheck1), - 14 => Ok(GateType::ForeignFieldAdd), - 15 => Ok(GateType::ForeignFieldMul), - 16 => Ok(GateType::Xor16), - 17 => Ok(GateType::Rot64), - _ => Err(Error::new( - Status::InvalidArg, - format!("unknown gate type discriminant {value}"), - )), - } -} - -fn gate_type_to_i32(value: GateType) -> i32 { - value as i32 -} - -fn js_wire_to_wire(wire: &JsWire) -> napi::Result { - Ok(Wire { - row: wire.row as usize, - col: wire.col as usize, - }) -} - -fn wire_to_js(wire: Wire) -> napi::Result { - Ok(JsWire { - row: u32::try_from(wire.row).map_err(|_| { - Error::new( - Status::InvalidArg, - format!("wire row {row} does not fit in u32", row = wire.row), - ) - })?, - col: u32::try_from(wire.col).map_err(|_| { - Error::new( - Status::InvalidArg, - format!("wire col {col} does not fit in u32", col = wire.col), - ) - })?, - }) -} - -fn js_wires_to_core(wires: &JsGateWires) -> napi::Result { - Ok(GateWires::new([ - js_wire_to_wire(&wires.w0)?, - js_wire_to_wire(&wires.w1)?, - js_wire_to_wire(&wires.w2)?, - js_wire_to_wire(&wires.w3)?, - js_wire_to_wire(&wires.w4)?, - js_wire_to_wire(&wires.w5)?, - js_wire_to_wire(&wires.w6)?, - ])) -} - -fn core_wires_to_js(wires: &GateWires) -> napi::Result { - let arr = wires.as_array(); - Ok(JsGateWires { - w0: wire_to_js(arr[0])?, - w1: wire_to_js(arr[1])?, - w2: wire_to_js(arr[2])?, - w3: wire_to_js(arr[3])?, - w4: wire_to_js(arr[4])?, - w5: wire_to_js(arr[5])?, - w6: wire_to_js(arr[6])?, - }) -} - -fn coeffs_from_bytes_fp(bytes: Vec) -> Vec { - FlatVector::::from_bytes(bytes) - .into_iter() - .map(Into::into) - .collect() -} - -fn coeffs_from_bytes_fq(bytes: Vec) -> Vec { - FlatVector::::from_bytes(bytes) - .into_iter() - .map(Into::into) - .collect() -} - -fn coeffs_to_bytes_fp(coeffs: &[Fp]) -> Vec { - coeffs - .iter() - .cloned() - .map(WasmPastaFp) - .flat_map(FlatVectorElem::flatten) - .collect() -} - -fn coeffs_to_bytes_fq(coeffs: &[Fq]) -> Vec { - coeffs - .iter() - .cloned() - .map(WasmPastaFq) - .flat_map(FlatVectorElem::flatten) - .collect() -} - -fn js_gate_fp_to_core(gate: JsGateFp) -> napi::Result> { - let typ = gate_type_from_i32(gate.typ)?; - let wires = js_wires_to_core(&gate.wires)?; - let coeff_bytes = gate.coeffs.to_vec(); - Ok(Gate { - typ, - wires, - coeffs: coeffs_from_bytes_fp(coeff_bytes), - }) -} - -fn js_gate_fq_to_core(gate: JsGateFq) -> napi::Result> { - let typ = gate_type_from_i32(gate.typ)?; - let wires = js_wires_to_core(&gate.wires)?; - let coeff_bytes = gate.coeffs.to_vec(); - Ok(Gate { - typ, - wires, - coeffs: coeffs_from_bytes_fq(coeff_bytes), - }) -} - -fn core_gate_fp_to_js(gate: Gate) -> napi::Result { - let coeff_bytes = coeffs_to_bytes_fp(&gate.coeffs); - Ok(JsGateFp { - typ: gate_type_to_i32(gate.typ), - wires: core_wires_to_js(&gate.wires)?, - coeffs: Uint8Array::from(coeff_bytes), - }) -} - -fn core_gate_fq_to_js(gate: Gate) -> napi::Result { - let coeff_bytes = coeffs_to_bytes_fq(&gate.coeffs); - Ok(JsGateFq { - typ: gate_type_to_i32(gate.typ), - wires: core_wires_to_js(&gate.wires)?, - coeffs: Uint8Array::from(coeff_bytes), - }) -} - -#[napi] -pub fn caml_pasta_fp_plonk_gate_vector_create() -> napi::Result> { - Ok(External::new(GateVectorHandleFp::new())) -} - -#[napi] -pub fn caml_pasta_fp_plonk_gate_vector_add( - mut gates: External, - gate: JsGateFp, -) -> napi::Result<()> { - let gate = js_gate_fp_to_core(gate)?; - gates.as_mut().inner_mut().push_gate(gate.into()); - Ok(()) -} - -#[napi] -pub fn caml_pasta_fp_plonk_gate_vector_get( - gates: External, - i: i32, -) -> napi::Result { - let gate = gates - .as_ref() - .inner() - .get_gate(i as usize) - .map(core_gate_fp_to_js) - .unwrap_or_else(|| { - Err(Error::new( - Status::InvalidArg, - format!("gate index {i} out of bounds"), - )) - })?; - Ok(gate) -} - -#[napi] -pub fn caml_pasta_fp_plonk_gate_vector_len( - gates: External, -) -> napi::Result { - let len = gates.as_ref().inner().len(); - Ok(u32::try_from(len).map_err(|_| { - Error::new( - Status::GenericFailure, - "gate vector length exceeds u32".to_string(), - ) - })?) -} - -#[napi] -pub fn caml_pasta_fp_plonk_gate_vector_wrap( - mut gates: External, - t: JsWire, - h: JsWire, -) -> napi::Result<()> { - let target = js_wire_to_wire(&t)?; - let replacement = js_wire_to_wire(&h)?; - gates.as_mut().inner_mut().wrap_wire(target, replacement); - Ok(()) -} - -#[napi] -pub fn caml_pasta_fp_plonk_gate_vector_digest( - gates: External, - public_input_size: u32, -) -> Uint8Array { - Uint8Array::from(gates.as_ref().inner().digest(public_input_size as usize)) -} - -#[napi] -pub fn caml_pasta_fp_plonk_circuit_serialize( - gates: External, - public_input_size: u32, -) -> napi::Result { - gates - .as_ref() - .inner() - .serialize(public_input_size as usize) - .map_err(|e| Error::new(Status::GenericFailure, e.to_string())) -} - -#[napi] -pub fn caml_pasta_fq_plonk_gate_vector_create() -> napi::Result> { - Ok(External::new(GateVectorHandleFq::new())) -} - -#[napi] -pub fn caml_pasta_fq_plonk_gate_vector_add( - mut gates: External, - gate: JsGateFq, -) -> napi::Result<()> { - let gate = js_gate_fq_to_core(gate)?; - gates.as_mut().inner_mut().push_gate(gate.into()); - Ok(()) -} - -#[napi] -pub fn caml_pasta_fq_plonk_gate_vector_get( - gates: External, - i: i32, -) -> napi::Result { - let gate = gates - .as_ref() - .inner() - .get_gate(i as usize) - .map(core_gate_fq_to_js) - .unwrap_or_else(|| { - Err(Error::new( - Status::InvalidArg, - format!("gate index {i} out of bounds"), - )) - })?; - Ok(gate) -} - -#[napi] -pub fn caml_pasta_fq_plonk_gate_vector_len( - gates: External, -) -> napi::Result { - let len = gates.as_ref().inner().len(); - Ok(u32::try_from(len).map_err(|_| { - Error::new( - Status::GenericFailure, - "gate vector length exceeds u32".to_string(), - ) - })?) -} - -#[napi] -pub fn caml_pasta_fq_plonk_gate_vector_wrap( - mut gates: External, - t: JsWire, - h: JsWire, -) -> napi::Result<()> { - let target = js_wire_to_wire(&t)?; - let replacement = js_wire_to_wire(&h)?; - gates.as_mut().inner_mut().wrap_wire(target, replacement); - Ok(()) -} - -#[napi] -pub fn caml_pasta_fq_plonk_gate_vector_digest( - gates: External, - public_input_size: u32, -) -> Uint8Array { - Uint8Array::from(gates.as_ref().inner().digest(public_input_size as usize)) -} - -#[napi] -pub fn caml_pasta_fq_plonk_circuit_serialize( - gates: External, - public_input_size: u32, -) -> napi::Result { - gates - .as_ref() - .inner() - .serialize(public_input_size as usize) - .map_err(|e| Error::new(Status::GenericFailure, e.to_string())) -} - -#[napi] -pub fn caml_pasta_fp_plonk_gate_vector_to_bytes( - gates: External, -) -> napi::Result { - let bytes = rmp_serde::to_vec(gates.as_ref().inner().as_slice()) - .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?; - Ok(Uint8Array::from(bytes)) -} - -#[napi] -pub fn caml_pasta_fp_plonk_gate_vector_from_bytes( - bytes: Uint8Array, -) -> napi::Result> { - let gates: Vec> = rmp_serde::from_slice(bytes.as_ref()) - .map_err(|e| Error::new(Status::InvalidArg, e.to_string()))?; - Ok(External::new(GateVectorHandleFp(GateVector::from_vec( - gates, - )))) -} - -#[napi] -pub fn caml_pasta_fq_plonk_gate_vector_from_bytes( - bytes: Uint8Array, -) -> napi::Result> { - let gates: Vec> = rmp_serde::from_slice(bytes.as_ref()) - .map_err(|e| Error::new(Status::InvalidArg, e.to_string()))?; - Ok(External::new(GateVectorHandleFq(GateVector::from_vec( - gates, - )))) -} diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index 7abdb96367..3520fb1f1f 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -181,9 +181,13 @@ pub fn caml_pasta_fp_plonk_index_decode( srs: External, ) -> Result, Error> { let mut deserializer = rmp_serde::Deserializer::new(bytes); - let mut index = - ProverIndex::>::deserialize(&mut deserializer) - .map_err(|e| Error::new(Status::InvalidArg, "caml_pasta_fp_plonk_index_decode"))?; + let mut index = ProverIndex::>::deserialize(&mut deserializer) + .map_err(|e| { + Error::new( + Status::InvalidArg, + format!("caml_pasta_fp_plonk_index_decode: {}", e), + ) + })?; index.srs = srs.0.clone(); let (linearization, powers_of_alpha) = expr_linearization(Some(&index.cs.feature_flags), true); diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index a39ec84bd2..da772afe33 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -177,10 +177,13 @@ pub fn caml_pasta_fq_plonk_index_decode( srs: External, ) -> Result, Error> { let mut deserializer = rmp_serde::Deserializer::new(bytes); - let mut index = - ProverIndex::>::deserialize(&mut deserializer) - .map_err(|e| Error::new(Status::InvalidArg, "caml_pasta_fq_plonk_index_decode"))?; - + let mut index = ProverIndex::>::deserialize(&mut deserializer) + .map_err(|e| { + Error::new( + Status::InvalidArg, + format!("caml_pasta_fq_plonk_index_decode: {}", e), + ) + })?; index.srs = srs.0.clone(); let (linearization, powers_of_alpha) = expr_linearization(Some(&index.cs.feature_flags), true); index.linearization = linearization; From 3ac952edbbb45a58802ff21d3c152f22a6554727 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 22 Oct 2025 15:45:13 +0700 Subject: [PATCH 38/75] make plonk-napi compile by reusing gate_vector types --- plonk-napi/src/lib.rs | 13 ------------- plonk-napi/src/pasta_fp_plonk_index.rs | 6 +++--- plonk-napi/src/pasta_fq_plonk_index.rs | 6 +++--- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index b84ed0b9a1..9064e60d19 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,5 +1,4 @@ mod circuit; -mod gate_vector; mod pasta_fp_plonk_index; mod pasta_fq_plonk_index; mod poly_comm; @@ -11,18 +10,6 @@ mod wrappers; mod wasm_vector; pub use circuit::prover_to_json; -pub use gate_vector::{ - caml_pasta_fp_plonk_circuit_serialize, caml_pasta_fp_plonk_gate_vector_add, - caml_pasta_fp_plonk_gate_vector_create, caml_pasta_fp_plonk_gate_vector_digest, - caml_pasta_fp_plonk_gate_vector_from_bytes, caml_pasta_fp_plonk_gate_vector_get, - caml_pasta_fp_plonk_gate_vector_len, caml_pasta_fp_plonk_gate_vector_to_bytes, - caml_pasta_fp_plonk_gate_vector_wrap, caml_pasta_fq_plonk_circuit_serialize, - caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, - caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_from_bytes, - caml_pasta_fq_plonk_gate_vector_get, caml_pasta_fq_plonk_gate_vector_len, - caml_pasta_fq_plonk_gate_vector_wrap, GateVectorHandleFp, GateVectorHandleFq, JsGateFp, - JsGateFq, JsGateWires, JsWire, -}; pub use pasta_fp_plonk_index::{ prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, }; diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index 3520fb1f1f..9f3565dae6 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -7,6 +7,7 @@ use mina_curves::pasta::{Fp, Pallas as GAffineOther, Vesta as GAffine, VestaPara use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; use napi_derive::napi; +use plonk_wasm::gate_vector::shared::GateVector; use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; @@ -18,7 +19,6 @@ use std::{ sync::Arc, }; -use crate::gate_vector::GateVectorHandleFp; use crate::tables::{ lookup_table_fp_from_js, runtime_table_cfg_fp_from_js, JsLookupTableFp, JsRuntimeTableCfgFp, }; @@ -119,7 +119,7 @@ pub fn caml_pasta_fp_plonk_index_domain_d8_size(index: External, + gates: External>, public_: i32, lookup_tables: Vec, runtime_table_cfgs: Vec, @@ -127,7 +127,7 @@ pub fn caml_pasta_fp_plonk_index_create( srs: External, lazy_mode: bool, ) -> Result, Error> { - let gates: Vec<_> = gates.as_ref().inner().as_slice().to_vec(); + let gates: Vec<_> = gates.as_ref().as_slice().to_vec(); let runtime_cfgs: Vec> = runtime_table_cfgs .into_iter() diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index da772afe33..36cfc9df9b 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -5,6 +5,7 @@ use mina_curves::pasta::{Fq, Pallas as GAffine, PallasParameters, Vesta as GAffi use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; use napi_derive::napi; +use plonk_wasm::gate_vector::shared::GateVector; use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; @@ -12,7 +13,6 @@ use std::fs::{File, OpenOptions}; use std::io::{BufReader, BufWriter, Seek, SeekFrom::Start}; use std::{io::Cursor, sync::Arc}; -use crate::gate_vector::GateVectorHandleFq; use crate::tables::{ lookup_table_fq_from_js, runtime_table_cfg_fq_from_js, JsLookupTableFq, JsRuntimeTableCfgFq, }; @@ -113,7 +113,7 @@ pub fn caml_pasta_fq_plonk_index_domain_d8_size(index: External, + gates: External>, public_: i32, lookup_tables: Vec, runtime_table_cfgs: Vec, @@ -123,7 +123,7 @@ pub fn caml_pasta_fq_plonk_index_create( ) -> Result, Error> { // TODO: check if and how we run rayon threads automatically in napi - let gates: Vec<_> = gates.as_ref().inner().as_slice().to_vec(); + let gates: Vec<_> = gates.as_ref().as_slice().to_vec(); let runtime_cfgs = runtime_table_cfgs .into_iter() From 0907e20d497f200fee3426b4a2d685bf331dc1f6 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 22 Oct 2025 15:51:35 +0700 Subject: [PATCH 39/75] merge fix --- plonk-napi/src/gate_vector.rs | 223 ++++++++++++++++++++++++++++++++++ plonk-napi/src/lib.rs | 14 ++- plonk-napi/src/poseidon.rs | 4 + 3 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 plonk-napi/src/gate_vector.rs diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs new file mode 100644 index 0000000000..2a4712ee26 --- /dev/null +++ b/plonk-napi/src/gate_vector.rs @@ -0,0 +1,223 @@ +use kimchi::circuits::{ + gate::{Circuit, CircuitGate, GateType}, + wires::{GateWires, Wire as KimchiWire}, +}; +use mina_curves::pasta::{Fp, Fq}; +use napi::bindgen_prelude::*; +use napi_derive::napi; +use o1_utils::hasher::CryptoDigest; +use paste::paste; +use wasm_types::{FlatVector as WasmFlatVector, FlatVectorElem}; + +use crate::wrappers::{ + field::{WasmPastaFp, WasmPastaFq}, + wires::NapiWire, +}; + +#[napi(object)] +#[derive(Clone, Debug, Default)] +pub struct NapiGateWires { + pub w0: NapiWire, + pub w1: NapiWire, + pub w2: NapiWire, + pub w3: NapiWire, + pub w4: NapiWire, + pub w5: NapiWire, + pub w6: NapiWire, +} + +impl NapiGateWires { + fn into_inner(self) -> GateWires { + [ + KimchiWire::from(self.w0), + KimchiWire::from(self.w1), + KimchiWire::from(self.w2), + KimchiWire::from(self.w3), + KimchiWire::from(self.w4), + KimchiWire::from(self.w5), + KimchiWire::from(self.w6), + ] + } +} + +impl From<&GateWires> for NapiGateWires { + fn from(value: &GateWires) -> Self { + Self { + w0: value[0].into(), + w1: value[1].into(), + w2: value[2].into(), + w3: value[3].into(), + w4: value[4].into(), + w5: value[5].into(), + w6: value[6].into(), + } + } +} + +fn gate_type_from_i32(value: i32) -> Result { + // Ocaml/JS int are signed, so we use i32 here + if value < 0 { + return Err(Error::new( + Status::InvalidArg, + format!("invalid GateType discriminant: {}", value), + )); + } + + let variants: &[GateType] = &[ + GateType::Zero, + GateType::Generic, + GateType::Poseidon, + GateType::CompleteAdd, + GateType::VarBaseMul, + GateType::EndoMul, + GateType::EndoMulScalar, + GateType::Lookup, + GateType::CairoClaim, + GateType::CairoInstruction, + GateType::CairoFlags, + GateType::CairoTransition, + GateType::RangeCheck0, + GateType::RangeCheck1, + GateType::ForeignFieldAdd, + GateType::ForeignFieldMul, + GateType::Xor16, + GateType::Rot64, + ]; + + let index = value as usize; + variants.get(index).copied().ok_or_else(|| { + Error::new( + Status::InvalidArg, + format!("invalid GateType discriminant: {}", value), + ) + }) +} + +// For convenience to not expose the GateType enum to JS +fn gate_type_to_i32(value: GateType) -> i32 { + value as i32 +} + +macro_rules! impl_gate_support { + ($field_name:ident, $F:ty, $WasmF:ty) => { + paste! { + #[napi(object)] + #[derive(Clone, Debug, Default)] + pub struct [] { + pub typ: i32, // for convenience, we use i32 instead of GateType + pub wires: NapiGateWires, + pub coeffs: Vec, // for now, serializing fields as flat bytes, but subject to changes + } + + impl [] { + fn into_inner(self) -> Result> { + let coeffs = WasmFlatVector::<$WasmF>::from_bytes(self.coeffs) + .into_iter() + .map(Into::into) + .collect(); + + Ok(CircuitGate { + typ: gate_type_from_i32(self.typ)?, + wires: self.wires.into_inner(), + coeffs, + }) + } + + fn from_inner(value: &CircuitGate<$F>) -> Self { + let coeffs = value + .coeffs + .iter() + .cloned() + .map($WasmF::from) + .flat_map(|elem| elem.flatten()) + .collect(); + + Self { + typ: gate_type_to_i32(value.typ), + wires: (&value.wires).into(), + coeffs, + } + } + } + + #[napi] + #[derive(Clone, Default, Debug)] + pub struct []( + #[napi(skip)] pub Vec>, + ); + + #[napi] + pub fn []() -> [] { + println!("from native rust creating gate vector"); + [](Vec::new()) + } + + #[napi] + pub fn []( + vector: &mut [], + gate: [], + ) -> Result<()> { + println!("from native rust adding gate to vector"); + vector.0.push(gate.into_inner()?); + Ok(()) + } + + #[napi] + pub fn []( + vector: &[], + index: i32, + ) -> [] { + println!("from native rust getting gate from vector"); + []::from_inner(&vector.0[index as usize]) + } + + #[napi] + pub fn []( + vector: &[], + ) -> i32 { + println!("from native rust getting gate vector length"); + vector.0.len() as i32 + } + + #[napi] + pub fn []( + vector: &mut [], + target: NapiWire, + head: NapiWire, + ) { + println!("from native rust wrapping wire in gate vector"); + vector.0[target.row as usize].wires[target.col as usize] = KimchiWire::from(head); + } + + #[napi] + pub fn []( + public_input_size: i32, + vector: &[], + ) -> Uint8Array { + println!("from native rust computing gate vector digest"); + let bytes = Circuit::new(public_input_size as usize, &vector.0) + .digest() + .to_vec(); + Uint8Array::from(bytes) + } + + #[napi] + pub fn []( + public_input_size: i32, + vector: &[], + ) -> Result { + println!("from native rust serializing gate vector to json"); + let circuit = Circuit::new(public_input_size as usize, &vector.0); + serde_json::to_string(&circuit).map_err(|err| { + Error::new( + Status::GenericFailure, + format!("couldn't serialize constraints: {}", err), + ) + }) + } + } + }; +} + +impl_gate_support!(fp, Fp, WasmPastaFp); +impl_gate_support!(fq, Fq, WasmPastaFq); diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 9064e60d19..04102b0bf8 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,15 +1,25 @@ mod circuit; +mod gate_vector; mod pasta_fp_plonk_index; mod pasta_fq_plonk_index; mod poly_comm; mod poseidon; mod srs; mod tables; -mod types; mod wrappers; mod wasm_vector; -pub use circuit::prover_to_json; +pub use gate_vector::{ + caml_pasta_fp_plonk_circuit_serialize, caml_pasta_fp_plonk_gate_vector_add, + caml_pasta_fp_plonk_gate_vector_create, caml_pasta_fp_plonk_gate_vector_digest, + caml_pasta_fp_plonk_gate_vector_get, caml_pasta_fp_plonk_gate_vector_len, + caml_pasta_fp_plonk_gate_vector_wrap, caml_pasta_fq_plonk_circuit_serialize, + caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, + caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, + caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, + NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, NapiFqGate as WasmFqGate, + NapiFqGateVector as WasmFqGateVector, +}; pub use pasta_fp_plonk_index::{ prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, }; diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index ba96f58bfb..fb8f7b66b4 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -9,6 +9,8 @@ use wasm_types::{FlatVector, FlatVectorElem}; #[napi] pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result { + //println!("from native rust fp poseidon"); + let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) @@ -32,6 +34,8 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result Result { + //println!("from native rust fq poseidon"); + let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) From d7f7afc3e28f7b3b3ab431caf5dedd5cb505869c Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 23 Oct 2025 19:30:12 +0200 Subject: [PATCH 40/75] napi: get rid of gate vector to use external from plonk-wasm --- plonk-napi/src/gate_vector.rs | 223 ---------------------------------- plonk-napi/src/lib.rs | 12 -- 2 files changed, 235 deletions(-) delete mode 100644 plonk-napi/src/gate_vector.rs diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs deleted file mode 100644 index 2a4712ee26..0000000000 --- a/plonk-napi/src/gate_vector.rs +++ /dev/null @@ -1,223 +0,0 @@ -use kimchi::circuits::{ - gate::{Circuit, CircuitGate, GateType}, - wires::{GateWires, Wire as KimchiWire}, -}; -use mina_curves::pasta::{Fp, Fq}; -use napi::bindgen_prelude::*; -use napi_derive::napi; -use o1_utils::hasher::CryptoDigest; -use paste::paste; -use wasm_types::{FlatVector as WasmFlatVector, FlatVectorElem}; - -use crate::wrappers::{ - field::{WasmPastaFp, WasmPastaFq}, - wires::NapiWire, -}; - -#[napi(object)] -#[derive(Clone, Debug, Default)] -pub struct NapiGateWires { - pub w0: NapiWire, - pub w1: NapiWire, - pub w2: NapiWire, - pub w3: NapiWire, - pub w4: NapiWire, - pub w5: NapiWire, - pub w6: NapiWire, -} - -impl NapiGateWires { - fn into_inner(self) -> GateWires { - [ - KimchiWire::from(self.w0), - KimchiWire::from(self.w1), - KimchiWire::from(self.w2), - KimchiWire::from(self.w3), - KimchiWire::from(self.w4), - KimchiWire::from(self.w5), - KimchiWire::from(self.w6), - ] - } -} - -impl From<&GateWires> for NapiGateWires { - fn from(value: &GateWires) -> Self { - Self { - w0: value[0].into(), - w1: value[1].into(), - w2: value[2].into(), - w3: value[3].into(), - w4: value[4].into(), - w5: value[5].into(), - w6: value[6].into(), - } - } -} - -fn gate_type_from_i32(value: i32) -> Result { - // Ocaml/JS int are signed, so we use i32 here - if value < 0 { - return Err(Error::new( - Status::InvalidArg, - format!("invalid GateType discriminant: {}", value), - )); - } - - let variants: &[GateType] = &[ - GateType::Zero, - GateType::Generic, - GateType::Poseidon, - GateType::CompleteAdd, - GateType::VarBaseMul, - GateType::EndoMul, - GateType::EndoMulScalar, - GateType::Lookup, - GateType::CairoClaim, - GateType::CairoInstruction, - GateType::CairoFlags, - GateType::CairoTransition, - GateType::RangeCheck0, - GateType::RangeCheck1, - GateType::ForeignFieldAdd, - GateType::ForeignFieldMul, - GateType::Xor16, - GateType::Rot64, - ]; - - let index = value as usize; - variants.get(index).copied().ok_or_else(|| { - Error::new( - Status::InvalidArg, - format!("invalid GateType discriminant: {}", value), - ) - }) -} - -// For convenience to not expose the GateType enum to JS -fn gate_type_to_i32(value: GateType) -> i32 { - value as i32 -} - -macro_rules! impl_gate_support { - ($field_name:ident, $F:ty, $WasmF:ty) => { - paste! { - #[napi(object)] - #[derive(Clone, Debug, Default)] - pub struct [] { - pub typ: i32, // for convenience, we use i32 instead of GateType - pub wires: NapiGateWires, - pub coeffs: Vec, // for now, serializing fields as flat bytes, but subject to changes - } - - impl [] { - fn into_inner(self) -> Result> { - let coeffs = WasmFlatVector::<$WasmF>::from_bytes(self.coeffs) - .into_iter() - .map(Into::into) - .collect(); - - Ok(CircuitGate { - typ: gate_type_from_i32(self.typ)?, - wires: self.wires.into_inner(), - coeffs, - }) - } - - fn from_inner(value: &CircuitGate<$F>) -> Self { - let coeffs = value - .coeffs - .iter() - .cloned() - .map($WasmF::from) - .flat_map(|elem| elem.flatten()) - .collect(); - - Self { - typ: gate_type_to_i32(value.typ), - wires: (&value.wires).into(), - coeffs, - } - } - } - - #[napi] - #[derive(Clone, Default, Debug)] - pub struct []( - #[napi(skip)] pub Vec>, - ); - - #[napi] - pub fn []() -> [] { - println!("from native rust creating gate vector"); - [](Vec::new()) - } - - #[napi] - pub fn []( - vector: &mut [], - gate: [], - ) -> Result<()> { - println!("from native rust adding gate to vector"); - vector.0.push(gate.into_inner()?); - Ok(()) - } - - #[napi] - pub fn []( - vector: &[], - index: i32, - ) -> [] { - println!("from native rust getting gate from vector"); - []::from_inner(&vector.0[index as usize]) - } - - #[napi] - pub fn []( - vector: &[], - ) -> i32 { - println!("from native rust getting gate vector length"); - vector.0.len() as i32 - } - - #[napi] - pub fn []( - vector: &mut [], - target: NapiWire, - head: NapiWire, - ) { - println!("from native rust wrapping wire in gate vector"); - vector.0[target.row as usize].wires[target.col as usize] = KimchiWire::from(head); - } - - #[napi] - pub fn []( - public_input_size: i32, - vector: &[], - ) -> Uint8Array { - println!("from native rust computing gate vector digest"); - let bytes = Circuit::new(public_input_size as usize, &vector.0) - .digest() - .to_vec(); - Uint8Array::from(bytes) - } - - #[napi] - pub fn []( - public_input_size: i32, - vector: &[], - ) -> Result { - println!("from native rust serializing gate vector to json"); - let circuit = Circuit::new(public_input_size as usize, &vector.0); - serde_json::to_string(&circuit).map_err(|err| { - Error::new( - Status::GenericFailure, - format!("couldn't serialize constraints: {}", err), - ) - }) - } - } - }; -} - -impl_gate_support!(fp, Fp, WasmPastaFp); -impl_gate_support!(fq, Fq, WasmPastaFq); diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 04102b0bf8..84c01766ac 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,5 +1,4 @@ mod circuit; -mod gate_vector; mod pasta_fp_plonk_index; mod pasta_fq_plonk_index; mod poly_comm; @@ -9,17 +8,6 @@ mod tables; mod wrappers; mod wasm_vector; -pub use gate_vector::{ - caml_pasta_fp_plonk_circuit_serialize, caml_pasta_fp_plonk_gate_vector_add, - caml_pasta_fp_plonk_gate_vector_create, caml_pasta_fp_plonk_gate_vector_digest, - caml_pasta_fp_plonk_gate_vector_get, caml_pasta_fp_plonk_gate_vector_len, - caml_pasta_fp_plonk_gate_vector_wrap, caml_pasta_fq_plonk_circuit_serialize, - caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, - caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, - caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, - NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, NapiFqGate as WasmFqGate, - NapiFqGateVector as WasmFqGateVector, -}; pub use pasta_fp_plonk_index::{ prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, }; From 0925ce302d1df01599a2b6b395d7415e1537f68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=AFs=20Querol?= Date: Tue, 7 Oct 2025 14:43:30 +0200 Subject: [PATCH 41/75] napi: ffi and types for srs --- plonk-napi/src/srs.rs | 284 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index 3f66c82ddd..3a260c5e4d 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -28,3 +28,287 @@ pub fn caml_fq_srs_from_bytes(bytes: Uint8Array) -> NapiResult { + pub mod $mod_name { + use super::*; + + #[napi] + #[derive(Clone)] + pub struct $struct_ident { + #[napi(skip)] + pub inner: Arc>, + } + + impl $struct_ident { + fn new(inner: SRS<$group_ty>) -> Self { + Self { + inner: Arc::new(inner), + } + } + + fn from_arc(inner: Arc>) -> Self { + Self { inner } + } + } + + fn invalid_domain_error() -> Error { + Error::new(Status::InvalidArg, "invalid domain size") + } + + fn map_error(context: &str, err: impl std::fmt::Display) -> Error { + Error::new(Status::GenericFailure, format!("{}: {}", context, err)) + } + + #[napi] + impl $struct_ident { + #[napi(factory)] + pub fn create(depth: i32) -> Result { + Ok(Self::from_arc(Arc::new(SRS::<$group_ty>::create(depth as usize)))) + } + + #[napi(factory)] + pub fn create_parallel(depth: i32) -> Result { + Ok(Self::from_arc(Arc::new(SRS::<$group_ty>::create_parallel( + depth as usize, + )))) + } + + #[napi] + pub fn add_lagrange_basis(&self, log2_size: i32) -> Result<()> { + let size = 1usize << (log2_size as usize); + let domain = EvaluationDomain::<$field_ty>::new(size).ok_or_else(invalid_domain_error)?; + self.inner.get_lagrange_basis(domain); + Ok(()) + } + + #[napi] + pub fn write(&self, append: Option, path: String) -> Result<()> { + let file = OpenOptions::new() + .write(true) + .create(true) + .append(append.unwrap_or(true)) + .open(&path) + .map_err(|err| map_error("srs_write", err))?; + let mut writer = BufWriter::new(file); + self.inner + .serialize(&mut rmp_serde::Serializer::new(&mut writer)) + .map_err(|err| map_error("srs_write", err)) + } + + #[napi] + pub fn read(offset: Option, path: String) -> Result> { + let file = match File::open(&path) { + Ok(file) => file, + Err(err) => return Err(map_error("srs_read", err)), + }; + let mut reader = BufReader::new(file); + + if let Some(off) = offset { + reader + .seek(SeekFrom::Start(off as u64)) + .map_err(|err| map_error("srs_read", err))?; + } + + match SRS::<$group_ty>::deserialize(&mut rmp_serde::Deserializer::new(reader)) { + Ok(srs) => Ok(Some(Self::from_arc(Arc::new(srs)))), + Err(_) => Ok(None), + } + } + + #[napi] + pub fn get(&self) -> WasmVector<$group_wrapper> { + let mut points: Vec<$group_wrapper> = vec![self.inner.h.into()]; + points.extend(self.inner.g.iter().cloned().map(Into::into)); + points.into() + } + + #[napi] + pub fn set(points: WasmVector<$group_wrapper>) -> Result { + let mut pts: Vec<$group_ty> = points.into_iter().map(Into::into).collect(); + if pts.is_empty() { + return Err(Error::new( + Status::InvalidArg, + "expected at least one element for SRS", + )); + } + let h = pts.remove(0); + let g = pts; + Ok(Self::from_arc(Arc::new(SRS::<$group_ty> { + h, + g, + lagrange_bases: HashMapCache::new(), + }))) + } + + #[napi] + pub fn maybe_lagrange_commitment( + &self, + domain_size: i32, + index: i32, + ) -> Option<$poly_comm_wrapper> { + if !self + .inner + .lagrange_bases + .contains_key(&(domain_size as usize)) + { + return None; + } + let basis = self + .inner + .get_lagrange_basis_from_domain_size(domain_size as usize); + basis.get(index as usize).cloned().map(Into::into) + } + + #[napi] + pub fn set_lagrange_basis( + &self, + domain_size: i32, + bases: WasmVector<$poly_comm_wrapper>, + ) { + let domain = domain_size as usize; + let commitments: Vec<_> = bases.into_iter().map(Into::into).collect(); + self.inner + .lagrange_bases + .get_or_generate(domain, || commitments.clone()); + } + + #[napi] + pub fn get_lagrange_basis( + &self, + domain_size: i32, + ) -> Result> { + let domain = EvaluationDomain::<$field_ty>::new(domain_size as usize) + .ok_or_else(invalid_domain_error)?; + let basis = self.inner.get_lagrange_basis(domain); + Ok(basis.iter().cloned().map(Into::into).collect()) + } + + #[napi] + pub fn commit_evaluations( + &self, + domain_size: i32, + evaluations: Uint8Array, + ) -> Result<$poly_comm_wrapper> { + let elems: Vec<$field_ty> = WasmFlatVector::<$wasm_field>::from_bytes( + evaluations.as_ref().to_vec(), + ) + .into_iter() + .map(Into::into) + .collect(); + let domain = EvaluationDomain::<$field_ty>::new(domain_size as usize) + .ok_or_else(invalid_domain_error)?; + let evals = Evaluations::from_vec_and_domain(elems, domain); + let poly = evals.interpolate(); + Ok(self.inner.commit(&poly, None).into()) + } + + #[napi] + pub fn b_poly_commitment(&self, chals: Uint8Array) -> Result<$poly_comm_wrapper> { + let elements: Vec<$field_ty> = WasmFlatVector::<$wasm_field>::from_bytes( + chals.as_ref().to_vec(), + ) + .into_iter() + .map(Into::into) + .collect(); + let coeffs = b_poly_coefficients(&elements); + let poly = DensePolynomial::<$field_ty>::from_coefficients_vec(coeffs); + Ok(self.inner.commit_non_hiding(&poly, 1).into()) + } + + #[napi] + pub fn batch_accumulator_check( + &self, + commitments: WasmVector<$group_wrapper>, + chals: Uint8Array, + ) -> Result { + let comms: Vec<$group_ty> = commitments.into_iter().map(Into::into).collect(); + let chals: Vec<$field_ty> = WasmFlatVector::<$wasm_field>::from_bytes( + chals.as_ref().to_vec(), + ) + .into_iter() + .map(Into::into) + .collect(); + Ok(poly_commitment::utils::batch_dlog_accumulator_check( + &self.inner, + &comms, + &chals, + )) + } + + #[napi] + pub fn batch_accumulator_generate( + &self, + count: i32, + chals: Uint8Array, + ) -> Result> { + let chals: Vec<$field_ty> = WasmFlatVector::<$wasm_field>::from_bytes( + chals.as_ref().to_vec(), + ) + .into_iter() + .map(Into::into) + .collect(); + let points = poly_commitment::utils::batch_dlog_accumulator_generate::<$group_ty>( + &self.inner, + count as usize, + &chals, + ); + Ok(points.into_iter().map(Into::into).collect()) + } + + #[napi] + pub fn h(&self) -> $group_wrapper { + self.inner.h.into() + } + } + } + }; +} + +impl_srs_module!( + fp, + mina_curves::pasta::Fp, + WasmPastaFp, + mina_curves::pasta::Vesta, + WasmGVesta, + WasmFpPolyComm, + WasmFpSrs +); + +impl_srs_module!( + fq, + mina_curves::pasta::Fq, + WasmPastaFq, + mina_curves::pasta::Pallas, + WasmGPallas, + WasmFqPolyComm, + WasmFqSrs +); From b90542cc11c645ed29990de61d6a4d437c458aff Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 20 Oct 2025 16:36:04 +0200 Subject: [PATCH 42/75] napi: use macro params closer to plonk-wasms names --- plonk-napi/src/srs.rs | 85 +++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index 3a260c5e4d..0138e61b39 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -44,39 +44,40 @@ use wasm_types::FlatVector as WasmFlatVector; use crate::{ poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}, wasm_vector::WasmVector, - wrappers::field::{WasmPastaFp, WasmPastaFq}, - wrappers::group::{WasmGPallas, WasmGVesta}, + wrappers::{ + field::{WasmPastaFp, WasmPastaFq}, + group::{WasmGPallas, WasmGVesta}, + }, }; -macro_rules! impl_srs_module { +macro_rules! impl_srs { ( - $mod_name:ident, + $name:ident, $field_ty:ty, - $wasm_field:ty, + $wasmF:ty, $group_ty:ty, $group_wrapper:ty, $poly_comm_wrapper:ty, - $struct_ident:ident + $field_name:ident ) => { - pub mod $mod_name { + pub mod $name { use super::*; #[napi] #[derive(Clone)] - pub struct $struct_ident { - #[napi(skip)] - pub inner: Arc>, - } + pub struct [Napi $field_name:camel Srs] ( + #[napi(skip)] pub Arc> + ); - impl $struct_ident { + impl [Napi $field_name:camel Srs] { fn new(inner: SRS<$group_ty>) -> Self { - Self { - inner: Arc::new(inner), - } + Self ( + Arc::new(inner), + ) } fn from_arc(inner: Arc>) -> Self { - Self { inner } + Self (inner) } } @@ -218,7 +219,7 @@ macro_rules! impl_srs_module { domain_size: i32, evaluations: Uint8Array, ) -> Result<$poly_comm_wrapper> { - let elems: Vec<$field_ty> = WasmFlatVector::<$wasm_field>::from_bytes( + let elems: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( evaluations.as_ref().to_vec(), ) .into_iter() @@ -233,7 +234,7 @@ macro_rules! impl_srs_module { #[napi] pub fn b_poly_commitment(&self, chals: Uint8Array) -> Result<$poly_comm_wrapper> { - let elements: Vec<$field_ty> = WasmFlatVector::<$wasm_field>::from_bytes( + let elements: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() @@ -251,7 +252,7 @@ macro_rules! impl_srs_module { chals: Uint8Array, ) -> Result { let comms: Vec<$group_ty> = commitments.into_iter().map(Into::into).collect(); - let chals: Vec<$field_ty> = WasmFlatVector::<$wasm_field>::from_bytes( + let chals: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() @@ -270,7 +271,7 @@ macro_rules! impl_srs_module { count: i32, chals: Uint8Array, ) -> Result> { - let chals: Vec<$field_ty> = WasmFlatVector::<$wasm_field>::from_bytes( + let chals: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() @@ -293,22 +294,28 @@ macro_rules! impl_srs_module { }; } -impl_srs_module!( - fp, - mina_curves::pasta::Fp, - WasmPastaFp, - mina_curves::pasta::Vesta, - WasmGVesta, - WasmFpPolyComm, - WasmFpSrs -); - -impl_srs_module!( - fq, - mina_curves::pasta::Fq, - WasmPastaFq, - mina_curves::pasta::Pallas, - WasmGPallas, - WasmFqPolyComm, - WasmFqSrs -); +pub mod fp { + use super::*; + impl_srs!( + fp, + mina_curves::pasta::Fp, + WasmPastaFp, + mina_curves::pasta::Vesta, + WasmGVesta, + WasmFpPolyComm, + Fp + ); +} + +pub mod fq { + use super::*; + impl_srs!( + fq, + mina_curves::pasta::Fq, + WasmPastaFq, + mina_curves::pasta::Pallas, + WasmGPallas, + WasmFqPolyComm, + Fq + ); +} From ba4289c0409de6dc1a51db8108f741ef04840679 Mon Sep 17 00:00:00 2001 From: leon chou Date: Mon, 27 Oct 2025 10:22:25 -0400 Subject: [PATCH 43/75] native prover build with proper types --- Cargo.lock | 103 +++++++++++++++++++++++++++------ Cargo.toml | 4 +- plonk-napi/src/circuit.rs | 2 +- plonk-napi/src/lib.rs | 4 +- plonk-napi/src/prover_index.rs | 21 +++++++ plonk-napi/src/types.rs | 26 ++------- 6 files changed, 116 insertions(+), 44 deletions(-) create mode 100644 plonk-napi/src/prover_index.rs diff --git a/Cargo.lock b/Cargo.lock index d7aaf3c947..c18856c343 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -905,6 +905,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -1025,6 +1034,38 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "ctor" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb" +dependencies = [ + "ctor-proc-macro 0.0.6", + "dtor", +] + +[[package]] +name = "ctor" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c9b8bdf64ee849747c1b12eb861d21aa47fa161564f48332f1afe2373bf899" +dependencies = [ + "ctor-proc-macro 0.0.7", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" + +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + [[package]] name = "cty" version = "0.2.2" @@ -1148,6 +1189,21 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "dtor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e58a0764cddb55ab28955347b45be00ade43d4d6f3ba4bf3dc354e4ec9432934" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + [[package]] name = "educe" version = "0.6.0" @@ -2388,15 +2444,16 @@ dependencies = [ [[package]] name = "napi" -version = "2.16.17" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55740c4ae1d8696773c78fdafd5d0e5fe9bc9f1b071c7ba493ba5c413a9184f3" +checksum = "f1b74e3dce5230795bb4d2821b941706dee733c7308752507254b0497f39cad7" dependencies = [ "bitflags 2.4.2", - "ctor", - "napi-derive", + "ctor 0.5.0", + "napi-build", "napi-sys", - "once_cell", + "nohash-hasher", + "rustc-hash", ] [[package]] @@ -2407,12 +2464,12 @@ checksum = "dcae8ad5609d14afb3a3b91dee88c757016261b151e9dcecabf1b2a31a6cab14" [[package]] name = "napi-derive" -version = "2.16.13" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c" +checksum = "78665d6bdf10e9a4e6b38123efb0f66962e6197c1aea2f07cff3f159a374696d" dependencies = [ - "cfg-if 1.0.0", - "convert_case", + "convert_case 0.8.0", + "ctor 0.6.0", "napi-derive-backend", "proc-macro2", "quote", @@ -2421,24 +2478,22 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "1.0.75" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf" +checksum = "42d55d01423e7264de3acc13b258fa48ca7cf38a4d25db848908ec3c1304a85a" dependencies = [ - "convert_case", - "once_cell", + "convert_case 0.8.0", "proc-macro2", "quote", - "regex", "semver", "syn 2.0.100", ] [[package]] name = "napi-sys" -version = "2.4.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" +checksum = "1ed8f0e23a62a3ce0fbb6527cdc056e9282ddd9916b068c46f8923e18eed5ee6" dependencies = [ "libloading", ] @@ -2491,6 +2546,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -2696,7 +2757,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7543703a85e10e5fd49258c8c820bda6e909d0feaf02f6db25197fe4b5f36bac" dependencies = [ - "convert_case", + "convert_case 0.6.0", "proc-macro2", "quote", "syn 1.0.109", @@ -3378,6 +3439,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustix" version = "0.38.30" @@ -3478,7 +3545,7 @@ dependencies = [ "ark-std", "clap 4.4.18", "criterion", - "ctor", + "ctor 0.2.9", "hex", "kimchi", "mina-curves", diff --git a/Cargo.toml b/Cargo.toml index cbb7773e07..7c1874723c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,8 +62,8 @@ libflate = "2" log = "0.4.20" num-bigint = { version = "0.4.4", features = ["rand", "serde"] } num-integer = "0.1.45" -napi = { version = "2.16.8", default-features = false, features = ["napi7"] } -napi-derive = "2.16.8" +napi = { version = "3.3.0", default-features = false, features = ["napi7"] } +napi-derive = { version = "3.3.0", features = ["type-def"] } napi-build = "2.1.0" ocaml = { version = "0.22.2" } ocaml-gen = { version = "1.0.0" } diff --git a/plonk-napi/src/circuit.rs b/plonk-napi/src/circuit.rs index 0c2a850228..81a20456b6 100644 --- a/plonk-napi/src/circuit.rs +++ b/plonk-napi/src/circuit.rs @@ -30,7 +30,7 @@ where } #[napi] -pub fn prover_to_json(prover_index: External) -> String { +pub fn prover_to_json(prover_index: &External) -> String { let circuit: Circuit = prover_index.0.cs.as_ref().into(); serde_json::to_string(&circuit).expect("couldn't serialize constraints") } diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index f0c304a7b9..7bda3894ce 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,8 +1,10 @@ mod circuit; mod poseidon; mod types; +mod prover_index; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; pub use circuit::prover_to_json; -pub use types::{prover_index_from_bytes, prover_index_to_bytes, WasmPastaFpPlonkIndex}; +pub use prover_index::{prover_index_from_bytes, prover_index_to_bytes}; +pub use types::WasmPastaFpPlonkIndex; diff --git a/plonk-napi/src/prover_index.rs b/plonk-napi/src/prover_index.rs new file mode 100644 index 0000000000..c38c47c3e3 --- /dev/null +++ b/plonk-napi/src/prover_index.rs @@ -0,0 +1,21 @@ +use napi::bindgen_prelude::*; +use napi_derive::napi; + +use crate::types::WasmPastaFpPlonkIndex; + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[napi] +pub fn prover_index_from_bytes(bytes: Uint8Array) -> Result> { + let index = WasmPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) + .map_err(|e| Error::new(Status::InvalidArg, e))?; + Ok(External::new(index)) +} + +// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +#[napi] +pub fn prover_index_to_bytes(index: &External) -> Result { + let bytes = index + .serialize_inner() + .map_err(|e| Error::new(Status::GenericFailure, e))?; + Ok(Uint8Array::from(bytes)) +} diff --git a/plonk-napi/src/types.rs b/plonk-napi/src/types.rs index 985bf50d35..50091937f2 100644 --- a/plonk-napi/src/types.rs +++ b/plonk-napi/src/types.rs @@ -1,8 +1,7 @@ use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; use mina_curves::pasta::{Vesta as GAffine, VestaParameters}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; -use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; -use napi_derive::napi; + use poly_commitment::ipa::{OpeningProof, SRS}; use serde::{Deserialize, Serialize}; use std::{io::Cursor, sync::Arc}; @@ -18,7 +17,7 @@ struct SerializedProverIndex { // TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around impl WasmPastaFpPlonkIndex { - fn serialize_inner(&self) -> Result, String> { + pub fn serialize_inner(&self) -> Result, String> { let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; let mut srs = Vec::new(); @@ -32,7 +31,7 @@ impl WasmPastaFpPlonkIndex { rmp_serde::to_vec(&serialized).map_err(|e| e.to_string()) } - fn deserialize_inner(bytes: &[u8]) -> Result { + pub fn deserialize_inner(bytes: &[u8]) -> Result { let serialized: SerializedProverIndex = rmp_serde::from_slice(bytes).map_err(|e| e.to_string())?; @@ -59,21 +58,4 @@ impl WasmPastaFpPlonkIndex { Ok(WasmPastaFpPlonkIndex(Box::new(index))) } -} - -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around -#[napi] -pub fn prover_index_from_bytes(bytes: Uint8Array) -> NapiResult> { - let index = WasmPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) - .map_err(|e| Error::new(Status::InvalidArg, e))?; - Ok(External::new(index)) -} - -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around -#[napi] -pub fn prover_index_to_bytes(index: External) -> NapiResult { - let bytes = index - .serialize_inner() - .map_err(|e| Error::new(Status::GenericFailure, e))?; - Ok(Uint8Array::from(bytes)) -} +} \ No newline at end of file From adaf261419ce8d3b5d071912cf06ea3bf64a3e2a Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 27 Oct 2025 19:19:57 +0100 Subject: [PATCH 44/75] napi: pass to srs impls --- plonk-napi/src/lib.rs | 7 +- plonk-napi/src/srs.rs | 268 ++++++++++++++++++++-------------- plonk-napi/src/tables.rs | 13 +- plonk-wasm/src/gate_vector.rs | 18 ++- 4 files changed, 181 insertions(+), 125 deletions(-) diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 84c01766ac..bc4a77b825 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -5,8 +5,8 @@ mod poly_comm; mod poseidon; mod srs; mod tables; -mod wrappers; mod wasm_vector; +mod wrappers; pub use pasta_fp_plonk_index::{ prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, @@ -19,4 +19,7 @@ pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_b pub use srs::{caml_fp_srs_from_bytes, caml_fp_srs_to_bytes, caml_fq_srs_from_bytes}; pub use tables::{JsLookupTableFp, JsLookupTableFq, JsRuntimeTableCfgFp, JsRuntimeTableCfgFq}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; -pub use wrappers::{field::{WasmPastaFp, WasmPastaFq}, group::{WasmGPallas, WasmGVesta}}; +pub use wrappers::{ + field::{WasmPastaFp, WasmPastaFq}, + group::{WasmGPallas, WasmGVesta}, +}; diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index 0138e61b39..750f89486e 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -1,13 +1,29 @@ -use std::sync::Arc; - +use crate::{ + poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}, + wasm_vector::WasmVector, + wrappers::{ + field::{WasmPastaFp, WasmPastaFq}, + group::{WasmGPallas, WasmGVesta}, + }, +}; +use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Evaluations}; +use core::ops::Deref; use mina_curves::pasta::{Pallas as GAffineOther, Vesta as GAffine}; -use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi::bindgen_prelude::{Error, External, Result, Status, Uint8Array}; use napi_derive::napi; -use plonk_wasm::srs::fp::WasmFpSrs as WasmSrsFp; -use plonk_wasm::srs::fq::WasmFqSrs as WasmSrsFq; - -use poly_commitment::ipa::SRS; +use paste::paste; +use poly_commitment::{ + commitment::b_poly_coefficients, hash_map_cache::HashMapCache, ipa::SRS, SRS as ISRS, +}; +use serde::{Deserialize, Serialize}; +use std::{ + fs::{File, OpenOptions}, + io::{BufReader, BufWriter, Seek, SeekFrom}, + sync::Arc, +}; +use wasm_types::FlatVector as WasmFlatVector; +/* #[napi] pub fn caml_fp_srs_to_bytes(srs: External) -> NapiResult { let buffer = rmp_serde::to_vec(srs.as_ref().0.as_ref()) @@ -28,27 +44,7 @@ pub fn caml_fq_srs_from_bytes(bytes: Uint8Array) -> NapiResult { - pub mod $name { - use super::*; + paste! { + + type WasmPolyComm = $poly_comm_wrapper; #[napi] #[derive(Clone)] - pub struct [Napi $field_name:camel Srs] ( + pub struct [] ( #[napi(skip)] pub Arc> ); - impl [Napi $field_name:camel Srs] { + impl Deref for [] { + type Target = Arc>; + + fn deref(&self) -> &Self::Target { &self.0 } + } + + impl From>> for [] { + fn from(x: Arc>) -> Self { + [](x) + } + } + + impl From<&Arc>> for [] { + fn from(x: &Arc>) -> Self { + [](x.clone()) + } + } + + impl From<[]> for Arc> { + fn from(x: []) -> Self { + x.0 + } + } + + impl From<&[]> for Arc> { + fn from(x: &[]) -> Self { + x.0.clone() + } + } + + impl<'a> From<&'a []> for &'a Arc> { + fn from(x: &'a []) -> Self { + &x.0 + } + } + + /* + impl [] { fn new(inner: SRS<$group_ty>) -> Self { Self ( Arc::new(inner), @@ -80,6 +114,7 @@ macro_rules! impl_srs { Self (inner) } } + */ fn invalid_domain_error() -> Error { Error::new(Status::InvalidArg, "invalid domain size") @@ -90,150 +125,163 @@ macro_rules! impl_srs { } #[napi] - impl $struct_ident { + impl [] { + + #[napi] + pub fn serialize(&self) -> Result { + let mut buf = Vec::new(); + self.0 + .serialize(&mut rmp_serde::Serializer::new(&mut buf)) + .map_err(|e| map_error("srs_serialize", e))?; + Ok(Uint8Array::from(buf)) + } + + #[napi] + pub fn deserialize(bytes: Uint8Array) -> Result { + let srs: SRS<$group_ty> = rmp_serde::from_slice(bytes.as_ref()) + .map_err(|e| map_error("srs_deserialize", e))?; + Ok(Arc::new(srs).into()) + } + #[napi(factory)] - pub fn create(depth: i32) -> Result { - Ok(Self::from_arc(Arc::new(SRS::<$group_ty>::create(depth as usize)))) + pub fn [](depth: i32) -> Result { + Ok(Arc::new(SRS::<$group_ty>::create(depth as usize)).into()) } #[napi(factory)] - pub fn create_parallel(depth: i32) -> Result { - Ok(Self::from_arc(Arc::new(SRS::<$group_ty>::create_parallel( + pub fn [](depth: i32) -> Result { + Ok(Arc::new(SRS::<$group_ty>::create_parallel( depth as usize, - )))) + )).into()) + } + + #[napi] + pub fn [](srs: &[]) -> Vec<$group_wrapper> { + let mut h_and_gs: Vec<$group_wrapper> = vec![srs.0.h.into()]; + h_and_gs.extend(srs.0.g.iter().cloned().map(Into::into)); + h_and_gs } #[napi] - pub fn add_lagrange_basis(&self, log2_size: i32) -> Result<()> { + pub fn [](srs: &[], log2_size: i32) -> Result<()> { let size = 1usize << (log2_size as usize); let domain = EvaluationDomain::<$field_ty>::new(size).ok_or_else(invalid_domain_error)?; - self.inner.get_lagrange_basis(domain); + srs.get_lagrange_basis(domain); Ok(()) } #[napi] - pub fn write(&self, append: Option, path: String) -> Result<()> { + pub fn [](append: Option, srs: &[], path: String) -> Result<()> { + let function_name = format!("caml_{0}_srs_write", stringify!($name).to_lowercase()); let file = OpenOptions::new() - .write(true) - .create(true) .append(append.unwrap_or(true)) .open(&path) - .map_err(|err| map_error("srs_write", err))?; - let mut writer = BufWriter::new(file); - self.inner - .serialize(&mut rmp_serde::Serializer::new(&mut writer)) - .map_err(|err| map_error("srs_write", err)) + .map_err(|err| map_error(&function_name, err))?; + let file = BufWriter::new(file); + srs.0.serialize(&mut rmp_serde::Serializer::new(file)) + .map_err(|err| map_error(&function_name, err)) } #[napi] - pub fn read(offset: Option, path: String) -> Result> { + pub fn [](offset: Option, path: String) -> Result> { + let function_name = format!("caml_{0}_srs_read", stringify!($name).to_lowercase()); let file = match File::open(&path) { Ok(file) => file, - Err(err) => return Err(map_error("srs_read", err)), + Err(err) => return Err(map_error(&function_name, err)), }; let mut reader = BufReader::new(file); if let Some(off) = offset { reader .seek(SeekFrom::Start(off as u64)) - .map_err(|err| map_error("srs_read", err))?; + .map_err(|err| map_error(&function_name, err))?; } match SRS::<$group_ty>::deserialize(&mut rmp_serde::Deserializer::new(reader)) { - Ok(srs) => Ok(Some(Self::from_arc(Arc::new(srs)))), + Ok(srs) => Ok(Some(Arc::new(srs).into())), Err(_) => Ok(None), } } #[napi] - pub fn get(&self) -> WasmVector<$group_wrapper> { - let mut points: Vec<$group_wrapper> = vec![self.inner.h.into()]; - points.extend(self.inner.g.iter().cloned().map(Into::into)); - points.into() + pub fn [](srs: &[]) -> Vec<$group_wrapper> { + let mut h_and_gs: Vec<$group_wrapper> = vec![srs.0.h.into()]; + h_and_gs.extend(srs.0.g.iter().cloned().map(Into::into)); + h_and_gs } #[napi] - pub fn set(points: WasmVector<$group_wrapper>) -> Result { - let mut pts: Vec<$group_ty> = points.into_iter().map(Into::into).collect(); - if pts.is_empty() { + pub fn [](h_and_gs: Vec<$group_wrapper>) -> Result { + let mut h_and_gs: Vec<$group_ty> = h_and_gs.into_iter().map(Into::into).collect(); + if h_and_gs.is_empty() { return Err(Error::new( Status::InvalidArg, "expected at least one element for SRS", )); } - let h = pts.remove(0); - let g = pts; - Ok(Self::from_arc(Arc::new(SRS::<$group_ty> { - h, - g, - lagrange_bases: HashMapCache::new(), - }))) + let h = h_and_gs.remove(0); + let g = h_and_gs; + let srs = SRS::<$group_ty> { h, g, lagrange_bases: HashMapCache::new() }; + Ok(Arc::new(srs).into()) } #[napi] - pub fn maybe_lagrange_commitment( - &self, + pub fn []( + srs: &[], domain_size: i32, - index: i32, - ) -> Option<$poly_comm_wrapper> { - if !self - .inner + i: i32, + ) -> Option { + if !srs + .0 .lagrange_bases .contains_key(&(domain_size as usize)) { return None; } - let basis = self - .inner + let basis = srs .get_lagrange_basis_from_domain_size(domain_size as usize); - basis.get(index as usize).cloned().map(Into::into) + Some(basis[i as usize].clone().into()) } #[napi] - pub fn set_lagrange_basis( - &self, + pub fn [](srs: &[], domain_size: i32, - bases: WasmVector<$poly_comm_wrapper>, + input_bases: WasmVector, ) { - let domain = domain_size as usize; - let commitments: Vec<_> = bases.into_iter().map(Into::into).collect(); - self.inner - .lagrange_bases - .get_or_generate(domain, || commitments.clone()); + srs.0.lagrange_bases + .get_or_generate(domain_size as usize, || input_bases); } #[napi] - pub fn get_lagrange_basis( - &self, + pub fn [](srs: &[], domain_size: i32, - ) -> Result> { + ) -> Result> { let domain = EvaluationDomain::<$field_ty>::new(domain_size as usize) .ok_or_else(invalid_domain_error)?; - let basis = self.inner.get_lagrange_basis(domain); + let basis = srs.0.get_lagrange_basis(domain); Ok(basis.iter().cloned().map(Into::into).collect()) } #[napi] - pub fn commit_evaluations( - &self, + pub fn [](srs: &[], domain_size: i32, - evaluations: Uint8Array, - ) -> Result<$poly_comm_wrapper> { + evals: Uint8Array, + ) -> Result { let elems: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( - evaluations.as_ref().to_vec(), + evals.as_ref().to_vec(), ) .into_iter() .map(Into::into) .collect(); - let domain = EvaluationDomain::<$field_ty>::new(domain_size as usize) + let x_domain = EvaluationDomain::<$field_ty>::new(domain_size as usize) .ok_or_else(invalid_domain_error)?; - let evals = Evaluations::from_vec_and_domain(elems, domain); - let poly = evals.interpolate(); - Ok(self.inner.commit(&poly, None).into()) + let evals = elems.into_iter().map(Into::into).collect(); + let p = Evaluations::<$field_ty>::from_vec_and_domain(evals, x_domain).interpolate(); + Ok(srs.commit_non_hiding(&p, 1).into()) } #[napi] - pub fn b_poly_commitment(&self, chals: Uint8Array) -> Result<$poly_comm_wrapper> { + pub fn b_poly_commitment(srs: &[], chals: Uint8Array) -> Result { let elements: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( chals.as_ref().to_vec(), ) @@ -241,17 +289,17 @@ macro_rules! impl_srs { .map(Into::into) .collect(); let coeffs = b_poly_coefficients(&elements); - let poly = DensePolynomial::<$field_ty>::from_coefficients_vec(coeffs); - Ok(self.inner.commit_non_hiding(&poly, 1).into()) + let p = DensePolynomial::<$field_ty>::from_coefficients_vec(coeffs); + Ok(srs.commit_non_hiding(&p, 1).into()) } #[napi] pub fn batch_accumulator_check( - &self, - commitments: WasmVector<$group_wrapper>, + srs: &[], + comms: WasmVector<$group_wrapper>, chals: Uint8Array, ) -> Result { - let comms: Vec<$group_ty> = commitments.into_iter().map(Into::into).collect(); + let comms: Vec<$group_ty> = comms.into_iter().map(Into::into).collect(); let chals: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( chals.as_ref().to_vec(), ) @@ -259,7 +307,7 @@ macro_rules! impl_srs { .map(Into::into) .collect(); Ok(poly_commitment::utils::batch_dlog_accumulator_check( - &self.inner, + &srs, &comms, &chals, )) @@ -267,8 +315,8 @@ macro_rules! impl_srs { #[napi] pub fn batch_accumulator_generate( - &self, - count: i32, + srs: &[], + comms: i32, chals: Uint8Array, ) -> Result> { let chals: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( @@ -278,20 +326,20 @@ macro_rules! impl_srs { .map(Into::into) .collect(); let points = poly_commitment::utils::batch_dlog_accumulator_generate::<$group_ty>( - &self.inner, - count as usize, + &srs, + comms as usize, &chals, ); Ok(points.into_iter().map(Into::into).collect()) } #[napi] - pub fn h(&self) -> $group_wrapper { - self.inner.h.into() + pub fn h(srs: &[]) -> $group_wrapper { + srs.h.into() } } } - }; + } } pub mod fp { diff --git a/plonk-napi/src/tables.rs b/plonk-napi/src/tables.rs index fd00cb94ae..cd9f4f718b 100644 --- a/plonk-napi/src/tables.rs +++ b/plonk-napi/src/tables.rs @@ -1,8 +1,5 @@ use arkworks::{WasmPastaFp, WasmPastaFq}; -use kimchi::circuits::lookup::{ - runtime_tables::RuntimeTableCfg, - tables::LookupTable, -}; +use kimchi::circuits::lookup::{runtime_tables::RuntimeTableCfg, tables::LookupTable}; use mina_curves::pasta::{Fp, Fq}; use napi::bindgen_prelude::Uint8Array; use napi_derive::napi; @@ -66,18 +63,14 @@ pub fn lookup_table_fq_from_js(js: JsLookupTableFq) -> napi::Result napi::Result> { +pub fn runtime_table_cfg_fp_from_js(js: JsRuntimeTableCfgFp) -> napi::Result> { Ok(RuntimeTableCfg { id: js.id, first_column: bytes_to_fp_vec(typed_array_to_vec(&js.first_column)), }) } -pub fn runtime_table_cfg_fq_from_js( - js: JsRuntimeTableCfgFq, -) -> napi::Result> { +pub fn runtime_table_cfg_fq_from_js(js: JsRuntimeTableCfgFq) -> napi::Result> { Ok(RuntimeTableCfg { id: js.id, first_column: bytes_to_fq_vec(typed_array_to_vec(&js.first_column)), diff --git a/plonk-wasm/src/gate_vector.rs b/plonk-wasm/src/gate_vector.rs index 7928845af1..d78f9d82a7 100644 --- a/plonk-wasm/src/gate_vector.rs +++ b/plonk-wasm/src/gate_vector.rs @@ -60,7 +60,12 @@ pub mod shared { Gate { typ: cg.typ, wires: GateWires::new([ - cg.wires[0], cg.wires[1], cg.wires[2], cg.wires[3], cg.wires[4], cg.wires[5], + cg.wires[0], + cg.wires[1], + cg.wires[2], + cg.wires[3], + cg.wires[4], + cg.wires[5], cg.wires[6], ]), coeffs: cg.coeffs, @@ -76,7 +81,12 @@ pub mod shared { Gate { typ: cg.typ, wires: GateWires::new([ - cg.wires[0], cg.wires[1], cg.wires[2], cg.wires[3], cg.wires[4], cg.wires[5], + cg.wires[0], + cg.wires[1], + cg.wires[2], + cg.wires[3], + cg.wires[4], + cg.wires[5], cg.wires[6], ]), coeffs: cg.coeffs.clone(), @@ -181,7 +191,9 @@ pub mod shared { } } -pub use self::shared::{Gate as CoreGate, GateVector as CoreGateVector, GateWires as CoreGateWires}; +pub use self::shared::{ + Gate as CoreGate, GateVector as CoreGateVector, GateWires as CoreGateWires, +}; #[wasm_bindgen] #[derive(Clone, Copy, Debug)] From db8bdd1965fe8a6835eae9f664550beb59e20e5d Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 27 Oct 2025 19:50:13 +0100 Subject: [PATCH 45/75] napi: implement FromNapiValue for polycomm --- plonk-napi/src/poly_comm.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plonk-napi/src/poly_comm.rs b/plonk-napi/src/poly_comm.rs index b988f3e1e7..8976a754e9 100644 --- a/plonk-napi/src/poly_comm.rs +++ b/plonk-napi/src/poly_comm.rs @@ -1,4 +1,5 @@ use crate::wasm_vector::WasmVector; +use napi::bindgen_prelude::{ClassInstance, FromNapiValue}; use napi_derive::napi; use paste::paste; use poly_commitment::commitment::PolyComm; @@ -93,6 +94,16 @@ macro_rules! impl_poly_comm { } } } + + impl FromNapiValue for [] { + unsafe fn from_napi_value( + env: napi::sys::napi_env, + napi_val: napi::sys::napi_value, + ) -> napi::Result { + let instance = ]> as FromNapiValue>::from_napi_value(env, napi_val)?; + Ok((*instance).clone()) + } + } } }; } From 5c19d073e0a4b3dd825f9991c875722aef741ffa Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 27 Oct 2025 19:50:36 +0100 Subject: [PATCH 46/75] napi: finish compilation of srs --- plonk-napi/src/lib.rs | 2 +- plonk-napi/src/srs.rs | 28 ++-------------------------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index bc4a77b825..ab4ab14bf3 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -16,7 +16,7 @@ pub use pasta_fq_plonk_index::{ }; pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; -pub use srs::{caml_fp_srs_from_bytes, caml_fp_srs_to_bytes, caml_fq_srs_from_bytes}; +pub use srs::*; pub use tables::{JsLookupTableFp, JsLookupTableFq, JsRuntimeTableCfgFp, JsRuntimeTableCfgFq}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; pub use wrappers::{ diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index 750f89486e..92947faee7 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -8,8 +8,7 @@ use crate::{ }; use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Evaluations}; use core::ops::Deref; -use mina_curves::pasta::{Pallas as GAffineOther, Vesta as GAffine}; -use napi::bindgen_prelude::{Error, External, Result, Status, Uint8Array}; +use napi::bindgen_prelude::{Error, Result, Status, Uint8Array}; use napi_derive::napi; use paste::paste; use poly_commitment::{ @@ -23,29 +22,6 @@ use std::{ }; use wasm_types::FlatVector as WasmFlatVector; -/* -#[napi] -pub fn caml_fp_srs_to_bytes(srs: External) -> NapiResult { - let buffer = rmp_serde::to_vec(srs.as_ref().0.as_ref()) - .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?; - Ok(Uint8Array::from(buffer)) -} - -#[napi] -pub fn caml_fp_srs_from_bytes(bytes: Uint8Array) -> NapiResult> { - let srs: SRS = rmp_serde::from_slice(bytes.as_ref()) - .map_err(|e| Error::new(Status::InvalidArg, e.to_string()))?; - Ok(External::new(Arc::new(srs).into())) -} - -#[napi] -pub fn caml_fq_srs_from_bytes(bytes: Uint8Array) -> NapiResult> { - let srs: SRS = rmp_serde::from_slice(bytes.as_ref()) - .map_err(|e: rmp_serde::decode::Error| Error::new(Status::InvalidArg, e.to_string()))?; - Ok(External::new(Arc::new(srs).into())) -} -*/ - macro_rules! impl_srs { ( $name:ident, @@ -249,7 +225,7 @@ macro_rules! impl_srs { input_bases: WasmVector, ) { srs.0.lagrange_bases - .get_or_generate(domain_size as usize, || input_bases); + .get_or_generate(domain_size as usize, || { input_bases.into_iter().map(Into::into).collect()}); } #[napi] From 4e998c566e2943546ad0be16792c0aeaa1cfeb8b Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 28 Oct 2025 13:34:33 +0100 Subject: [PATCH 47/75] napi: replicate format in plonk-wasm and export --- plonk-napi/src/lib.rs | 2 +- plonk-napi/src/srs.rs | 184 +++++++++++++++++++----------------------- 2 files changed, 84 insertions(+), 102 deletions(-) diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index ab4ab14bf3..76b14e7ff8 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -16,7 +16,7 @@ pub use pasta_fq_plonk_index::{ }; pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; -pub use srs::*; +pub use srs::{fp::NapiFpSrs as WasmFpSrs, fq::NapiFqSrs as WasmFqSrs}; pub use tables::{JsLookupTableFp, JsLookupTableFq, JsRuntimeTableCfgFp, JsRuntimeTableCfgFq}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; pub use wrappers::{ diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index 92947faee7..a95fbcd049 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -1,11 +1,4 @@ -use crate::{ - poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}, - wasm_vector::WasmVector, - wrappers::{ - field::{WasmPastaFp, WasmPastaFq}, - group::{WasmGPallas, WasmGVesta}, - }, -}; +use crate::wasm_vector::WasmVector; use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Evaluations}; use core::ops::Deref; use napi::bindgen_prelude::{Error, Result, Status, Uint8Array}; @@ -25,73 +18,56 @@ use wasm_types::FlatVector as WasmFlatVector; macro_rules! impl_srs { ( $name:ident, - $field_ty:ty, - $wasmF:ty, - $group_ty:ty, - $group_wrapper:ty, - $poly_comm_wrapper:ty, - $field_name:ident + $WasmF:ty, + $WasmG:ty, + $F:ty, + $G:ty, + $WasmPolyComm:ty, ) => { paste! { - type WasmPolyComm = $poly_comm_wrapper; - #[napi] #[derive(Clone)] - pub struct [] ( - #[napi(skip)] pub Arc> + pub struct [] ( + #[napi(skip)] pub Arc> ); - impl Deref for [] { - type Target = Arc>; + impl Deref for [] { + type Target = Arc>; fn deref(&self) -> &Self::Target { &self.0 } } - impl From>> for [] { - fn from(x: Arc>) -> Self { - [](x) + impl From>> for [] { + fn from(x: Arc>) -> Self { + [](x) } } - impl From<&Arc>> for [] { - fn from(x: &Arc>) -> Self { - [](x.clone()) + impl From<&Arc>> for [] { + fn from(x: &Arc>) -> Self { + [](x.clone()) } } - impl From<[]> for Arc> { - fn from(x: []) -> Self { + impl From<[]> for Arc> { + fn from(x: []) -> Self { x.0 } } - impl From<&[]> for Arc> { - fn from(x: &[]) -> Self { + impl From<&[]> for Arc> { + fn from(x: &[]) -> Self { x.0.clone() } } - impl<'a> From<&'a []> for &'a Arc> { - fn from(x: &'a []) -> Self { + impl<'a> From<&'a []> for &'a Arc> { + fn from(x: &'a []) -> Self { &x.0 } } - /* - impl [] { - fn new(inner: SRS<$group_ty>) -> Self { - Self ( - Arc::new(inner), - ) - } - - fn from_arc(inner: Arc>) -> Self { - Self (inner) - } - } - */ - fn invalid_domain_error() -> Error { Error::new(Status::InvalidArg, "invalid domain size") } @@ -101,7 +77,7 @@ macro_rules! impl_srs { } #[napi] - impl [] { + impl [] { #[napi] pub fn serialize(&self) -> Result { @@ -114,40 +90,40 @@ macro_rules! impl_srs { #[napi] pub fn deserialize(bytes: Uint8Array) -> Result { - let srs: SRS<$group_ty> = rmp_serde::from_slice(bytes.as_ref()) + let srs: SRS<$G> = rmp_serde::from_slice(bytes.as_ref()) .map_err(|e| map_error("srs_deserialize", e))?; Ok(Arc::new(srs).into()) } #[napi(factory)] pub fn [](depth: i32) -> Result { - Ok(Arc::new(SRS::<$group_ty>::create(depth as usize)).into()) + Ok(Arc::new(SRS::<$G>::create(depth as usize)).into()) } #[napi(factory)] pub fn [](depth: i32) -> Result { - Ok(Arc::new(SRS::<$group_ty>::create_parallel( + Ok(Arc::new(SRS::<$G>::create_parallel( depth as usize, )).into()) } #[napi] - pub fn [](srs: &[]) -> Vec<$group_wrapper> { - let mut h_and_gs: Vec<$group_wrapper> = vec![srs.0.h.into()]; + pub fn [](srs: &[]) -> Vec<$WasmG> { + let mut h_and_gs: Vec<$WasmG> = vec![srs.0.h.into()]; h_and_gs.extend(srs.0.g.iter().cloned().map(Into::into)); h_and_gs } #[napi] - pub fn [](srs: &[], log2_size: i32) -> Result<()> { + pub fn [](srs: &[], log2_size: i32) -> Result<()> { let size = 1usize << (log2_size as usize); - let domain = EvaluationDomain::<$field_ty>::new(size).ok_or_else(invalid_domain_error)?; + let domain = EvaluationDomain::<$F>::new(size).ok_or_else(invalid_domain_error)?; srs.get_lagrange_basis(domain); Ok(()) } #[napi] - pub fn [](append: Option, srs: &[], path: String) -> Result<()> { + pub fn [](append: Option, srs: &[], path: String) -> Result<()> { let function_name = format!("caml_{0}_srs_write", stringify!($name).to_lowercase()); let file = OpenOptions::new() .append(append.unwrap_or(true)) @@ -173,22 +149,22 @@ macro_rules! impl_srs { .map_err(|err| map_error(&function_name, err))?; } - match SRS::<$group_ty>::deserialize(&mut rmp_serde::Deserializer::new(reader)) { + match SRS::<$G>::deserialize(&mut rmp_serde::Deserializer::new(reader)) { Ok(srs) => Ok(Some(Arc::new(srs).into())), Err(_) => Ok(None), } } #[napi] - pub fn [](srs: &[]) -> Vec<$group_wrapper> { - let mut h_and_gs: Vec<$group_wrapper> = vec![srs.0.h.into()]; + pub fn [](srs: &[]) -> Vec<$WasmG> { + let mut h_and_gs: Vec<$WasmG> = vec![srs.0.h.into()]; h_and_gs.extend(srs.0.g.iter().cloned().map(Into::into)); h_and_gs } #[napi] - pub fn [](h_and_gs: Vec<$group_wrapper>) -> Result { - let mut h_and_gs: Vec<$group_ty> = h_and_gs.into_iter().map(Into::into).collect(); + pub fn [](h_and_gs: Vec<$WasmG>) -> Result { + let mut h_and_gs: Vec<$G> = h_and_gs.into_iter().map(Into::into).collect(); if h_and_gs.is_empty() { return Err(Error::new( Status::InvalidArg, @@ -197,16 +173,16 @@ macro_rules! impl_srs { } let h = h_and_gs.remove(0); let g = h_and_gs; - let srs = SRS::<$group_ty> { h, g, lagrange_bases: HashMapCache::new() }; + let srs = SRS::<$G> { h, g, lagrange_bases: HashMapCache::new() }; Ok(Arc::new(srs).into()) } #[napi] pub fn []( - srs: &[], + srs: &[], domain_size: i32, i: i32, - ) -> Option { + ) -> Option<$WasmPolyComm> { if !srs .0 .lagrange_bases @@ -220,63 +196,63 @@ macro_rules! impl_srs { } #[napi] - pub fn [](srs: &[], + pub fn [](srs: &[], domain_size: i32, - input_bases: WasmVector, + input_bases: WasmVector<$WasmPolyComm>, ) { srs.0.lagrange_bases .get_or_generate(domain_size as usize, || { input_bases.into_iter().map(Into::into).collect()}); } #[napi] - pub fn [](srs: &[], + pub fn [](srs: &[], domain_size: i32, - ) -> Result> { - let domain = EvaluationDomain::<$field_ty>::new(domain_size as usize) + ) -> Result> { + let domain = EvaluationDomain::<$F>::new(domain_size as usize) .ok_or_else(invalid_domain_error)?; let basis = srs.0.get_lagrange_basis(domain); Ok(basis.iter().cloned().map(Into::into).collect()) } #[napi] - pub fn [](srs: &[], + pub fn [](srs: &[], domain_size: i32, evals: Uint8Array, - ) -> Result { - let elems: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( + ) -> Result<$WasmPolyComm> { + let elems: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( evals.as_ref().to_vec(), ) .into_iter() .map(Into::into) .collect(); - let x_domain = EvaluationDomain::<$field_ty>::new(domain_size as usize) + let x_domain = EvaluationDomain::<$F>::new(domain_size as usize) .ok_or_else(invalid_domain_error)?; let evals = elems.into_iter().map(Into::into).collect(); - let p = Evaluations::<$field_ty>::from_vec_and_domain(evals, x_domain).interpolate(); + let p = Evaluations::<$F>::from_vec_and_domain(evals, x_domain).interpolate(); Ok(srs.commit_non_hiding(&p, 1).into()) } #[napi] - pub fn b_poly_commitment(srs: &[], chals: Uint8Array) -> Result { - let elements: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( + pub fn [](srs: &[], chals: Uint8Array) -> Result<$WasmPolyComm> { + let elements: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() .map(Into::into) .collect(); let coeffs = b_poly_coefficients(&elements); - let p = DensePolynomial::<$field_ty>::from_coefficients_vec(coeffs); + let p = DensePolynomial::<$F>::from_coefficients_vec(coeffs); Ok(srs.commit_non_hiding(&p, 1).into()) } #[napi] - pub fn batch_accumulator_check( - srs: &[], - comms: WasmVector<$group_wrapper>, + pub fn []( + srs: &[], + comms: WasmVector<$WasmG>, chals: Uint8Array, ) -> Result { - let comms: Vec<$group_ty> = comms.into_iter().map(Into::into).collect(); - let chals: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( + let comms: Vec<$G> = comms.into_iter().map(Into::into).collect(); + let chals: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() @@ -290,18 +266,18 @@ macro_rules! impl_srs { } #[napi] - pub fn batch_accumulator_generate( - srs: &[], + pub fn []( + srs: &[], comms: i32, chals: Uint8Array, - ) -> Result> { - let chals: Vec<$field_ty> = WasmFlatVector::<$wasmF>::from_bytes( + ) -> Result> { + let chals: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() .map(Into::into) .collect(); - let points = poly_commitment::utils::batch_dlog_accumulator_generate::<$group_ty>( + let points = poly_commitment::utils::batch_dlog_accumulator_generate::<$G>( &srs, comms as usize, &chals, @@ -310,7 +286,7 @@ macro_rules! impl_srs { } #[napi] - pub fn h(srs: &[]) -> $group_wrapper { + pub fn h(srs: &[]) -> $WasmG { srs.h.into() } } @@ -320,26 +296,32 @@ macro_rules! impl_srs { pub mod fp { use super::*; + use crate::{ + poly_comm::vesta::WasmFpPolyComm, + wrappers::{field::WasmPastaFp, group::WasmGVesta}, + }; impl_srs!( - fp, - mina_curves::pasta::Fp, - WasmPastaFp, - mina_curves::pasta::Vesta, - WasmGVesta, - WasmFpPolyComm, - Fp + fp, // field name + WasmPastaFp, // Napi field wrapper + WasmGVesta, // Napi group wrapper + mina_curves::pasta::Fp, // Actual Kimchi field + mina_curves::pasta::Vesta, // Actual kimchi group + WasmFpPolyComm, // Napi poly commitment type ); } pub mod fq { use super::*; + use crate::{ + poly_comm::pallas::WasmFqPolyComm, + wrappers::{field::WasmPastaFq, group::WasmGPallas}, + }; impl_srs!( - fq, - mina_curves::pasta::Fq, - WasmPastaFq, - mina_curves::pasta::Pallas, - WasmGPallas, - WasmFqPolyComm, - Fq + fq, // Field name + WasmPastaFq, // Napi field wrapper + WasmGPallas, // Napi group wrapper + mina_curves::pasta::Fq, // Actual Kimchi field + mina_curves::pasta::Pallas, // Actual kimchi group + WasmFqPolyComm, // Napi poly commitment type ); } From bcc5eb607b9ad42a56f6aa81afcb8a24d49bb996 Mon Sep 17 00:00:00 2001 From: leon chou Date: Tue, 28 Oct 2025 10:49:19 -0400 Subject: [PATCH 48/75] add build info --- plonk-napi/src/build_info.rs | 25 +++++++++++++++++++++++++ plonk-napi/src/lib.rs | 1 + 2 files changed, 26 insertions(+) create mode 100644 plonk-napi/src/build_info.rs diff --git a/plonk-napi/src/build_info.rs b/plonk-napi/src/build_info.rs new file mode 100644 index 0000000000..802a255dba --- /dev/null +++ b/plonk-napi/src/build_info.rs @@ -0,0 +1,25 @@ +use napi_derive::napi; + +#[cfg(target_os = "windows")] +#[napi] +pub const OS_NAME: &str = "Windows"; + +#[cfg(target_os = "linux")] +#[napi] +pub const OS_NAME: &str = "Linux"; + +#[cfg(target_os = "macos")] +#[napi] +pub const OS_NAME: &str = "macOS"; + +#[cfg(target_arch = "x86_64")] +#[napi] +pub const ARCH_NAME: &str = "x86_64"; + +#[cfg(target_arch = "arm")] +#[napi] +pub const ARCH_NAME: &str = "ARM"; + +#[cfg(target_arch = "aarch64")] +#[napi] +pub const ARCH_NAME: &str = "AArch64"; diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 7bda3894ce..a9760208b0 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -2,6 +2,7 @@ mod circuit; mod poseidon; mod types; mod prover_index; +mod build_info; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; From cdf3022147554855a94fcaf54c7cb2eab52a9b44 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 28 Oct 2025 15:59:51 +0100 Subject: [PATCH 49/75] napi: use napi::bindgen_prelude::Result instead of NapiResult for typegen --- plonk-napi/src/pasta_fp_plonk_index.rs | 32 +++++++++++++++----------- plonk-napi/src/pasta_fq_plonk_index.rs | 28 ++++++++++++++-------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index 9f3565dae6..26ab12c041 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -1,21 +1,25 @@ use ark_poly::EvaluationDomain; -use kimchi::circuits::constraints::ConstraintSystem; -use kimchi::circuits::lookup::runtime_tables::RuntimeTableCfg; -use kimchi::circuits::lookup::tables::LookupTable; -use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; +use kimchi::{ + circuits::{ + constraints::ConstraintSystem, + lookup::{runtime_tables::RuntimeTableCfg, tables::LookupTable}, + }, + linearization::expr_linearization, + prover_index::ProverIndex, +}; use mina_curves::pasta::{Fp, Pallas as GAffineOther, Vesta as GAffine, VestaParameters}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; -use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi::bindgen_prelude::{Error, External, Status, Uint8Array}; use napi_derive::napi; use plonk_wasm::gate_vector::shared::GateVector; -use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; -use poly_commitment::SRS; +use poly_commitment::{ + ipa::{OpeningProof, SRS as IPA_SRS}, + SRS, +}; use serde::{Deserialize, Serialize}; -use std::fs::{File, OpenOptions}; -use std::io::{BufReader, BufWriter}; use std::{ - io::Cursor, - io::{Seek, SeekFrom::Start}, + fs::{File, OpenOptions}, + io::{BufReader, BufWriter, Cursor, Seek, SeekFrom::Start}, sync::Arc, }; @@ -78,14 +82,16 @@ impl WasmPastaFpPlonkIndex { #[napi] pub fn prover_index_fp_from_bytes( bytes: Uint8Array, -) -> NapiResult> { +) -> napi::bindgen_prelude::Result> { let index = WasmPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) .map_err(|e| Error::new(Status::InvalidArg, e))?; Ok(External::new(index)) } #[napi] -pub fn prover_index_fp_to_bytes(index: External) -> NapiResult { +pub fn prover_index_fp_to_bytes( + index: External, +) -> napi::bindgen_prelude::Result { let bytes = index .serialize_inner() .map_err(|e| Error::new(Status::GenericFailure, e))?; diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index 36cfc9df9b..4203bd4505 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -1,17 +1,23 @@ use ark_poly::EvaluationDomain; -use kimchi::circuits::constraints::ConstraintSystem; -use kimchi::{linearization::expr_linearization, prover_index::ProverIndex}; +use kimchi::{ + circuits::constraints::ConstraintSystem, linearization::expr_linearization, + prover_index::ProverIndex, +}; use mina_curves::pasta::{Fq, Pallas as GAffine, PallasParameters, Vesta as GAffineOther}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; -use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi::bindgen_prelude::{Error, External, Status, Uint8Array}; use napi_derive::napi; use plonk_wasm::gate_vector::shared::GateVector; -use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; -use poly_commitment::SRS; +use poly_commitment::{ + ipa::{OpeningProof, SRS as IPA_SRS}, + SRS, +}; use serde::{Deserialize, Serialize}; -use std::fs::{File, OpenOptions}; -use std::io::{BufReader, BufWriter, Seek, SeekFrom::Start}; -use std::{io::Cursor, sync::Arc}; +use std::{ + fs::{File, OpenOptions}, + io::{BufReader, BufWriter, Cursor, Seek, SeekFrom::Start}, + sync::Arc, +}; use crate::tables::{ lookup_table_fq_from_js, runtime_table_cfg_fq_from_js, JsLookupTableFq, JsRuntimeTableCfgFq, @@ -72,14 +78,16 @@ impl WasmPastaFqPlonkIndex { #[napi] pub fn prover_index_fq_from_bytes( bytes: Uint8Array, -) -> NapiResult> { +) -> napi::bindgen_prelude::Result> { let index = WasmPastaFqPlonkIndex::deserialize_inner(bytes.as_ref()) .map_err(|e| Error::new(Status::InvalidArg, e))?; Ok(External::new(index)) } #[napi] -pub fn prover_index_fq_to_bytes(index: External) -> NapiResult { +pub fn prover_index_fq_to_bytes( + index: External, +) -> napi::bindgen_prelude::Result { let bytes = index .serialize_inner() .map_err(|e| Error::new(Status::GenericFailure, e))?; From a04edaeee5780c8af77a2cd8fff59610e92e2735 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 28 Oct 2025 19:05:08 +0100 Subject: [PATCH 50/75] napi: fix naming of srs functions inside macro --- plonk-napi/src/srs.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index a95fbcd049..c15b0de664 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -108,14 +108,7 @@ macro_rules! impl_srs { } #[napi] - pub fn [](srs: &[]) -> Vec<$WasmG> { - let mut h_and_gs: Vec<$WasmG> = vec![srs.0.h.into()]; - h_and_gs.extend(srs.0.g.iter().cloned().map(Into::into)); - h_and_gs - } - - #[napi] - pub fn [](srs: &[], log2_size: i32) -> Result<()> { + pub fn [](srs: &[], log2_size: i32) -> Result<()> { let size = 1usize << (log2_size as usize); let domain = EvaluationDomain::<$F>::new(size).ok_or_else(invalid_domain_error)?; srs.get_lagrange_basis(domain); From d205c85eaf46685260ea228bf8008e07deb22123 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 28 Oct 2025 20:01:33 +0100 Subject: [PATCH 51/75] napi: reintroduce gate vector --- plonk-napi/src/gate_vector.rs | 223 ++++++++++++++++++++++++++++++++++ plonk-napi/src/lib.rs | 13 ++ 2 files changed, 236 insertions(+) create mode 100644 plonk-napi/src/gate_vector.rs diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs new file mode 100644 index 0000000000..2a4712ee26 --- /dev/null +++ b/plonk-napi/src/gate_vector.rs @@ -0,0 +1,223 @@ +use kimchi::circuits::{ + gate::{Circuit, CircuitGate, GateType}, + wires::{GateWires, Wire as KimchiWire}, +}; +use mina_curves::pasta::{Fp, Fq}; +use napi::bindgen_prelude::*; +use napi_derive::napi; +use o1_utils::hasher::CryptoDigest; +use paste::paste; +use wasm_types::{FlatVector as WasmFlatVector, FlatVectorElem}; + +use crate::wrappers::{ + field::{WasmPastaFp, WasmPastaFq}, + wires::NapiWire, +}; + +#[napi(object)] +#[derive(Clone, Debug, Default)] +pub struct NapiGateWires { + pub w0: NapiWire, + pub w1: NapiWire, + pub w2: NapiWire, + pub w3: NapiWire, + pub w4: NapiWire, + pub w5: NapiWire, + pub w6: NapiWire, +} + +impl NapiGateWires { + fn into_inner(self) -> GateWires { + [ + KimchiWire::from(self.w0), + KimchiWire::from(self.w1), + KimchiWire::from(self.w2), + KimchiWire::from(self.w3), + KimchiWire::from(self.w4), + KimchiWire::from(self.w5), + KimchiWire::from(self.w6), + ] + } +} + +impl From<&GateWires> for NapiGateWires { + fn from(value: &GateWires) -> Self { + Self { + w0: value[0].into(), + w1: value[1].into(), + w2: value[2].into(), + w3: value[3].into(), + w4: value[4].into(), + w5: value[5].into(), + w6: value[6].into(), + } + } +} + +fn gate_type_from_i32(value: i32) -> Result { + // Ocaml/JS int are signed, so we use i32 here + if value < 0 { + return Err(Error::new( + Status::InvalidArg, + format!("invalid GateType discriminant: {}", value), + )); + } + + let variants: &[GateType] = &[ + GateType::Zero, + GateType::Generic, + GateType::Poseidon, + GateType::CompleteAdd, + GateType::VarBaseMul, + GateType::EndoMul, + GateType::EndoMulScalar, + GateType::Lookup, + GateType::CairoClaim, + GateType::CairoInstruction, + GateType::CairoFlags, + GateType::CairoTransition, + GateType::RangeCheck0, + GateType::RangeCheck1, + GateType::ForeignFieldAdd, + GateType::ForeignFieldMul, + GateType::Xor16, + GateType::Rot64, + ]; + + let index = value as usize; + variants.get(index).copied().ok_or_else(|| { + Error::new( + Status::InvalidArg, + format!("invalid GateType discriminant: {}", value), + ) + }) +} + +// For convenience to not expose the GateType enum to JS +fn gate_type_to_i32(value: GateType) -> i32 { + value as i32 +} + +macro_rules! impl_gate_support { + ($field_name:ident, $F:ty, $WasmF:ty) => { + paste! { + #[napi(object)] + #[derive(Clone, Debug, Default)] + pub struct [] { + pub typ: i32, // for convenience, we use i32 instead of GateType + pub wires: NapiGateWires, + pub coeffs: Vec, // for now, serializing fields as flat bytes, but subject to changes + } + + impl [] { + fn into_inner(self) -> Result> { + let coeffs = WasmFlatVector::<$WasmF>::from_bytes(self.coeffs) + .into_iter() + .map(Into::into) + .collect(); + + Ok(CircuitGate { + typ: gate_type_from_i32(self.typ)?, + wires: self.wires.into_inner(), + coeffs, + }) + } + + fn from_inner(value: &CircuitGate<$F>) -> Self { + let coeffs = value + .coeffs + .iter() + .cloned() + .map($WasmF::from) + .flat_map(|elem| elem.flatten()) + .collect(); + + Self { + typ: gate_type_to_i32(value.typ), + wires: (&value.wires).into(), + coeffs, + } + } + } + + #[napi] + #[derive(Clone, Default, Debug)] + pub struct []( + #[napi(skip)] pub Vec>, + ); + + #[napi] + pub fn []() -> [] { + println!("from native rust creating gate vector"); + [](Vec::new()) + } + + #[napi] + pub fn []( + vector: &mut [], + gate: [], + ) -> Result<()> { + println!("from native rust adding gate to vector"); + vector.0.push(gate.into_inner()?); + Ok(()) + } + + #[napi] + pub fn []( + vector: &[], + index: i32, + ) -> [] { + println!("from native rust getting gate from vector"); + []::from_inner(&vector.0[index as usize]) + } + + #[napi] + pub fn []( + vector: &[], + ) -> i32 { + println!("from native rust getting gate vector length"); + vector.0.len() as i32 + } + + #[napi] + pub fn []( + vector: &mut [], + target: NapiWire, + head: NapiWire, + ) { + println!("from native rust wrapping wire in gate vector"); + vector.0[target.row as usize].wires[target.col as usize] = KimchiWire::from(head); + } + + #[napi] + pub fn []( + public_input_size: i32, + vector: &[], + ) -> Uint8Array { + println!("from native rust computing gate vector digest"); + let bytes = Circuit::new(public_input_size as usize, &vector.0) + .digest() + .to_vec(); + Uint8Array::from(bytes) + } + + #[napi] + pub fn []( + public_input_size: i32, + vector: &[], + ) -> Result { + println!("from native rust serializing gate vector to json"); + let circuit = Circuit::new(public_input_size as usize, &vector.0); + serde_json::to_string(&circuit).map_err(|err| { + Error::new( + Status::GenericFailure, + format!("couldn't serialize constraints: {}", err), + ) + }) + } + } + }; +} + +impl_gate_support!(fp, Fp, WasmPastaFp); +impl_gate_support!(fq, Fq, WasmPastaFq); diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 76b14e7ff8..0e17eb8215 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,4 +1,5 @@ mod circuit; +mod gate_vector; mod pasta_fp_plonk_index; mod pasta_fq_plonk_index; mod poly_comm; @@ -8,6 +9,18 @@ mod tables; mod wasm_vector; mod wrappers; +pub use circuit::prover_to_json; +pub use gate_vector::{ + caml_pasta_fp_plonk_circuit_serialize, caml_pasta_fp_plonk_gate_vector_add, + caml_pasta_fp_plonk_gate_vector_create, caml_pasta_fp_plonk_gate_vector_digest, + caml_pasta_fp_plonk_gate_vector_get, caml_pasta_fp_plonk_gate_vector_len, + caml_pasta_fp_plonk_gate_vector_wrap, caml_pasta_fq_plonk_circuit_serialize, + caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, + caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, + caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, + NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, NapiFqGate as WasmFqGate, + NapiFqGateVector as WasmFqGateVector, +}; pub use pasta_fp_plonk_index::{ prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, }; From 1b937725ef1901245c64a8391c8364882eca11ab Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 29 Oct 2025 18:32:57 +0100 Subject: [PATCH 52/75] napi: remove prints for gate vector --- plonk-napi/src/gate_vector.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index 2a4712ee26..9c77299502 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -148,7 +148,6 @@ macro_rules! impl_gate_support { #[napi] pub fn []() -> [] { - println!("from native rust creating gate vector"); [](Vec::new()) } @@ -157,7 +156,6 @@ macro_rules! impl_gate_support { vector: &mut [], gate: [], ) -> Result<()> { - println!("from native rust adding gate to vector"); vector.0.push(gate.into_inner()?); Ok(()) } @@ -167,7 +165,6 @@ macro_rules! impl_gate_support { vector: &[], index: i32, ) -> [] { - println!("from native rust getting gate from vector"); []::from_inner(&vector.0[index as usize]) } @@ -175,7 +172,6 @@ macro_rules! impl_gate_support { pub fn []( vector: &[], ) -> i32 { - println!("from native rust getting gate vector length"); vector.0.len() as i32 } @@ -185,7 +181,6 @@ macro_rules! impl_gate_support { target: NapiWire, head: NapiWire, ) { - println!("from native rust wrapping wire in gate vector"); vector.0[target.row as usize].wires[target.col as usize] = KimchiWire::from(head); } @@ -194,7 +189,6 @@ macro_rules! impl_gate_support { public_input_size: i32, vector: &[], ) -> Uint8Array { - println!("from native rust computing gate vector digest"); let bytes = Circuit::new(public_input_size as usize, &vector.0) .digest() .to_vec(); @@ -206,7 +200,6 @@ macro_rules! impl_gate_support { public_input_size: i32, vector: &[], ) -> Result { - println!("from native rust serializing gate vector to json"); let circuit = Circuit::new(public_input_size as usize, &vector.0); serde_json::to_string(&circuit).map_err(|err| { Error::new( From 570a29aada1d09087bda961d3bc4f9e25deaaeec Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 29 Oct 2025 18:33:03 +0100 Subject: [PATCH 53/75] napi: add prints for srs --- plonk-napi/src/srs.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index c15b0de664..0242a10def 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -97,11 +97,13 @@ macro_rules! impl_srs { #[napi(factory)] pub fn [](depth: i32) -> Result { + println!("Creating SRS with napi"); Ok(Arc::new(SRS::<$G>::create(depth as usize)).into()) } #[napi(factory)] pub fn [](depth: i32) -> Result { + println!("Creating SRS in parallel with napi"); Ok(Arc::new(SRS::<$G>::create_parallel( depth as usize, )).into()) @@ -109,6 +111,7 @@ macro_rules! impl_srs { #[napi] pub fn [](srs: &[], log2_size: i32) -> Result<()> { + println!("Adding lagrange basis with napi"); let size = 1usize << (log2_size as usize); let domain = EvaluationDomain::<$F>::new(size).ok_or_else(invalid_domain_error)?; srs.get_lagrange_basis(domain); @@ -117,6 +120,7 @@ macro_rules! impl_srs { #[napi] pub fn [](append: Option, srs: &[], path: String) -> Result<()> { + println!("Writing SRS to file with napi"); let function_name = format!("caml_{0}_srs_write", stringify!($name).to_lowercase()); let file = OpenOptions::new() .append(append.unwrap_or(true)) @@ -129,6 +133,7 @@ macro_rules! impl_srs { #[napi] pub fn [](offset: Option, path: String) -> Result> { + println!("Reading SRS from file with napi"); let function_name = format!("caml_{0}_srs_read", stringify!($name).to_lowercase()); let file = match File::open(&path) { Ok(file) => file, @@ -150,6 +155,7 @@ macro_rules! impl_srs { #[napi] pub fn [](srs: &[]) -> Vec<$WasmG> { + println!("Getting SRS with napi"); let mut h_and_gs: Vec<$WasmG> = vec![srs.0.h.into()]; h_and_gs.extend(srs.0.g.iter().cloned().map(Into::into)); h_and_gs @@ -157,6 +163,7 @@ macro_rules! impl_srs { #[napi] pub fn [](h_and_gs: Vec<$WasmG>) -> Result { + println!("Setting SRS with napi"); let mut h_and_gs: Vec<$G> = h_and_gs.into_iter().map(Into::into).collect(); if h_and_gs.is_empty() { return Err(Error::new( @@ -176,6 +183,7 @@ macro_rules! impl_srs { domain_size: i32, i: i32, ) -> Option<$WasmPolyComm> { + println!("Getting maybe lagrange commitment with napi"); if !srs .0 .lagrange_bases @@ -193,6 +201,7 @@ macro_rules! impl_srs { domain_size: i32, input_bases: WasmVector<$WasmPolyComm>, ) { + println!("Setting lagrange basis with napi"); srs.0.lagrange_bases .get_or_generate(domain_size as usize, || { input_bases.into_iter().map(Into::into).collect()}); } @@ -201,6 +210,7 @@ macro_rules! impl_srs { pub fn [](srs: &[], domain_size: i32, ) -> Result> { + println!("Getting lagrange basis with napi"); let domain = EvaluationDomain::<$F>::new(domain_size as usize) .ok_or_else(invalid_domain_error)?; let basis = srs.0.get_lagrange_basis(domain); @@ -212,6 +222,7 @@ macro_rules! impl_srs { domain_size: i32, evals: Uint8Array, ) -> Result<$WasmPolyComm> { + println!("Committing evaluations with napi"); let elems: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( evals.as_ref().to_vec(), ) @@ -227,6 +238,7 @@ macro_rules! impl_srs { #[napi] pub fn [](srs: &[], chals: Uint8Array) -> Result<$WasmPolyComm> { + println!("Computing b poly commitment with napi"); let elements: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( chals.as_ref().to_vec(), ) @@ -244,6 +256,7 @@ macro_rules! impl_srs { comms: WasmVector<$WasmG>, chals: Uint8Array, ) -> Result { + println!("Performing batch accumulator check with napi"); let comms: Vec<$G> = comms.into_iter().map(Into::into).collect(); let chals: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( chals.as_ref().to_vec(), @@ -264,6 +277,7 @@ macro_rules! impl_srs { comms: i32, chals: Uint8Array, ) -> Result> { + println!("Generating batch accumulator with napi"); let chals: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( chals.as_ref().to_vec(), ) @@ -280,6 +294,7 @@ macro_rules! impl_srs { #[napi] pub fn h(srs: &[]) -> $WasmG { + println!("Getting h point with napi"); srs.h.into() } } From c3c580720aa98a8fbddc5e799e4da8525fcea905 Mon Sep 17 00:00:00 2001 From: Florian Date: Thu, 30 Oct 2025 16:57:51 +0700 Subject: [PATCH 54/75] types tbd --- plonk-napi/src/lib.rs | 1 + plonk-napi/src/plonk_verifier_index/fp.rs | 82 ++++++++++++++++++++++ plonk-napi/src/plonk_verifier_index/fq.rs | 82 ++++++++++++++++++++++ plonk-napi/src/plonk_verifier_index/mod.rs | 35 +++++++++ 4 files changed, 200 insertions(+) create mode 100644 plonk-napi/src/plonk_verifier_index/fp.rs create mode 100644 plonk-napi/src/plonk_verifier_index/fq.rs create mode 100644 plonk-napi/src/plonk_verifier_index/mod.rs diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index f0c304a7b9..f99b86c228 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,4 +1,5 @@ mod circuit; +mod plonk_verifier_index; mod poseidon; mod types; diff --git a/plonk-napi/src/plonk_verifier_index/fp.rs b/plonk-napi/src/plonk_verifier_index/fp.rs new file mode 100644 index 0000000000..e265c21013 --- /dev/null +++ b/plonk-napi/src/plonk_verifier_index/fp.rs @@ -0,0 +1,82 @@ +use serde::{Deserialize, Serialize}; + +use super::WasmLookupInfo; + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFpDomain { + pub log_size_of_group: i32, + pub group_gen: Vec, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFpPolyComm { + pub unshifted: Vec>, + pub shifted: Option>, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFpShifts { + pub s0: Vec, + pub s1: Vec, + pub s2: Vec, + pub s3: Vec, + pub s4: Vec, + pub s5: Vec, + pub s6: Vec, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFpLookupSelectors { + pub xor: Option, + pub lookup: Option, + pub range_check: Option, + pub ffmul: Option, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFpLookupVerifierIndex { + pub joint_lookup_used: bool, + pub lookup_table: Vec, + pub lookup_selectors: WasmFpLookupSelectors, + pub table_ids: Option, + pub lookup_info: WasmLookupInfo, + pub runtime_tables_selector: Option, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFpPlonkVerificationEvals { + pub sigma_comm: Vec, + pub coefficients_comm: Vec, + pub generic_comm: WasmFpPolyComm, + pub psm_comm: WasmFpPolyComm, + pub complete_add_comm: WasmFpPolyComm, + pub mul_comm: WasmFpPolyComm, + pub emul_comm: WasmFpPolyComm, + pub endomul_scalar_comm: WasmFpPolyComm, + pub xor_comm: Option, + pub range_check0_comm: Option, + pub range_check1_comm: Option, + pub foreign_field_add_comm: Option, + pub foreign_field_mul_comm: Option, + pub rot_comm: Option, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFpPlonkVerifierIndex { + pub domain: WasmFpDomain, + pub max_poly_size: i32, + pub public_: i32, + pub prev_challenges: i32, + pub srs: Vec, + pub evals: WasmFpPlonkVerificationEvals, + pub shifts: WasmFpShifts, + pub lookup_index: Option, + pub zk_rows: i32, +} diff --git a/plonk-napi/src/plonk_verifier_index/fq.rs b/plonk-napi/src/plonk_verifier_index/fq.rs new file mode 100644 index 0000000000..b8f4f6a362 --- /dev/null +++ b/plonk-napi/src/plonk_verifier_index/fq.rs @@ -0,0 +1,82 @@ +use serde::{Deserialize, Serialize}; + +use super::WasmLookupInfo; + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFqDomain { + pub log_size_of_group: i32, + pub group_gen: Vec, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFqPolyComm { + pub unshifted: Vec>, + pub shifted: Option>, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFqShifts { + pub s0: Vec, + pub s1: Vec, + pub s2: Vec, + pub s3: Vec, + pub s4: Vec, + pub s5: Vec, + pub s6: Vec, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFqLookupSelectors { + pub xor: Option, + pub lookup: Option, + pub range_check: Option, + pub ffmul: Option, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFqLookupVerifierIndex { + pub joint_lookup_used: bool, + pub lookup_table: Vec, + pub lookup_selectors: WasmFqLookupSelectors, + pub table_ids: Option, + pub lookup_info: WasmLookupInfo, + pub runtime_tables_selector: Option, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFqPlonkVerificationEvals { + pub sigma_comm: Vec, + pub coefficients_comm: Vec, + pub generic_comm: WasmFqPolyComm, + pub psm_comm: WasmFqPolyComm, + pub complete_add_comm: WasmFqPolyComm, + pub mul_comm: WasmFqPolyComm, + pub emul_comm: WasmFqPolyComm, + pub endomul_scalar_comm: WasmFqPolyComm, + pub xor_comm: Option, + pub range_check0_comm: Option, + pub range_check1_comm: Option, + pub foreign_field_add_comm: Option, + pub foreign_field_mul_comm: Option, + pub rot_comm: Option, +} + +#[napi_derive::napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmFqPlonkVerifierIndex { + pub domain: WasmFqDomain, + pub max_poly_size: i32, + pub public_: i32, + pub prev_challenges: i32, + pub srs: Vec, + pub evals: WasmFqPlonkVerificationEvals, + pub shifts: WasmFqShifts, + pub lookup_index: Option, + pub zk_rows: i32, +} diff --git a/plonk-napi/src/plonk_verifier_index/mod.rs b/plonk-napi/src/plonk_verifier_index/mod.rs new file mode 100644 index 0000000000..2ed532c7d4 --- /dev/null +++ b/plonk-napi/src/plonk_verifier_index/mod.rs @@ -0,0 +1,35 @@ +use napi_derive::napi; +use serde::{Deserialize, Serialize}; + +#[napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmLookupPatterns { + pub xor: bool, + pub lookup: bool, + pub range_check: bool, + pub foreign_field_mul: bool, +} + +#[napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmLookupFeatures { + pub patterns: WasmLookupPatterns, + pub joint_lookup_used: bool, + pub uses_runtime_tables: bool, +} + +#[napi(object)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct WasmLookupInfo { + pub max_per_row: i32, + pub max_joint_size: i32, + pub features: WasmLookupFeatures, +} + +pub mod fp; +pub mod fq; + +#[allow(unused_imports)] +pub use fp::*; +#[allow(unused_imports)] +pub use fq::*; From 0c044463256cd3aa429a4bee1bec638790e3336d Mon Sep 17 00:00:00 2001 From: Florian Date: Thu, 30 Oct 2025 18:53:59 +0700 Subject: [PATCH 55/75] base types and caml_pasta_fp_plonk_verifier_index_shifts --- plonk-napi/src/lib.rs | 2 +- plonk-napi/src/plonk_verifier_index/fp.rs | 66 ++++++++++++++++++++--- plonk-napi/src/plonk_verifier_index/fq.rs | 66 ++++++++++++++++++++--- 3 files changed, 119 insertions(+), 15 deletions(-) diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index f99b86c228..00400e52b0 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,5 +1,5 @@ mod circuit; -mod plonk_verifier_index; +pub mod plonk_verifier_index; mod poseidon; mod types; diff --git a/plonk-napi/src/plonk_verifier_index/fp.rs b/plonk-napi/src/plonk_verifier_index/fp.rs index e265c21013..bd19ec029a 100644 --- a/plonk-napi/src/plonk_verifier_index/fp.rs +++ b/plonk-napi/src/plonk_verifier_index/fp.rs @@ -1,22 +1,28 @@ +use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as Domain}; +use ark_serialize::CanonicalSerialize; +use kimchi::circuits::polynomials::permutation::Shifts as KimchiShifts; +use mina_curves::pasta::Fp; +use napi::bindgen_prelude::{Error, Result as NapiResult, Status}; +use napi_derive::napi; use serde::{Deserialize, Serialize}; use super::WasmLookupInfo; -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFpDomain { pub log_size_of_group: i32, pub group_gen: Vec, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFpPolyComm { pub unshifted: Vec>, pub shifted: Option>, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFpShifts { pub s0: Vec, @@ -28,7 +34,7 @@ pub struct WasmFpShifts { pub s6: Vec, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFpLookupSelectors { pub xor: Option, @@ -37,7 +43,7 @@ pub struct WasmFpLookupSelectors { pub ffmul: Option, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFpLookupVerifierIndex { pub joint_lookup_used: bool, @@ -48,7 +54,7 @@ pub struct WasmFpLookupVerifierIndex { pub runtime_tables_selector: Option, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFpPlonkVerificationEvals { pub sigma_comm: Vec, @@ -67,7 +73,7 @@ pub struct WasmFpPlonkVerificationEvals { pub rot_comm: Option, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFpPlonkVerifierIndex { pub domain: WasmFpDomain, @@ -80,3 +86,49 @@ pub struct WasmFpPlonkVerifierIndex { pub lookup_index: Option, pub zk_rows: i32, } + +#[napi] +pub fn caml_pasta_fp_plonk_verifier_index_shifts(log2_size: i32) -> NapiResult { + println!( + "from napi! caml_pasta_fp_plonk_verifier_index_shifts with log2_size {}", + log2_size + ); + if log2_size < 0 { + return Err(Error::new( + Status::InvalidArg, + "log2_size must be non-negative", + )); + } + + if log2_size as u32 >= usize::BITS { + return Err(Error::new( + Status::InvalidArg, + "log2_size is too large for usize", + )); + } + + let size = 1usize << (log2_size as u32); + let domain = Domain::::new(size) + .ok_or_else(|| Error::new(Status::InvalidArg, "failed to create evaluation domain"))?; + + let shifts = KimchiShifts::new(&domain); + let s = shifts.shifts(); + + Ok(WasmFpShifts { + s0: serialize_fp(&s[0])?, + s1: serialize_fp(&s[1])?, + s2: serialize_fp(&s[2])?, + s3: serialize_fp(&s[3])?, + s4: serialize_fp(&s[4])?, + s5: serialize_fp(&s[5])?, + s6: serialize_fp(&s[6])?, + }) +} + +fn serialize_fp(value: &Fp) -> NapiResult> { + let mut bytes = Vec::new(); + value + .serialize_compressed(&mut bytes) + .map_err(|err| Error::new(Status::GenericFailure, format!("serialize_fp: {err}")))?; + Ok(bytes) +} diff --git a/plonk-napi/src/plonk_verifier_index/fq.rs b/plonk-napi/src/plonk_verifier_index/fq.rs index b8f4f6a362..eec530c424 100644 --- a/plonk-napi/src/plonk_verifier_index/fq.rs +++ b/plonk-napi/src/plonk_verifier_index/fq.rs @@ -1,22 +1,28 @@ +use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as Domain}; +use ark_serialize::CanonicalSerialize; +use kimchi::circuits::polynomials::permutation::Shifts as KimchiShifts; +use mina_curves::pasta::Fq; +use napi::bindgen_prelude::{Error, Result as NapiResult, Status}; +use napi_derive::napi; use serde::{Deserialize, Serialize}; use super::WasmLookupInfo; -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFqDomain { pub log_size_of_group: i32, pub group_gen: Vec, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFqPolyComm { pub unshifted: Vec>, pub shifted: Option>, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFqShifts { pub s0: Vec, @@ -28,7 +34,7 @@ pub struct WasmFqShifts { pub s6: Vec, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFqLookupSelectors { pub xor: Option, @@ -37,7 +43,7 @@ pub struct WasmFqLookupSelectors { pub ffmul: Option, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFqLookupVerifierIndex { pub joint_lookup_used: bool, @@ -48,7 +54,7 @@ pub struct WasmFqLookupVerifierIndex { pub runtime_tables_selector: Option, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFqPlonkVerificationEvals { pub sigma_comm: Vec, @@ -67,7 +73,7 @@ pub struct WasmFqPlonkVerificationEvals { pub rot_comm: Option, } -#[napi_derive::napi(object)] +#[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFqPlonkVerifierIndex { pub domain: WasmFqDomain, @@ -80,3 +86,49 @@ pub struct WasmFqPlonkVerifierIndex { pub lookup_index: Option, pub zk_rows: i32, } + +#[napi] +pub fn caml_pasta_fq_plonk_verifier_index_shifts(log2_size: i32) -> NapiResult { + println!( + "from napi! caml_pasta_fp_plonk_verifier_index_shifts with log2_size {}", + log2_size + ); + if log2_size < 0 { + return Err(Error::new( + Status::InvalidArg, + "log2_size must be non-negative", + )); + } + + if log2_size as u32 >= usize::BITS { + return Err(Error::new( + Status::InvalidArg, + "log2_size is too large for usize", + )); + } + + let size = 1usize << (log2_size as u32); + let domain = Domain::::new(size) + .ok_or_else(|| Error::new(Status::InvalidArg, "failed to create evaluation domain"))?; + + let shifts = KimchiShifts::new(&domain); + let s = shifts.shifts(); + + Ok(WasmFqShifts { + s0: serialize_fp(&s[0])?, + s1: serialize_fp(&s[1])?, + s2: serialize_fp(&s[2])?, + s3: serialize_fp(&s[3])?, + s4: serialize_fp(&s[4])?, + s5: serialize_fp(&s[5])?, + s6: serialize_fp(&s[6])?, + }) +} + +fn serialize_fp(value: &Fq) -> NapiResult> { + let mut bytes = Vec::new(); + value + .serialize_uncompressed(&mut bytes) + .map_err(|err| Error::new(Status::GenericFailure, format!("serialize_fp: {err}")))?; + Ok(bytes) +} From 953bc32b9865fc707abebd4f47f07d520eb72008 Mon Sep 17 00:00:00 2001 From: Florian Date: Thu, 30 Oct 2025 19:16:30 +0700 Subject: [PATCH 56/75] simplify --- plonk-napi/src/plonk_verifier_index/fp.rs | 13 ------------- plonk-napi/src/plonk_verifier_index/fq.rs | 13 ------------- 2 files changed, 26 deletions(-) diff --git a/plonk-napi/src/plonk_verifier_index/fp.rs b/plonk-napi/src/plonk_verifier_index/fp.rs index bd19ec029a..147a656c43 100644 --- a/plonk-napi/src/plonk_verifier_index/fp.rs +++ b/plonk-napi/src/plonk_verifier_index/fp.rs @@ -93,19 +93,6 @@ pub fn caml_pasta_fp_plonk_verifier_index_shifts(log2_size: i32) -> NapiResult= usize::BITS { - return Err(Error::new( - Status::InvalidArg, - "log2_size is too large for usize", - )); - } let size = 1usize << (log2_size as u32); let domain = Domain::::new(size) diff --git a/plonk-napi/src/plonk_verifier_index/fq.rs b/plonk-napi/src/plonk_verifier_index/fq.rs index eec530c424..efcfc72508 100644 --- a/plonk-napi/src/plonk_verifier_index/fq.rs +++ b/plonk-napi/src/plonk_verifier_index/fq.rs @@ -93,19 +93,6 @@ pub fn caml_pasta_fq_plonk_verifier_index_shifts(log2_size: i32) -> NapiResult= usize::BITS { - return Err(Error::new( - Status::InvalidArg, - "log2_size is too large for usize", - )); - } let size = 1usize << (log2_size as u32); let domain = Domain::::new(size) From ab2d728c46287f905bd6b08e2952297f735bccf7 Mon Sep 17 00:00:00 2001 From: leon chou Date: Thu, 30 Oct 2025 13:11:52 -0400 Subject: [PATCH 57/75] pub(crate) --- plonk-napi/src/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plonk-napi/src/types.rs b/plonk-napi/src/types.rs index 50091937f2..d80cf1495b 100644 --- a/plonk-napi/src/types.rs +++ b/plonk-napi/src/types.rs @@ -17,7 +17,7 @@ struct SerializedProverIndex { // TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around impl WasmPastaFpPlonkIndex { - pub fn serialize_inner(&self) -> Result, String> { + pub(crate) fn serialize_inner(&self) -> Result, String> { let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; let mut srs = Vec::new(); @@ -31,7 +31,7 @@ impl WasmPastaFpPlonkIndex { rmp_serde::to_vec(&serialized).map_err(|e| e.to_string()) } - pub fn deserialize_inner(bytes: &[u8]) -> Result { + pub(crate) fn deserialize_inner(bytes: &[u8]) -> Result { let serialized: SerializedProverIndex = rmp_serde::from_slice(bytes).map_err(|e| e.to_string())?; From a68221c28f89d14c54c750ad1f74f35e430761ce Mon Sep 17 00:00:00 2001 From: leon chou Date: Thu, 30 Oct 2025 17:19:30 -0400 Subject: [PATCH 58/75] plonk_proof_poc and renaming some fns --- plonk-napi/src/lib.rs | 7 +++++-- plonk-napi/src/pasta_plonk_proof.rs | 14 ++++++++++++++ plonk-napi/src/poseidon.rs | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 plonk-napi/src/pasta_plonk_proof.rs diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index a9760208b0..b286e21b65 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,11 +1,14 @@ +mod build_info; mod circuit; +mod pasta_plonk_proof; mod poseidon; -mod types; mod prover_index; -mod build_info; +mod types; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; pub use circuit::prover_to_json; pub use prover_index::{prover_index_from_bytes, prover_index_to_bytes}; pub use types::WasmPastaFpPlonkIndex; + +pub use pasta_plonk_proof::caml_pasta_fq_plonk_proof_create; diff --git a/plonk-napi/src/pasta_plonk_proof.rs b/plonk-napi/src/pasta_plonk_proof.rs new file mode 100644 index 0000000000..32fff09def --- /dev/null +++ b/plonk-napi/src/pasta_plonk_proof.rs @@ -0,0 +1,14 @@ +use napi::bindgen_prelude::*; +use napi::Error; +use napi_derive::napi; + +#[napi(js_name = "caml_pasta_fq_plonk_proof_create")] +pub fn caml_pasta_fq_plonk_proof_create(index: Uint8Array) -> Result { + println!("caml_pasta_fq_plonk_proof_create from native rust"); + + if index.len() > 100 { + Ok(index) + } else { + Err(Error::from_reason("not implemented")) + } +} diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index dc7c9f108d..0c46836072 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -7,7 +7,7 @@ use wasm_types::{FlatVector, FlatVectorElem}; // fp -#[napi] +#[napi(js_name = "caml_pasta_fp_poseidon_block_cipher")] pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result { println!("from native rust"); @@ -32,7 +32,7 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result Result { println!("from native rust"); From e7aff41879af03bde41c71527318faaab16a98ee Mon Sep 17 00:00:00 2001 From: querolita Date: Fri, 31 Oct 2025 16:06:59 +0100 Subject: [PATCH 59/75] napi: refactor gate vector --- plonk-napi/src/gate_vector.rs | 374 ++++++++++++++++++++++--- plonk-napi/src/lib.rs | 13 +- plonk-napi/src/pasta_fp_plonk_index.rs | 6 +- plonk-napi/src/pasta_fq_plonk_index.rs | 6 +- 4 files changed, 346 insertions(+), 53 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index 9c77299502..a6fda3ca12 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -1,12 +1,14 @@ +use ark_ff::PrimeField; use kimchi::circuits::{ gate::{Circuit, CircuitGate, GateType}, - wires::{GateWires, Wire as KimchiWire}, + wires::Wire, }; use mina_curves::pasta::{Fp, Fq}; use napi::bindgen_prelude::*; use napi_derive::napi; use o1_utils::hasher::CryptoDigest; use paste::paste; +use std::ops::Deref; use wasm_types::{FlatVector as WasmFlatVector, FlatVectorElem}; use crate::wrappers::{ @@ -14,8 +16,198 @@ use crate::wrappers::{ wires::NapiWire, }; +pub mod shared { + use super::*; + + /// Number of wires stored per gate. + pub const WIRE_COUNT: usize = 7; + + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub struct GateWires(pub [Wire; WIRE_COUNT]); + + impl GateWires { + pub fn new(wires: [Wire; WIRE_COUNT]) -> Self { + Self(wires) + } + + pub fn as_array(&self) -> &[Wire; WIRE_COUNT] { + &self.0 + } + + pub fn into_array(self) -> [Wire; WIRE_COUNT] { + self.0 + } + } + + impl From<[Wire; WIRE_COUNT]> for GateWires { + fn from(wires: [Wire; WIRE_COUNT]) -> Self { + GateWires::new(wires) + } + } + + impl From for [Wire; WIRE_COUNT] { + fn from(gw: GateWires) -> Self { + gw.into_array() + } + } + + #[derive(Clone, Debug)] + pub struct Gate { + pub typ: GateType, + pub wires: GateWires, + pub coeffs: Vec, + } + + impl From> for Gate + where + F: PrimeField, + { + fn from(cg: CircuitGate) -> Self { + Gate { + typ: cg.typ, + wires: GateWires::new([ + cg.wires[0], + cg.wires[1], + cg.wires[2], + cg.wires[3], + cg.wires[4], + cg.wires[5], + cg.wires[6], + ]), + coeffs: cg.coeffs, + } + } + } + + impl From<&CircuitGate> for Gate + where + F: PrimeField, + { + fn from(cg: &CircuitGate) -> Self { + Gate { + typ: cg.typ, + wires: GateWires::new([ + cg.wires[0], + cg.wires[1], + cg.wires[2], + cg.wires[3], + cg.wires[4], + cg.wires[5], + cg.wires[6], + ]), + coeffs: cg.coeffs.clone(), + } + } + } + + impl From> for CircuitGate + where + F: PrimeField, + { + fn from(gate: Gate) -> Self { + CircuitGate { + typ: gate.typ, + wires: gate.wires.into_array(), + coeffs: gate.coeffs, + } + } + } + + #[derive(Clone, Debug, Default)] + pub struct GateVector { + gates: Vec>, + } + + impl GateVector + where + F: PrimeField, + { + pub fn new() -> Self { + Self { gates: Vec::new() } + } + + pub fn from_vec(gates: Vec>) -> Self { + Self { gates } + } + + pub fn into_inner(self) -> Vec> { + self.gates + } + + pub fn as_slice(&self) -> &[CircuitGate] { + &self.gates + } + + pub fn iter(&self) -> core::slice::Iter<'_, CircuitGate> { + self.gates.iter() + } + + pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, CircuitGate> { + self.gates.iter_mut() + } + + pub fn push_gate(&mut self, gate: CircuitGate) { + self.gates.push(gate); + } + + pub fn len(&self) -> usize { + self.gates.len() + } + + pub fn get_gate(&self, index: usize) -> Option> { + self.gates.get(index).map(Gate::from) + } + + pub fn wrap_wire(&mut self, target: Wire, replacement: Wire) { + if let Some(gate) = self.gates.get_mut(target.row) { + if target.col < gate.wires.len() { + gate.wires[target.col] = replacement; + } + } + } + + pub fn digest(&self, public_input_size: usize) -> Vec { + Circuit::new(public_input_size, self.as_slice()) + .digest() + .to_vec() + } + + pub fn serialize( + &self, + public_input_size: usize, + ) -> std::result::Result { + let circuit = Circuit::new(public_input_size, self.as_slice()); + serde_json::to_string(&circuit) + } + } + + impl From>> for GateVector + where + F: PrimeField, + { + fn from(gates: Vec>) -> Self { + GateVector::from_vec(gates) + } + } + + impl From> for Vec> + where + F: PrimeField, + { + fn from(vec: GateVector) -> Self { + vec.into_inner() + } + } +} + +pub use self::shared::{GateVector as CoreGateVector, GateWires as CoreGateWires}; + +fn gate_vector_error(context: &str, err: impl std::fmt::Display) -> Error { + Error::new(Status::GenericFailure, format!("{}: {}", context, err)) +} + #[napi(object)] -#[derive(Clone, Debug, Default)] +#[derive(Clone, Copy, Debug, Default)] pub struct NapiGateWires { pub w0: NapiWire, pub w1: NapiWire, @@ -26,31 +218,38 @@ pub struct NapiGateWires { pub w6: NapiWire, } -impl NapiGateWires { - fn into_inner(self) -> GateWires { - [ - KimchiWire::from(self.w0), - KimchiWire::from(self.w1), - KimchiWire::from(self.w2), - KimchiWire::from(self.w3), - KimchiWire::from(self.w4), - KimchiWire::from(self.w5), - KimchiWire::from(self.w6), - ] +impl From for NapiGateWires { + fn from(wires: CoreGateWires) -> Self { + let array = wires.into_array(); + NapiGateWires { + w0: array[0].into(), + w1: array[1].into(), + w2: array[2].into(), + w3: array[3].into(), + w4: array[4].into(), + w5: array[5].into(), + w6: array[6].into(), + } } } -impl From<&GateWires> for NapiGateWires { - fn from(value: &GateWires) -> Self { - Self { - w0: value[0].into(), - w1: value[1].into(), - w2: value[2].into(), - w3: value[3].into(), - w4: value[4].into(), - w5: value[5].into(), - w6: value[6].into(), - } +impl From for CoreGateWires { + fn from(wires: NapiGateWires) -> Self { + CoreGateWires::new(wires.into_inner()) + } +} + +impl NapiGateWires { + fn into_inner(self) -> [Wire; shared::WIRE_COUNT] { + [ + self.w0.into(), + self.w1.into(), + self.w2.into(), + self.w3.into(), + self.w4.into(), + self.w5.into(), + self.w6.into(), + ] } } @@ -132,23 +331,91 @@ macro_rules! impl_gate_support { .flat_map(|elem| elem.flatten()) .collect(); + let wires = CoreGateWires::new([ + value.wires[0], + value.wires[1], + value.wires[2], + value.wires[3], + value.wires[4], + value.wires[5], + value.wires[6], + ]); + Self { typ: gate_type_to_i32(value.typ), - wires: (&value.wires).into(), + wires: wires.into(), coeffs, } } } #[napi] - #[derive(Clone, Default, Debug)] + #[derive(Clone, Debug, Default)] pub struct []( - #[napi(skip)] pub Vec>, + #[napi(skip)] pub CoreGateVector<$F>, ); + impl Deref for [] { + type Target = CoreGateVector<$F>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl From> for [] { + fn from(inner: CoreGateVector<$F>) -> Self { + Self(inner) + } + } + + impl From<[]> for CoreGateVector<$F> { + fn from(vector: []) -> Self { + vector.0 + } + } + + #[napi] + impl [] { + #[napi(constructor)] + pub fn new() -> Self { + CoreGateVector::new().into() + } + + #[napi(js_name = "serialize")] + pub fn serialize(&self) -> Result { + let bytes = rmp_serde::to_vec(self.0.as_slice()) + .map_err(|e| gate_vector_error("gate vector serialize failed", e))?; + Ok(Uint8Array::from(bytes)) + } + + #[napi(factory, js_name = "deserialize")] + pub fn deserialize(bytes: Uint8Array) -> Result { + let gates: Vec> = rmp_serde::from_slice(bytes.as_ref()) + .map_err(|e| gate_vector_error("gate vector deserialize failed", e))?; + Ok(CoreGateVector::from_vec(gates).into()) + } + + pub(crate) fn inner(&self) -> &CoreGateVector<$F> { + &self.0 + } + + pub(crate) fn inner_mut(&mut self) -> &mut CoreGateVector<$F> { + &mut self.0 + } + + pub(crate) fn as_slice(&self) -> &[CircuitGate<$F>] { + self.0.as_slice() + } + + pub(crate) fn to_vec(&self) -> Vec> { + self.0.as_slice().to_vec() + } + } + #[napi] pub fn []() -> [] { - [](Vec::new()) + []::new() } #[napi] @@ -156,7 +423,8 @@ macro_rules! impl_gate_support { vector: &mut [], gate: [], ) -> Result<()> { - vector.0.push(gate.into_inner()?); + let gate = gate.into_inner()?; + vector.inner_mut().push_gate(gate); Ok(()) } @@ -165,14 +433,18 @@ macro_rules! impl_gate_support { vector: &[], index: i32, ) -> [] { - []::from_inner(&vector.0[index as usize]) + let gate = vector + .as_slice() + .get(index as usize) + .expect("index out of bounds"); + []::from_inner(gate) } #[napi] pub fn []( vector: &[], ) -> i32 { - vector.0.len() as i32 + vector.as_slice().len() as i32 } #[napi] @@ -181,17 +453,17 @@ macro_rules! impl_gate_support { target: NapiWire, head: NapiWire, ) { - vector.0[target.row as usize].wires[target.col as usize] = KimchiWire::from(head); - } + let target: Wire = target.into(); + let head: Wire = head.into(); + vector.inner_mut().wrap_wire(target, head); + } #[napi] pub fn []( public_input_size: i32, vector: &[], ) -> Uint8Array { - let bytes = Circuit::new(public_input_size as usize, &vector.0) - .digest() - .to_vec(); + let bytes = vector.inner().digest(public_input_size as usize); Uint8Array::from(bytes) } @@ -200,13 +472,29 @@ macro_rules! impl_gate_support { public_input_size: i32, vector: &[], ) -> Result { - let circuit = Circuit::new(public_input_size as usize, &vector.0); - serde_json::to_string(&circuit).map_err(|err| { - Error::new( - Status::GenericFailure, - format!("couldn't serialize constraints: {}", err), - ) - }) + vector + .inner() + .serialize(public_input_size as usize) + .map_err(|err| { + Error::new( + Status::GenericFailure, + format!("couldn't serialize constraints: {}", err), + ) + }) + } + + #[napi] + pub fn []( + vector: &[], + ) -> Result { + vector.serialize() + } + + #[napi] + pub fn []( + bytes: Uint8Array, + ) -> Result<[]> { + []::deserialize(bytes) } } }; diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 0e17eb8215..811d6b524f 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -13,11 +13,13 @@ pub use circuit::prover_to_json; pub use gate_vector::{ caml_pasta_fp_plonk_circuit_serialize, caml_pasta_fp_plonk_gate_vector_add, caml_pasta_fp_plonk_gate_vector_create, caml_pasta_fp_plonk_gate_vector_digest, - caml_pasta_fp_plonk_gate_vector_get, caml_pasta_fp_plonk_gate_vector_len, + caml_pasta_fp_plonk_gate_vector_from_bytes, caml_pasta_fp_plonk_gate_vector_get, + caml_pasta_fp_plonk_gate_vector_len, caml_pasta_fp_plonk_gate_vector_to_bytes, caml_pasta_fp_plonk_gate_vector_wrap, caml_pasta_fq_plonk_circuit_serialize, caml_pasta_fq_plonk_gate_vector_add, caml_pasta_fq_plonk_gate_vector_create, - caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_get, - caml_pasta_fq_plonk_gate_vector_len, caml_pasta_fq_plonk_gate_vector_wrap, + caml_pasta_fq_plonk_gate_vector_digest, caml_pasta_fq_plonk_gate_vector_from_bytes, + caml_pasta_fq_plonk_gate_vector_get, caml_pasta_fq_plonk_gate_vector_len, + caml_pasta_fq_plonk_gate_vector_to_bytes, caml_pasta_fq_plonk_gate_vector_wrap, NapiFpGate as WasmFpGate, NapiFpGateVector as WasmFpGateVector, NapiFqGate as WasmFqGate, NapiFqGateVector as WasmFqGateVector, }; @@ -29,7 +31,10 @@ pub use pasta_fq_plonk_index::{ }; pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; -pub use srs::{fp::NapiFpSrs as WasmFpSrs, fq::NapiFqSrs as WasmFqSrs}; +pub use srs::{ + caml_fp_srs_from_bytes, caml_fp_srs_to_bytes, caml_fq_srs_from_bytes, + fp::NapiFpSrs as WasmFpSrs, fq::NapiFqSrs as WasmFqSrs, +}; pub use tables::{JsLookupTableFp, JsLookupTableFq, JsRuntimeTableCfgFp, JsRuntimeTableCfgFq}; pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; pub use wrappers::{ diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index 9f3565dae6..6a7165395c 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -7,7 +7,7 @@ use mina_curves::pasta::{Fp, Pallas as GAffineOther, Vesta as GAffine, VestaPara use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; use napi_derive::napi; -use plonk_wasm::gate_vector::shared::GateVector; +use crate::gate_vector::NapiFpGateVector; use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; @@ -119,7 +119,7 @@ pub fn caml_pasta_fp_plonk_index_domain_d8_size(index: External>, + gates: &NapiFpGateVector, public_: i32, lookup_tables: Vec, runtime_table_cfgs: Vec, @@ -127,7 +127,7 @@ pub fn caml_pasta_fp_plonk_index_create( srs: External, lazy_mode: bool, ) -> Result, Error> { - let gates: Vec<_> = gates.as_ref().as_slice().to_vec(); + let gates: Vec<_> = gates.to_vec(); let runtime_cfgs: Vec> = runtime_table_cfgs .into_iter() diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index 36cfc9df9b..94537da99b 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -5,7 +5,7 @@ use mina_curves::pasta::{Fq, Pallas as GAffine, PallasParameters, Vesta as GAffi use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; use napi_derive::napi; -use plonk_wasm::gate_vector::shared::GateVector; +use crate::gate_vector::NapiFqGateVector; use poly_commitment::ipa::{OpeningProof, SRS as IPA_SRS}; use poly_commitment::SRS; use serde::{Deserialize, Serialize}; @@ -113,7 +113,7 @@ pub fn caml_pasta_fq_plonk_index_domain_d8_size(index: External>, + gates: &NapiFqGateVector, public_: i32, lookup_tables: Vec, runtime_table_cfgs: Vec, @@ -123,7 +123,7 @@ pub fn caml_pasta_fq_plonk_index_create( ) -> Result, Error> { // TODO: check if and how we run rayon threads automatically in napi - let gates: Vec<_> = gates.as_ref().as_slice().to_vec(); + let gates: Vec<_> = gates.to_vec(); let runtime_cfgs = runtime_table_cfgs .into_iter() From bf6ae6f6731ed788a58ff0ba8eda134fda43a343 Mon Sep 17 00:00:00 2001 From: querolita Date: Fri, 31 Oct 2025 16:09:12 +0100 Subject: [PATCH 60/75] napi: serde napi srs type --- plonk-napi/src/srs.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index 0242a10def..4f84a8920a 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -217,6 +217,16 @@ macro_rules! impl_srs { Ok(basis.iter().cloned().map(Into::into).collect()) } + #[napi] + pub fn [](srs: &[]) -> Result { + srs.serialize() + } + + #[napi] + pub fn [](bytes: Uint8Array) -> Result { + Self::deserialize(bytes) + } + #[napi] pub fn [](srs: &[], domain_size: i32, @@ -302,6 +312,26 @@ macro_rules! impl_srs { } } +#[napi] +pub fn caml_fp_srs_to_bytes(srs: &fp::NapiFpSrs) -> Result { + srs.serialize() +} + +#[napi] +pub fn caml_fp_srs_from_bytes(bytes: Uint8Array) -> Result { + fp::NapiFpSrs::deserialize(bytes) +} + +#[napi] +pub fn caml_fq_srs_to_bytes(srs: &fq::NapiFqSrs) -> Result { + srs.serialize() +} + +#[napi] +pub fn caml_fq_srs_from_bytes(bytes: Uint8Array) -> Result { + fq::NapiFqSrs::deserialize(bytes) +} + pub mod fp { use super::*; use crate::{ From 666085484b38ea3b33973896e970ba1271301bed Mon Sep 17 00:00:00 2001 From: leon chou Date: Fri, 31 Oct 2025 15:30:36 -0400 Subject: [PATCH 61/75] add reporting --- plonk-napi/src/build_info.rs | 16 ++++++++++++++++ plonk-napi/src/circuit.rs | 6 ++++-- plonk-napi/src/pasta_plonk_proof.rs | 3 +++ plonk-napi/src/poseidon.rs | 6 ++++++ plonk-napi/src/prover_index.rs | 10 +++++++--- plonk-napi/src/types.rs | 6 +++--- 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/plonk-napi/src/build_info.rs b/plonk-napi/src/build_info.rs index 802a255dba..3f1a6635b7 100644 --- a/plonk-napi/src/build_info.rs +++ b/plonk-napi/src/build_info.rs @@ -1,3 +1,5 @@ +use std::sync::atomic::{AtomicU64, Ordering}; + use napi_derive::napi; #[cfg(target_os = "windows")] @@ -23,3 +25,17 @@ pub const ARCH_NAME: &str = "ARM"; #[cfg(target_arch = "aarch64")] #[napi] pub const ARCH_NAME: &str = "AArch64"; + +#[napi] +pub const BACKING: &str = "native"; + +static NATIVE_CALLS: AtomicU64 = AtomicU64::new(0); + +#[napi] +pub fn get_native_calls() -> u64 { + NATIVE_CALLS.load(Ordering::Relaxed) +} + +pub(crate) fn report_native_call() { + NATIVE_CALLS.fetch_add(1, Ordering::Relaxed); +} diff --git a/plonk-napi/src/circuit.rs b/plonk-napi/src/circuit.rs index 81a20456b6..96a00c62cd 100644 --- a/plonk-napi/src/circuit.rs +++ b/plonk-napi/src/circuit.rs @@ -5,7 +5,7 @@ use napi::bindgen_prelude::*; use napi_derive::napi; use serde::Serialize; -use crate::types::WasmPastaFpPlonkIndex; +use crate::{build_info::report_native_call, types::WasmPastaFpPlonkIndex}; #[derive(Serialize)] struct Circuit @@ -29,8 +29,10 @@ where } } -#[napi] +#[napi(js_name = "prover_to_json")] pub fn prover_to_json(prover_index: &External) -> String { + report_native_call(); + let circuit: Circuit = prover_index.0.cs.as_ref().into(); serde_json::to_string(&circuit).expect("couldn't serialize constraints") } diff --git a/plonk-napi/src/pasta_plonk_proof.rs b/plonk-napi/src/pasta_plonk_proof.rs index 32fff09def..0c98a8d5e4 100644 --- a/plonk-napi/src/pasta_plonk_proof.rs +++ b/plonk-napi/src/pasta_plonk_proof.rs @@ -2,8 +2,11 @@ use napi::bindgen_prelude::*; use napi::Error; use napi_derive::napi; +use crate::build_info::report_native_call; + #[napi(js_name = "caml_pasta_fq_plonk_proof_create")] pub fn caml_pasta_fq_plonk_proof_create(index: Uint8Array) -> Result { + report_native_call(); println!("caml_pasta_fq_plonk_proof_create from native rust"); if index.len() > 100 { diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index 0c46836072..13a64ab86a 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -5,10 +5,14 @@ use napi::bindgen_prelude::*; use napi_derive::napi; use wasm_types::{FlatVector, FlatVectorElem}; +use crate::build_info::report_native_call; + // fp #[napi(js_name = "caml_pasta_fp_poseidon_block_cipher")] pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result { + report_native_call(); + println!("from native rust"); let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) @@ -34,6 +38,8 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result Result { + report_native_call(); + println!("from native rust"); let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) diff --git a/plonk-napi/src/prover_index.rs b/plonk-napi/src/prover_index.rs index c38c47c3e3..106ebffe55 100644 --- a/plonk-napi/src/prover_index.rs +++ b/plonk-napi/src/prover_index.rs @@ -1,19 +1,23 @@ use napi::bindgen_prelude::*; use napi_derive::napi; -use crate::types::WasmPastaFpPlonkIndex; +use crate::{build_info::report_native_call, types::WasmPastaFpPlonkIndex}; // TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around -#[napi] +#[napi(js_name = "prover_index_from_bytes")] pub fn prover_index_from_bytes(bytes: Uint8Array) -> Result> { + report_native_call(); + let index = WasmPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) .map_err(|e| Error::new(Status::InvalidArg, e))?; Ok(External::new(index)) } // TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around -#[napi] +#[napi(js_name = "prover_index_to_bytes")] pub fn prover_index_to_bytes(index: &External) -> Result { + report_native_call(); + let bytes = index .serialize_inner() .map_err(|e| Error::new(Status::GenericFailure, e))?; diff --git a/plonk-napi/src/types.rs b/plonk-napi/src/types.rs index 50091937f2..0e119936d6 100644 --- a/plonk-napi/src/types.rs +++ b/plonk-napi/src/types.rs @@ -8,14 +8,14 @@ use std::{io::Cursor, sync::Arc}; pub struct WasmPastaFpPlonkIndex(pub Box>>); -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +// TODO: remove incl all dependencies when no longer needed and we only pass napi objects around #[derive(Serialize, Deserialize)] struct SerializedProverIndex { prover_index: Vec, srs: Vec, } -// TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around +// TODO: remove incl all dependencies when no longer needed and we only pass napi objects around impl WasmPastaFpPlonkIndex { pub fn serialize_inner(&self) -> Result, String> { let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; @@ -58,4 +58,4 @@ impl WasmPastaFpPlonkIndex { Ok(WasmPastaFpPlonkIndex(Box::new(index))) } -} \ No newline at end of file +} From 609861454f263d14aacf7484ad83317ee656f7f0 Mon Sep 17 00:00:00 2001 From: leon chou Date: Fri, 31 Oct 2025 15:31:42 -0400 Subject: [PATCH 62/75] do not want this --- plonk-napi/src/lib.rs | 3 --- plonk-napi/src/pasta_plonk_proof.rs | 17 ----------------- 2 files changed, 20 deletions(-) delete mode 100644 plonk-napi/src/pasta_plonk_proof.rs diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index b286e21b65..8815e39984 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,6 +1,5 @@ mod build_info; mod circuit; -mod pasta_plonk_proof; mod poseidon; mod prover_index; mod types; @@ -10,5 +9,3 @@ pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_b pub use circuit::prover_to_json; pub use prover_index::{prover_index_from_bytes, prover_index_to_bytes}; pub use types::WasmPastaFpPlonkIndex; - -pub use pasta_plonk_proof::caml_pasta_fq_plonk_proof_create; diff --git a/plonk-napi/src/pasta_plonk_proof.rs b/plonk-napi/src/pasta_plonk_proof.rs deleted file mode 100644 index 0c98a8d5e4..0000000000 --- a/plonk-napi/src/pasta_plonk_proof.rs +++ /dev/null @@ -1,17 +0,0 @@ -use napi::bindgen_prelude::*; -use napi::Error; -use napi_derive::napi; - -use crate::build_info::report_native_call; - -#[napi(js_name = "caml_pasta_fq_plonk_proof_create")] -pub fn caml_pasta_fq_plonk_proof_create(index: Uint8Array) -> Result { - report_native_call(); - println!("caml_pasta_fq_plonk_proof_create from native rust"); - - if index.len() > 100 { - Ok(index) - } else { - Err(Error::from_reason("not implemented")) - } -} From 36a021246ce82abacd2ea9b146bee12e6466a2fd Mon Sep 17 00:00:00 2001 From: leon chou Date: Mon, 3 Nov 2025 09:53:13 -0500 Subject: [PATCH 63/75] pinning napi-rs fork --- Cargo.lock | 43 ++++++++++++++----------------------------- Cargo.toml | 4 ++-- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c18856c343..45afbd36d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1034,32 +1034,16 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "ctor" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb" -dependencies = [ - "ctor-proc-macro 0.0.6", - "dtor", -] - [[package]] name = "ctor" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59c9b8bdf64ee849747c1b12eb861d21aa47fa161564f48332f1afe2373bf899" dependencies = [ - "ctor-proc-macro 0.0.7", + "ctor-proc-macro", "dtor", ] -[[package]] -name = "ctor-proc-macro" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" - [[package]] name = "ctor-proc-macro" version = "0.0.7" @@ -2444,13 +2428,12 @@ dependencies = [ [[package]] name = "napi" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b74e3dce5230795bb4d2821b941706dee733c7308752507254b0497f39cad7" +version = "3.4.0" +source = "git+https://github.com/o1-labs/napi-rs.git?rev=023d1d4f31bd75e8ab55c95b5077a319b5208cdf#023d1d4f31bd75e8ab55c95b5077a319b5208cdf" dependencies = [ "bitflags 2.4.2", - "ctor 0.5.0", - "napi-build", + "ctor 0.6.0", + "napi-build 2.2.4", "napi-sys", "nohash-hasher", "rustc-hash", @@ -2462,11 +2445,15 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcae8ad5609d14afb3a3b91dee88c757016261b151e9dcecabf1b2a31a6cab14" +[[package]] +name = "napi-build" +version = "2.2.4" +source = "git+https://github.com/o1-labs/napi-rs.git?rev=023d1d4f31bd75e8ab55c95b5077a319b5208cdf#023d1d4f31bd75e8ab55c95b5077a319b5208cdf" + [[package]] name = "napi-derive" version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78665d6bdf10e9a4e6b38123efb0f66962e6197c1aea2f07cff3f159a374696d" +source = "git+https://github.com/o1-labs/napi-rs.git?rev=023d1d4f31bd75e8ab55c95b5077a319b5208cdf#023d1d4f31bd75e8ab55c95b5077a319b5208cdf" dependencies = [ "convert_case 0.8.0", "ctor 0.6.0", @@ -2479,8 +2466,7 @@ dependencies = [ [[package]] name = "napi-derive-backend" version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d55d01423e7264de3acc13b258fa48ca7cf38a4d25db848908ec3c1304a85a" +source = "git+https://github.com/o1-labs/napi-rs.git?rev=023d1d4f31bd75e8ab55c95b5077a319b5208cdf#023d1d4f31bd75e8ab55c95b5077a319b5208cdf" dependencies = [ "convert_case 0.8.0", "proc-macro2", @@ -2492,8 +2478,7 @@ dependencies = [ [[package]] name = "napi-sys" version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed8f0e23a62a3ce0fbb6527cdc056e9282ddd9916b068c46f8923e18eed5ee6" +source = "git+https://github.com/o1-labs/napi-rs.git?rev=023d1d4f31bd75e8ab55c95b5077a319b5208cdf#023d1d4f31bd75e8ab55c95b5077a319b5208cdf" dependencies = [ "libloading", ] @@ -3000,7 +2985,7 @@ dependencies = [ "mina-curves", "mina-poseidon", "napi", - "napi-build", + "napi-build 2.2.3", "napi-derive", "num-bigint", "o1-utils", diff --git a/Cargo.toml b/Cargo.toml index 7c1874723c..fc03d01c81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,8 +62,8 @@ libflate = "2" log = "0.4.20" num-bigint = { version = "0.4.4", features = ["rand", "serde"] } num-integer = "0.1.45" -napi = { version = "3.3.0", default-features = false, features = ["napi7"] } -napi-derive = { version = "3.3.0", features = ["type-def"] } +napi = { git = "https://github.com/o1-labs/napi-rs.git", rev = "023d1d4f31bd75e8ab55c95b5077a319b5208cdf", version = "3.3.0", default-features = false, features = ["napi7"] } +napi-derive = { git="https://github.com/o1-labs/napi-rs.git", rev = "023d1d4f31bd75e8ab55c95b5077a319b5208cdf", version = "3.3.0", features = ["type-def"] } napi-build = "2.1.0" ocaml = { version = "0.22.2" } ocaml-gen = { version = "1.0.0" } From 9e4d1febcee50f80b110e78cf8a1b5b37bdebdf2 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 4 Nov 2025 22:18:30 +0100 Subject: [PATCH 64/75] napi: prefix wrappers with napi and implement missing traits --- plonk-napi/src/lib.rs | 17 +++-- plonk-napi/src/poly_comm.rs | 76 +++++++++++++------- plonk-napi/src/poseidon.rs | 10 +-- plonk-napi/src/{wasm_vector.rs => vector.rs} | 76 +++++++++++++------- plonk-napi/src/wrappers/field.rs | 51 +++++++++---- plonk-napi/src/wrappers/group.rs | 61 ++++++++-------- 6 files changed, 182 insertions(+), 109 deletions(-) rename plonk-napi/src/{wasm_vector.rs => vector.rs} (71%) diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 18379ab979..74c704a9c8 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -1,20 +1,25 @@ mod build_info; mod circuit; -pub mod plonk_verifier_index; +mod plonk_verifier_index; mod poly_comm; mod poseidon; mod prover_index; mod types; -mod wasm_vector; +mod vector; mod wrappers; pub use circuit::prover_to_json; -pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm}; +pub use plonk_verifier_index::{ + caml_pasta_fp_plonk_verifier_index_shifts, caml_pasta_fq_plonk_verifier_index_shifts, +}; +pub use poly_comm::{ + pallas::NapiFqPolyComm as WasmFqPolyComm, vesta::NapiFpPolyComm as WasmFpPolyComm, +}; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; pub use prover_index::{prover_index_from_bytes, prover_index_to_bytes}; pub use types::WasmPastaFpPlonkIndex; -pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}; +pub use vector::{fp::NapiVecVecFp as WasmVecVecFp, fq::NapiVecVecFq as WasmVecVecFq}; pub use wrappers::{ - field::{WasmPastaFp, WasmPastaFq}, - group::{WasmGPallas, WasmGVesta}, + field::{NapiPastaFp as WasmPastaFp, NapiPastaFq as WasmPastaFq}, + group::{NapiGPallas as WasmGPallas, NapiGVesta as WasmGVesta}, }; diff --git a/plonk-napi/src/poly_comm.rs b/plonk-napi/src/poly_comm.rs index b988f3e1e7..f6a3c13b19 100644 --- a/plonk-napi/src/poly_comm.rs +++ b/plonk-napi/src/poly_comm.rs @@ -1,27 +1,30 @@ -use crate::wasm_vector::WasmVector; +use crate::vector::NapiVector; +use napi::bindgen_prelude::{ClassInstance, FromNapiValue}; use napi_derive::napi; use paste::paste; use poly_commitment::commitment::PolyComm; +use serde::{Deserialize, Serialize}; macro_rules! impl_poly_comm { ( - $WasmG:ty, + $NapiG:ty, $g:ty, $field_name:ident ) => { paste! { #[napi] - #[derive(Clone)] - pub struct [] { + #[derive(Clone, Debug, Serialize, Deserialize, Default)] + pub struct [] { #[napi(skip)] - pub unshifted: WasmVector<$WasmG>, - pub shifted: Option<$WasmG>, + pub unshifted: NapiVector<$NapiG>, + #[napi(skip)] + pub shifted: Option<$NapiG>, } #[napi] - impl [] { + impl [] { #[napi(constructor)] - pub fn new(unshifted: WasmVector<$WasmG>, shifted: Option<$WasmG>) -> Self { + pub fn new(unshifted: NapiVector<$NapiG>, shifted: Option<$NapiG>) -> Self { assert!( shifted.is_none(), "mina#14628: Shifted commitments are deprecated and must not be used", @@ -30,20 +33,30 @@ macro_rules! impl_poly_comm { } #[napi(getter)] - pub fn unshifted(&self) -> WasmVector<$WasmG> { + pub fn unshifted(&self) -> NapiVector<$NapiG> { self.unshifted.clone() } #[napi(setter)] - pub fn set_unshifted(&mut self, x: WasmVector<$WasmG>) { + pub fn set_unshifted(&mut self, x: NapiVector<$NapiG>) { self.unshifted = x; } + + #[napi(getter)] + pub fn shifted(&self) -> Option<$NapiG> { + self.shifted.clone() + } + + #[napi(setter)] + pub fn set_shifted(&mut self, value: Option<$NapiG>) { + self.shifted = value; + } } - impl From> for [] { + impl From> for [] { fn from(x: PolyComm<$g>) -> Self { let PolyComm { chunks } = x; - let unshifted: Vec<$WasmG> = chunks.into_iter().map(Into::into).collect(); + let unshifted: Vec<$NapiG> = chunks.into_iter().map(Into::into).collect(); Self { unshifted: unshifted.into(), shifted: None, @@ -51,9 +64,9 @@ macro_rules! impl_poly_comm { } } - impl From<&PolyComm<$g>> for [] { + impl From<&PolyComm<$g>> for [] { fn from(x: &PolyComm<$g>) -> Self { - let unshifted: Vec<$WasmG> = x.chunks.iter().map(|chunk| (*chunk).into()).collect(); + let unshifted: Vec<$NapiG> = x.chunks.iter().map(|chunk| (*chunk).into()).collect(); Self { unshifted: unshifted.into(), shifted: None, @@ -61,15 +74,15 @@ macro_rules! impl_poly_comm { } } - impl From<[]> for PolyComm<$g> { - fn from(x: []) -> Self { - let [] { unshifted, shifted } = x; + impl From<[]> for PolyComm<$g> { + fn from(x: []) -> Self { + let [] { unshifted, shifted } = x; assert!( shifted.is_none(), "mina#14628: Shifted commitments are deprecated and must not be used", ); PolyComm { - chunks: Vec::<$WasmG>::from(unshifted) + chunks: Vec::<$NapiG>::from(unshifted) .into_iter() .map(Into::into) .collect(), @@ -77,8 +90,8 @@ macro_rules! impl_poly_comm { } } - impl From<&[]> for PolyComm<$g> { - fn from(x: &[]) -> Self { + impl From<&[]> for PolyComm<$g> { + fn from(x: &[]) -> Self { assert!( x.shifted.is_none(), "mina#14628: Shifted commitments are deprecated and must not be used", @@ -93,22 +106,33 @@ macro_rules! impl_poly_comm { } } } + + impl FromNapiValue for [] { + unsafe fn from_napi_value( + env: napi::sys::napi_env, + napi_val: napi::sys::napi_value, + ) -> napi::Result { + let instance = ]> as FromNapiValue>::from_napi_value(env, napi_val)?; + Ok((*instance).clone()) + } + } + } }; } pub mod pallas { use super::*; - use crate::wrappers::group::WasmGPallas; - use mina_curves::pasta::Pallas as GAffine; + use crate::wrappers::group::NapiGPallas; + use mina_curves::pasta::Pallas; - impl_poly_comm!(WasmGPallas, GAffine, Fq); + impl_poly_comm!(NapiGPallas, Pallas, Fq); } pub mod vesta { use super::*; - use crate::wrappers::group::WasmGVesta; - use mina_curves::pasta::Vesta as GAffine; + use crate::wrappers::group::NapiGVesta; + use mina_curves::pasta::Vesta; - impl_poly_comm!(WasmGVesta, GAffine, Fp); + impl_poly_comm!(NapiGVesta, Vesta, Fp); } diff --git a/plonk-napi/src/poseidon.rs b/plonk-napi/src/poseidon.rs index 607fbea7e4..cc81d93de8 100644 --- a/plonk-napi/src/poseidon.rs +++ b/plonk-napi/src/poseidon.rs @@ -1,4 +1,4 @@ -use crate::wrappers::field::{WasmPastaFp, WasmPastaFq}; +use crate::wrappers::field::{NapiPastaFp, NapiPastaFq}; use mina_curves::pasta::{Fp, Fq}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, permutation::poseidon_block_cipher}; use napi::bindgen_prelude::*; @@ -15,7 +15,7 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result = FlatVector::::from_bytes(state.to_vec()) + let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) .collect(); @@ -27,7 +27,7 @@ pub fn caml_pasta_fp_poseidon_block_cipher(state: Uint8Array) -> Result = state_vec .into_iter() - .map(WasmPastaFp) + .map(NapiPastaFp) .flat_map(FlatVectorElem::flatten) .collect(); @@ -42,7 +42,7 @@ pub fn caml_pasta_fq_poseidon_block_cipher(state: Uint8Array) -> Result = FlatVector::::from_bytes(state.to_vec()) + let mut state_vec: Vec = FlatVector::::from_bytes(state.to_vec()) .into_iter() .map(Into::into) .collect(); @@ -54,7 +54,7 @@ pub fn caml_pasta_fq_poseidon_block_cipher(state: Uint8Array) -> Result = state_vec .into_iter() - .map(WasmPastaFq) + .map(NapiPastaFq) .flat_map(FlatVectorElem::flatten) .collect(); diff --git a/plonk-napi/src/wasm_vector.rs b/plonk-napi/src/vector.rs similarity index 71% rename from plonk-napi/src/wasm_vector.rs rename to plonk-napi/src/vector.rs index 278b408a21..23cf87cbb8 100644 --- a/plonk-napi/src/wasm_vector.rs +++ b/plonk-napi/src/vector.rs @@ -1,18 +1,18 @@ -use std::{iter::FromIterator, ops::Deref}; - use napi::{bindgen_prelude::*, sys}; +use serde::{Deserialize, Serialize}; +use std::{iter::FromIterator, ops::Deref}; use wasm_types::{FlatVector, FlatVectorElem}; -#[derive(Clone, Debug, Default)] -pub struct WasmVector(pub Vec); +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct NapiVector(pub Vec); -impl WasmVector { +impl NapiVector { pub fn into_inner(self) -> Vec { self.0 } } -impl Deref for WasmVector { +impl Deref for NapiVector { type Target = Vec; fn deref(&self) -> &Self::Target { @@ -20,25 +20,25 @@ impl Deref for WasmVector { } } -impl From> for WasmVector { +impl From> for NapiVector { fn from(value: Vec) -> Self { - WasmVector(value) + NapiVector(value) } } -impl From> for Vec { - fn from(value: WasmVector) -> Self { +impl From> for Vec { + fn from(value: NapiVector) -> Self { value.0 } } -impl<'a, T> From<&'a WasmVector> for &'a Vec { - fn from(value: &'a WasmVector) -> Self { +impl<'a, T> From<&'a NapiVector> for &'a Vec { + fn from(value: &'a NapiVector) -> Self { &value.0 } } -impl IntoIterator for WasmVector { +impl IntoIterator for NapiVector { type Item = T; type IntoIter = as IntoIterator>::IntoIter; @@ -47,7 +47,7 @@ impl IntoIterator for WasmVector { } } -impl<'a, T> IntoIterator for &'a WasmVector { +impl<'a, T> IntoIterator for &'a NapiVector { type Item = &'a T; type IntoIter = <&'a Vec as IntoIterator>::IntoIter; @@ -56,19 +56,19 @@ impl<'a, T> IntoIterator for &'a WasmVector { } } -impl FromIterator for WasmVector { +impl FromIterator for NapiVector { fn from_iter>(iter: I) -> Self { - WasmVector(Vec::from_iter(iter)) + NapiVector(Vec::from_iter(iter)) } } -impl Extend for WasmVector { +impl Extend for NapiVector { fn extend>(&mut self, iter: I) { self.0.extend(iter); } } -impl TypeName for WasmVector +impl TypeName for NapiVector where Vec: TypeName, { @@ -81,7 +81,7 @@ where } } -impl ValidateNapiValue for WasmVector +impl ValidateNapiValue for NapiVector where Vec: ValidateNapiValue, T: FromNapiValue, @@ -91,18 +91,18 @@ where } } -impl FromNapiValue for WasmVector +impl FromNapiValue for NapiVector where Vec: FromNapiValue, { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { - Ok(WasmVector( as FromNapiValue>::from_napi_value( + Ok(NapiVector( as FromNapiValue>::from_napi_value( env, napi_val, )?)) } } -impl ToNapiValue for WasmVector +impl ToNapiValue for NapiVector where Vec: ToNapiValue, { @@ -111,6 +111,28 @@ where } } +impl<'a, T> ToNapiValue for &'a NapiVector +where + Vec: ToNapiValue, + T: Clone, +{ + unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { + let cloned: Vec = val.0.clone(); + as ToNapiValue>::to_napi_value(env, cloned) + } +} + +impl<'a, T> ToNapiValue for &'a mut NapiVector +where + Vec: ToNapiValue, + T: Clone, +{ + unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { + let cloned: Vec = val.0.clone(); + as ToNapiValue>::to_napi_value(env, cloned) + } +} + macro_rules! impl_vec_vec_fp { ($name:ident, $field:ty, $wasm_field:ty) => { #[napi] @@ -182,18 +204,18 @@ macro_rules! impl_vec_vec_fp { pub mod fp { use super::*; - use crate::wrappers::field::WasmPastaFp; + use crate::wrappers::field::NapiPastaFp; use mina_curves::pasta::Fp; use napi_derive::napi; - impl_vec_vec_fp!(WasmVecVecFp, Fp, WasmPastaFp); + impl_vec_vec_fp!(NapiVecVecFp, Fp, NapiPastaFp); } pub mod fq { use super::*; - use crate::wrappers::field::WasmPastaFq; + use crate::wrappers::field::NapiPastaFq; use mina_curves::pasta::Fq; use napi_derive::napi; - impl_vec_vec_fp!(WasmVecVecFq, Fq, WasmPastaFq); -} \ No newline at end of file + impl_vec_vec_fp!(NapiVecVecFq, Fq, NapiPastaFq); +} diff --git a/plonk-napi/src/wrappers/field.rs b/plonk-napi/src/wrappers/field.rs index 8f396ab97e..022636f39d 100644 --- a/plonk-napi/src/wrappers/field.rs +++ b/plonk-napi/src/wrappers/field.rs @@ -1,29 +1,50 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use mina_curves::pasta::{Fp, Fq}; use napi::bindgen_prelude::*; +use serde::{Deserialize, Serialize}; use wasm_types::FlatVectorElem; -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct WasmPastaFp(pub Fp); +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] +pub struct NapiPastaFp(pub Fp); -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct WasmPastaFq(pub Fq); +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] +pub struct NapiPastaFq(pub Fq); macro_rules! impl_field_wrapper { ($name:ident, $field:ty) => { impl $name { - fn serialize(&self) -> Vec { + fn from_bytes(bytes: &[u8]) -> Self { + let value = + <$field>::deserialize_compressed(bytes).expect("deserialization failure"); + Self(value) + } + + fn to_bytes(&self) -> Vec { let mut bytes = Vec::with_capacity(core::mem::size_of::<$field>()); self.0 .serialize_compressed(&mut bytes) .expect("serialization failure"); bytes } + } - fn deserialize(bytes: &[u8]) -> Self { - let value = - <$field>::deserialize_compressed(bytes).expect("deserialization failure"); - Self(value) + impl Serialize for $name { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + serializer.serialize_bytes(&self.to_bytes()) + } + } + impl<'de> Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + let bytes: Vec = Vec::::deserialize(deserializer)?; + <$field>::deserialize_compressed(bytes.as_slice()) + .map(Self) + .map_err(serde::de::Error::custom) } } @@ -49,11 +70,11 @@ macro_rules! impl_field_wrapper { const FLATTENED_SIZE: usize = core::mem::size_of::<$field>(); fn flatten(self) -> Vec { - self.serialize() + self.to_bytes() } fn unflatten(flat: Vec) -> Self { - Self::deserialize(&flat) + Self::from_bytes(&flat) } } @@ -82,18 +103,18 @@ macro_rules! impl_field_wrapper { napi_val: sys::napi_value, ) -> Result { let buffer = ::from_napi_value(env, napi_val)?; - Ok(Self::deserialize(buffer.as_ref())) + Ok(Self::from_bytes(buffer.as_ref())) } } impl ToNapiValue for $name { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { - let buffer = Buffer::from(val.serialize()); + let buffer = Buffer::from(val.to_bytes()); ::to_napi_value(env, buffer) } } }; } -impl_field_wrapper!(WasmPastaFp, Fp); -impl_field_wrapper!(WasmPastaFq, Fq); \ No newline at end of file +impl_field_wrapper!(NapiPastaFp, Fp); +impl_field_wrapper!(NapiPastaFq, Fq); diff --git a/plonk-napi/src/wrappers/group.rs b/plonk-napi/src/wrappers/group.rs index be8cbff4a0..ed082dd922 100644 --- a/plonk-napi/src/wrappers/group.rs +++ b/plonk-napi/src/wrappers/group.rs @@ -1,4 +1,4 @@ -use crate::wrappers::field::{WasmPastaFp, WasmPastaFq}; +use crate::wrappers::field::{NapiPastaFp, NapiPastaFq}; use mina_curves::pasta::{ curves::{ pallas::{G_GENERATOR_X as GeneratorPallasX, G_GENERATOR_Y as GeneratorPallasY}, @@ -7,24 +7,25 @@ use mina_curves::pasta::{ Pallas as AffinePallas, Vesta as AffineVesta, }; use napi_derive::napi; +use serde::{Deserialize, Serialize}; #[napi(object)] -#[derive(Clone, Debug)] -pub struct WasmGPallas { - pub x: WasmPastaFp, - pub y: WasmPastaFp, +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct NapiGPallas { + pub x: NapiPastaFp, + pub y: NapiPastaFp, pub infinity: bool, } #[napi(object)] -#[derive(Clone, Debug)] -pub struct WasmGVesta { - pub x: WasmPastaFq, - pub y: WasmPastaFq, +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct NapiGVesta { + pub x: NapiPastaFq, + pub y: NapiPastaFq, pub infinity: bool, } -impl From for WasmGPallas { +impl From for NapiGPallas { fn from(point: AffinePallas) -> Self { Self { x: point.x.into(), @@ -34,7 +35,7 @@ impl From for WasmGPallas { } } -impl From<&AffinePallas> for WasmGPallas { +impl From<&AffinePallas> for NapiGPallas { fn from(point: &AffinePallas) -> Self { Self { x: point.x.into(), @@ -44,8 +45,8 @@ impl From<&AffinePallas> for WasmGPallas { } } -impl From for AffinePallas { - fn from(point: WasmGPallas) -> Self { +impl From for AffinePallas { + fn from(point: NapiGPallas) -> Self { AffinePallas { x: point.x.into(), y: point.y.into(), @@ -54,8 +55,8 @@ impl From for AffinePallas { } } -impl From<&WasmGPallas> for AffinePallas { - fn from(point: &WasmGPallas) -> Self { +impl From<&NapiGPallas> for AffinePallas { + fn from(point: &NapiGPallas) -> Self { AffinePallas { x: point.x.into(), y: point.y.into(), @@ -64,7 +65,7 @@ impl From<&WasmGPallas> for AffinePallas { } } -impl From for WasmGVesta { +impl From for NapiGVesta { fn from(point: AffineVesta) -> Self { Self { x: point.x.into(), @@ -74,7 +75,7 @@ impl From for WasmGVesta { } } -impl From<&AffineVesta> for WasmGVesta { +impl From<&AffineVesta> for NapiGVesta { fn from(point: &AffineVesta) -> Self { Self { x: point.x.into(), @@ -84,8 +85,8 @@ impl From<&AffineVesta> for WasmGVesta { } } -impl From for AffineVesta { - fn from(point: WasmGVesta) -> Self { +impl From for AffineVesta { + fn from(point: NapiGVesta) -> Self { AffineVesta { x: point.x.into(), y: point.y.into(), @@ -94,8 +95,8 @@ impl From for AffineVesta { } } -impl From<&WasmGVesta> for AffineVesta { - fn from(point: &WasmGVesta) -> Self { +impl From<&NapiGVesta> for AffineVesta { + fn from(point: &NapiGVesta) -> Self { AffineVesta { x: point.x.into(), y: point.y.into(), @@ -105,19 +106,19 @@ impl From<&WasmGVesta> for AffineVesta { } #[napi] -pub fn caml_pallas_affine_one() -> WasmGPallas { - WasmGPallas { - x: WasmPastaFp::from(GeneratorPallasX), - y: WasmPastaFp::from(GeneratorPallasY), +pub fn caml_pallas_affine_one() -> NapiGPallas { + NapiGPallas { + x: NapiPastaFp::from(GeneratorPallasX), + y: NapiPastaFp::from(GeneratorPallasY), infinity: false, } } #[napi] -pub fn caml_vesta_affine_one() -> WasmGVesta { - WasmGVesta { - x: WasmPastaFq::from(GeneratorVestaX), - y: WasmPastaFq::from(GeneratorVestaY), +pub fn caml_vesta_affine_one() -> NapiGVesta { + NapiGVesta { + x: NapiPastaFq::from(GeneratorVestaX), + y: NapiPastaFq::from(GeneratorVestaY), infinity: false, } -} \ No newline at end of file +} From bb874bc1dbf2a4aea7d52a994a7bf5133b0ae130 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 4 Nov 2025 23:35:53 +0100 Subject: [PATCH 65/75] napi: fix merge conflicts and reuse lookups types --- plonk-napi/Cargo.toml | 3 +- plonk-napi/src/gate_vector.rs | 6 +- plonk-napi/src/lib.rs | 7 +- plonk-napi/src/plonk_verifier_index/fp.rs | 4 +- plonk-napi/src/plonk_verifier_index/fq.rs | 5 +- plonk-napi/src/plonk_verifier_index/mod.rs | 28 ------ plonk-napi/src/vector.rs | 11 +++ plonk-napi/src/wrappers/lookups.rs | 109 ++++++++++----------- 8 files changed, 74 insertions(+), 99 deletions(-) diff --git a/plonk-napi/Cargo.toml b/plonk-napi/Cargo.toml index 6b91ebbffb..71c1d82523 100644 --- a/plonk-napi/Cargo.toml +++ b/plonk-napi/Cargo.toml @@ -23,14 +23,13 @@ ark-serialize.workspace = true arkworks.workspace = true # proof-systems -kimchi.workspace = true mina-curves = { path = "../curves" } mina-poseidon = { path = "../poseidon" } o1-utils = { path = "../utils" } -kimchi = { path = "../kimchi" } poly-commitment = { path = "../poly-commitment" } getrandom.workspace = true +kimchi.workspace = true libc.workspace = true num-bigint.workspace = true once_cell.workspace = true diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index 2a4712ee26..7bbad67295 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -10,7 +10,7 @@ use paste::paste; use wasm_types::{FlatVector as WasmFlatVector, FlatVectorElem}; use crate::wrappers::{ - field::{WasmPastaFp, WasmPastaFq}, + field::{NapiPastaFp, NapiPastaFq}, wires::NapiWire, }; @@ -219,5 +219,5 @@ macro_rules! impl_gate_support { }; } -impl_gate_support!(fp, Fp, WasmPastaFp); -impl_gate_support!(fq, Fq, WasmPastaFq); +impl_gate_support!(fp, Fp, NapiPastaFp); +impl_gate_support!(fq, Fq, NapiPastaFq); diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 2104ee3f17..ef2b4c751a 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -25,14 +25,13 @@ pub use plonk_verifier_index::{ caml_pasta_fp_plonk_verifier_index_shifts, caml_pasta_fq_plonk_verifier_index_shifts, }; pub use poly_comm::{ - pallas::{NapiFqPolyComm as WasmFqPolyComm, WasmFqPolyComm}, - vesta::{NapiFpPolyComm as WasmFpPolyComm, WasmFpPolyComm}, + pallas::NapiFqPolyComm as WasmFqPolyComm, vesta::NapiFpPolyComm as WasmFpPolyComm, }; pub use poseidon::{caml_pasta_fp_poseidon_block_cipher, caml_pasta_fq_poseidon_block_cipher}; pub use prover_index::{prover_index_from_bytes, prover_index_to_bytes}; pub use types::WasmPastaFpPlonkIndex; pub use vector::{fp::NapiVecVecFp as WasmVecVecFp, fq::NapiVecVecFq as WasmVecVecFq}; pub use wrappers::{ - field::{NapiPastaFp as WasmPastaFp, NapiPastaFq as WasmPastaFq, WasmPastaFp, WasmPastaFq}, - group::{NapiGPallas as WasmGPallas, NapiGVesta as WasmGVesta, WasmGPallas, WasmGVesta}, + field::{NapiPastaFp as WasmPastaFp, NapiPastaFq as WasmPastaFq}, + group::{NapiGPallas as WasmGPallas, NapiGVesta as WasmGVesta}, }; diff --git a/plonk-napi/src/plonk_verifier_index/fp.rs b/plonk-napi/src/plonk_verifier_index/fp.rs index 147a656c43..6e13c85d89 100644 --- a/plonk-napi/src/plonk_verifier_index/fp.rs +++ b/plonk-napi/src/plonk_verifier_index/fp.rs @@ -6,7 +6,7 @@ use napi::bindgen_prelude::{Error, Result as NapiResult, Status}; use napi_derive::napi; use serde::{Deserialize, Serialize}; -use super::WasmLookupInfo; +use crate::wrappers::lookups::NapiLookupInfo; #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] @@ -50,7 +50,7 @@ pub struct WasmFpLookupVerifierIndex { pub lookup_table: Vec, pub lookup_selectors: WasmFpLookupSelectors, pub table_ids: Option, - pub lookup_info: WasmLookupInfo, + pub lookup_info: NapiLookupInfo, pub runtime_tables_selector: Option, } diff --git a/plonk-napi/src/plonk_verifier_index/fq.rs b/plonk-napi/src/plonk_verifier_index/fq.rs index efcfc72508..d640713dca 100644 --- a/plonk-napi/src/plonk_verifier_index/fq.rs +++ b/plonk-napi/src/plonk_verifier_index/fq.rs @@ -1,3 +1,4 @@ +use crate::wrappers::lookups::NapiLookupInfo; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as Domain}; use ark_serialize::CanonicalSerialize; use kimchi::circuits::polynomials::permutation::Shifts as KimchiShifts; @@ -6,8 +7,6 @@ use napi::bindgen_prelude::{Error, Result as NapiResult, Status}; use napi_derive::napi; use serde::{Deserialize, Serialize}; -use super::WasmLookupInfo; - #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFqDomain { @@ -50,7 +49,7 @@ pub struct WasmFqLookupVerifierIndex { pub lookup_table: Vec, pub lookup_selectors: WasmFqLookupSelectors, pub table_ids: Option, - pub lookup_info: WasmLookupInfo, + pub lookup_info: NapiLookupInfo, pub runtime_tables_selector: Option, } diff --git a/plonk-napi/src/plonk_verifier_index/mod.rs b/plonk-napi/src/plonk_verifier_index/mod.rs index 2ed532c7d4..19c16c73c1 100644 --- a/plonk-napi/src/plonk_verifier_index/mod.rs +++ b/plonk-napi/src/plonk_verifier_index/mod.rs @@ -1,31 +1,3 @@ -use napi_derive::napi; -use serde::{Deserialize, Serialize}; - -#[napi(object)] -#[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmLookupPatterns { - pub xor: bool, - pub lookup: bool, - pub range_check: bool, - pub foreign_field_mul: bool, -} - -#[napi(object)] -#[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmLookupFeatures { - pub patterns: WasmLookupPatterns, - pub joint_lookup_used: bool, - pub uses_runtime_tables: bool, -} - -#[napi(object)] -#[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmLookupInfo { - pub max_per_row: i32, - pub max_joint_size: i32, - pub features: WasmLookupFeatures, -} - pub mod fp; pub mod fq; diff --git a/plonk-napi/src/vector.rs b/plonk-napi/src/vector.rs index 23cf87cbb8..d42cc0d16f 100644 --- a/plonk-napi/src/vector.rs +++ b/plonk-napi/src/vector.rs @@ -188,6 +188,17 @@ macro_rules! impl_vec_vec_fp { } } + impl FromNapiValue for $name { + unsafe fn from_napi_value( + env: sys::napi_env, + napi_val: sys::napi_value, + ) -> Result { + let instance = + as FromNapiValue>::from_napi_value(env, napi_val)?; + Ok((*instance).clone()) + } + } + impl From>> for $name { fn from(value: Vec>) -> Self { Self(value) diff --git a/plonk-napi/src/wrappers/lookups.rs b/plonk-napi/src/wrappers/lookups.rs index cd9b7a4fbe..b6077fad24 100644 --- a/plonk-napi/src/wrappers/lookups.rs +++ b/plonk-napi/src/wrappers/lookups.rs @@ -1,30 +1,25 @@ +use crate::{ + vector::{fp::NapiVecVecFp, fq::NapiVecVecFq}, + wrappers::field::{NapiPastaFp, NapiPastaFq}, +}; use kimchi::circuits::lookup::{ - lookups::{ - LookupFeatures as KimchiLookupFeatures, LookupInfo as KimchiLookupInfo, - LookupPatterns as KimchiLookupPatterns, - }, - runtime_tables::{ - RuntimeTable as KimchiRuntimeTable, RuntimeTableCfg as KimchiRuntimeTableCfg, - }, - tables::LookupTable as KimchiLookupTable, + lookups::{LookupFeatures, LookupInfo, LookupPatterns}, + runtime_tables::{RuntimeTable, RuntimeTableCfg}, + tables::LookupTable, }; use mina_curves::pasta::{Fp, Fq}; use napi::bindgen_prelude::*; use napi_derive::napi; use paste::paste; +use serde::{Deserialize, Serialize}; use wasm_types::{FlatVector, FlatVectorElem}; -use crate::{ - wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq}, - wrappers::field::{WasmPastaFp, WasmPastaFq}, -}; - // ----------------- // Lookup pattern and info wrappers // ----------------- #[napi(object)] -#[derive(Clone, Copy, Debug, Default)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Default)] pub struct NapiLookupPatterns { pub xor: bool, pub lookup: bool, @@ -32,8 +27,8 @@ pub struct NapiLookupPatterns { pub foreign_field_mul: bool, } -impl From for NapiLookupPatterns { - fn from(value: KimchiLookupPatterns) -> Self { +impl From for NapiLookupPatterns { + fn from(value: LookupPatterns) -> Self { Self { xor: value.xor, lookup: value.lookup, @@ -43,9 +38,9 @@ impl From for NapiLookupPatterns { } } -impl From for KimchiLookupPatterns { +impl From for LookupPatterns { fn from(value: NapiLookupPatterns) -> Self { - KimchiLookupPatterns { + LookupPatterns { xor: value.xor, lookup: value.lookup, range_check: value.range_check, @@ -55,15 +50,15 @@ impl From for KimchiLookupPatterns { } #[napi(object)] -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct NapiLookupFeatures { pub patterns: NapiLookupPatterns, pub joint_lookup_used: bool, pub uses_runtime_tables: bool, } -impl From for NapiLookupFeatures { - fn from(value: KimchiLookupFeatures) -> Self { +impl From for NapiLookupFeatures { + fn from(value: LookupFeatures) -> Self { Self { patterns: value.patterns.into(), joint_lookup_used: value.joint_lookup_used, @@ -72,9 +67,9 @@ impl From for NapiLookupFeatures { } } -impl From for KimchiLookupFeatures { +impl From for LookupFeatures { fn from(value: NapiLookupFeatures) -> Self { - KimchiLookupFeatures { + LookupFeatures { patterns: value.patterns.into(), joint_lookup_used: value.joint_lookup_used, uses_runtime_tables: value.uses_runtime_tables, @@ -83,28 +78,28 @@ impl From for KimchiLookupFeatures { } #[napi(object)] -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct NapiLookupInfo { - pub max_per_row: u32, - pub max_joint_size: u32, + pub max_per_row: i32, + pub max_joint_size: i32, pub features: NapiLookupFeatures, } -impl From for NapiLookupInfo { - fn from(value: KimchiLookupInfo) -> Self { +impl From for NapiLookupInfo { + fn from(value: LookupInfo) -> Self { Self { - max_per_row: value.max_per_row as u32, - max_joint_size: value.max_joint_size as u32, + max_per_row: value.max_per_row as i32, + max_joint_size: value.max_joint_size as i32, features: value.features.into(), } } } -impl From for KimchiLookupInfo { +impl From for LookupInfo { fn from(value: NapiLookupInfo) -> Self { - KimchiLookupInfo { + LookupInfo { max_per_row: value.max_per_row as usize, - max_joint_size: value.max_joint_size, + max_joint_size: value.max_joint_size as u32, features: value.features.into(), } } @@ -115,7 +110,7 @@ impl From for KimchiLookupInfo { // ----------------- macro_rules! impl_lookup_wrappers { - ($name:ident, $field:ty, $wasm_field:ty, $vec_vec:ty) => { + ($name:ident, $field:ty, $NapiF:ty, $vec_vec:ty) => { paste! { #[napi] #[derive(Clone)] @@ -127,10 +122,10 @@ macro_rules! impl_lookup_wrappers { #[napi] impl [] { #[napi(constructor)] - pub fn new(id: i32, data: External<$vec_vec>) -> Self { + pub fn new(id: i32, data: $vec_vec) -> Self { Self { id, - data: data.as_ref().clone(), + data: data.clone(), } } @@ -145,18 +140,18 @@ macro_rules! impl_lookup_wrappers { } #[napi(getter)] - pub fn data(&self) -> External<$vec_vec> { - External::new(self.data.clone()) + pub fn data(&self) -> $vec_vec { + self.data.clone() } #[napi(setter)] - pub fn set_data(&mut self, data: External<$vec_vec>) { - self.data = data.as_ref().clone(); + pub fn set_data(&mut self, data: $vec_vec) { + self.data = data.clone(); } } - impl From> for [] { - fn from(value: KimchiLookupTable<$field>) -> Self { + impl From> for [] { + fn from(value: LookupTable<$field>) -> Self { Self { id: value.id, data: value.data.into(), @@ -164,7 +159,7 @@ macro_rules! impl_lookup_wrappers { } } - impl From<[]> for KimchiLookupTable<$field> { + impl From<[]> for LookupTable<$field> { fn from(value: []) -> Self { Self { id: value.id, @@ -185,7 +180,7 @@ macro_rules! impl_lookup_wrappers { #[napi(constructor)] pub fn new(id: i32, first_column: Uint8Array) -> Result { let bytes = first_column.as_ref().to_vec(); - let elements: Vec<$field> = FlatVector::<$wasm_field>::from_bytes(bytes) + let elements: Vec<$field> = FlatVector::<$NapiF>::from_bytes(bytes) .into_iter() .map(Into::into) .collect(); @@ -204,17 +199,17 @@ macro_rules! impl_lookup_wrappers { #[napi(getter)] pub fn first_column(&self) -> Result { - let mut bytes = Vec::with_capacity(self.first_column.len() * <$wasm_field>::FLATTENED_SIZE); + let mut bytes = Vec::with_capacity(self.first_column.len() * <$NapiF>::FLATTENED_SIZE); for value in &self.first_column { - let element = <$wasm_field>::from(*value); + let element = <$NapiF>::from(*value); bytes.extend(element.flatten()); } Ok(Uint8Array::from(bytes)) } } - impl From> for [] { - fn from(value: KimchiRuntimeTableCfg<$field>) -> Self { + impl From> for [] { + fn from(value: RuntimeTableCfg<$field>) -> Self { Self { id: value.id, first_column: value.first_column, @@ -222,7 +217,7 @@ macro_rules! impl_lookup_wrappers { } } - impl From<[]> for KimchiRuntimeTableCfg<$field> { + impl From<[]> for RuntimeTableCfg<$field> { fn from(value: []) -> Self { Self { id: value.id, @@ -243,7 +238,7 @@ macro_rules! impl_lookup_wrappers { #[napi(constructor)] pub fn new(id: i32, data: Uint8Array) -> Result { let bytes = data.as_ref().to_vec(); - let elements: Vec<$field> = FlatVector::<$wasm_field>::from_bytes(bytes) + let elements: Vec<$field> = FlatVector::<$NapiF>::from_bytes(bytes) .into_iter() .map(Into::into) .collect(); @@ -262,17 +257,17 @@ macro_rules! impl_lookup_wrappers { #[napi(getter)] pub fn data(&self) -> Result { - let mut bytes = Vec::with_capacity(self.data.len() * <$wasm_field>::FLATTENED_SIZE); + let mut bytes = Vec::with_capacity(self.data.len() * <$NapiF>::FLATTENED_SIZE); for value in &self.data { - let element = <$wasm_field>::from(*value); + let element = <$NapiF>::from(*value); bytes.extend(element.flatten()); } Ok(Uint8Array::from(bytes)) } } - impl From> for [] { - fn from(value: KimchiRuntimeTable<$field>) -> Self { + impl From> for [] { + fn from(value: RuntimeTable<$field>) -> Self { Self { id: value.id, data: value.data, @@ -280,7 +275,7 @@ macro_rules! impl_lookup_wrappers { } } - impl From<[]> for KimchiRuntimeTable<$field> { + impl From<[]> for RuntimeTable<$field> { fn from(value: []) -> Self { Self { id: value.id, @@ -292,5 +287,5 @@ macro_rules! impl_lookup_wrappers { }; } -impl_lookup_wrappers!(Fp, Fp, WasmPastaFp, WasmVecVecFp); -impl_lookup_wrappers!(Fq, Fq, WasmPastaFq, WasmVecVecFq); +impl_lookup_wrappers!(Fp, Fp, NapiPastaFp, NapiVecVecFp); +impl_lookup_wrappers!(Fq, Fq, NapiPastaFq, NapiVecVecFq); From fb3f2337c18019e88dd08c85570fd10f0e35bda7 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 4 Nov 2025 23:49:39 +0100 Subject: [PATCH 66/75] napi: use existing polycomm in verifier index --- plonk-napi/src/plonk_verifier_index/fp.rs | 80 ++++++++++------------ plonk-napi/src/plonk_verifier_index/fq.rs | 83 +++++++++++------------ 2 files changed, 76 insertions(+), 87 deletions(-) diff --git a/plonk-napi/src/plonk_verifier_index/fp.rs b/plonk-napi/src/plonk_verifier_index/fp.rs index 6e13c85d89..370825b953 100644 --- a/plonk-napi/src/plonk_verifier_index/fp.rs +++ b/plonk-napi/src/plonk_verifier_index/fp.rs @@ -1,13 +1,12 @@ +use crate::{poly_comm::vesta::NapiFpPolyComm, wrappers::lookups::NapiLookupInfo}; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as Domain}; use ark_serialize::CanonicalSerialize; use kimchi::circuits::polynomials::permutation::Shifts as KimchiShifts; use mina_curves::pasta::Fp; -use napi::bindgen_prelude::{Error, Result as NapiResult, Status}; +use napi::bindgen_prelude::{Error, Status}; use napi_derive::napi; use serde::{Deserialize, Serialize}; -use crate::wrappers::lookups::NapiLookupInfo; - #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct WasmFpDomain { @@ -17,14 +16,7 @@ pub struct WasmFpDomain { #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFpPolyComm { - pub unshifted: Vec>, - pub shifted: Option>, -} - -#[napi(object)] -#[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFpShifts { +pub struct NapiFpShifts { pub s0: Vec, pub s1: Vec, pub s2: Vec, @@ -36,59 +28,61 @@ pub struct WasmFpShifts { #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFpLookupSelectors { - pub xor: Option, - pub lookup: Option, - pub range_check: Option, - pub ffmul: Option, +pub struct NapiFpLookupSelectors { + pub xor: Option, + pub lookup: Option, + pub range_check: Option, + pub ffmul: Option, } #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFpLookupVerifierIndex { +pub struct NapiFpLookupVerifierIndex { pub joint_lookup_used: bool, - pub lookup_table: Vec, - pub lookup_selectors: WasmFpLookupSelectors, - pub table_ids: Option, + pub lookup_table: Vec, + pub lookup_selectors: NapiFpLookupSelectors, + pub table_ids: Option, pub lookup_info: NapiLookupInfo, - pub runtime_tables_selector: Option, + pub runtime_tables_selector: Option, } #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFpPlonkVerificationEvals { - pub sigma_comm: Vec, - pub coefficients_comm: Vec, - pub generic_comm: WasmFpPolyComm, - pub psm_comm: WasmFpPolyComm, - pub complete_add_comm: WasmFpPolyComm, - pub mul_comm: WasmFpPolyComm, - pub emul_comm: WasmFpPolyComm, - pub endomul_scalar_comm: WasmFpPolyComm, - pub xor_comm: Option, - pub range_check0_comm: Option, - pub range_check1_comm: Option, - pub foreign_field_add_comm: Option, - pub foreign_field_mul_comm: Option, - pub rot_comm: Option, +pub struct NapiFpPlonkVerificationEvals { + pub sigma_comm: Vec, + pub coefficients_comm: Vec, + pub generic_comm: NapiFpPolyComm, + pub psm_comm: NapiFpPolyComm, + pub complete_add_comm: NapiFpPolyComm, + pub mul_comm: NapiFpPolyComm, + pub emul_comm: NapiFpPolyComm, + pub endomul_scalar_comm: NapiFpPolyComm, + pub xor_comm: Option, + pub range_check0_comm: Option, + pub range_check1_comm: Option, + pub foreign_field_add_comm: Option, + pub foreign_field_mul_comm: Option, + pub rot_comm: Option, } #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFpPlonkVerifierIndex { +pub struct NapiFpPlonkVerifierIndex { pub domain: WasmFpDomain, pub max_poly_size: i32, pub public_: i32, pub prev_challenges: i32, pub srs: Vec, - pub evals: WasmFpPlonkVerificationEvals, - pub shifts: WasmFpShifts, - pub lookup_index: Option, + pub evals: NapiFpPlonkVerificationEvals, + pub shifts: NapiFpShifts, + pub lookup_index: Option, pub zk_rows: i32, } #[napi] -pub fn caml_pasta_fp_plonk_verifier_index_shifts(log2_size: i32) -> NapiResult { +pub fn caml_pasta_fp_plonk_verifier_index_shifts( + log2_size: i32, +) -> napi::bindgen_prelude::Result { println!( "from napi! caml_pasta_fp_plonk_verifier_index_shifts with log2_size {}", log2_size @@ -101,7 +95,7 @@ pub fn caml_pasta_fp_plonk_verifier_index_shifts(log2_size: i32) -> NapiResult NapiResult NapiResult> { +fn serialize_fp(value: &Fp) -> napi::bindgen_prelude::Result> { let mut bytes = Vec::new(); value .serialize_compressed(&mut bytes) diff --git a/plonk-napi/src/plonk_verifier_index/fq.rs b/plonk-napi/src/plonk_verifier_index/fq.rs index d640713dca..de1a45cba7 100644 --- a/plonk-napi/src/plonk_verifier_index/fq.rs +++ b/plonk-napi/src/plonk_verifier_index/fq.rs @@ -1,29 +1,22 @@ -use crate::wrappers::lookups::NapiLookupInfo; +use crate::{poly_comm::pallas::NapiFqPolyComm, wrappers::lookups::NapiLookupInfo}; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as Domain}; use ark_serialize::CanonicalSerialize; use kimchi::circuits::polynomials::permutation::Shifts as KimchiShifts; use mina_curves::pasta::Fq; -use napi::bindgen_prelude::{Error, Result as NapiResult, Status}; +use napi::bindgen_prelude::{Error, Status}; use napi_derive::napi; use serde::{Deserialize, Serialize}; #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFqDomain { +pub struct NapiFqDomain { pub log_size_of_group: i32, pub group_gen: Vec, } #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFqPolyComm { - pub unshifted: Vec>, - pub shifted: Option>, -} - -#[napi(object)] -#[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFqShifts { +pub struct NapiFqShifts { pub s0: Vec, pub s1: Vec, pub s2: Vec, @@ -35,59 +28,61 @@ pub struct WasmFqShifts { #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFqLookupSelectors { - pub xor: Option, - pub lookup: Option, - pub range_check: Option, - pub ffmul: Option, +pub struct NapiFqLookupSelectors { + pub xor: Option, + pub lookup: Option, + pub range_check: Option, + pub ffmul: Option, } #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFqLookupVerifierIndex { +pub struct NapiFqLookupVerifierIndex { pub joint_lookup_used: bool, - pub lookup_table: Vec, - pub lookup_selectors: WasmFqLookupSelectors, - pub table_ids: Option, + pub lookup_table: Vec, + pub lookup_selectors: NapiFqLookupSelectors, + pub table_ids: Option, pub lookup_info: NapiLookupInfo, - pub runtime_tables_selector: Option, + pub runtime_tables_selector: Option, } #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFqPlonkVerificationEvals { - pub sigma_comm: Vec, - pub coefficients_comm: Vec, - pub generic_comm: WasmFqPolyComm, - pub psm_comm: WasmFqPolyComm, - pub complete_add_comm: WasmFqPolyComm, - pub mul_comm: WasmFqPolyComm, - pub emul_comm: WasmFqPolyComm, - pub endomul_scalar_comm: WasmFqPolyComm, - pub xor_comm: Option, - pub range_check0_comm: Option, - pub range_check1_comm: Option, - pub foreign_field_add_comm: Option, - pub foreign_field_mul_comm: Option, - pub rot_comm: Option, +pub struct NapiFqPlonkVerificationEvals { + pub sigma_comm: Vec, + pub coefficients_comm: Vec, + pub generic_comm: NapiFqPolyComm, + pub psm_comm: NapiFqPolyComm, + pub complete_add_comm: NapiFqPolyComm, + pub mul_comm: NapiFqPolyComm, + pub emul_comm: NapiFqPolyComm, + pub endomul_scalar_comm: NapiFqPolyComm, + pub xor_comm: Option, + pub range_check0_comm: Option, + pub range_check1_comm: Option, + pub foreign_field_add_comm: Option, + pub foreign_field_mul_comm: Option, + pub rot_comm: Option, } #[napi(object)] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFqPlonkVerifierIndex { - pub domain: WasmFqDomain, +pub struct NapiFqPlonkVerifierIndex { + pub domain: NapiFqDomain, pub max_poly_size: i32, pub public_: i32, pub prev_challenges: i32, pub srs: Vec, - pub evals: WasmFqPlonkVerificationEvals, - pub shifts: WasmFqShifts, - pub lookup_index: Option, + pub evals: NapiFqPlonkVerificationEvals, + pub shifts: NapiFqShifts, + pub lookup_index: Option, pub zk_rows: i32, } #[napi] -pub fn caml_pasta_fq_plonk_verifier_index_shifts(log2_size: i32) -> NapiResult { +pub fn caml_pasta_fq_plonk_verifier_index_shifts( + log2_size: i32, +) -> napi::bindgen_prelude::Result { println!( "from napi! caml_pasta_fp_plonk_verifier_index_shifts with log2_size {}", log2_size @@ -100,7 +95,7 @@ pub fn caml_pasta_fq_plonk_verifier_index_shifts(log2_size: i32) -> NapiResult NapiResult NapiResult> { +fn serialize_fp(value: &Fq) -> napi::bindgen_prelude::Result> { let mut bytes = Vec::new(); value .serialize_uncompressed(&mut bytes) From 37e96a39c0e63c1fb5554a15aca8ec7e98780c20 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 5 Nov 2025 01:07:57 +0100 Subject: [PATCH 67/75] napi: external by reference --- plonk-napi/src/circuit.rs | 4 +- plonk-napi/src/lib.rs | 6 ++- plonk-napi/src/pasta_fp_plonk_index.rs | 50 +++++++++++----------- plonk-napi/src/pasta_fq_plonk_index.rs | 50 +++++++++++----------- plonk-napi/src/srs.rs | 58 +++++++++++++------------- 5 files changed, 87 insertions(+), 81 deletions(-) diff --git a/plonk-napi/src/circuit.rs b/plonk-napi/src/circuit.rs index 6a887e37c7..299a8954d2 100644 --- a/plonk-napi/src/circuit.rs +++ b/plonk-napi/src/circuit.rs @@ -1,4 +1,4 @@ -use crate::{build_info::report_native_call, pasta_fp_plonk_index::WasmPastaFpPlonkIndex}; +use crate::{build_info::report_native_call, pasta_fp_plonk_index::NapiPastaFpPlonkIndex}; use ark_ff::PrimeField; use kimchi::circuits::{constraints::ConstraintSystem, gate::CircuitGate}; use mina_curves::pasta::Fp; @@ -29,7 +29,7 @@ where } #[napi(js_name = "prover_to_json")] -pub fn prover_to_json(prover_index: &External) -> String { +pub fn prover_to_json(prover_index: &External) -> String { report_native_call(); let circuit: Circuit = prover_index.0.cs.as_ref().into(); diff --git a/plonk-napi/src/lib.rs b/plonk-napi/src/lib.rs index 8b8c381b46..757489bf60 100644 --- a/plonk-napi/src/lib.rs +++ b/plonk-napi/src/lib.rs @@ -26,10 +26,12 @@ pub use gate_vector::{ NapiFqGateVector as WasmFqGateVector, }; pub use pasta_fp_plonk_index::{ - prover_index_fp_from_bytes, prover_index_fp_to_bytes, WasmPastaFpPlonkIndex, + prover_index_fp_from_bytes, prover_index_fp_to_bytes, + NapiPastaFpPlonkIndex as WasmPastaFpPlonkIndex, }; pub use pasta_fq_plonk_index::{ - prover_index_fq_from_bytes, prover_index_fq_to_bytes, WasmPastaFqPlonkIndex, + prover_index_fq_from_bytes, prover_index_fq_to_bytes, + NapiPastaFqPlonkIndex as WasmPastaFqPlonkIndex, }; pub use plonk_verifier_index::{ caml_pasta_fp_plonk_verifier_index_shifts, caml_pasta_fq_plonk_verifier_index_shifts, diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index 4ee2eabfcf..d42e24d110 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -1,6 +1,7 @@ use crate::{ build_info::report_native_call, gate_vector::NapiFpGateVector, + srs::fp::NapiFpSrs, tables::{ lookup_table_fp_from_js, runtime_table_cfg_fp_from_js, JsLookupTableFp, JsRuntimeTableCfgFp, }, @@ -16,9 +17,8 @@ use kimchi::{ }; use mina_curves::pasta::{Fp, Pallas as GAffineOther, Vesta as GAffine, VestaParameters}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; -use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi::bindgen_prelude::{Error, External, Status, Uint8Array}; use napi_derive::napi; -use plonk_wasm::srs::fp::WasmFpSrs as WasmSrs; use poly_commitment::{ ipa::{OpeningProof, SRS as IPA_SRS}, SRS, @@ -29,7 +29,7 @@ use std::{ io::{BufReader, BufWriter, Cursor, Seek, SeekFrom::Start}, sync::Arc, }; -pub struct WasmPastaFpPlonkIndex(pub Box>>); +pub struct NapiPastaFpPlonkIndex(pub Box>>); #[derive(Serialize, Deserialize)] struct SerializedProverIndex { @@ -37,7 +37,7 @@ struct SerializedProverIndex { srs: Vec, } -impl WasmPastaFpPlonkIndex { +impl NapiPastaFpPlonkIndex { fn serialize_inner(&self) -> Result, String> { let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; @@ -77,7 +77,7 @@ impl WasmPastaFpPlonkIndex { DefaultFqSponge, >(); - Ok(WasmPastaFpPlonkIndex(Box::new(index))) + Ok(NapiPastaFpPlonkIndex(Box::new(index))) } } @@ -85,17 +85,19 @@ impl WasmPastaFpPlonkIndex { #[napi(js_name = "prover_index_fp_from_bytes")] pub fn prover_index_fp_from_bytes( bytes: Uint8Array, -) -> NapiResult> { +) -> napi::bindgen_prelude::Result> { report_native_call(); - let index = WasmPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) + let index = NapiPastaFpPlonkIndex::deserialize_inner(bytes.as_ref()) .map_err(|e| Error::new(Status::InvalidArg, e))?; Ok(External::new(index)) } // TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around #[napi(js_name = "prover_index_fp_to_bytes")] -pub fn prover_index_fp_to_bytes(index: External) -> NapiResult { +pub fn prover_index_fp_to_bytes( + index: &External, +) -> napi::bindgen_prelude::Result { report_native_call(); let bytes = index @@ -105,27 +107,27 @@ pub fn prover_index_fp_to_bytes(index: External) -> NapiR } #[napi] -pub fn caml_pasta_fp_plonk_index_max_degree(index: External) -> i32 { +pub fn caml_pasta_fp_plonk_index_max_degree(index: &External) -> i32 { index.0.srs.max_poly_size() as i32 } #[napi] -pub fn caml_pasta_fp_plonk_index_public_inputs(index: External) -> i32 { +pub fn caml_pasta_fp_plonk_index_public_inputs(index: &External) -> i32 { index.0.cs.public as i32 } #[napi] -pub fn caml_pasta_fp_plonk_index_domain_d1_size(index: External) -> i32 { +pub fn caml_pasta_fp_plonk_index_domain_d1_size(index: &External) -> i32 { index.0.cs.domain.d1.size() as i32 } #[napi] -pub fn caml_pasta_fp_plonk_index_domain_d4_size(index: External) -> i32 { +pub fn caml_pasta_fp_plonk_index_domain_d4_size(index: &External) -> i32 { index.0.cs.domain.d4.size() as i32 } #[napi] -pub fn caml_pasta_fp_plonk_index_domain_d8_size(index: External) -> i32 { +pub fn caml_pasta_fp_plonk_index_domain_d8_size(index: &External) -> i32 { index.0.cs.domain.d8.size() as i32 } @@ -136,9 +138,9 @@ pub fn caml_pasta_fp_plonk_index_create( lookup_tables: Vec, runtime_table_cfgs: Vec, prev_challenges: i32, - srs: External, + srs: &External, lazy_mode: bool, -) -> Result, Error> { +) -> Result, Error> { let gates: Vec<_> = gates.to_vec(); let runtime_cfgs: Vec> = runtime_table_cfgs @@ -184,14 +186,14 @@ pub fn caml_pasta_fp_plonk_index_create( ); index.compute_verifier_index_digest::>(); - Ok(External::new(WasmPastaFpPlonkIndex(Box::new(index)))) + Ok(External::new(NapiPastaFpPlonkIndex(Box::new(index)))) } #[napi] pub fn caml_pasta_fp_plonk_index_decode( bytes: &[u8], - srs: External, -) -> Result, Error> { + srs: &External, +) -> Result, Error> { let mut deserializer = rmp_serde::Deserializer::new(bytes); let mut index = ProverIndex::>::deserialize(&mut deserializer) .map_err(|e| { @@ -206,12 +208,12 @@ pub fn caml_pasta_fp_plonk_index_decode( index.linearization = linearization; index.powers_of_alpha = powers_of_alpha; - Ok(External::new(WasmPastaFpPlonkIndex(Box::new(index)))) + Ok(External::new(NapiPastaFpPlonkIndex(Box::new(index)))) } #[napi] pub fn caml_pasta_fp_plonk_index_encode( - index: External, + index: &External, ) -> Result, Error> { let mut buffer = Vec::new(); let mut serializer = rmp_serde::Serializer::new(&mut buffer); @@ -227,7 +229,7 @@ pub fn caml_pasta_fp_plonk_index_encode( #[napi] pub fn caml_pasta_fp_plonk_index_write( append: Option, - index: External, + index: &External, path: String, ) -> Result<(), Error> { let file = OpenOptions::new() @@ -249,9 +251,9 @@ pub fn caml_pasta_fp_plonk_index_write( #[napi] pub fn caml_pasta_fp_plonk_index_read( offset: Option, - srs: External, + srs: &External, path: String, -) -> Result, Error> { +) -> Result, Error> { // read from file let file = match File::open(path) { Err(_) => { @@ -290,5 +292,5 @@ pub fn caml_pasta_fp_plonk_index_read( t.powers_of_alpha = powers_of_alpha; // - Ok(External::new(WasmPastaFpPlonkIndex(Box::new(t)))) + Ok(External::new(NapiPastaFpPlonkIndex(Box::new(t)))) } diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index 8145ac4bdd..eae617fc16 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -1,6 +1,7 @@ use crate::{ build_info::report_native_call, gate_vector::NapiFqGateVector, + srs::fq::NapiFqSrs, tables::{ lookup_table_fq_from_js, runtime_table_cfg_fq_from_js, JsLookupTableFq, JsRuntimeTableCfgFq, }, @@ -12,9 +13,8 @@ use kimchi::{ }; use mina_curves::pasta::{Fq, Pallas as GAffine, PallasParameters, Vesta as GAffineOther}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge}; -use napi::bindgen_prelude::{Error, External, Result as NapiResult, Status, Uint8Array}; +use napi::bindgen_prelude::{Error, External, Status, Uint8Array}; use napi_derive::napi; -use plonk_wasm::srs::fq::WasmFqSrs as WasmSrs; use poly_commitment::{ ipa::{OpeningProof, SRS as IPA_SRS}, SRS, @@ -25,7 +25,7 @@ use std::{ io::{BufReader, BufWriter, Cursor, Seek, SeekFrom::Start}, sync::Arc, }; -pub struct WasmPastaFqPlonkIndex(pub Box>>); +pub struct NapiPastaFqPlonkIndex(pub Box>>); #[derive(Serialize, Deserialize)] struct SerializedProverIndex { @@ -33,7 +33,7 @@ struct SerializedProverIndex { srs: Vec, } -impl WasmPastaFqPlonkIndex { +impl NapiPastaFqPlonkIndex { fn serialize_inner(&self) -> Result, String> { let prover_index = rmp_serde::to_vec(self.0.as_ref()).map_err(|e| e.to_string())?; @@ -73,7 +73,7 @@ impl WasmPastaFqPlonkIndex { DefaultFqSponge, >(); - Ok(WasmPastaFqPlonkIndex(Box::new(index))) + Ok(NapiPastaFqPlonkIndex(Box::new(index))) } } @@ -81,17 +81,19 @@ impl WasmPastaFqPlonkIndex { #[napi(js_name = "prover_index_fq_from_bytes")] pub fn prover_index_fq_from_bytes( bytes: Uint8Array, -) -> NapiResult> { +) -> napi::bindgen_prelude::Result> { report_native_call(); - let index = WasmPastaFqPlonkIndex::deserialize_inner(bytes.as_ref()) + let index = NapiPastaFqPlonkIndex::deserialize_inner(bytes.as_ref()) .map_err(|e| Error::new(Status::InvalidArg, e))?; Ok(External::new(index)) } // TOOD: remove incl all dependencies when no longer needed and we only pass napi objects around #[napi(js_name = "prover_index_fq_to_bytes")] -pub fn prover_index_fq_to_bytes(index: External) -> NapiResult { +pub fn prover_index_fq_to_bytes( + index: &External, +) -> napi::bindgen_prelude::Result { report_native_call(); let bytes = index @@ -101,27 +103,27 @@ pub fn prover_index_fq_to_bytes(index: External) -> NapiR } #[napi] -pub fn caml_pasta_fq_plonk_index_max_degree(index: External) -> i32 { +pub fn caml_pasta_fq_plonk_index_max_degree(index: &External) -> i32 { index.0.srs.max_poly_size() as i32 } #[napi] -pub fn caml_pasta_fq_plonk_index_public_inputs(index: External) -> i32 { +pub fn caml_pasta_fq_plonk_index_public_inputs(index: &External) -> i32 { index.0.cs.public as i32 } #[napi] -pub fn caml_pasta_fq_plonk_index_domain_d1_size(index: External) -> i32 { +pub fn caml_pasta_fq_plonk_index_domain_d1_size(index: &External) -> i32 { index.0.cs.domain.d1.size() as i32 } #[napi] -pub fn caml_pasta_fq_plonk_index_domain_d4_size(index: External) -> i32 { +pub fn caml_pasta_fq_plonk_index_domain_d4_size(index: &External) -> i32 { index.0.cs.domain.d4.size() as i32 } #[napi] -pub fn caml_pasta_fq_plonk_index_domain_d8_size(index: External) -> i32 { +pub fn caml_pasta_fq_plonk_index_domain_d8_size(index: &External) -> i32 { index.0.cs.domain.d8.size() as i32 } @@ -132,9 +134,9 @@ pub fn caml_pasta_fq_plonk_index_create( lookup_tables: Vec, runtime_table_cfgs: Vec, prev_challenges: i32, - srs: External, + srs: &External, lazy_mode: bool, -) -> Result, Error> { +) -> Result, Error> { // TODO: check if and how we run rayon threads automatically in napi let gates: Vec<_> = gates.to_vec(); @@ -182,14 +184,14 @@ pub fn caml_pasta_fq_plonk_index_create( ); index.compute_verifier_index_digest::>(); - Ok(External::new(WasmPastaFqPlonkIndex(Box::new(index)))) + Ok(External::new(NapiPastaFqPlonkIndex(Box::new(index)))) } #[napi] pub fn caml_pasta_fq_plonk_index_decode( bytes: &[u8], - srs: External, -) -> Result, Error> { + srs: &External, +) -> Result, Error> { let mut deserializer = rmp_serde::Deserializer::new(bytes); let mut index = ProverIndex::>::deserialize(&mut deserializer) .map_err(|e| { @@ -203,12 +205,12 @@ pub fn caml_pasta_fq_plonk_index_decode( index.linearization = linearization; index.powers_of_alpha = powers_of_alpha; - Ok(External::new(WasmPastaFqPlonkIndex(Box::new(index)))) + Ok(External::new(NapiPastaFqPlonkIndex(Box::new(index)))) } #[napi] pub fn caml_pasta_fq_plonk_index_encode( - index: External, + index: &External, ) -> Result, Error> { let mut buffer = Vec::new(); let mut serializer = rmp_serde::Serializer::new(&mut buffer); @@ -224,7 +226,7 @@ pub fn caml_pasta_fq_plonk_index_encode( #[napi] pub fn caml_pasta_fq_plonk_index_write( append: Option, - index: External, + index: &External, path: String, ) -> Result<(), Error> { let file = OpenOptions::new() @@ -246,9 +248,9 @@ pub fn caml_pasta_fq_plonk_index_write( #[napi] pub fn caml_pasta_fq_plonk_index_read( offset: Option, - srs: External, + srs: &External, path: String, -) -> Result, Error> { +) -> Result, Error> { // read from file let file = match File::open(path) { Err(_) => { @@ -287,5 +289,5 @@ pub fn caml_pasta_fq_plonk_index_read( t.powers_of_alpha = powers_of_alpha; // - Ok(External::new(WasmPastaFqPlonkIndex(Box::new(t)))) + Ok(External::new(NapiPastaFqPlonkIndex(Box::new(t)))) } diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index 4f84a8920a..3ed5820600 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -1,4 +1,4 @@ -use crate::wasm_vector::WasmVector; +use crate::vector::NapiVector; use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Evaluations}; use core::ops::Deref; use napi::bindgen_prelude::{Error, Result, Status, Uint8Array}; @@ -18,11 +18,11 @@ use wasm_types::FlatVector as WasmFlatVector; macro_rules! impl_srs { ( $name:ident, - $WasmF:ty, - $WasmG:ty, + $NapiF:ty, + $NapiG:ty, $F:ty, $G:ty, - $WasmPolyComm:ty, + $NapiPolyComm:ty, ) => { paste! { @@ -154,15 +154,15 @@ macro_rules! impl_srs { } #[napi] - pub fn [](srs: &[]) -> Vec<$WasmG> { + pub fn [](srs: &[]) -> Vec<$NapiG> { println!("Getting SRS with napi"); - let mut h_and_gs: Vec<$WasmG> = vec![srs.0.h.into()]; + let mut h_and_gs: Vec<$NapiG> = vec![srs.0.h.into()]; h_and_gs.extend(srs.0.g.iter().cloned().map(Into::into)); h_and_gs } #[napi] - pub fn [](h_and_gs: Vec<$WasmG>) -> Result { + pub fn [](h_and_gs: Vec<$NapiG>) -> Result { println!("Setting SRS with napi"); let mut h_and_gs: Vec<$G> = h_and_gs.into_iter().map(Into::into).collect(); if h_and_gs.is_empty() { @@ -182,7 +182,7 @@ macro_rules! impl_srs { srs: &[], domain_size: i32, i: i32, - ) -> Option<$WasmPolyComm> { + ) -> Option<$NapiPolyComm> { println!("Getting maybe lagrange commitment with napi"); if !srs .0 @@ -199,7 +199,7 @@ macro_rules! impl_srs { #[napi] pub fn [](srs: &[], domain_size: i32, - input_bases: WasmVector<$WasmPolyComm>, + input_bases: NapiVector<$NapiPolyComm>, ) { println!("Setting lagrange basis with napi"); srs.0.lagrange_bases @@ -209,7 +209,7 @@ macro_rules! impl_srs { #[napi] pub fn [](srs: &[], domain_size: i32, - ) -> Result> { + ) -> Result> { println!("Getting lagrange basis with napi"); let domain = EvaluationDomain::<$F>::new(domain_size as usize) .ok_or_else(invalid_domain_error)?; @@ -231,9 +231,9 @@ macro_rules! impl_srs { pub fn [](srs: &[], domain_size: i32, evals: Uint8Array, - ) -> Result<$WasmPolyComm> { + ) -> Result<$NapiPolyComm> { println!("Committing evaluations with napi"); - let elems: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( + let elems: Vec<$F> = WasmFlatVector::<$NapiF>::from_bytes( evals.as_ref().to_vec(), ) .into_iter() @@ -247,9 +247,9 @@ macro_rules! impl_srs { } #[napi] - pub fn [](srs: &[], chals: Uint8Array) -> Result<$WasmPolyComm> { + pub fn [](srs: &[], chals: Uint8Array) -> Result<$NapiPolyComm> { println!("Computing b poly commitment with napi"); - let elements: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( + let elements: Vec<$F> = WasmFlatVector::<$NapiF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() @@ -263,12 +263,12 @@ macro_rules! impl_srs { #[napi] pub fn []( srs: &[], - comms: WasmVector<$WasmG>, + comms: NapiVector<$NapiG>, chals: Uint8Array, ) -> Result { println!("Performing batch accumulator check with napi"); let comms: Vec<$G> = comms.into_iter().map(Into::into).collect(); - let chals: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( + let chals: Vec<$F> = WasmFlatVector::<$NapiF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() @@ -286,9 +286,9 @@ macro_rules! impl_srs { srs: &[], comms: i32, chals: Uint8Array, - ) -> Result> { + ) -> Result> { println!("Generating batch accumulator with napi"); - let chals: Vec<$F> = WasmFlatVector::<$WasmF>::from_bytes( + let chals: Vec<$F> = WasmFlatVector::<$NapiF>::from_bytes( chals.as_ref().to_vec(), ) .into_iter() @@ -303,7 +303,7 @@ macro_rules! impl_srs { } #[napi] - pub fn h(srs: &[]) -> $WasmG { + pub fn h(srs: &[]) -> $NapiG { println!("Getting h point with napi"); srs.h.into() } @@ -335,31 +335,31 @@ pub fn caml_fq_srs_from_bytes(bytes: Uint8Array) -> Result { pub mod fp { use super::*; use crate::{ - poly_comm::vesta::WasmFpPolyComm, - wrappers::{field::WasmPastaFp, group::WasmGVesta}, + poly_comm::vesta::NapiFpPolyComm, + wrappers::{field::NapiPastaFp, group::NapiGVesta}, }; impl_srs!( fp, // field name - WasmPastaFp, // Napi field wrapper - WasmGVesta, // Napi group wrapper + NapiPastaFp, // Napi field wrapper + NapiGVesta, // Napi group wrapper mina_curves::pasta::Fp, // Actual Kimchi field mina_curves::pasta::Vesta, // Actual kimchi group - WasmFpPolyComm, // Napi poly commitment type + NapiFpPolyComm, // Napi poly commitment type ); } pub mod fq { use super::*; use crate::{ - poly_comm::pallas::WasmFqPolyComm, - wrappers::{field::WasmPastaFq, group::WasmGPallas}, + poly_comm::pallas::NapiFqPolyComm, + wrappers::{field::NapiPastaFq, group::NapiGPallas}, }; impl_srs!( fq, // Field name - WasmPastaFq, // Napi field wrapper - WasmGPallas, // Napi group wrapper + NapiPastaFq, // Napi field wrapper + NapiGPallas, // Napi group wrapper mina_curves::pasta::Fq, // Actual Kimchi field mina_curves::pasta::Pallas, // Actual kimchi group - WasmFqPolyComm, // Napi poly commitment type + NapiFqPolyComm, // Napi poly commitment type ); } From 9e9154c9cb1175160bf6a0a24cc8f83f1136ecfb Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 5 Nov 2025 22:33:41 +0100 Subject: [PATCH 68/75] napi: delete js_name for one-words --- plonk-napi/src/gate_vector.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index 47f9b46fb0..a85c82c246 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -382,14 +382,14 @@ macro_rules! impl_gate_support { CoreGateVector::new().into() } - #[napi(js_name = "serialize")] + #[napi] pub fn serialize(&self) -> Result { let bytes = rmp_serde::to_vec(self.0.as_slice()) .map_err(|e| gate_vector_error("gate vector serialize failed", e))?; Ok(Uint8Array::from(bytes)) } - #[napi(factory, js_name = "deserialize")] + #[napi(factory)] pub fn deserialize(bytes: Uint8Array) -> Result { let gates: Vec> = rmp_serde::from_slice(bytes.as_ref()) .map_err(|e| gate_vector_error("gate vector deserialize failed", e))?; From e7a3178e8ec9d0b3a845a6015eb860655bedfe47 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 5 Nov 2025 23:16:37 +0100 Subject: [PATCH 69/75] napi: annotate js_name for srs --- plonk-napi/src/srs.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/plonk-napi/src/srs.rs b/plonk-napi/src/srs.rs index 3ed5820600..f996bbb9c8 100644 --- a/plonk-napi/src/srs.rs +++ b/plonk-napi/src/srs.rs @@ -26,7 +26,7 @@ macro_rules! impl_srs { ) => { paste! { - #[napi] + #[napi(js_name = [<"Wasm" $name:camel "Srs">])] #[derive(Clone)] pub struct [] ( #[napi(skip)] pub Arc> @@ -95,13 +95,13 @@ macro_rules! impl_srs { Ok(Arc::new(srs).into()) } - #[napi(factory)] + #[napi(factory, js_name = [<"caml_" $name:snake "_srs_create">])] pub fn [](depth: i32) -> Result { println!("Creating SRS with napi"); Ok(Arc::new(SRS::<$G>::create(depth as usize)).into()) } - #[napi(factory)] + #[napi(factory, js_name = [<"caml_" $name:snake "_srs_create_parallel">])] pub fn [](depth: i32) -> Result { println!("Creating SRS in parallel with napi"); Ok(Arc::new(SRS::<$G>::create_parallel( @@ -109,7 +109,7 @@ macro_rules! impl_srs { )).into()) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_add_lagrange_basis">])] pub fn [](srs: &[], log2_size: i32) -> Result<()> { println!("Adding lagrange basis with napi"); let size = 1usize << (log2_size as usize); @@ -118,7 +118,7 @@ macro_rules! impl_srs { Ok(()) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_write">])] pub fn [](append: Option, srs: &[], path: String) -> Result<()> { println!("Writing SRS to file with napi"); let function_name = format!("caml_{0}_srs_write", stringify!($name).to_lowercase()); @@ -131,7 +131,7 @@ macro_rules! impl_srs { .map_err(|err| map_error(&function_name, err)) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_read">])] pub fn [](offset: Option, path: String) -> Result> { println!("Reading SRS from file with napi"); let function_name = format!("caml_{0}_srs_read", stringify!($name).to_lowercase()); @@ -153,7 +153,7 @@ macro_rules! impl_srs { } } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_get">])] pub fn [](srs: &[]) -> Vec<$NapiG> { println!("Getting SRS with napi"); let mut h_and_gs: Vec<$NapiG> = vec![srs.0.h.into()]; @@ -161,7 +161,7 @@ macro_rules! impl_srs { h_and_gs } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_set">])] pub fn [](h_and_gs: Vec<$NapiG>) -> Result { println!("Setting SRS with napi"); let mut h_and_gs: Vec<$G> = h_and_gs.into_iter().map(Into::into).collect(); @@ -177,7 +177,7 @@ macro_rules! impl_srs { Ok(Arc::new(srs).into()) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_maybe_lagrange_commitment">])] pub fn []( srs: &[], domain_size: i32, @@ -196,7 +196,7 @@ macro_rules! impl_srs { Some(basis[i as usize].clone().into()) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_set_lagrange_basis">])] pub fn [](srs: &[], domain_size: i32, input_bases: NapiVector<$NapiPolyComm>, @@ -206,7 +206,7 @@ macro_rules! impl_srs { .get_or_generate(domain_size as usize, || { input_bases.into_iter().map(Into::into).collect()}); } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_get_lagrange_basis">])] pub fn [](srs: &[], domain_size: i32, ) -> Result> { @@ -217,17 +217,17 @@ macro_rules! impl_srs { Ok(basis.iter().cloned().map(Into::into).collect()) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_to_bytes">])] pub fn [](srs: &[]) -> Result { srs.serialize() } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_from_bytes">])] pub fn [](bytes: Uint8Array) -> Result { Self::deserialize(bytes) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_commit_evaluations">])] pub fn [](srs: &[], domain_size: i32, evals: Uint8Array, @@ -246,7 +246,7 @@ macro_rules! impl_srs { Ok(srs.commit_non_hiding(&p, 1).into()) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_b_poly_commitment">])] pub fn [](srs: &[], chals: Uint8Array) -> Result<$NapiPolyComm> { println!("Computing b poly commitment with napi"); let elements: Vec<$F> = WasmFlatVector::<$NapiF>::from_bytes( @@ -260,7 +260,7 @@ macro_rules! impl_srs { Ok(srs.commit_non_hiding(&p, 1).into()) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_batch_accumulator_check">])] pub fn []( srs: &[], comms: NapiVector<$NapiG>, @@ -281,7 +281,7 @@ macro_rules! impl_srs { )) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_batch_accumulator_generate">])] pub fn []( srs: &[], comms: i32, @@ -302,7 +302,7 @@ macro_rules! impl_srs { Ok(points.into_iter().map(Into::into).collect()) } - #[napi] + #[napi(js_name = [<"caml_" $name:snake "_srs_get_h">])] pub fn h(srs: &[]) -> $NapiG { println!("Getting h point with napi"); srs.h.into() From 145cb882e71cfc2ffdaf91e83df114ba83582f1a Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 5 Nov 2025 23:23:08 +0100 Subject: [PATCH 70/75] napi: annotate js_name for prover index --- plonk-napi/src/pasta_fp_plonk_index.rs | 20 ++++++++++---------- plonk-napi/src/pasta_fq_plonk_index.rs | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/plonk-napi/src/pasta_fp_plonk_index.rs b/plonk-napi/src/pasta_fp_plonk_index.rs index d42e24d110..46fa3bf268 100644 --- a/plonk-napi/src/pasta_fp_plonk_index.rs +++ b/plonk-napi/src/pasta_fp_plonk_index.rs @@ -106,32 +106,32 @@ pub fn prover_index_fp_to_bytes( Ok(Uint8Array::from(bytes)) } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_max_degree")] pub fn caml_pasta_fp_plonk_index_max_degree(index: &External) -> i32 { index.0.srs.max_poly_size() as i32 } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_public_inputs")] pub fn caml_pasta_fp_plonk_index_public_inputs(index: &External) -> i32 { index.0.cs.public as i32 } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_domain_d1_size")] pub fn caml_pasta_fp_plonk_index_domain_d1_size(index: &External) -> i32 { index.0.cs.domain.d1.size() as i32 } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_domain_d4_size")] pub fn caml_pasta_fp_plonk_index_domain_d4_size(index: &External) -> i32 { index.0.cs.domain.d4.size() as i32 } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_domain_d8_size")] pub fn caml_pasta_fp_plonk_index_domain_d8_size(index: &External) -> i32 { index.0.cs.domain.d8.size() as i32 } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_create")] pub fn caml_pasta_fp_plonk_index_create( gates: &NapiFpGateVector, public_: i32, @@ -189,7 +189,7 @@ pub fn caml_pasta_fp_plonk_index_create( Ok(External::new(NapiPastaFpPlonkIndex(Box::new(index)))) } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_decode")] pub fn caml_pasta_fp_plonk_index_decode( bytes: &[u8], srs: &External, @@ -211,7 +211,7 @@ pub fn caml_pasta_fp_plonk_index_decode( Ok(External::new(NapiPastaFpPlonkIndex(Box::new(index)))) } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_encode")] pub fn caml_pasta_fp_plonk_index_encode( index: &External, ) -> Result, Error> { @@ -226,7 +226,7 @@ pub fn caml_pasta_fp_plonk_index_encode( Ok(buffer) } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_write")] pub fn caml_pasta_fp_plonk_index_write( append: Option, index: &External, @@ -248,7 +248,7 @@ pub fn caml_pasta_fp_plonk_index_write( }) } -#[napi] +#[napi(js_name = "pasta_fp_plonk_index_read")] pub fn caml_pasta_fp_plonk_index_read( offset: Option, srs: &External, diff --git a/plonk-napi/src/pasta_fq_plonk_index.rs b/plonk-napi/src/pasta_fq_plonk_index.rs index eae617fc16..451f379124 100644 --- a/plonk-napi/src/pasta_fq_plonk_index.rs +++ b/plonk-napi/src/pasta_fq_plonk_index.rs @@ -102,32 +102,32 @@ pub fn prover_index_fq_to_bytes( Ok(Uint8Array::from(bytes)) } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_max_degree")] pub fn caml_pasta_fq_plonk_index_max_degree(index: &External) -> i32 { index.0.srs.max_poly_size() as i32 } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_public_inputs")] pub fn caml_pasta_fq_plonk_index_public_inputs(index: &External) -> i32 { index.0.cs.public as i32 } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_domain_d1_size")] pub fn caml_pasta_fq_plonk_index_domain_d1_size(index: &External) -> i32 { index.0.cs.domain.d1.size() as i32 } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_domain_d4_size")] pub fn caml_pasta_fq_plonk_index_domain_d4_size(index: &External) -> i32 { index.0.cs.domain.d4.size() as i32 } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_domain_d8_size")] pub fn caml_pasta_fq_plonk_index_domain_d8_size(index: &External) -> i32 { index.0.cs.domain.d8.size() as i32 } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_create")] pub fn caml_pasta_fq_plonk_index_create( gates: &NapiFqGateVector, public_: i32, @@ -187,7 +187,7 @@ pub fn caml_pasta_fq_plonk_index_create( Ok(External::new(NapiPastaFqPlonkIndex(Box::new(index)))) } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_decode")] pub fn caml_pasta_fq_plonk_index_decode( bytes: &[u8], srs: &External, @@ -208,7 +208,7 @@ pub fn caml_pasta_fq_plonk_index_decode( Ok(External::new(NapiPastaFqPlonkIndex(Box::new(index)))) } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_encode")] pub fn caml_pasta_fq_plonk_index_encode( index: &External, ) -> Result, Error> { @@ -223,7 +223,7 @@ pub fn caml_pasta_fq_plonk_index_encode( Ok(buffer) } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_write")] pub fn caml_pasta_fq_plonk_index_write( append: Option, index: &External, @@ -245,7 +245,7 @@ pub fn caml_pasta_fq_plonk_index_write( }) } -#[napi] +#[napi(js_name = "pasta_fq_plonk_index_read")] pub fn caml_pasta_fq_plonk_index_read( offset: Option, srs: &External, From 6a9450a2369fce53ca4a3559379fc19626a5bb56 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 5 Nov 2025 23:33:55 +0100 Subject: [PATCH 71/75] napi: added annotations js_name for polycomm and affine --- plonk-napi/src/poly_comm.rs | 6 +++--- plonk-napi/src/wrappers/group.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plonk-napi/src/poly_comm.rs b/plonk-napi/src/poly_comm.rs index f6a3c13b19..58d4bdeff2 100644 --- a/plonk-napi/src/poly_comm.rs +++ b/plonk-napi/src/poly_comm.rs @@ -12,7 +12,7 @@ macro_rules! impl_poly_comm { $field_name:ident ) => { paste! { - #[napi] + #[napi(js_name = [<"Wasm" $field_name "PolyComm">])] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct [] { #[napi(skip)] @@ -37,7 +37,7 @@ macro_rules! impl_poly_comm { self.unshifted.clone() } - #[napi(setter)] + #[napi(setter, js_name = "set_unshifted")] pub fn set_unshifted(&mut self, x: NapiVector<$NapiG>) { self.unshifted = x; } @@ -47,7 +47,7 @@ macro_rules! impl_poly_comm { self.shifted.clone() } - #[napi(setter)] + #[napi(setter, js_name = "set_shifted")] pub fn set_shifted(&mut self, value: Option<$NapiG>) { self.shifted = value; } diff --git a/plonk-napi/src/wrappers/group.rs b/plonk-napi/src/wrappers/group.rs index ed082dd922..cf192b5c0c 100644 --- a/plonk-napi/src/wrappers/group.rs +++ b/plonk-napi/src/wrappers/group.rs @@ -9,7 +9,7 @@ use mina_curves::pasta::{ use napi_derive::napi; use serde::{Deserialize, Serialize}; -#[napi(object)] +#[napi(object, js_name = "WasmGPallas")] #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct NapiGPallas { pub x: NapiPastaFp, @@ -17,7 +17,7 @@ pub struct NapiGPallas { pub infinity: bool, } -#[napi(object)] +#[napi(object, js_name = "WasmGVesta")] #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct NapiGVesta { pub x: NapiPastaFq, @@ -105,7 +105,7 @@ impl From<&NapiGVesta> for AffineVesta { } } -#[napi] +#[napi(js_name = "caml_pallas_affine_one")] pub fn caml_pallas_affine_one() -> NapiGPallas { NapiGPallas { x: NapiPastaFp::from(GeneratorPallasX), @@ -114,7 +114,7 @@ pub fn caml_pallas_affine_one() -> NapiGPallas { } } -#[napi] +#[napi(js_name = "caml_vesta_affine_one")] pub fn caml_vesta_affine_one() -> NapiGVesta { NapiGVesta { x: NapiPastaFq::from(GeneratorVestaX), From 9929eb55368925e53d24055c0d5e069094f20218 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 5 Nov 2025 23:56:18 +0100 Subject: [PATCH 72/75] napi: annotate js_name for verifier index --- plonk-napi/src/plonk_verifier_index/fp.rs | 18 +++++++++--------- plonk-napi/src/plonk_verifier_index/fq.rs | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/plonk-napi/src/plonk_verifier_index/fp.rs b/plonk-napi/src/plonk_verifier_index/fp.rs index 370825b953..b6e54161a2 100644 --- a/plonk-napi/src/plonk_verifier_index/fp.rs +++ b/plonk-napi/src/plonk_verifier_index/fp.rs @@ -7,14 +7,14 @@ use napi::bindgen_prelude::{Error, Status}; use napi_derive::napi; use serde::{Deserialize, Serialize}; -#[napi(object)] +#[napi(object, js_name = "WasmFpDomain")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct WasmFpDomain { +pub struct NapiFpDomain { pub log_size_of_group: i32, pub group_gen: Vec, } -#[napi(object)] +#[napi(object, js_name = "WasmFpShifts")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFpShifts { pub s0: Vec, @@ -26,7 +26,7 @@ pub struct NapiFpShifts { pub s6: Vec, } -#[napi(object)] +#[napi(object, js_name = "WasmFpLookupSelectors")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFpLookupSelectors { pub xor: Option, @@ -35,7 +35,7 @@ pub struct NapiFpLookupSelectors { pub ffmul: Option, } -#[napi(object)] +#[napi(object, js_name = "WasmFpLookupVerifierIndex")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFpLookupVerifierIndex { pub joint_lookup_used: bool, @@ -46,7 +46,7 @@ pub struct NapiFpLookupVerifierIndex { pub runtime_tables_selector: Option, } -#[napi(object)] +#[napi(object, js_name = "WasmFpPlonkVerificationEvals")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFpPlonkVerificationEvals { pub sigma_comm: Vec, @@ -65,10 +65,10 @@ pub struct NapiFpPlonkVerificationEvals { pub rot_comm: Option, } -#[napi(object)] +#[napi(object, js_name = "WasmFpPlonkVerifierIndex")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFpPlonkVerifierIndex { - pub domain: WasmFpDomain, + pub domain: NapiFpDomain, pub max_poly_size: i32, pub public_: i32, pub prev_challenges: i32, @@ -79,7 +79,7 @@ pub struct NapiFpPlonkVerifierIndex { pub zk_rows: i32, } -#[napi] +#[napi(js_name = "pasta_fp_plonk_verifier_index_shifts")] pub fn caml_pasta_fp_plonk_verifier_index_shifts( log2_size: i32, ) -> napi::bindgen_prelude::Result { diff --git a/plonk-napi/src/plonk_verifier_index/fq.rs b/plonk-napi/src/plonk_verifier_index/fq.rs index de1a45cba7..ab449340b4 100644 --- a/plonk-napi/src/plonk_verifier_index/fq.rs +++ b/plonk-napi/src/plonk_verifier_index/fq.rs @@ -7,14 +7,14 @@ use napi::bindgen_prelude::{Error, Status}; use napi_derive::napi; use serde::{Deserialize, Serialize}; -#[napi(object)] +#[napi(object, js_name = "WasmFqDomain")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFqDomain { pub log_size_of_group: i32, pub group_gen: Vec, } -#[napi(object)] +#[napi(object, js_name = "WasmFqShifts")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFqShifts { pub s0: Vec, @@ -26,7 +26,7 @@ pub struct NapiFqShifts { pub s6: Vec, } -#[napi(object)] +#[napi(object, js_name = "WasmFqLookupSelectors")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFqLookupSelectors { pub xor: Option, @@ -35,7 +35,7 @@ pub struct NapiFqLookupSelectors { pub ffmul: Option, } -#[napi(object)] +#[napi(object, js_name = "WasmFqLookupVerifierIndex")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFqLookupVerifierIndex { pub joint_lookup_used: bool, @@ -46,7 +46,7 @@ pub struct NapiFqLookupVerifierIndex { pub runtime_tables_selector: Option, } -#[napi(object)] +#[napi(object, js_name = "WasmFqPlonkVerificationEvals")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFqPlonkVerificationEvals { pub sigma_comm: Vec, @@ -65,7 +65,7 @@ pub struct NapiFqPlonkVerificationEvals { pub rot_comm: Option, } -#[napi(object)] +#[napi(object, js_name = "WasmFqPlonkVerifierIndex")] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct NapiFqPlonkVerifierIndex { pub domain: NapiFqDomain, @@ -79,12 +79,12 @@ pub struct NapiFqPlonkVerifierIndex { pub zk_rows: i32, } -#[napi] +#[napi(js_name = "pasta_fq_plonk_verifier_index_shifts")] pub fn caml_pasta_fq_plonk_verifier_index_shifts( log2_size: i32, ) -> napi::bindgen_prelude::Result { println!( - "from napi! caml_pasta_fp_plonk_verifier_index_shifts with log2_size {}", + "from napi! caml_pasta_fq_plonk_verifier_index_shifts with log2_size {}", log2_size ); From b092588c964e61d07ddd7969911c0315c11e1a0b Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 5 Nov 2025 23:56:53 +0100 Subject: [PATCH 73/75] napi: annotate js_name for feature flags --- plonk-napi/src/wrappers/feature_flags.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plonk-napi/src/wrappers/feature_flags.rs b/plonk-napi/src/wrappers/feature_flags.rs index 64f93895bf..53fae3f37d 100644 --- a/plonk-napi/src/wrappers/feature_flags.rs +++ b/plonk-napi/src/wrappers/feature_flags.rs @@ -1,10 +1,10 @@ use kimchi::circuits::{ - constraints::FeatureFlags as KimchiFeatureFlags, + constraints::FeatureFlags, lookup::lookups::{LookupFeatures, LookupPatterns}, }; use napi_derive::napi; -#[napi(object)] +#[napi(object, js_name = "WasmFeatureFlags")] #[derive(Clone, Copy, Debug, Default)] pub struct NapiFeatureFlags { pub range_check0: bool, @@ -17,8 +17,8 @@ pub struct NapiFeatureFlags { pub runtime_tables: bool, } -impl From for NapiFeatureFlags { - fn from(value: KimchiFeatureFlags) -> Self { +impl From for NapiFeatureFlags { + fn from(value: FeatureFlags) -> Self { let LookupPatterns { xor, lookup, @@ -39,9 +39,9 @@ impl From for NapiFeatureFlags { } } -impl From for KimchiFeatureFlags { +impl From for FeatureFlags { fn from(value: NapiFeatureFlags) -> Self { - KimchiFeatureFlags { + FeatureFlags { range_check0: value.range_check0, range_check1: value.range_check1, foreign_field_add: value.foreign_field_add, From 214a69c214dd71bcb81e53c686f005b13065a00e Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 5 Nov 2025 23:57:23 +0100 Subject: [PATCH 74/75] napi: annotate js_name for lookups and fix naming of structs --- plonk-napi/src/wrappers/lookups.rs | 42 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/plonk-napi/src/wrappers/lookups.rs b/plonk-napi/src/wrappers/lookups.rs index b6077fad24..a33fcb4f61 100644 --- a/plonk-napi/src/wrappers/lookups.rs +++ b/plonk-napi/src/wrappers/lookups.rs @@ -18,7 +18,7 @@ use wasm_types::{FlatVector, FlatVectorElem}; // Lookup pattern and info wrappers // ----------------- -#[napi(object)] +#[napi(object, js_name = "WasmLookupPatterns")] #[derive(Clone, Copy, Debug, Serialize, Deserialize, Default)] pub struct NapiLookupPatterns { pub xor: bool, @@ -49,7 +49,7 @@ impl From for LookupPatterns { } } -#[napi(object)] +#[napi(object, js_name = "WasmLookupFeatures")] #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct NapiLookupFeatures { pub patterns: NapiLookupPatterns, @@ -77,7 +77,7 @@ impl From for LookupFeatures { } } -#[napi(object)] +#[napi(object, js_name = "WasmLookupInfo")] #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct NapiLookupInfo { pub max_per_row: i32, @@ -112,15 +112,15 @@ impl From for LookupInfo { macro_rules! impl_lookup_wrappers { ($name:ident, $field:ty, $NapiF:ty, $vec_vec:ty) => { paste! { - #[napi] + #[napi(js_name = [<"WasmPasta" $name:camel "LookupTable">])] #[derive(Clone)] - pub struct [] { + pub struct [] { id: i32, data: $vec_vec, } #[napi] - impl [] { + impl [] { #[napi(constructor)] pub fn new(id: i32, data: $vec_vec) -> Self { Self { @@ -150,7 +150,7 @@ macro_rules! impl_lookup_wrappers { } } - impl From> for [] { + impl From> for [] { fn from(value: LookupTable<$field>) -> Self { Self { id: value.id, @@ -159,8 +159,8 @@ macro_rules! impl_lookup_wrappers { } } - impl From<[]> for LookupTable<$field> { - fn from(value: []) -> Self { + impl From<[]> for LookupTable<$field> { + fn from(value: []) -> Self { Self { id: value.id, data: value.data.into(), @@ -168,15 +168,15 @@ macro_rules! impl_lookup_wrappers { } } - #[napi] + #[napi(js_name = [<"WasmPasta" $name:camel "RuntimeTableCfg">])] #[derive(Clone)] - pub struct [] { + pub struct [] { id: i32, first_column: Vec<$field>, } #[napi] - impl [] { + impl [] { #[napi(constructor)] pub fn new(id: i32, first_column: Uint8Array) -> Result { let bytes = first_column.as_ref().to_vec(); @@ -208,7 +208,7 @@ macro_rules! impl_lookup_wrappers { } } - impl From> for [] { + impl From> for [] { fn from(value: RuntimeTableCfg<$field>) -> Self { Self { id: value.id, @@ -217,8 +217,8 @@ macro_rules! impl_lookup_wrappers { } } - impl From<[]> for RuntimeTableCfg<$field> { - fn from(value: []) -> Self { + impl From<[]> for RuntimeTableCfg<$field> { + fn from(value: []) -> Self { Self { id: value.id, first_column: value.first_column, @@ -226,15 +226,15 @@ macro_rules! impl_lookup_wrappers { } } - #[napi] + #[napi(js_name = [<"Wasm" $name:camel "RuntimeTable">])] #[derive(Clone)] - pub struct [] { + pub struct [] { id: i32, data: Vec<$field>, } #[napi] - impl [] { + impl [] { #[napi(constructor)] pub fn new(id: i32, data: Uint8Array) -> Result { let bytes = data.as_ref().to_vec(); @@ -266,7 +266,7 @@ macro_rules! impl_lookup_wrappers { } } - impl From> for [] { + impl From> for [] { fn from(value: RuntimeTable<$field>) -> Self { Self { id: value.id, @@ -275,8 +275,8 @@ macro_rules! impl_lookup_wrappers { } } - impl From<[]> for RuntimeTable<$field> { - fn from(value: []) -> Self { + impl From<[]> for RuntimeTable<$field> { + fn from(value: []) -> Self { Self { id: value.id, data: value.data, From 4f80d3cecc361686b2f48fbadded2dceb0e9a1c1 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 6 Nov 2025 00:00:41 +0100 Subject: [PATCH 75/75] napi: annotate js_name for gate vector --- plonk-napi/src/gate_vector.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plonk-napi/src/gate_vector.rs b/plonk-napi/src/gate_vector.rs index a85c82c246..2873c78917 100644 --- a/plonk-napi/src/gate_vector.rs +++ b/plonk-napi/src/gate_vector.rs @@ -206,7 +206,7 @@ fn gate_vector_error(context: &str, err: impl std::fmt::Display) -> Error { Error::new(Status::GenericFailure, format!("{}: {}", context, err)) } -#[napi(object)] +#[napi(object, js_name = "WasmGateWires")] #[derive(Clone, Copy, Debug, Default)] pub struct NapiGateWires { pub w0: NapiWire, @@ -300,7 +300,7 @@ fn gate_type_to_i32(value: GateType) -> i32 { macro_rules! impl_gate_support { ($field_name:ident, $F:ty, $WasmF:ty) => { paste! { - #[napi(object)] + #[napi(object, js_name = [<"Wasm" $field_name:camel "Gate">])] #[derive(Clone, Debug, Default)] pub struct [] { pub typ: i32, // for convenience, we use i32 instead of GateType @@ -349,7 +349,7 @@ macro_rules! impl_gate_support { } } - #[napi] + #[napi(js_name = [<"Wasm" $field_name:camel "GateVector">])] #[derive(Clone, Debug, Default)] pub struct []( #[napi(skip)] pub CoreGateVector<$F>, @@ -413,12 +413,12 @@ macro_rules! impl_gate_support { } } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_gate_vector_create">])] pub fn []() -> [] { []::new() } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_gate_vector_add">])] pub fn []( vector: &mut [], gate: [], @@ -428,7 +428,7 @@ macro_rules! impl_gate_support { Ok(()) } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_gate_vector_get">])] pub fn []( vector: &[], index: i32, @@ -440,14 +440,14 @@ macro_rules! impl_gate_support { []::from_inner(gate) } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_gate_vector_len">])] pub fn []( vector: &[], ) -> i32 { vector.as_slice().len() as i32 } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_gate_vector_wrap">])] pub fn []( vector: &mut [], target: NapiWire, @@ -458,7 +458,7 @@ macro_rules! impl_gate_support { vector.inner_mut().wrap_wire(target, head); } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_gate_vector_digest">])] pub fn []( public_input_size: i32, vector: &[], @@ -467,7 +467,7 @@ macro_rules! impl_gate_support { Uint8Array::from(bytes) } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_circuit_serialize">])] pub fn []( public_input_size: i32, vector: &[], @@ -483,14 +483,14 @@ macro_rules! impl_gate_support { }) } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_gate_vector_to_bytes">])] pub fn []( vector: &[], ) -> Result { vector.serialize() } - #[napi] + #[napi(js_name = [<"caml_pasta_" $field_name:snake "_plonk_gate_vector_from_bytes">])] pub fn []( bytes: Uint8Array, ) -> Result<[]> {