diff --git a/src/hash/merkle_utils.rs b/src/hash/merkle_utils.rs index c37dde5..bc88250 100644 --- a/src/hash/merkle_utils.rs +++ b/src/hash/merkle_utils.rs @@ -2,7 +2,11 @@ use plonky2::hash::hash_types::RichField; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use super::{sha256::WitnessHashSha2, sha256_merkle::{MerkleProofSha256Gadget, DeltaMerkleProofSha256Gadget}, WitnessHash}; +use super::{ + sha256::WitnessHashSha2, + sha256_merkle::{DeltaMerkleProofSha256Gadget, MerkleProofSha256Gadget}, + WitnessHash, +}; #[serde_as] #[derive(Serialize, Deserialize, PartialEq, Clone, Copy)] @@ -102,8 +106,6 @@ impl MerkleProofSha256Gadget { } } - - impl DeltaMerkleProofSha256Gadget { pub fn set_witness_from_proof>( &self, diff --git a/src/hash/mod.rs b/src/hash/mod.rs index 90db853..f7fb0bd 100644 --- a/src/hash/mod.rs +++ b/src/hash/mod.rs @@ -4,4 +4,4 @@ pub mod types; pub use types::*; pub mod merkle_utils; -pub mod sha256_merkle; \ No newline at end of file +pub mod sha256_merkle; diff --git a/src/hash/sha256.rs b/src/hash/sha256.rs index 1293270..8639fcf 100644 --- a/src/hash/sha256.rs +++ b/src/hash/sha256.rs @@ -324,29 +324,15 @@ impl, const D: usize> CircuitBuilderHashSha2 state[5] = self.add_u32_lo(state[5], f); state[6] = self.add_u32_lo(state[6], g); state[7] = self.add_u32_lo(state[7], h); - + // round 2 let zero = self.constant_u32(0); let cx80 = self.constant_u32(0x80000000); let c512 = self.constant_u32(512); let mut w: [U32Target; 16] = [ - cx80, - zero, - zero, - zero, - zero, - zero, - zero, - zero, - zero, - zero, - zero, - zero, - zero, - zero, - zero, - c512, + cx80, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, + zero, c512, ]; // Initialize working variables to current hash value @@ -410,76 +396,75 @@ mod tests { use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use sha2::{Digest, Sha256}; + use crate::hash::merkle_utils::Hash256; use crate::hash::sha256::{CircuitBuilderHashSha2, WitnessHashSha2}; use crate::hash::{CircuitBuilderHash, WitnessHash}; - use crate::hash::merkle_utils::{Hash256}; const SHA256_BLOCK: usize = 512; #[test] fn test_sha256_two_to_one() { - let tests = [ [ - "44205ea3a71ee1cbd02eef7b084a409450c21d11a3b41769f02bb3e2dd89d5e2", - "8ecf785b86dd1715d4c193f280a118b82200742f102bf1e59a4a65194a126f03", - "a452e23aab1e4baae2e3da7c66da43954038e6505dc5b1cb24c8b5d95cf7634c" + "44205ea3a71ee1cbd02eef7b084a409450c21d11a3b41769f02bb3e2dd89d5e2", + "8ecf785b86dd1715d4c193f280a118b82200742f102bf1e59a4a65194a126f03", + "a452e23aab1e4baae2e3da7c66da43954038e6505dc5b1cb24c8b5d95cf7634c", ], [ - "42f584ee07afb6754770ea07fc7f498cb7200ba89eb67361a7f2564612040cd3", - "09e0ed078a0113619c033eec41b65e3168394dc377998bc13481b5f1942f7119", - "2096622ca7f5aeda8d4c9a9cd4523e1bb9ea09e661f092f515c0c2cbaadcc2c6" + "42f584ee07afb6754770ea07fc7f498cb7200ba89eb67361a7f2564612040cd3", + "09e0ed078a0113619c033eec41b65e3168394dc377998bc13481b5f1942f7119", + "2096622ca7f5aeda8d4c9a9cd4523e1bb9ea09e661f092f515c0c2cbaadcc2c6", ], [ - "8560e7d4c6e014b01b70bf5e1e2ffaa1e4115c9d21eb685b796b172872b71150", - "3d38f5e8fc6c4612f27932b009bea0fd41a99c30af7a14a1e5316d9bbd5a4df6", - "eab6fce22d0679c304d7419cf0746552921b31245d715171a5ec7c9caf81f084" + "8560e7d4c6e014b01b70bf5e1e2ffaa1e4115c9d21eb685b796b172872b71150", + "3d38f5e8fc6c4612f27932b009bea0fd41a99c30af7a14a1e5316d9bbd5a4df6", + "eab6fce22d0679c304d7419cf0746552921b31245d715171a5ec7c9caf81f084", ], [ - "7c909a4734e36fd67e11cd97a9a4222795672690f3eb081a2dd43a413ba6490c", - "39a08a837c5bfef00ebb6e3b72f7fc5a8275f13fb5d5a86f03541ebf5ee8edec", - "f537f1e2ac17a2af3524b7e3fc81ca88adcee65906236dab22250e071924e527" + "7c909a4734e36fd67e11cd97a9a4222795672690f3eb081a2dd43a413ba6490c", + "39a08a837c5bfef00ebb6e3b72f7fc5a8275f13fb5d5a86f03541ebf5ee8edec", + "f537f1e2ac17a2af3524b7e3fc81ca88adcee65906236dab22250e071924e527", ], [ - "130151db7ac8036300c80c58a37de8119719ce60600b6e009d09df3a71d5f741", - "a6bf923dbbcaae29701d82e0a1492ffe388aa14bd3e6ffbfa834aa9b23ad154a", - "e70822e27d35acff57fc210d451aba171285025ac2fa77911e893427a8430b25" + "130151db7ac8036300c80c58a37de8119719ce60600b6e009d09df3a71d5f741", + "a6bf923dbbcaae29701d82e0a1492ffe388aa14bd3e6ffbfa834aa9b23ad154a", + "e70822e27d35acff57fc210d451aba171285025ac2fa77911e893427a8430b25", ], [ - "9992ff1b7ff438d5132b2b5ddd875c10ca62bcb46f681ef228548abdcd6db5c1", - "4080eca86a5ea164518fc7426dc793ce5c9f95831bc8a97b2f06bc53722c78bb", - "1bdbe0e67971989362b44c66f7ff26eea7d6c7f5f791d91e96bfa46a6934b97b" + "9992ff1b7ff438d5132b2b5ddd875c10ca62bcb46f681ef228548abdcd6db5c1", + "4080eca86a5ea164518fc7426dc793ce5c9f95831bc8a97b2f06bc53722c78bb", + "1bdbe0e67971989362b44c66f7ff26eea7d6c7f5f791d91e96bfa46a6934b97b", ], [ - "2a6f3577676eb6493d62268cf402f39f432490f8ca64d2323eab7ffb8fa5e239", - "a004b81f69f9b6694fad09f0193e9120789d4e870681f436a97a2eef9089a3e2", - "3dd8900540834a3fe28407796f128a21dd4c947b6b991ed14d6167ae4fc29cc3" + "2a6f3577676eb6493d62268cf402f39f432490f8ca64d2323eab7ffb8fa5e239", + "a004b81f69f9b6694fad09f0193e9120789d4e870681f436a97a2eef9089a3e2", + "3dd8900540834a3fe28407796f128a21dd4c947b6b991ed14d6167ae4fc29cc3", ], [ - "7b4e5361bddc8029f76c3fead78e0a0a49e02dd40666cdff03ea40609de3c8d9", - "bf7b76a80a3a70151640263f13bb62f72d66f0075f03b64e51aaec781b36d8c9", - "809cf278ede0e210b29e7ce57b12a058d5d1f78be62a16df0c301995be7e7a5d" + "7b4e5361bddc8029f76c3fead78e0a0a49e02dd40666cdff03ea40609de3c8d9", + "bf7b76a80a3a70151640263f13bb62f72d66f0075f03b64e51aaec781b36d8c9", + "809cf278ede0e210b29e7ce57b12a058d5d1f78be62a16df0c301995be7e7a5d", ], [ - "a52ae0c843df054f6a9489a743f293a74b7fe21f14bff5d35e9c9ec4fe336522", - "e3e6379804432520b7eba2a7b46d0b016a4025f32da7cb8aa0003aaf57dab15c", - "f56647e8f500efaafe8aaaf9a90b142685896cba145a06a6bc9853d9765079b8" + "a52ae0c843df054f6a9489a743f293a74b7fe21f14bff5d35e9c9ec4fe336522", + "e3e6379804432520b7eba2a7b46d0b016a4025f32da7cb8aa0003aaf57dab15c", + "f56647e8f500efaafe8aaaf9a90b142685896cba145a06a6bc9853d9765079b8", ], [ - "386d9d8e6851f030ac2f510b6a8ebcc2f00e16a9cc7b7707d7d65f8a95ae82f3", - "bb2b56422cd46210f5ab0c53527e8bf7ef71ad723a77a2cba0d990da15c9bde8", - "d4d029cc7fbc6eba897d5659bb4d0298f9d3609c383526de67ab15b26fa95ad2" + "386d9d8e6851f030ac2f510b6a8ebcc2f00e16a9cc7b7707d7d65f8a95ae82f3", + "bb2b56422cd46210f5ab0c53527e8bf7ef71ad723a77a2cba0d990da15c9bde8", + "d4d029cc7fbc6eba897d5659bb4d0298f9d3609c383526de67ab15b26fa95ad2", ], [ - "6e326b458d8bbef8b5a592e939d8bfa2dffb769a5f616034fb0cbf1267d4a600", - "d5b60f7116771c9033a32bd2ccd22912d97bd3cf30d526fdcaff9f1bc9453397", - "6c915b5095aca9df36491281c04a4f127b9fd81b4362742f07314d945b44582a" + "6e326b458d8bbef8b5a592e939d8bfa2dffb769a5f616034fb0cbf1267d4a600", + "d5b60f7116771c9033a32bd2ccd22912d97bd3cf30d526fdcaff9f1bc9453397", + "6c915b5095aca9df36491281c04a4f127b9fd81b4362742f07314d945b44582a", ], [ - "4af3eaf1108b48e0df66988876570f2044db09a0cad061da7d2448871fc52cb6", - "cf5c4c57391fa60fbd613b2bdd5ddb5da9435239d073f2cdd265d0788e0b9cec", - "54a342f852b7d41a5aab4a6a73cfc9adbc3b5fc42303627dbd604eede98e334f" - ] - ]; + "4af3eaf1108b48e0df66988876570f2044db09a0cad061da7d2448871fc52cb6", + "cf5c4c57391fa60fbd613b2bdd5ddb5da9435239d073f2cdd265d0788e0b9cec", + "54a342f852b7d41a5aab4a6a73cfc9adbc3b5fc42303627dbd604eede98e334f", + ], + ]; // build circuit once const D: usize = 2; @@ -493,7 +478,7 @@ mod tests { let expected_output_target = builder.add_virtual_hash256_target(); let output_target = builder.two_to_one_sha256(left_target, right_target); builder.connect_hash256(output_target, expected_output_target); - + let num_gates = builder.num_gates(); // let copy_constraints = builder.copy_constraints.len(); let copy_constraints = ""; @@ -503,21 +488,17 @@ mod tests { num_gates, copy_constraints, data.common.quotient_degree_factor ); - - for t in tests { let left = Hash256::from_str(t[0]).unwrap(); let right = Hash256::from_str(t[1]).unwrap(); let expected_output = Hash256::from_str(t[2]).unwrap(); - - // test circuit let mut pw = PartialWitness::new(); pw.set_hash256_target(&left_target, &left.0); pw.set_hash256_target(&right_target, &right.0); pw.set_hash256_target(&expected_output_target, &expected_output.0); - + let proof = data.prove(pw).unwrap(); // println!("sha256 proof.public_inputs =\n{:08x?}", proof.public_inputs); assert!(data.verify(proof).is_ok()); diff --git a/src/hash/sha256_merkle.rs b/src/hash/sha256_merkle.rs index 92d24a9..4b8c6d2 100644 --- a/src/hash/sha256_merkle.rs +++ b/src/hash/sha256_merkle.rs @@ -144,9 +144,9 @@ impl DeltaMerkleProofSha256Gadget { #[cfg(test)] mod tests { + use crate::hash::merkle_utils::{DeltaMerkleProof256, MerkleProof256}; + use crate::hash::sha256_merkle::{DeltaMerkleProofSha256Gadget, MerkleProofSha256Gadget}; use crate::hash::{CircuitBuilderHash, WitnessHash}; - use crate::hash::merkle_utils::{MerkleProof256, DeltaMerkleProof256}; - use crate::hash::sha256_merkle::{MerkleProofSha256Gadget, DeltaMerkleProofSha256Gadget}; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; @@ -223,33 +223,32 @@ mod tests { assert!(data.verify(proof).is_ok()); } - #[test] fn test_verify_small_delta_merkle_proof() { - // build circuit once - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - let merkle_proof_gadget = DeltaMerkleProofSha256Gadget::add_virtual_to(&mut builder, 3); - let expected_old_root_target = builder.add_virtual_hash256_target(); - let expected_new_root_target = builder.add_virtual_hash256_target(); - builder.connect_hash256(expected_old_root_target, merkle_proof_gadget.old_root); - builder.connect_hash256(expected_new_root_target, merkle_proof_gadget.new_root); - - let num_gates = builder.num_gates(); - // let copy_constraints = builder.copy_constraints.len(); - let data = builder.build::(); - println!( - "circuit num_gates={}, quotient_degree_factor={}", - num_gates, data.common.quotient_degree_factor - ); - - let mut pw = PartialWitness::new(); - let proof_serialized = r#" + // build circuit once + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + let merkle_proof_gadget = DeltaMerkleProofSha256Gadget::add_virtual_to(&mut builder, 3); + let expected_old_root_target = builder.add_virtual_hash256_target(); + let expected_new_root_target = builder.add_virtual_hash256_target(); + builder.connect_hash256(expected_old_root_target, merkle_proof_gadget.old_root); + builder.connect_hash256(expected_new_root_target, merkle_proof_gadget.new_root); + + let num_gates = builder.num_gates(); + // let copy_constraints = builder.copy_constraints.len(); + let data = builder.build::(); + println!( + "circuit num_gates={}, quotient_degree_factor={}", + num_gates, data.common.quotient_degree_factor + ); + + let mut pw = PartialWitness::new(); + let proof_serialized = r#" { "index": 5, "siblings": [ @@ -263,17 +262,16 @@ mod tests { "new_root": "c7d129a209e40611a4cc44632f38c6fd577b4329c27dae5a651d2f67c715a618" } "#; - let proof = - serde_json::from_str::(proof_serialized).unwrap(); - merkle_proof_gadget.set_witness_from_proof(&mut pw, &proof); - pw.set_hash256_target(&expected_old_root_target, &proof.old_root.0); - pw.set_hash256_target(&expected_new_root_target, &proof.new_root.0); - - let start_time = std::time::Instant::now(); - - let proof = data.prove(pw).unwrap(); - let duration_ms = start_time.elapsed().as_millis(); - println!("proved in {}ms", duration_ms); - assert!(data.verify(proof).is_ok()); + let proof = serde_json::from_str::(proof_serialized).unwrap(); + merkle_proof_gadget.set_witness_from_proof(&mut pw, &proof); + pw.set_hash256_target(&expected_old_root_target, &proof.old_root.0); + pw.set_hash256_target(&expected_new_root_target, &proof.new_root.0); + + let start_time = std::time::Instant::now(); + + let proof = data.prove(pw).unwrap(); + let duration_ms = start_time.elapsed().as_millis(); + println!("proved in {}ms", duration_ms); + assert!(data.verify(proof).is_ok()); } } diff --git a/src/hash/types.rs b/src/hash/types.rs index 3ce3043..fee37a0 100644 --- a/src/hash/types.rs +++ b/src/hash/types.rs @@ -10,8 +10,6 @@ use crate::biguint::{BigUintTarget, CircuitBuilderBiguint, WitnessBigUint}; use crate::u32::arithmetic_u32::{CircuitBuilderU32, U32Target}; use crate::u32::witness::WitnessU32; - - pub type Hash256Target = [U32Target; 8]; #[derive(Clone, Debug)] pub struct HashTarget { @@ -31,10 +29,10 @@ pub struct HashInputTarget { pub type HashOutputTarget = BigUintTarget; fn read_u32_be_at(array: &[u8], index: usize) -> u32 { - ((array[index] as u32) << 24) + - ((array[index+1] as u32) << 16) + - ((array[index+2] as u32) << 8) + - ((array[index+3] as u32) << 0) + ((array[index] as u32) << 24) + + ((array[index + 1] as u32) << 16) + + ((array[index + 2] as u32) << 8) + + ((array[index + 3] as u32) << 0) } pub trait WitnessHash: Witness { @@ -218,13 +216,12 @@ impl, const D: usize> CircuitBuilderHash hash_target } - fn add_virtual_hash256_target(&mut self) -> Hash256Target{ + fn add_virtual_hash256_target(&mut self) -> Hash256Target { [ self.add_virtual_u32_target(), self.add_virtual_u32_target(), self.add_virtual_u32_target(), self.add_virtual_u32_target(), - self.add_virtual_u32_target(), self.add_virtual_u32_target(), self.add_virtual_u32_target(), @@ -243,4 +240,3 @@ impl, const D: usize> CircuitBuilderHash self.connect_u32(x[7], y[7]); } } - diff --git a/src/nonnative/gadgets/biguint.rs b/src/nonnative/gadgets/biguint.rs index 16e25ae..658a0da 100644 --- a/src/nonnative/gadgets/biguint.rs +++ b/src/nonnative/gadgets/biguint.rs @@ -1,6 +1,9 @@ use alloc::vec; use alloc::vec::Vec; use core::marker::PhantomData; +use itertools::Itertools; +use plonky2::plonk::circuit_data::CommonCircuitData; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use num::{BigUint, Integer, Zero}; use plonky2::field::extension::Extendable; @@ -28,6 +31,16 @@ impl BigUintTarget { pub fn get_limb(&self, i: usize) -> U32Target { self.limbs[i] } + + pub fn write_to_serializer(&self, dst: &mut Vec) -> IoResult<()> { + dst.write_target_vec(&self.limbs.iter().map(|l| l.0).collect_vec()) + } + pub fn deserialize(src: &mut Buffer) -> IoResult { + let limbs = src.read_target_vec()?; + Ok(Self { + limbs: limbs.into_iter().map(U32Target).collect(), + }) + } } pub trait CircuitBuilderBiguint, const D: usize> { @@ -439,9 +452,13 @@ struct BigUintDivRemGenerator, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for BigUintDivRemGenerator { + fn id(&self) -> String { + "BigUintDivRemGenerator".to_string() + } + fn dependencies(&self) -> Vec { self.a .limbs @@ -459,6 +476,27 @@ impl, const D: usize> SimpleGenerator out_buffer.set_biguint_target(&self.div, &div); out_buffer.set_biguint_target(&self.rem, &rem); } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + self.a.write_to_serializer(dst)?; + self.b.write_to_serializer(dst)?; + self.div.write_to_serializer(dst)?; + self.rem.write_to_serializer(dst) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let a = BigUintTarget::deserialize(src)?; + let b = BigUintTarget::deserialize(src)?; + let div = BigUintTarget::deserialize(src)?; + let rem = BigUintTarget::deserialize(src)?; + Ok(Self { + a, + b, + div, + rem, + _phantom: PhantomData, + }) + } } #[cfg(test)] diff --git a/src/u32/gadgets/arithmetic_u32.rs b/src/u32/gadgets/arithmetic_u32.rs index 4f33baf..7c38c34 100644 --- a/src/u32/gadgets/arithmetic_u32.rs +++ b/src/u32/gadgets/arithmetic_u32.rs @@ -1,6 +1,8 @@ use alloc::vec; use alloc::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::hash::hash_types::RichField; @@ -11,6 +13,7 @@ use plonky2::plonk::circuit_builder::CircuitBuilder; use crate::u32::gates::add_many_u32::U32AddManyGate; use crate::u32::gates::arithmetic_u32::U32ArithmeticGate; +use crate::u32::gates::serialization::{ReadU32, WriteU32}; use crate::u32::gates::subtraction_u32::U32SubtractionGate; use crate::u32::witness::GeneratedValuesU32; @@ -244,9 +247,13 @@ struct SplitToU32Generator, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for SplitToU32Generator { + fn id(&self) -> String { + "SplitToU32Generator".to_string() + } + fn dependencies(&self) -> Vec { vec![self.x] } @@ -260,6 +267,24 @@ impl, const D: usize> SimpleGenerator out_buffer.set_u32_target(self.low, low); out_buffer.set_u32_target(self.high, high); } + + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_target(self.x)?; + dst.write_target_u32(self.low)?; + dst.write_target_u32(self.high) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let x = src.read_target()?; + let low = src.read_target_u32()?; + let high = src.read_target_u32()?; + Ok(Self { + x, + low, + high, + _phantom: PhantomData, + }) + } } #[cfg(test)] diff --git a/src/u32/gates/add_many_u32.rs b/src/u32/gates/add_many_u32.rs index ba31ce7..d1304f5 100644 --- a/src/u32/gates/add_many_u32.rs +++ b/src/u32/gates/add_many_u32.rs @@ -1,8 +1,8 @@ -use alloc::boxed::Box; use alloc::format; use alloc::string::String; use alloc::vec::Vec; use core::marker::PhantomData; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use itertools::unfold; use plonky2::field::extension::Extendable; @@ -11,12 +11,12 @@ use plonky2::gates::gate::Gate; use plonky2::gates::util::StridedConstraintConsumer; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGeneratorRef}; use plonky2::iop::target::Target; use plonky2::iop::wire::Wire; use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; use plonky2::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use plonky2::util::ceil_div_usize; @@ -91,6 +91,21 @@ impl, const D: usize> Gate for U32AddManyGate format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_addends)?; + dst.write_usize(self.num_ops) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let num_addends = src.read_usize()?; + let num_ops = src.read_usize()?; + Ok(Self { + num_addends, + num_ops, + _phantom: PhantomData, + }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = Vec::with_capacity(self.num_constraints()); for i in 0..self.num_ops { @@ -236,10 +251,10 @@ impl, const D: usize> Gate for U32AddManyGate constraints } - fn generators(&self, row: usize, _local_constants: &[F]) -> Vec>> { + fn generators(&self, row: usize, _local_constants: &[F]) -> Vec> { (0..self.num_ops) .map(|i| { - let g: Box> = Box::new( + WitnessGeneratorRef::new( U32AddManyGenerator { gate: *self, row, @@ -247,8 +262,7 @@ impl, const D: usize> Gate for U32AddManyGate _phantom: PhantomData, } .adapter(), - ); - g + ) }) .collect() } @@ -278,9 +292,31 @@ struct U32AddManyGenerator, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for U32AddManyGenerator { + fn id(&self) -> String { + "U32AddManyGenerator".to_string() + } + + fn serialize(&self, dst: &mut Vec, common_data: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, common_data)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i) + } + + fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData) -> IoResult { + let gate = U32AddManyGate::deserialize(src, common_data)?; + let row = src.read_usize()?; + let i = src.read_usize()?; + Ok(Self { + gate, + row, + i, + _phantom: PhantomData, + }) + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); diff --git a/src/u32/gates/arithmetic_u32.rs b/src/u32/gates/arithmetic_u32.rs index c65b32a..447cc59 100644 --- a/src/u32/gates/arithmetic_u32.rs +++ b/src/u32/gates/arithmetic_u32.rs @@ -1,8 +1,8 @@ -use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use alloc::{format, vec}; use core::marker::PhantomData; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use itertools::unfold; use plonky2::field::extension::Extendable; @@ -13,12 +13,12 @@ use plonky2::gates::packed_util::PackedEvaluableBase; use plonky2::gates::util::StridedConstraintConsumer; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGeneratorRef}; use plonky2::iop::target::Target; use plonky2::iop::wire::Wire; use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, @@ -93,6 +93,18 @@ impl, const D: usize> Gate for U32ArithmeticG format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let num_ops = src.read_usize()?; + Ok(Self { + num_ops, + _phantom: PhantomData, + }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = Vec::with_capacity(self.num_constraints()); for i in 0..self.num_ops { @@ -240,10 +252,10 @@ impl, const D: usize> Gate for U32ArithmeticG constraints } - fn generators(&self, row: usize, _local_constants: &[F]) -> Vec>> { + fn generators(&self, row: usize, _local_constants: &[F]) -> Vec> { (0..self.num_ops) .map(|i| { - let g: Box> = Box::new( + WitnessGeneratorRef::new( U32ArithmeticGenerator { gate: *self, row, @@ -251,8 +263,7 @@ impl, const D: usize> Gate for U32ArithmeticG _phantom: PhantomData, } .adapter(), - ); - g + ) }) .collect() } @@ -347,9 +358,13 @@ struct U32ArithmeticGenerator, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for U32ArithmeticGenerator { + fn id(&self) -> String { + "U32ArithmeticGenerator".to_string() + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -411,6 +426,24 @@ impl, const D: usize> SimpleGenerator out_buffer.set_wire(wire, output_limb); } } + + fn serialize(&self, dst: &mut Vec, common_data: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, common_data)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i) + } + + fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData) -> IoResult { + let gate = U32ArithmeticGate::deserialize(src, common_data)?; + let row = src.read_usize()?; + let i = src.read_usize()?; + Ok(Self { + gate, + row, + i, + _phantom: PhantomData, + }) + } } #[cfg(test)] diff --git a/src/u32/gates/comparison.rs b/src/u32/gates/comparison.rs index 45eed40..4b18078 100644 --- a/src/u32/gates/comparison.rs +++ b/src/u32/gates/comparison.rs @@ -1,8 +1,9 @@ -use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use alloc::{format, 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::packed::PackedField; @@ -12,7 +13,7 @@ use plonky2::gates::packed_util::PackedEvaluableBase; use plonky2::gates::util::StridedConstraintConsumer; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGeneratorRef}; use plonky2::iop::target::Target; use plonky2::iop::wire::Wire; use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; @@ -98,6 +99,22 @@ impl, const D: usize> Gate for ComparisonGate format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_bits)?; + dst.write_usize(self.num_chunks)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let num_bits = src.read_usize()?; + let num_chunks = src.read_usize()?; + Ok(Self { + num_bits, + num_chunks, + _phantom: PhantomData, + }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = Vec::with_capacity(self.num_constraints()); @@ -287,12 +304,12 @@ impl, const D: usize> Gate for ComparisonGate constraints } - fn generators(&self, row: usize, _local_constants: &[F]) -> Vec>> { + fn generators(&self, row: usize, _local_constants: &[F]) -> Vec> { let gen = ComparisonGenerator:: { row, gate: self.clone(), }; - vec![Box::new(gen.adapter())] + vec![WitnessGeneratorRef::new(gen.adapter())] } fn num_wires(&self) -> usize { @@ -401,9 +418,13 @@ struct ComparisonGenerator, const D: usize> { gate: ComparisonGate, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for ComparisonGenerator { + fn id(&self) -> String { + "ComparisonGenerator".to_string() + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -512,6 +533,17 @@ impl, const D: usize> SimpleGenerator ); } } + + fn serialize(&self, dst: &mut Vec, common_data: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, common_data)?; + dst.write_usize(self.row) + } + + fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData) -> IoResult { + let gate = ComparisonGate::deserialize(src, common_data)?; + let row = src.read_usize()?; + Ok(Self { gate, row }) + } } #[cfg(test)] diff --git a/src/u32/gates/interleave_u32.rs b/src/u32/gates/interleave_u32.rs index 2cbc579..6b9430e 100644 --- a/src/u32/gates/interleave_u32.rs +++ b/src/u32/gates/interleave_u32.rs @@ -8,17 +8,18 @@ use plonky2::gates::packed_util::PackedEvaluableBase; use plonky2::gates::util::StridedConstraintConsumer; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGeneratorRef}; use plonky2::iop::target::Target; use plonky2::iop::wire::Wire; use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; use plonky2::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_circuit}; use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, }; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; /// Take a target x, which we assume is constrained to be a U32, and interleave it with zeroes (allows efficient XOR and AND) /// @@ -85,6 +86,15 @@ impl, const D: usize> Gate for U32InterleaveG format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let num_ops = src.read_usize()?; + Ok(Self { num_ops }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = vec![]; @@ -182,18 +192,17 @@ impl, const D: usize> Gate for U32InterleaveG self.eval_unfiltered_base_batch_packed(vars_base) } - fn generators(&self, row: usize, _local_constants: &[F]) -> Vec>> { + fn generators(&self, row: usize, _local_constants: &[F]) -> Vec> { (0..self.num_ops) .map(|i| { - let g: Box> = Box::new( + WitnessGeneratorRef::new( U32InterleaveGenerator { gate: *self, row, i, } .adapter(), - ); - g + ) }) .collect() } @@ -261,7 +270,13 @@ pub struct U32InterleaveGenerator { } // Populate the bit wires and the x_interleaved wire, given that the x wire's value has been set -impl SimpleGenerator for U32InterleaveGenerator { +impl, const D: usize> SimpleGenerator + for U32InterleaveGenerator +{ + fn id(&self) -> String { + "U32InterleaveGenerator".to_string() + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -298,6 +313,19 @@ impl SimpleGenerator for U32InterleaveGenerator { let x_interleaved_wire = local_wire(self.gate.wire_ith_x_interleaved(self.i)); out_buffer.set_wire(x_interleaved_wire, F::from_canonical_u64(x_interleaved)); } + + fn serialize(&self, dst: &mut Vec, common_data: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, common_data)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i) + } + + fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData) -> IoResult { + let gate = U32InterleaveGate::deserialize(src, common_data)?; + let row = src.read_usize()?; + let i = src.read_usize()?; + Ok(Self { gate, row, i }) + } } #[cfg(test)] diff --git a/src/u32/gates/mod.rs b/src/u32/gates/mod.rs index fbe317f..9f36963 100644 --- a/src/u32/gates/mod.rs +++ b/src/u32/gates/mod.rs @@ -3,6 +3,7 @@ pub mod arithmetic_u32; pub mod comparison; pub mod interleave_u32; pub mod range_check_u32; +pub mod serialization; pub mod subtraction_u32; pub mod uninterleave_to_b32; pub mod uninterleave_to_u32; diff --git a/src/u32/gates/range_check_u32.rs b/src/u32/gates/range_check_u32.rs index ddea3cc..086c53c 100644 --- a/src/u32/gates/range_check_u32.rs +++ b/src/u32/gates/range_check_u32.rs @@ -1,8 +1,9 @@ -use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use alloc::{format, 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::types::Field; @@ -10,7 +11,7 @@ use plonky2::gates::gate::Gate; use plonky2::gates::util::StridedConstraintConsumer; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGeneratorRef}; use plonky2::iop::target::Target; use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; @@ -55,6 +56,18 @@ impl, const D: usize> Gate for U32RangeCheckG format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_input_limbs) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let num_input_limbs = src.read_usize()?; + Ok(Self { + num_input_limbs, + _phantom: PhantomData, + }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = Vec::with_capacity(self.num_constraints()); @@ -138,9 +151,9 @@ impl, const D: usize> Gate for U32RangeCheckG constraints } - fn generators(&self, row: usize, _local_constants: &[F]) -> Vec>> { + fn generators(&self, row: usize, _local_constants: &[F]) -> Vec> { let gen = U32RangeCheckGenerator { gate: *self, row }; - vec![Box::new(gen.adapter())] + vec![WitnessGeneratorRef::new(gen.adapter())] } fn num_wires(&self) -> usize { @@ -168,9 +181,13 @@ pub struct U32RangeCheckGenerator, const D: usize> row: usize, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for U32RangeCheckGenerator { + fn id(&self) -> String { + "U32RangeCheckGenerator".to_string() + } + fn dependencies(&self) -> Vec { let num_input_limbs = self.gate.num_input_limbs; (0..num_input_limbs) @@ -201,6 +218,17 @@ impl, const D: usize> SimpleGenerator } } } + + fn serialize(&self, dst: &mut Vec, common_data: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, common_data)?; + dst.write_usize(self.row) + } + + fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData) -> IoResult { + let gate = U32RangeCheckGate::deserialize(src, common_data)?; + let row = src.read_usize()?; + Ok(Self { gate, row }) + } } #[cfg(test)] diff --git a/src/u32/gates/serialization.rs b/src/u32/gates/serialization.rs new file mode 100644 index 0000000..a4220bd --- /dev/null +++ b/src/u32/gates/serialization.rs @@ -0,0 +1,26 @@ +use alloc::vec::Vec; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; + +use crate::u32::arithmetic_u32::U32Target; + +pub trait WriteU32 { + fn write_target_u32(&mut self, x: U32Target) -> IoResult<()>; +} + +impl WriteU32 for Vec { + #[inline] + fn write_target_u32(&mut self, x: U32Target) -> IoResult<()> { + self.write_target(x.0) + } +} + +pub trait ReadU32 { + fn read_target_u32(&mut self) -> IoResult; +} + +impl ReadU32 for Buffer<'_> { + #[inline] + fn read_target_u32(&mut self) -> IoResult { + Ok(U32Target(self.read_target()?)) + } +} diff --git a/src/u32/gates/subtraction_u32.rs b/src/u32/gates/subtraction_u32.rs index 87ce47e..067551a 100644 --- a/src/u32/gates/subtraction_u32.rs +++ b/src/u32/gates/subtraction_u32.rs @@ -1,8 +1,8 @@ -use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use alloc::{format, vec}; use core::marker::PhantomData; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use plonky2::field::extension::Extendable; use plonky2::field::packed::PackedField; @@ -12,12 +12,12 @@ use plonky2::gates::packed_util::PackedEvaluableBase; use plonky2::gates::util::StridedConstraintConsumer; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGeneratorRef}; use plonky2::iop::target::Target; use plonky2::iop::wire::Wire; use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, @@ -87,6 +87,18 @@ impl, const D: usize> Gate for U32Subtraction format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let num_ops = src.read_usize()?; + Ok(Self { + num_ops, + _phantom: PhantomData, + }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = Vec::with_capacity(self.num_constraints()); for i in 0..self.num_ops { @@ -186,10 +198,10 @@ impl, const D: usize> Gate for U32Subtraction constraints } - fn generators(&self, row: usize, _local_constants: &[F]) -> Vec>> { + fn generators(&self, row: usize, _local_constants: &[F]) -> Vec> { (0..self.num_ops) .map(|i| { - let g: Box> = Box::new( + WitnessGeneratorRef::new( U32SubtractionGenerator { gate: *self, row, @@ -197,8 +209,7 @@ impl, const D: usize> Gate for U32Subtraction _phantom: PhantomData, } .adapter(), - ); - g + ) }) .collect() } @@ -270,9 +281,13 @@ struct U32SubtractionGenerator, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for U32SubtractionGenerator { + fn id(&self) -> String { + "U32SubtractionGenerator".to_string() + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -329,6 +344,24 @@ impl, const D: usize> SimpleGenerator out_buffer.set_wire(wire, output_limb); } } + + fn serialize(&self, dst: &mut Vec, common_data: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, common_data)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i) + } + + fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData) -> IoResult { + let gate = U32SubtractionGate::deserialize(src, common_data)?; + let row = src.read_usize()?; + let i = src.read_usize()?; + Ok(Self { + gate, + row, + i, + _phantom: PhantomData, + }) + } } #[cfg(test)] diff --git a/src/u32/gates/uninterleave_to_b32.rs b/src/u32/gates/uninterleave_to_b32.rs index 91d1e5c..affc635 100644 --- a/src/u32/gates/uninterleave_to_b32.rs +++ b/src/u32/gates/uninterleave_to_b32.rs @@ -8,17 +8,18 @@ use plonky2::gates::packed_util::PackedEvaluableBase; use plonky2::gates::util::StridedConstraintConsumer; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGeneratorRef}; use plonky2::iop::target::Target; use plonky2::iop::wire::Wire; use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; use plonky2::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_circuit}; use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, }; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; /// TODO: This code is grossly redundant to uninterleave_to_u32.rs, the diff is literally four lines (the calculation of coeff) /// Just wanted something up quickly, a cleaner more future-proof solution would be to make this one gate with @@ -98,6 +99,15 @@ impl, const D: usize> Gate for UninterleaveTo format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let num_ops = src.read_usize()?; + Ok(Self { num_ops }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = vec![]; @@ -219,18 +229,17 @@ impl, const D: usize> Gate for UninterleaveTo self.eval_unfiltered_base_batch_packed(vars_base) } - fn generators(&self, row: usize, _local_constants: &[F]) -> Vec>> { + fn generators(&self, row: usize, _local_constants: &[F]) -> Vec> { (0..self.num_ops) .map(|i| { - let g: Box> = Box::new( + WitnessGeneratorRef::new( UninterleaveToB32Generator { gate: *self, row, i, } .adapter(), - ); - g + ) }) .collect() } @@ -309,7 +318,13 @@ pub struct UninterleaveToB32Generator { } // Populate the bit wires and the x_interleaved wire, given that the x wire's value has been set -impl SimpleGenerator for UninterleaveToB32Generator { +impl, const D: usize> SimpleGenerator + for UninterleaveToB32Generator +{ + fn id(&self) -> String { + "UninterleaveToB32Generator".to_string() + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -354,6 +369,19 @@ impl SimpleGenerator for UninterleaveToB32Generator { out_buffer.set_wire(x_evens_wire, F::from_canonical_u64(x_evens)); out_buffer.set_wire(x_odds_wire, F::from_canonical_u64(x_odds)); } + + fn serialize(&self, dst: &mut Vec, common_data: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, common_data)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i) + } + + fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData) -> IoResult { + let gate = UninterleaveToB32Gate::deserialize(src, common_data)?; + let row = src.read_usize()?; + let i = src.read_usize()?; + Ok(Self { gate, row, i }) + } } #[cfg(test)] diff --git a/src/u32/gates/uninterleave_to_u32.rs b/src/u32/gates/uninterleave_to_u32.rs index 8194918..3f4916c 100644 --- a/src/u32/gates/uninterleave_to_u32.rs +++ b/src/u32/gates/uninterleave_to_u32.rs @@ -8,17 +8,18 @@ use plonky2::gates::packed_util::PackedEvaluableBase; use plonky2::gates::util::StridedConstraintConsumer; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGeneratorRef}; use plonky2::iop::target::Target; use plonky2::iop::wire::Wire; use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; use plonky2::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_circuit}; use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, }; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; /// Note: This gate should not be used for arbitrary targets, its specific use case /// is to be applied to the sum of the outputs of two instances of the U32InterleaveGate. @@ -94,6 +95,15 @@ impl, const D: usize> Gate for UninterleaveTo format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _common_data: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops) + } + + fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult { + let num_ops = src.read_usize()?; + Ok(Self { num_ops }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = vec![]; @@ -214,18 +224,17 @@ impl, const D: usize> Gate for UninterleaveTo self.eval_unfiltered_base_batch_packed(vars_base) } - fn generators(&self, row: usize, _local_constants: &[F]) -> Vec>> { + fn generators(&self, row: usize, _local_constants: &[F]) -> Vec> { (0..self.num_ops) .map(|i| { - let g: Box> = Box::new( + WitnessGeneratorRef::new( UninterleaveToU32Generator { gate: *self, row, i, } .adapter(), - ); - g + ) }) .collect() } @@ -304,7 +313,13 @@ pub struct UninterleaveToU32Generator { } // Populate the bit wires and the x_interleaved wire, given that the x wire's value has been set -impl SimpleGenerator for UninterleaveToU32Generator { +impl, const D: usize> SimpleGenerator + for UninterleaveToU32Generator +{ + fn id(&self) -> String { + "UninterleaveToU32Generator".to_string() + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -349,6 +364,19 @@ impl SimpleGenerator for UninterleaveToU32Generator { out_buffer.set_wire(x_evens_wire, F::from_canonical_u64(x_evens)); out_buffer.set_wire(x_odds_wire, F::from_canonical_u64(x_odds)); } + + fn serialize(&self, dst: &mut Vec, common_data: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, common_data)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i) + } + + fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData) -> IoResult { + let gate = UninterleaveToU32Gate::deserialize(src, common_data)?; + let row = src.read_usize()?; + let i = src.read_usize()?; + Ok(Self { gate, row, i }) + } } #[cfg(test)]