diff --git a/Cargo.toml b/Cargo.toml index 0a15665..fb9de8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,8 @@ anyhow = { version = "1.0.40", default-features = false } itertools = { version = "0.10.0", default-features = false } plonky2_maybe_rayon = { version = "0.1.0", default-features = false } num = { version = "0.4.0", default-features = false } -plonky2 = { version = "0.1.2", default-features = false } -plonky2_u32 = { version = "0.1.0", default-features = false } +plonky2 = { version = "0.1.4", default-features = false } +plonky2_u32 = { git = "https://github.com/mir-protocol/plonky2-u32" } serde = { version = "1.0", default-features = false, features = ["derive"] } [dev-dependencies] diff --git a/src/gadgets/biguint.rs b/src/gadgets/biguint.rs index 59e48d0..3a194ae 100644 --- a/src/gadgets/biguint.rs +++ b/src/gadgets/biguint.rs @@ -1,6 +1,8 @@ use alloc::vec; -use alloc::vec::Vec; +use alloc::{string::String, vec::Vec}; use core::marker::PhantomData; +use plonky2::plonk::circuit_data::CommonCircuitData; +use plonky2::util::serialization::{Buffer, IoResult}; use num::{BigUint, Integer, Zero}; use plonky2::field::extension::Extendable; @@ -14,6 +16,8 @@ use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target}; use plonky2_u32::gadgets::multiple_comparison::list_le_u32_circuit; use plonky2_u32::witness::{GeneratedValuesU32, WitnessU32}; +use crate::serialization::{ReadBigUintTarget, WriteBigUintTarget}; + #[derive(Clone, Debug)] pub struct BigUintTarget { pub limbs: Vec, @@ -322,7 +326,7 @@ struct BigUintDivRemGenerator, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for BigUintDivRemGenerator { fn dependencies(&self) -> Vec { @@ -342,6 +346,35 @@ impl, const D: usize> SimpleGenerator out_buffer.set_biguint_target(&self.div, &div); out_buffer.set_biguint_target(&self.rem, &rem); } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let a = src.read_biguint_target()?; + let b = src.read_biguint_target()?; + let div = src.read_biguint_target()?; + let rem = src.read_biguint_target()?; + Ok(Self { + a, + b, + div, + rem, + _phantom: PhantomData, + }) + } + + fn id(&self) -> String { + String::from("BigUintDivRemGenerator") + } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_biguint_target(self.a.clone())?; + dst.write_biguint_target(self.b.clone())?; + dst.write_biguint_target(self.div.clone())?; + dst.write_biguint_target(self.rem.clone())?; + Ok(()) + } } #[cfg(test)] diff --git a/src/gadgets/glv.rs b/src/gadgets/glv.rs index 8ffa9c8..61fe6ab 100644 --- a/src/gadgets/glv.rs +++ b/src/gadgets/glv.rs @@ -1,5 +1,7 @@ -use alloc::vec::Vec; +use alloc::{string::String, vec::Vec}; use core::marker::PhantomData; +use plonky2::plonk::circuit_data::CommonCircuitData; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use plonky2::field::extension::Extendable; use plonky2::field::secp256k1_base::Secp256K1Base; @@ -17,6 +19,7 @@ use crate::gadgets::biguint::{GeneratedValuesBigUint, WitnessBigUint}; use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve}; use crate::gadgets::curve_msm::curve_msm_circuit; use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget}; +use crate::serialization::{ReadBigUintTarget, WriteBigUintTarget}; pub trait CircuitBuilderGlv, const D: usize> { fn secp256k1_glv_beta(&mut self) -> NonNativeTarget; @@ -109,7 +112,7 @@ struct GLVDecompositionGenerator, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for GLVDecompositionGenerator { fn dependencies(&self) -> Vec { @@ -128,6 +131,48 @@ impl, const D: usize> SimpleGenerator out_buffer.set_bool_target(self.k1_neg, k1_neg); out_buffer.set_bool_target(self.k2_neg, k2_neg); } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let k = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let k1 = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let k2 = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let k1_neg = BoolTarget::new_unsafe(src.read_target()?); + let k2_neg = BoolTarget::new_unsafe(src.read_target()?); + + Ok(Self { + k, + k1, + k2, + k1_neg, + k2_neg, + _phantom: PhantomData, + }) + } + + fn id(&self) -> String { + String::from("GLVDecompositionGenerator") + } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_biguint_target(self.k.value.clone())?; + dst.write_biguint_target(self.k1.value.clone())?; + dst.write_biguint_target(self.k2.value.clone())?; + dst.write_target_bool(self.k1_neg)?; + dst.write_target_bool(self.k2_neg)?; + Ok(()) + } } #[cfg(test)] diff --git a/src/gadgets/nonnative.rs b/src/gadgets/nonnative.rs index f1c8f03..92cca71 100644 --- a/src/gadgets/nonnative.rs +++ b/src/gadgets/nonnative.rs @@ -1,6 +1,9 @@ use alloc::vec; -use alloc::vec::Vec; +use alloc::{string::String, vec::Vec}; use core::marker::PhantomData; +use plonky2::plonk::circuit_data::CommonCircuitData; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; +use plonky2_u32::serialization::ReadU32; use num::{BigUint, Integer, One, Zero}; use plonky2::field::extension::Extendable; @@ -18,6 +21,7 @@ use plonky2_u32::witness::GeneratedValuesU32; use crate::gadgets::biguint::{ BigUintTarget, CircuitBuilderBiguint, GeneratedValuesBigUint, WitnessBigUint, }; +use crate::serialization::{ReadBigUintTarget, WriteBigUintTarget}; #[derive(Clone, Debug)] pub struct NonNativeTarget { @@ -454,7 +458,7 @@ struct NonNativeAdditionGenerator, const D: usize, _phantom: PhantomData, } -impl, const D: usize, FF: PrimeField> SimpleGenerator +impl, const D: usize, FF: PrimeField> SimpleGenerator for NonNativeAdditionGenerator { fn dependencies(&self) -> Vec { @@ -484,6 +488,47 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat out_buffer.set_biguint_target(&self.sum.value, &sum_reduced); out_buffer.set_bool_target(self.overflow, overflow); } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let a = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let b = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let sum = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let overflow = BoolTarget::new_unsafe(src.read_target()?); + + Ok(Self { + a, + b, + sum, + overflow, + _phantom: PhantomData, + }) + } + + fn id(&self) -> String { + String::from("NonNativeAdditionGenerator") + } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_biguint_target(self.a.value.clone())?; + dst.write_biguint_target(self.b.value.clone())?; + + dst.write_biguint_target(self.sum.value.clone())?; + dst.write_target_bool(self.overflow)?; + + Ok(()) + } } #[derive(Debug)] @@ -495,7 +540,7 @@ struct NonNativeMultipleAddsGenerator, const D: usi _phantom: PhantomData, } -impl, const D: usize, FF: PrimeField> SimpleGenerator +impl, const D: usize, FF: PrimeField> SimpleGenerator for NonNativeMultipleAddsGenerator { fn dependencies(&self) -> Vec { @@ -529,6 +574,52 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat out_buffer.set_biguint_target(&self.sum.value, &sum_reduced); out_buffer.set_u32_target(self.overflow, overflow); } + + fn deserialize(src: &mut Buffer<'_>, _common_data: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let mut summands_len_be = [0u8; 8]; + for i in 0..8 { + summands_len_be[i] = src.read_u8()?; + } + let summands_len = usize::from_be_bytes(summands_len_be); + let mut summands = vec![]; + for _ in 0..summands_len { + summands.push(NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }); + } + let sum = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let overflow = src.read_target_u32()?; + Ok(Self { + summands, + sum, + overflow, + _phantom: PhantomData, + }) + } + + fn id(&self) -> String { + String::from("NonNativeMultipleAddsGenerator") + } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + let summands_len = self.summands.len(); + let summands_len_be = summands_len.to_be_bytes(); + for byte in summands_len_be { + dst.write_u8(byte)? + } + for i in 0..summands_len { + dst.write_biguint_target(self.summands[i].value.clone())?; + } + dst.write_biguint_target(self.sum.value.clone())?; + Ok(()) + } } #[derive(Debug)] @@ -540,7 +631,7 @@ struct NonNativeSubtractionGenerator, const D: usiz _phantom: PhantomData, } -impl, const D: usize, FF: PrimeField> SimpleGenerator +impl, const D: usize, FF: PrimeField> SimpleGenerator for NonNativeSubtractionGenerator { fn dependencies(&self) -> Vec { @@ -570,6 +661,44 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat out_buffer.set_biguint_target(&self.diff.value, &diff_biguint); out_buffer.set_bool_target(self.overflow, overflow); } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let a = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let b = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let diff = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let overflow = src.read_target_bool()?; + Ok(Self { + a, + b, + diff, + overflow, + _phantom: PhantomData, + }) + } + + fn id(&self) -> String { + String::from("NonNativeSubtractionGenerator") + } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_biguint_target(self.a.value.clone())?; + dst.write_biguint_target(self.b.value.clone())?; + dst.write_biguint_target(self.diff.value.clone())?; + dst.write_target_bool(self.overflow)?; + Ok(()) + } } #[derive(Debug)] @@ -581,7 +710,7 @@ struct NonNativeMultiplicationGenerator, const D: u _phantom: PhantomData, } -impl, const D: usize, FF: PrimeField> SimpleGenerator +impl, const D: usize, FF: PrimeField> SimpleGenerator for NonNativeMultiplicationGenerator { fn dependencies(&self) -> Vec { @@ -609,6 +738,45 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat out_buffer.set_biguint_target(&self.prod.value, &prod_reduced); out_buffer.set_biguint_target(&self.overflow, &overflow_biguint); } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let a = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let b = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let prod = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let overflow = src.read_biguint_target()?; + Ok(Self { + a, + b, + prod, + overflow, + _phantom: PhantomData, + }) + } + + fn id(&self) -> String { + String::from("NonNativeMultiplicationGenerator") + } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_biguint_target(self.a.value.clone())?; + dst.write_biguint_target(self.b.value.clone())?; + dst.write_biguint_target(self.prod.value.clone())?; + dst.write_biguint_target(self.overflow.clone())?; + + Ok(()) + } } #[derive(Debug)] @@ -619,7 +787,7 @@ struct NonNativeInverseGenerator, const D: usize, F _phantom: PhantomData, } -impl, const D: usize, FF: PrimeField> SimpleGenerator +impl, const D: usize, FF: PrimeField> SimpleGenerator for NonNativeInverseGenerator { fn dependencies(&self) -> Vec { @@ -639,6 +807,36 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat out_buffer.set_biguint_target(&self.div, &div); out_buffer.set_biguint_target(&self.inv, &inv_biguint); } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let x = NonNativeTarget { + value: src.read_biguint_target()?, + _phantom: PhantomData, + }; + let inv = src.read_biguint_target()?; + let div = src.read_biguint_target()?; + Ok(Self { + x, + inv, + div, + _phantom: PhantomData, + }) + } + + fn id(&self) -> String { + String::from("NonNativeInverseGenerator") + } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_biguint_target(self.x.value.clone())?; + dst.write_biguint_target(self.div.clone())?; + dst.write_biguint_target(self.inv.clone())?; + + Ok(()) + } } #[cfg(test)] diff --git a/src/lib.rs b/src/lib.rs index bf84913..cbf0899 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,3 +5,5 @@ extern crate alloc; pub mod curve; pub mod gadgets; + +mod serialization; diff --git a/src/serialization.rs b/src/serialization.rs new file mode 100644 index 0000000..6ef6ac5 --- /dev/null +++ b/src/serialization.rs @@ -0,0 +1,89 @@ +use alloc::vec::Vec; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; +use plonky2_u32::serialization::{ReadU32, WriteU32}; + +use crate::gadgets::biguint::BigUintTarget; + +pub trait WriteBigUintTarget { + fn write_biguint_target(&mut self, biguint_target: BigUintTarget) -> IoResult<()>; +} + +impl WriteBigUintTarget for Vec { + fn write_biguint_target(&mut self, biguint_target: BigUintTarget) -> IoResult<()> { + let num_limbs = biguint_target.num_limbs(); + let num_limbs_be = num_limbs.to_be_bytes(); + for byte in &num_limbs_be { + self.write_u8(*byte)? + } + for limb in &biguint_target.limbs { + self.write_target_u32(*limb)?; + } + + Ok(()) + } +} + +pub trait ReadBigUintTarget { + fn read_biguint_target(&mut self) -> IoResult; +} + +impl ReadBigUintTarget for Buffer<'_> { + fn read_biguint_target(&mut self) -> IoResult { + let mut num_limbs_be = [0_u8; core::mem::size_of::()]; + + self.read_exact(&mut num_limbs_be)?; + + let num_limbs = usize::from_be_bytes(num_limbs_be); + let mut limbs = Vec::new(); + + for _ in 0..num_limbs { + let limb = self.read_target_u32()?; + limbs.push(limb) + } + + Ok(BigUintTarget { limbs }) + } +} + +#[cfg(test)] +mod tests { + use plonky2::iop::{target::Target, wire::Wire}; + use plonky2_u32::gadgets::arithmetic_u32::U32Target; + + use super::*; + + #[test] + fn test_read_write_biguint_target() { + let biguint_target = BigUintTarget { + limbs: vec![ + U32Target(Target::VirtualTarget { index: 0 }), + U32Target(Target::Wire(Wire { row: 0, column: 0 })), + ], + }; + let mut buff = vec![]; + buff.write_biguint_target(biguint_target.clone()) + .expect("Failed to write `BigUintTarget`"); + + let mut len_bytes = [0u8; core::mem::size_of::()]; + len_bytes.copy_from_slice(&buff[0..core::mem::size_of::()]); + assert_eq!(usize::from_be_bytes(len_bytes), 2); + + let mut buff = Buffer::new(&buff); + let expected_biguint_target = buff + .read_biguint_target() + .expect("Failed to read `BigUintTarget`"); + + assert_eq!( + biguint_target.limbs.len(), + expected_biguint_target.limbs.len() + ); + + for (limb, expected_limb) in biguint_target + .limbs + .iter() + .zip(expected_biguint_target.limbs) + { + assert_eq!(limb.0, expected_limb.0); + } + } +}