diff --git a/Cargo.toml b/Cargo.toml index 9cd080c..bf1595c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] anyhow = { version = "1.0.40", default-features = false } -plonky2 = { version = "0.1", default-features = false, features = ["gate_testing", "rand_chacha", "std", "parallel"]} -plonky2_maybe_rayon = { version = "0.1" } +plonky2_maybe_rayon = { version = "0.2" } +plonky2 = "0.2.2" itertools = "0.10.5" num = { version = "0.4.0", default-features = false } serde = "1.0.152" @@ -16,6 +16,7 @@ serde_with = { version = "2.2.0", features = ["hex"] } rayon = { version = "1.5.3" } hex = { version = "0.4.3" } rand = { version = "0.8.5", default-features = false, features = ["getrandom"] } +log = "0.4.20" [dev-dependencies] debug_print = { version = "1.0.0" } @@ -23,3 +24,6 @@ sha2 = { version = "0.10.6" } sha3 = { version = "0.10.6" } serde_json = "1.0" criterion = "0.3" + +[patch.crates-io] +plonky2 = { git = "https://github.com/Lagrange-Labs/plonky2", branch = "upstream" } \ No newline at end of file diff --git a/README.md b/README.md index 87de527..72a50f5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +**Fork: updated to compile and testable with latest versions of plonky2** + # Crypto Gadgets for Plonky2 A collection of efficient gadgets for Plonky2. diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..07ade69 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly \ No newline at end of file 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..9c23ee2 100644 --- a/src/hash/sha256_merkle.rs +++ b/src/hash/sha256_merkle.rs @@ -28,9 +28,9 @@ fn select_hash256, const D: usize>( pub fn compute_merkle_root, const D: usize>( builder: &mut CircuitBuilder, - index_bits: &Vec, + index_bits: &[BoolTarget], value: Hash256Target, - siblings: &Vec, + siblings: &[Hash256Target], ) -> Hash256Target { let mut current = value; for (i, sibling) in siblings.iter().enumerate() { @@ -77,7 +77,7 @@ impl MerkleProofSha256Gadget { witness: &mut W, index: u64, value: &[u8; 32], - siblings: &Vec<[u8; 32]>, + siblings: &[[u8; 32]], ) { witness.set_hash256_target(&self.value, value); witness.set_target(self.index, F::from_noncanonical_u64(index)); @@ -130,7 +130,7 @@ impl DeltaMerkleProofSha256Gadget { index: u64, old_value: &[u8; 32], new_value: &[u8; 32], - siblings: &Vec<[u8; 32]>, + siblings: &[[u8; 32]], ) { witness.set_hash256_target(&self.old_value, old_value); witness.set_hash256_target(&self.new_value, new_value); @@ -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..e9bf2b3 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) } 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..d6d5e45 100644 --- a/src/nonnative/gadgets/biguint.rs +++ b/src/nonnative/gadgets/biguint.rs @@ -1,6 +1,7 @@ use alloc::vec; use alloc::vec::Vec; use core::marker::PhantomData; +use plonky2::plonk::circuit_data::CommonCircuitData; use num::{BigUint, Integer, Zero}; use plonky2::field::extension::Extendable; @@ -10,12 +11,13 @@ use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; use plonky2::iop::target::{BoolTarget, Target}; use plonky2::iop::witness::{PartitionWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use crate::u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target}; use crate::u32::gadgets::multiple_comparison::list_le_u32_circuit; use crate::u32::witness::{GeneratedValuesU32, WitnessU32}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct BigUintTarget { pub limbs: Vec, } @@ -28,6 +30,22 @@ impl BigUintTarget { pub fn get_limb(&self, i: usize) -> U32Target { self.limbs[i] } + + fn write(&self, dst: &mut Vec) -> IoResult<()> { + dst.write_usize(self.limbs.len())?; + for limb in &self.limbs { + dst.write_target(limb.0)?; + } + Ok(()) + } + fn read(src: &mut Buffer) -> IoResult { + let num_limbs = src.read_usize()?; + let mut limbs = Vec::with_capacity(num_limbs); + for _ in 0..num_limbs { + limbs.push(U32Target(src.read_target()?)); + } + Ok(Self { limbs }) + } } pub trait CircuitBuilderBiguint, const D: usize> { @@ -430,8 +448,8 @@ impl GeneratedValuesBigUint for GeneratedValues { } } -#[derive(Debug)] -struct BigUintDivRemGenerator, const D: usize> { +#[derive(Debug, Default)] +pub struct BigUintDivRemGenerator, const D: usize> { a: BigUintTarget, b: BigUintTarget, div: BigUintTarget, @@ -439,9 +457,16 @@ struct BigUintDivRemGenerator, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for BigUintDivRemGenerator { + fn id(&self) -> String { + format!( + "BigUintDivRemGenerator({:?}, {:?}, {:?}, {:?})", + self.a, self.b, self.div, self.rem + ) + } + fn dependencies(&self) -> Vec { self.a .limbs @@ -459,6 +484,31 @@ 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, c: &CommonCircuitData) -> IoResult<()> { + self.a.write(dst)?; + self.b.write(dst)?; + self.div.write(dst)?; + self.rem.write(dst)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let a = BigUintTarget::read(src)?; + let b = BigUintTarget::read(src)?; + let div = BigUintTarget::read(src)?; + let rem = BigUintTarget::read(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..28740de 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 serde::{Deserialize, Serialize}; use plonky2::field::extension::Extendable; use plonky2::hash::hash_types::RichField; @@ -8,13 +10,14 @@ use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; use plonky2::iop::target::Target; use plonky2::iop::witness::{PartitionWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use crate::u32::gates::add_many_u32::U32AddManyGate; use crate::u32::gates::arithmetic_u32::U32ArithmeticGate; use crate::u32::gates::subtraction_u32::U32SubtractionGate; use crate::u32::witness::GeneratedValuesU32; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] pub struct U32Target(pub Target); pub trait CircuitBuilderU32, const D: usize> { @@ -236,17 +239,21 @@ impl, const D: usize> CircuitBuilderU32 } } -#[derive(Debug)] -struct SplitToU32Generator, const D: usize> { +#[derive(Debug, Default)] +pub struct SplitToU32Generator, const D: usize> { x: Target, low: U32Target, high: U32Target, _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for SplitToU32Generator { + fn id(&self) -> String { + format!("split_to_u32_: {:?}", self.x) + } + fn dependencies(&self) -> Vec { vec![self.x] } @@ -260,6 +267,28 @@ 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, c: &CommonCircuitData) -> IoResult<()> { + dst.write_target(self.x)?; + dst.write_target(self.low.0)?; + dst.write_target(self.high.0)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let x = src.read_target()?; + let low = src.read_target()?; + let high = src.read_target()?; + Ok(Self { + x, + low: U32Target(low), + high: U32Target(high), + _phantom: PhantomData, + }) + } } #[cfg(test)] diff --git a/src/u32/gadgets/interleaved_u32.rs b/src/u32/gadgets/interleaved_u32.rs index 1848a6a..02a1eaa 100644 --- a/src/u32/gadgets/interleaved_u32.rs +++ b/src/u32/gadgets/interleaved_u32.rs @@ -193,7 +193,7 @@ impl, const D: usize> CircuitBuilderB32 // x -> X [0 x 0 x 0 x 0 x] // y -> Y [0 y 0 y 0 y 0 y] - // X+Y + // X xor Y fn and_xor_u32_to_u32(&mut self, x: U32Target, y: U32Target) -> (U32Target, U32Target) { let x = self.interleave_u32(x); let y = self.interleave_u32(y); diff --git a/src/u32/gates/add_many_u32.rs b/src/u32/gates/add_many_u32.rs index ba31ce7..d9e143b 100644 --- a/src/u32/gates/add_many_u32.rs +++ b/src/u32/gates/add_many_u32.rs @@ -1,4 +1,3 @@ -use alloc::boxed::Box; use alloc::format; use alloc::string::String; use alloc::vec::Vec; @@ -11,20 +10,21 @@ 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; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; const LOG2_MAX_NUM_ADDENDS: usize = 4; const MAX_NUM_ADDENDS: usize = 24; /// A gate to perform addition on `num_addends` different 32-bit values, plus a small carry -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] pub struct U32AddManyGate, const D: usize> { pub num_addends: usize, pub num_ops: usize, @@ -91,6 +91,25 @@ impl, const D: usize> Gate for U32AddManyGate format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_addends)?; + dst.write_usize(self.num_ops)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, _: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + 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 +255,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( + let g: WitnessGeneratorRef = WitnessGeneratorRef::new( U32AddManyGenerator { gate: *self, row, @@ -270,17 +289,21 @@ impl, const D: usize> Gate for U32AddManyGate } } -#[derive(Clone, Debug)] -struct U32AddManyGenerator, const D: usize> { +#[derive(Clone, Debug, Default)] +pub struct U32AddManyGenerator, const D: usize> { gate: U32AddManyGate, row: usize, i: usize, _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for U32AddManyGenerator { + fn id(&self) -> String { + format!("u32_add_many") + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -340,6 +363,28 @@ impl, const D: usize> SimpleGenerator out_buffer.set_wire(wire, limb); } } + + fn serialize(&self, dst: &mut Vec, c: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, c)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let gate = U32AddManyGate::::deserialize(src, c)?; + 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/arithmetic_u32.rs b/src/u32/gates/arithmetic_u32.rs index c65b32a..203187f 100644 --- a/src/u32/gates/arithmetic_u32.rs +++ b/src/u32/gates/arithmetic_u32.rs @@ -1,4 +1,3 @@ -use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use alloc::{format, vec}; @@ -13,19 +12,20 @@ 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, }; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; /// A gate to perform a basic mul-add on 32-bit values (we assume they are range-checked beforehand). -#[derive(Copy, Clone, Debug)] +#[derive(Default, Copy, Clone, Debug)] pub struct U32ArithmeticGate, const D: usize> { pub num_ops: usize, _phantom: PhantomData, @@ -93,6 +93,21 @@ impl, const D: usize> Gate for U32ArithmeticG format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, _: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, _: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + num_ops: src.read_usize()?, + _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 +255,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( + let g: WitnessGeneratorRef = WitnessGeneratorRef::new( U32ArithmeticGenerator { gate: *self, row, @@ -339,17 +354,21 @@ impl, const D: usize> PackedEvaluableBase } } -#[derive(Clone, Debug)] -struct U32ArithmeticGenerator, const D: usize> { +#[derive(Default, Clone, Debug)] +pub struct U32ArithmeticGenerator, const D: usize> { gate: U32ArithmeticGate, row: usize, i: usize, _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for U32ArithmeticGenerator { + fn id(&self) -> String { + format!("u32_arith") + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -411,6 +430,28 @@ impl, const D: usize> SimpleGenerator out_buffer.set_wire(wire, output_limb); } } + + fn serialize(&self, dst: &mut Vec, c: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, c)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let gate = U32ArithmeticGate::::deserialize(src, c)?; + 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..3418b20 100644 --- a/src/u32/gates/comparison.rs +++ b/src/u32/gates/comparison.rs @@ -1,8 +1,10 @@ -use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use alloc::{format, vec}; +use anyhow::Ok; use core::marker::PhantomData; +use plonky2::plonk::circuit_data::CommonCircuitData; +use std::result::Result as RR; use plonky2::field::extension::Extendable; use plonky2::field::packed::PackedField; @@ -12,7 +14,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}; @@ -22,10 +24,11 @@ use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, }; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use plonky2::util::{bits_u64, ceil_div_usize}; /// A gate for checking that one value is less than or equal to another. -#[derive(Clone, Debug)] +#[derive(Default, Clone, Debug)] pub struct ComparisonGate, const D: usize> { pub(crate) num_bits: usize, pub(crate) num_chunks: usize, @@ -98,6 +101,23 @@ impl, const D: usize> Gate for ComparisonGate format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, c: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_bits)?; + dst.write_usize(self.num_chunks)?; + RR::Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + RR::Ok(Self { + num_bits: src.read_usize()?, + num_chunks: src.read_usize()?, + _phantom: PhantomData, + }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = Vec::with_capacity(self.num_constraints()); @@ -287,12 +307,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 { @@ -395,15 +415,19 @@ impl, const D: usize> PackedEvaluableBase } } -#[derive(Debug)] -struct ComparisonGenerator, const D: usize> { +#[derive(Debug, Default)] +pub struct ComparisonGenerator, const D: usize> { row: usize, gate: ComparisonGate, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for ComparisonGenerator { + fn id(&self) -> String { + format!("comparison") + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -512,6 +536,21 @@ impl, const D: usize> SimpleGenerator ); } } + + fn serialize(&self, dst: &mut Vec, c: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.row)?; + self.gate.serialize(dst, c)?; + RR::Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let row = src.read_usize()?; + let gate = ComparisonGate::deserialize(src, c)?; + RR::Ok(Self { row, gate }) + } } #[cfg(test)] diff --git a/src/u32/gates/interleave_u32.rs b/src/u32/gates/interleave_u32.rs index 2cbc579..38dd3f1 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) /// @@ -28,7 +29,7 @@ use plonky2::plonk::vars::{ /// An example /// x: b0000_0000_0000_0000_1111_0111_0011_1110 /// x_interleaved: b0101_0101_0001_0101_0000_0101_0101_0100 -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] pub struct U32InterleaveGate { pub num_ops: usize, } @@ -182,10 +183,10 @@ 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( + let g: WitnessGeneratorRef = WitnessGeneratorRef::new( U32InterleaveGenerator { gate: *self, row, @@ -213,6 +214,20 @@ impl, const D: usize> Gate for U32InterleaveG fn num_constraints(&self) -> usize { self.num_ops * (Self::NUM_BITS + 1 + 1) } + + fn serialize(&self, dst: &mut Vec, _: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, _: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + num_ops: src.read_usize()?, + }) + } } impl, const D: usize> PackedEvaluableBase for U32InterleaveGate { @@ -253,7 +268,7 @@ impl, const D: usize> PackedEvaluableBase for } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct U32InterleaveGenerator { gate: U32InterleaveGate, row: usize, @@ -261,7 +276,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 { + format!("u32_interleave") + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -298,6 +319,25 @@ 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, c: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, c)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let gate = U32InterleaveGate::deserialize(src, c)?; + Ok(Self { + gate, + row: src.read_usize()?, + i: src.read_usize()?, + }) + } } #[cfg(test)] diff --git a/src/u32/gates/mod.rs b/src/u32/gates/mod.rs index fbe317f..db48152 100644 --- a/src/u32/gates/mod.rs +++ b/src/u32/gates/mod.rs @@ -1,3 +1,44 @@ +use std::marker::PhantomData; + +use plonky2::{ + field::extension::Extendable, + gadgets::{ + arithmetic::EqualityGenerator, + arithmetic_extension::QuotientGeneratorExtension, + range_check::LowHighGenerator, + split_base::BaseSumGenerator, + split_join::{SplitGenerator, WireSplitGenerator}, + }, + gates::{ + arithmetic_base::{ArithmeticBaseGenerator, ArithmeticGate}, + arithmetic_extension::{ArithmeticExtensionGate, ArithmeticExtensionGenerator}, + base_sum::{BaseSplitGenerator, BaseSumGate}, + constant::ConstantGate, + coset_interpolation::{CosetInterpolationGate, InterpolationGenerator}, + exponentiation::{ExponentiationGate, ExponentiationGenerator}, + lookup::{LookupGate, LookupGenerator}, + lookup_table::{LookupTableGate, LookupTableGenerator}, + multiplication_extension::{MulExtensionGate, MulExtensionGenerator}, + noop::NoopGate, + poseidon::{PoseidonGate, PoseidonGenerator}, + poseidon_mds::{PoseidonMdsGate, PoseidonMdsGenerator}, + public_input::PublicInputGate, + random_access::{RandomAccessGate, RandomAccessGenerator}, + reducing::ReducingGate, + reducing::ReducingGenerator, + reducing_extension::ReducingExtensionGate, + reducing_extension::ReducingGenerator as ReducingExtensionGenerator, + }, + hash::hash_types::RichField, + impl_gate_serializer, impl_generator_serializer, + iop::generator::{ + ConstantGenerator, CopyGenerator, NonzeroTestGenerator, RandomValueGenerator, + }, + plonk::config::{AlgebraicHasher, GenericConfig}, + recursion::dummy_circuit::DummyProofGenerator, + util::serialization::{GateSerializer, WitnessGeneratorSerializer}, +}; + pub mod add_many_u32; pub mod arithmetic_u32; pub mod comparison; @@ -6,3 +47,104 @@ pub mod range_check_u32; pub mod subtraction_u32; pub mod uninterleave_to_b32; pub mod uninterleave_to_u32; +use self::{ + add_many_u32::U32AddManyGate, + arithmetic_u32::U32ArithmeticGenerator, + comparison::ComparisonGenerator, + interleave_u32::{U32InterleaveGate, U32InterleaveGenerator}, + range_check_u32::{U32RangeCheckGate, U32RangeCheckGenerator}, + subtraction_u32::{U32SubtractionGate, U32SubtractionGenerator}, + uninterleave_to_b32::{UninterleaveToB32Gate, UninterleaveToB32Generator}, + uninterleave_to_u32::{UninterleaveToU32Gate, UninterleaveToU32Generator}, +}; +use super::arithmetic_u32::SplitToU32Generator; +use crate::biguint::BigUintDivRemGenerator; +use crate::u32::gates::add_many_u32::U32AddManyGenerator; +use crate::u32::gates::arithmetic_u32::U32ArithmeticGate; +use crate::u32::gates::comparison::ComparisonGate; +use plonky2::get_gate_tag_impl; +use plonky2::get_generator_tag_impl; +use plonky2::read_gate_impl; +use plonky2::read_generator_impl; +use std::default::Default; +pub struct HashGeneratorSerializer, const D: usize> { + pub _phantom: PhantomData, +} + +impl WitnessGeneratorSerializer for HashGeneratorSerializer +where + F: RichField + Extendable, + C: GenericConfig + 'static, + C::Hasher: AlgebraicHasher, +{ + impl_generator_serializer! { + DefaultGeneratorSerializer, + ArithmeticBaseGenerator, + ArithmeticExtensionGenerator, + BaseSplitGenerator<2>, + BaseSumGenerator<2>, + ConstantGenerator, + CopyGenerator, + DummyProofGenerator, + EqualityGenerator, + ExponentiationGenerator, + InterpolationGenerator, + LookupGenerator, + LookupTableGenerator, + LowHighGenerator, + MulExtensionGenerator, + NonzeroTestGenerator, + PoseidonGenerator, + PoseidonMdsGenerator, + QuotientGeneratorExtension, + RandomAccessGenerator, + RandomValueGenerator, + ReducingGenerator, + ReducingExtensionGenerator, + SplitGenerator, + WireSplitGenerator, + // hash generators added + BigUintDivRemGenerator, + SplitToU32Generator, + U32AddManyGenerator, + U32ArithmeticGenerator, + ComparisonGenerator, + U32InterleaveGenerator, + U32RangeCheckGenerator, + U32SubtractionGenerator, + UninterleaveToB32Generator, + UninterleaveToU32Generator + } +} + +pub struct HashGateSerializer; +impl, const D: usize> GateSerializer for HashGateSerializer { + impl_gate_serializer! { + DefaultGateSerializer, + ArithmeticGate, + ArithmeticExtensionGate, + BaseSumGate<2>, + ConstantGate, + CosetInterpolationGate, + ExponentiationGate, + LookupGate, + LookupTableGate, + MulExtensionGate, + NoopGate, + PoseidonMdsGate, + PoseidonGate, + PublicInputGate, + RandomAccessGate, + ReducingExtensionGate, + ReducingGate, + //hash gates + U32AddManyGate, + U32ArithmeticGate, + ComparisonGate, + U32InterleaveGate, + U32RangeCheckGate, + U32SubtractionGate, + UninterleaveToB32Gate, + UninterleaveToU32Gate + } +} diff --git a/src/u32/gates/range_check_u32.rs b/src/u32/gates/range_check_u32.rs index ddea3cc..b9f2319 100644 --- a/src/u32/gates/range_check_u32.rs +++ b/src/u32/gates/range_check_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::plonk::circuit_data::CommonCircuitData; use plonky2::field::extension::Extendable; use plonky2::field::types::Field; @@ -10,16 +10,17 @@ 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; use plonky2::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_circuit}; use plonky2::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use plonky2::util::ceil_div_usize; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; /// A gate which can decompose a number into base B little-endian limbs. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] pub struct U32RangeCheckGate, const D: usize> { pub num_input_limbs: usize, _phantom: PhantomData, @@ -55,6 +56,21 @@ impl, const D: usize> Gate for U32RangeCheckG format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, c: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_input_limbs)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + num_input_limbs: src.read_usize()?, + _phantom: PhantomData, + }) + } + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let mut constraints = Vec::with_capacity(self.num_constraints()); @@ -138,9 +154,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 { @@ -162,15 +178,19 @@ impl, const D: usize> Gate for U32RangeCheckG } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct U32RangeCheckGenerator, const D: usize> { gate: U32RangeCheckGate, row: usize, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for U32RangeCheckGenerator { + fn id(&self) -> String { + format!("u32_range_check") + } + fn dependencies(&self) -> Vec { let num_input_limbs = self.gate.num_input_limbs; (0..num_input_limbs) @@ -201,6 +221,21 @@ impl, const D: usize> SimpleGenerator } } } + + fn serialize(&self, dst: &mut Vec, c: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, c)?; + dst.write_usize(self.row)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + let gate = U32RangeCheckGate::deserialize(src, c)?; + let row = src.read_usize()?; + Ok(Self { gate, row }) + } } #[cfg(test)] diff --git a/src/u32/gates/subtraction_u32.rs b/src/u32/gates/subtraction_u32.rs index 87ce47e..5b6d35b 100644 --- a/src/u32/gates/subtraction_u32.rs +++ b/src/u32/gates/subtraction_u32.rs @@ -1,4 +1,3 @@ -use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use alloc::{format, vec}; @@ -12,20 +11,21 @@ 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, }; +use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; /// A gate to perform a subtraction on 32-bit limbs: given `x`, `y`, and `borrow`, it returns /// the result `x - y - borrow` and, if this underflows, a new `borrow`. Inputs are not range-checked. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] pub struct U32SubtractionGate, const D: usize> { pub num_ops: usize, _phantom: PhantomData, @@ -87,6 +87,21 @@ impl, const D: usize> Gate for U32Subtraction format!("{self:?}") } + fn serialize(&self, dst: &mut Vec, c: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + num_ops: src.read_usize()?, + _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 +201,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( + let g: WitnessGeneratorRef = WitnessGeneratorRef::new( U32SubtractionGenerator { gate: *self, row, @@ -262,17 +277,21 @@ impl, const D: usize> PackedEvaluableBase } } -#[derive(Clone, Debug)] -struct U32SubtractionGenerator, const D: usize> { +#[derive(Clone, Debug, Default)] +pub struct U32SubtractionGenerator, const D: usize> { gate: U32SubtractionGate, row: usize, i: usize, _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator +impl, const D: usize> SimpleGenerator for U32SubtractionGenerator { + fn id(&self) -> String { + format!("u32_subtraction") + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -329,6 +348,25 @@ impl, const D: usize> SimpleGenerator out_buffer.set_wire(wire, output_limb); } } + + fn serialize(&self, dst: &mut Vec, c: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, c)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + gate: U32SubtractionGate::deserialize(src, c)?, + row: src.read_usize()?, + i: src.read_usize()?, + _phantom: PhantomData, + }) + } } #[cfg(test)] diff --git a/src/u32/gates/uninterleave_to_b32.rs b/src/u32/gates/uninterleave_to_b32.rs index 91d1e5c..a98cf4f 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 @@ -30,7 +31,7 @@ use plonky2::plonk::vars::{ /// /// Given a Goldilocks field element, treat it as 0bxyxyxy... /// and split it into two B32Targets, 0b0x0x0x... and 0b0y0y0y... -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] pub struct UninterleaveToB32Gate { pub num_ops: usize, } @@ -219,10 +220,10 @@ 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( + let g: WitnessGeneratorRef = WitnessGeneratorRef::new( UninterleaveToB32Generator { gate: *self, row, @@ -250,6 +251,20 @@ impl, const D: usize> Gate for UninterleaveTo fn num_constraints(&self) -> usize { self.num_ops * (Self::NUM_BITS + 1 + 2) } + + fn serialize(&self, dst: &mut Vec, _: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, _: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + num_ops: src.read_usize()?, + }) + } } impl, const D: usize> PackedEvaluableBase @@ -301,7 +316,7 @@ impl, const D: usize> PackedEvaluableBase } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct UninterleaveToB32Generator { gate: UninterleaveToB32Gate, row: usize, @@ -309,7 +324,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 { + format!("uninterleave_to_b32") + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -354,6 +375,24 @@ 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, c: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, c)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + gate: UninterleaveToB32Gate::deserialize(src, c)?, + row: src.read_usize()?, + i: src.read_usize()?, + }) + } } #[cfg(test)] diff --git a/src/u32/gates/uninterleave_to_u32.rs b/src/u32/gates/uninterleave_to_u32.rs index 8194918..a156ab0 100644 --- a/src/u32/gates/uninterleave_to_u32.rs +++ b/src/u32/gates/uninterleave_to_u32.rs @@ -8,24 +8,25 @@ 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. /// /// Given a Goldilocks field element, treat it as 0bxyxyxy... /// and split it into two U32Targets, 0bxxx... and 0byyy... -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] pub struct UninterleaveToU32Gate { pub num_ops: usize, } @@ -214,10 +215,10 @@ 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( + let g: WitnessGeneratorRef = WitnessGeneratorRef::new( UninterleaveToU32Generator { gate: *self, row, @@ -245,6 +246,20 @@ impl, const D: usize> Gate for UninterleaveTo fn num_constraints(&self) -> usize { self.num_ops * (Self::NUM_BITS + 1 + 2) } + + fn serialize(&self, dst: &mut Vec, _: &CommonCircuitData) -> IoResult<()> { + dst.write_usize(self.num_ops)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, _: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + num_ops: src.read_usize()?, + }) + } } impl, const D: usize> PackedEvaluableBase @@ -296,7 +311,7 @@ impl, const D: usize> PackedEvaluableBase } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct UninterleaveToU32Generator { gate: UninterleaveToU32Gate, row: usize, @@ -304,7 +319,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 { + format!("uninterleave_to_u32") + } + fn dependencies(&self) -> Vec { let local_target = |column| Target::wire(self.row, column); @@ -349,6 +370,24 @@ 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, c: &CommonCircuitData) -> IoResult<()> { + self.gate.serialize(dst, c)?; + dst.write_usize(self.row)?; + dst.write_usize(self.i)?; + Ok(()) + } + + fn deserialize(src: &mut Buffer, c: &CommonCircuitData) -> IoResult + where + Self: Sized, + { + Ok(Self { + gate: UninterleaveToU32Gate::deserialize(src, c)?, + row: src.read_usize()?, + i: src.read_usize()?, + }) + } } #[cfg(test)]