Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions plonk-napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ arkworks.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
Expand All @@ -37,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

Expand Down
254 changes: 254 additions & 0 deletions plonk-napi/src/gate_vector.rs
Original file line number Diff line number Diff line change
@@ -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<GateType> {
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 [<Napi $module:camel Gate>] {
pub typ: i32,
pub wires: NapiGateWires,
pub coeffs: Vec<u8>,
}

impl [<Napi $module:camel Gate>] {
fn into_inner(self) -> Result<CircuitGate<$field>> {
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 $module:camel GateVector>] {
#[napi(skip)]
pub inner: Vec<CircuitGate<$field>>,
}

#[napi]
impl [<Napi $module:camel GateVector>] {
#[napi(constructor)]
pub fn new() -> Self {
Self { inner: Vec::new() }
}

#[napi]
pub fn add(&mut self, gate: [<Napi $module:camel Gate>]) -> Result<()> {
self.inner.push(gate.into_inner()?);
Ok(())
}

#[napi]
pub fn get(&self, index: i32) -> [<Napi $module:camel Gate>] {
[<Napi $module:camel Gate>]::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<u8> {
Circuit::new(public_input_size as usize, &self.inner)
.digest()
.to_vec()
}

#[napi]
pub fn serialize(&self, public_input_size: i32) -> Result<String> {
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 [<caml_pasta_ $module:snake _plonk_gate_vector_create>]() -> [<Napi $module:camel GateVector>] {
[<Napi $module:camel GateVector>]::new()
}

#[napi]
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_add>](
vector: &mut [<Napi $module:camel GateVector>],
gate: [<Napi $module:camel Gate>],
) -> Result<()> {
vector.add(gate)
}

#[napi]
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_get>](
vector: &[<Napi $module:camel GateVector>],
index: i32,
) -> [<Napi $module:camel Gate>] {
vector.get(index)
}

#[napi]
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_len>](
vector: &[<Napi $module:camel GateVector>],
) -> i32 {
vector.len()
}

#[napi]
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_wrap>](
vector: &mut [<Napi $module:camel GateVector>],
target: NapiWire,
head: NapiWire,
) {
vector.wrap(target, head);
}

#[napi]
pub fn [<caml_pasta_ $module:snake _plonk_gate_vector_digest>](
public_input_size: i32,
vector: &[<Napi $module:camel GateVector>],
) -> Vec<u8> {
vector.digest(public_input_size)
}

#[napi]
pub fn [<caml_pasta_ $module:snake _plonk_circuit_serialize>](
public_input_size: i32,
vector: &[<Napi $module:camel GateVector>],
) -> Result<String> {
vector.serialize(public_input_size)
}
}
};
}

impl_gate_support!(fp, Fp, WasmPastaFp);
impl_gate_support!(fq, Fq, WasmPastaFq);
7 changes: 4 additions & 3 deletions plonk-napi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
pub(crate) mod gate_vector;
pub(crate) mod poly_comm;
pub(crate) mod poseidon;
pub(crate) mod wrappers;
pub(crate) mod wasm_vector;
pub(crate) mod poly_comm;
pub(crate) mod wrappers;

pub use poseidon::{
caml_pasta_fp_poseidon_block_cipher,
Expand All @@ -10,4 +11,4 @@ pub use poseidon::{

pub use wrappers::group::{WasmGPallas, WasmGVesta};
pub use wasm_vector::{fp::WasmVecVecFp, fq::WasmVecVecFq};
pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm};
pub use poly_comm::{pallas::WasmFqPolyComm, vesta::WasmFpPolyComm};
63 changes: 63 additions & 0 deletions plonk-napi/src/wrappers/feature_flags.rs
Original file line number Diff line number Diff line change
@@ -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<KimchiFeatureFlags> 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<NapiFeatureFlags> 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,
},
}
}
}
Loading
Loading