Skip to content

Commit 683210d

Browse files
committed
napi: ffi for gate vector
1 parent 73d5f8a commit 683210d

File tree

4 files changed

+260
-3
lines changed

4 files changed

+260
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plonk-napi/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ rand.workspace = true
3838
rayon.workspace = true
3939
rmp-serde.workspace = true
4040
serde.workspace = true
41+
serde_json.workspace = true
4142
serde_with.workspace = true
4243
wasm-types.workspace = true
4344

plonk-napi/src/gate_vector.rs

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
use kimchi::circuits::{
2+
gate::{Circuit, CircuitGate, GateType},
3+
wires::{GateWires, Wire as KimchiWire},
4+
};
5+
use mina_curves::pasta::{Fp, Fq};
6+
use napi::bindgen_prelude::*;
7+
use napi_derive::napi;
8+
use o1_utils::hasher::CryptoDigest;
9+
use paste::paste;
10+
use wasm_types::{FlatVector as WasmFlatVector, FlatVectorElem};
11+
12+
use crate::wrappers::{
13+
field::{WasmPastaFp, WasmPastaFq},
14+
wires::NapiWire,
15+
};
16+
17+
#[napi(object)]
18+
#[derive(Clone, Debug, Default)]
19+
pub struct NapiGateWires {
20+
pub w0: NapiWire,
21+
pub w1: NapiWire,
22+
pub w2: NapiWire,
23+
pub w3: NapiWire,
24+
pub w4: NapiWire,
25+
pub w5: NapiWire,
26+
pub w6: NapiWire,
27+
}
28+
29+
impl NapiGateWires {
30+
fn into_inner(self) -> GateWires {
31+
[
32+
KimchiWire::from(self.w0),
33+
KimchiWire::from(self.w1),
34+
KimchiWire::from(self.w2),
35+
KimchiWire::from(self.w3),
36+
KimchiWire::from(self.w4),
37+
KimchiWire::from(self.w5),
38+
KimchiWire::from(self.w6),
39+
]
40+
}
41+
}
42+
43+
impl From<&GateWires> for NapiGateWires {
44+
fn from(value: &GateWires) -> Self {
45+
Self {
46+
w0: value[0].into(),
47+
w1: value[1].into(),
48+
w2: value[2].into(),
49+
w3: value[3].into(),
50+
w4: value[4].into(),
51+
w5: value[5].into(),
52+
w6: value[6].into(),
53+
}
54+
}
55+
}
56+
57+
fn gate_type_from_i32(value: i32) -> Result<GateType> {
58+
if value < 0 {
59+
return Err(Error::new(
60+
Status::InvalidArg,
61+
format!("invalid GateType discriminant: {}", value),
62+
));
63+
}
64+
65+
let variants: &[GateType] = &[
66+
GateType::Zero,
67+
GateType::Generic,
68+
GateType::Poseidon,
69+
GateType::CompleteAdd,
70+
GateType::VarBaseMul,
71+
GateType::EndoMul,
72+
GateType::EndoMulScalar,
73+
GateType::Lookup,
74+
GateType::CairoClaim,
75+
GateType::CairoInstruction,
76+
GateType::CairoFlags,
77+
GateType::CairoTransition,
78+
GateType::RangeCheck0,
79+
GateType::RangeCheck1,
80+
GateType::ForeignFieldAdd,
81+
GateType::ForeignFieldMul,
82+
GateType::Xor16,
83+
GateType::Rot64,
84+
];
85+
86+
let index = value as usize;
87+
variants.get(index).copied().ok_or_else(|| {
88+
Error::new(
89+
Status::InvalidArg,
90+
format!("invalid GateType discriminant: {}", value),
91+
)
92+
})
93+
}
94+
95+
fn gate_type_to_i32(value: GateType) -> i32 {
96+
value as i32
97+
}
98+
99+
macro_rules! impl_gate_support {
100+
($module:ident, $field:ty, $wasm_field:ty) => {
101+
paste! {
102+
#[napi(object)]
103+
#[derive(Clone, Debug, Default)]
104+
pub struct [<Napi $module:camel Gate>] {
105+
pub typ: i32,
106+
pub wires: NapiGateWires,
107+
pub coeffs: Vec<u8>,
108+
}
109+
110+
impl [<Napi $module:camel Gate>] {
111+
fn into_inner(self) -> Result<CircuitGate<$field>> {
112+
let coeffs = WasmFlatVector::<$wasm_field>::from_bytes(self.coeffs)
113+
.into_iter()
114+
.map(Into::into)
115+
.collect();
116+
117+
Ok(CircuitGate {
118+
typ: gate_type_from_i32(self.typ)?,
119+
wires: self.wires.into_inner(),
120+
coeffs,
121+
})
122+
}
123+
124+
fn from_inner(value: &CircuitGate<$field>) -> Self {
125+
let coeffs = value
126+
.coeffs
127+
.iter()
128+
.cloned()
129+
.map($wasm_field::from)
130+
.flat_map(|elem| elem.flatten())
131+
.collect();
132+
133+
Self {
134+
typ: gate_type_to_i32(value.typ),
135+
wires: (&value.wires).into(),
136+
coeffs,
137+
}
138+
}
139+
}
140+
141+
#[napi]
142+
#[derive(Clone, Default, Debug)]
143+
pub struct [<Napi $module:camel GateVector>] {
144+
#[napi(skip)]
145+
pub inner: Vec<CircuitGate<$field>>,
146+
}
147+
148+
#[napi]
149+
impl [<Napi $module:camel GateVector>] {
150+
#[napi(constructor)]
151+
pub fn new() -> Self {
152+
Self { inner: Vec::new() }
153+
}
154+
155+
#[napi]
156+
pub fn add(&mut self, gate: [<Napi $module:camel Gate>]) -> Result<()> {
157+
self.inner.push(gate.into_inner()?);
158+
Ok(())
159+
}
160+
161+
#[napi]
162+
pub fn get(&self, index: i32) -> [<Napi $module:camel Gate>] {
163+
[<Napi $module:camel Gate>]::from_inner(&self.inner[index as usize])
164+
}
165+
166+
#[napi]
167+
pub fn len(&self) -> i32 {
168+
self.inner.len() as i32
169+
}
170+
171+
#[napi]
172+
pub fn wrap(&mut self, target: NapiWire, head: NapiWire) {
173+
let row = target.row as usize;
174+
let col = target.col as usize;
175+
self.inner[row].wires[col] = KimchiWire::from(head);
176+
}
177+
178+
#[napi]
179+
pub fn digest(&self, public_input_size: i32) -> Vec<u8> {
180+
Circuit::new(public_input_size as usize, &self.inner)
181+
.digest()
182+
.to_vec()
183+
}
184+
185+
#[napi]
186+
pub fn serialize(&self, public_input_size: i32) -> Result<String> {
187+
let circuit = Circuit::new(public_input_size as usize, &self.inner);
188+
serde_json::to_string(&circuit).map_err(|err| {
189+
Error::new(
190+
Status::GenericFailure,
191+
format!("failed to serialize circuit: {}", err),
192+
)
193+
})
194+
}
195+
}
196+
197+
#[napi]
198+
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_create>]() -> [<Napi $module:camel GateVector>] {
199+
[<Napi $module:camel GateVector>]::new()
200+
}
201+
202+
#[napi]
203+
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_add>](
204+
vector: &mut [<Napi $module:camel GateVector>],
205+
gate: [<Napi $module:camel Gate>],
206+
) -> Result<()> {
207+
vector.add(gate)
208+
}
209+
210+
#[napi]
211+
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_get>](
212+
vector: &[<Napi $module:camel GateVector>],
213+
index: i32,
214+
) -> [<Napi $module:camel Gate>] {
215+
vector.get(index)
216+
}
217+
218+
#[napi]
219+
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_len>](
220+
vector: &[<Napi $module:camel GateVector>],
221+
) -> i32 {
222+
vector.len()
223+
}
224+
225+
#[napi]
226+
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_wrap>](
227+
vector: &mut [<Napi $module:camel GateVector>],
228+
target: NapiWire,
229+
head: NapiWire,
230+
) {
231+
vector.wrap(target, head);
232+
}
233+
234+
#[napi]
235+
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_digest>](
236+
public_input_size: i32,
237+
vector: &[<Napi $module:camel GateVector>],
238+
) -> Vec<u8> {
239+
vector.digest(public_input_size)
240+
}
241+
242+
#[napi]
243+
pub fn [<caml_pasta_ $module:snake _plonk_circuit_serialize>](
244+
public_input_size: i32,
245+
vector: &[<Napi $module:camel GateVector>],
246+
) -> Result<String> {
247+
vector.serialize(public_input_size)
248+
}
249+
}
250+
};
251+
}
252+
253+
impl_gate_support!(fp, Fp, WasmPastaFp);
254+
impl_gate_support!(fq, Fq, WasmPastaFq);

plonk-napi/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
pub(crate) mod gate_vector;
2+
pub(crate) mod poly_comm;
13
pub(crate) mod poseidon;
2-
pub(crate) mod wrappers;
34
pub(crate) mod wasm_vector;
4-
pub(crate) mod poly_comm;
5+
pub(crate) mod wrappers;
56

67
pub use poseidon::{
78
caml_pasta_fp_poseidon_block_cipher,
@@ -10,4 +11,4 @@ pub use poseidon::{
1011

1112
pub use wrappers::group::{WasmGPallas, WasmGVesta};
1213
pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq};
13-
pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm};
14+
pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm};

0 commit comments

Comments
 (0)