diff --git a/beacon-light-client/plonky2/crates/Cargo.lock b/beacon-light-client/plonky2/crates/Cargo.lock index 91d9a1c68..7a9a56f69 100644 --- a/beacon-light-client/plonky2/crates/Cargo.lock +++ b/beacon-light-client/plonky2/crates/Cargo.lock @@ -1149,11 +1149,13 @@ dependencies = [ name = "circuit" version = "0.1.0" dependencies = [ + "circuit_derive", "deriving_via", "itertools 0.10.5", "num-bigint 0.4.5", "plonky2", "plonky2_crypto", + "primitive-types 0.12.2", "serde", "serde-big-array 0.5.1", "starky", diff --git a/beacon-light-client/plonky2/crates/circuit/Cargo.toml b/beacon-light-client/plonky2/crates/circuit/Cargo.toml index 928987ef4..54016e14c 100644 --- a/beacon-light-client/plonky2/crates/circuit/Cargo.toml +++ b/beacon-light-client/plonky2/crates/circuit/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition.workspace = true [dependencies] +circuit_derive = { path = "../circuit_derive" } plonky2 = { git = "https://github.com/metacraft-labs/plonky2" } plonky2_crypto = { git = "https://github.com/metacraft-labs/plonky2-crypto" } starky = { git = "https://github.com/metacraft-labs/plonky2" } @@ -12,3 +13,4 @@ itertools = "0.10.5" deriving_via = "1.6.1" serde = "1.0.164" serde-big-array = "0.5.1" +primitive-types = "0.12.2" diff --git a/beacon-light-client/plonky2/crates/circuit/src/lib.rs b/beacon-light-client/plonky2/crates/circuit/src/lib.rs index db23c9e98..756cd5fc4 100644 --- a/beacon-light-client/plonky2/crates/circuit/src/lib.rs +++ b/beacon-light-client/plonky2/crates/circuit/src/lib.rs @@ -6,9 +6,12 @@ pub mod array; pub mod circuit; pub mod circuit_builder_extensions; pub mod public_inputs; +pub mod serde; pub mod serde_circuit_target; pub mod set_witness; +pub mod ssz_hash_tree_root; pub mod target_primitive; +pub mod targets; pub mod to_targets; pub use add_virtual_target::AddVirtualTarget; @@ -20,6 +23,7 @@ pub use public_inputs::{ }; pub use serde_circuit_target::SerdeCircuitTarget; pub use set_witness::SetWitness; +pub use ssz_hash_tree_root::SSZHashTreeRoot; pub use target_primitive::TargetPrimitive; pub use to_targets::ToTargets; diff --git a/beacon-light-client/plonky2/crates/circuit/src/serde.rs b/beacon-light-client/plonky2/crates/circuit/src/serde.rs new file mode 100644 index 000000000..3db382c04 --- /dev/null +++ b/beacon-light-client/plonky2/crates/circuit/src/serde.rs @@ -0,0 +1,73 @@ +pub mod serde_u64_str { + use core::fmt; + + use serde::{de::Visitor, Deserializer, Serializer}; + + pub fn serialize(value: &u64, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&value.to_string()) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Vis; + + impl<'de> Visitor<'de> for Vis { + type Value = u64; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(v.parse().unwrap()) + } + } + + deserializer.deserialize_str(Vis) + } +} + +pub mod serde_u128_str { + use core::fmt; + + use serde::{de::Visitor, Deserializer, Serializer}; + + pub fn serialize(value: &u128, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&value.to_string()) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Vis; + + impl<'de> Visitor<'de> for Vis { + type Value = u128; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(v.parse().unwrap()) + } + } + + deserializer.deserialize_str(Vis) + } +} diff --git a/beacon-light-client/plonky2/crates/circuit/src/serde_circuit_target.rs b/beacon-light-client/plonky2/crates/circuit/src/serde_circuit_target.rs index 4ffb4a726..342484d24 100644 --- a/beacon-light-client/plonky2/crates/circuit/src/serde_circuit_target.rs +++ b/beacon-light-client/plonky2/crates/circuit/src/serde_circuit_target.rs @@ -4,7 +4,7 @@ use plonky2::{ plonk::{circuit_data::VerifierCircuitTarget, proof::ProofWithPublicInputsTarget}, util::serialization::{Buffer, IoResult, Read, Write}, }; -use plonky2_crypto::biguint::BigUintTarget; +use plonky2_crypto::{biguint::BigUintTarget, u32::arithmetic_u32::U32Target}; use starky::proof::{StarkOpeningSetTarget, StarkProofTarget, StarkProofWithPublicInputsTarget}; use crate::{Circuit, PublicInputsTargetReadable}; @@ -118,8 +118,24 @@ impl SerdeCircuitTarget } } +impl SerdeCircuitTarget for U32Target { + fn serialize(&self) -> IoResult> { + let mut buffer: Vec = Vec::new(); + buffer.write_target(self.0)?; + Ok(buffer) + } + + fn deserialize(buffer: &mut Buffer) -> IoResult + where + Self: Sized, + { + let target = buffer.read_target()?; + Ok(Self(target)) + } +} + impl SerdeCircuitTarget for BigUintTarget { - fn serialize(&self) -> plonky2::util::serialization::IoResult> { + fn serialize(&self) -> IoResult> { assert_eq!(self.num_limbs(), 2); let mut buffer: Vec = Vec::new(); @@ -128,9 +144,7 @@ impl SerdeCircuitTarget for BigUintTarget { Ok(buffer) } - fn deserialize( - buffer: &mut plonky2::util::serialization::Buffer, - ) -> plonky2::util::serialization::IoResult + fn deserialize(buffer: &mut Buffer) -> IoResult where Self: Sized, { diff --git a/beacon-light-client/plonky2/crates/circuit/src/ssz_hash_tree_root.rs b/beacon-light-client/plonky2/crates/circuit/src/ssz_hash_tree_root.rs new file mode 100644 index 000000000..e226d83e7 --- /dev/null +++ b/beacon-light-client/plonky2/crates/circuit/src/ssz_hash_tree_root.rs @@ -0,0 +1,32 @@ +use itertools::Itertools; +use plonky2::{ + field::extension::Extendable, hash::hash_types::RichField, iop::target::BoolTarget, + plonk::circuit_builder::CircuitBuilder, +}; + +use crate::targets::uint::Uint64Target; + +pub trait SSZHashTreeRoot, const D: usize> { + fn ssz_hash_tree_root(self, builder: &mut CircuitBuilder) -> [BoolTarget; 256]; +} + +impl, const D: usize> SSZHashTreeRoot for Uint64Target { + fn ssz_hash_tree_root(self, builder: &mut CircuitBuilder) -> [BoolTarget; 256] { + let _false = builder._false(); + + self.to_le_bytes(builder) + .into_iter() + .pad_using(256, |_| _false) + .collect_vec() + .try_into() + .unwrap() + } +} + +impl, const D: usize> SSZHashTreeRoot for BoolTarget { + fn ssz_hash_tree_root(self, builder: &mut CircuitBuilder) -> [BoolTarget; 256] { + let mut ssz_leaf = [builder._false(); 256]; + ssz_leaf[7] = self; + ssz_leaf + } +} diff --git a/beacon-light-client/plonky2/crates/circuit/src/targets/mod.rs b/beacon-light-client/plonky2/crates/circuit/src/targets/mod.rs new file mode 100644 index 000000000..ed1a50fd8 --- /dev/null +++ b/beacon-light-client/plonky2/crates/circuit/src/targets/mod.rs @@ -0,0 +1 @@ +pub mod uint; diff --git a/beacon-light-client/plonky2/crates/circuit/src/targets/uint/macro.rs b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/macro.rs new file mode 100644 index 000000000..589305214 --- /dev/null +++ b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/macro.rs @@ -0,0 +1,347 @@ +#[macro_export] +macro_rules! define_uint_target_type { + ($ident:ident, $ty:ty) => { + /// An unsigned integer type encoded as little-endian u32 limbs. + /// Performs wrapping unsigned integer arithmetic. + #[derive(SerdeCircuitTarget, Debug, Clone, Copy)] + pub struct $ident { + pub limbs: [U32Target; num_limbs::<$ty>()], + } + + impl $ident { + pub fn num_limbs(self) -> usize { + self.limbs.len() + } + + pub fn constant, const D: usize>( + value: $ty, + builder: &mut CircuitBuilder, + ) -> Self { + let mut limbs: Vec = Vec::new(); + + for index in 0..num_limbs::<$ty>() { + let limb = (value >> (32 * index)) & <$ty>::from(0xffffffff as u32); + limbs.push(builder.constant_u32(limb.try_into().unwrap())); + } + + Self { + limbs: limbs.try_into().unwrap(), + } + } + + pub fn to_biguint(self) -> BigUintTarget { + BigUintTarget { + limbs: self.limbs.to_vec(), + } + } + + pub fn truncate_biguint, const D: usize>( + biguint: &BigUintTarget, + builder: &mut CircuitBuilder, + ) -> Self { + let zero = U32Target(builder.zero()); + Self { + limbs: biguint + .limbs + .iter() + .take(num_limbs::<$ty>()) + .pad_using(num_limbs::<$ty>(), |_| &zero) + .copied() + .collect_vec() + .try_into() + .unwrap(), + } + } + + pub fn from_le_bits, const D: usize>( + bits: &[BoolTarget], + builder: &mut CircuitBuilder, + ) -> Self { + assert_eq!(bits.len(), std::mem::size_of::<$ty>() * 8); + + Self { + limbs: bits + .into_iter() + .chunks(32) + .into_iter() + .map(|limb_bits| U32Target(builder.le_sum(limb_bits))) + .collect_vec() + .try_into() + .unwrap(), + } + } + + pub fn to_le_bits, const D: usize>( + self, + builder: &mut CircuitBuilder, + ) -> Vec { + self.limbs + .into_iter() + .flat_map(|limb| builder.split_le(limb.0, 32)) + .collect_vec() + } + + pub fn to_le_bytes, const D: usize>( + self, + builder: &mut CircuitBuilder, + ) -> Vec { + self.to_le_bits(builder) + .into_iter() + .chunks(8) + .into_iter() + .flat_map(|chunk| chunk.collect_vec().into_iter().rev()) + .collect_vec() + } + + pub fn from_le_bytes, const D: usize>( + bits: &[BoolTarget], + builder: &mut CircuitBuilder, + ) -> Self { + assert_eq!(bits.len(), std::mem::size_of::<$ty>() * 8); + + Self { + limbs: bits + .chunks(32) + .map(|limb_le_bytes| { + let limb_le_bits = builder.le_sum( + limb_le_bytes + .chunks(8) + .map(|byte| byte.into_iter().rev()) + .flatten(), + ); + + U32Target(limb_le_bits) + }) + .collect_vec() + .try_into() + .unwrap(), + } + } + + pub fn to_be_bits, const D: usize>( + self, + builder: &mut CircuitBuilder, + ) -> Vec { + self.to_le_bits(builder).into_iter().rev().collect_vec() + } + } + + impl TargetPrimitive for $ident { + type Primitive = $ty; + } + + impl SetWitness for $ident { + type Input = <$ident as TargetPrimitive>::Primitive; + + fn set_witness(&self, witness: &mut PartialWitness, input: &Self::Input) { + for (index, limb) in self.limbs.into_iter().enumerate() { + let value: u32 = ((input >> (32 * index)) + & Self::Input::from(0xffffffff as u32)) + .try_into() + .unwrap(); + witness.set_u32_target(limb, value as u32); + } + } + } + + impl AddVirtualTarget for $ident { + fn add_virtual_target, const D: usize>( + builder: &mut CircuitBuilder, + ) -> Self { + let targets = builder.add_virtual_u32_targets(num_limbs::<$ty>()); + assert_limbs_are_valid(builder, &targets); + Self { + limbs: targets.try_into().unwrap(), + } + } + } + + impl PublicInputsReadable for $ident { + fn from_elements(elements: &[F]) -> Self::Primitive { + assert_eq!(elements.len(), Self::get_size()); + elements + .iter() + .rev() + .fold(Self::Primitive::from(0u32), |acc, limb| { + (acc << 32) + Self::Primitive::from(limb.to_canonical_u64() as u32) + }) + } + } + + impl PublicInputsTargetReadable for $ident { + fn get_size() -> usize { + num_limbs::<$ty>() + } + + fn from_targets(targets: &[Target]) -> Self { + assert_eq!(targets.len(), Self::get_size()); + Self { + limbs: targets + .iter() + .map(|&target| U32Target(target)) + .collect_vec() + .try_into() + .unwrap(), + } + } + } + + impl ToTargets for $ident { + fn to_targets(&self) -> Vec { + self.limbs.iter().map(|limb| limb.0).collect_vec() + } + } + + impl, const D: usize> Zero for $ident { + fn zero(builder: &mut CircuitBuilder) -> Self { + Self { + limbs: [U32Target(builder.zero()); num_limbs::<$ty>()], + } + } + } + + impl, const D: usize> One for $ident { + fn one(builder: &mut CircuitBuilder) -> Self { + let zero = U32Target(builder.zero()); + let one = U32Target(builder.one()); + let mut limbs = [zero; num_limbs::<$ty>()]; + limbs[0] = one; + Self { limbs } + } + } + + impl, const D: usize> Add for $ident { + type Output = Self; + + fn add(self, rhs: $ident, builder: &mut CircuitBuilder) -> Self::Output { + let self_biguint = BigUintTarget { + limbs: self.limbs.to_vec(), + }; + let rhs_biguint = BigUintTarget { + limbs: rhs.limbs.to_vec(), + }; + let sum_biguint = builder.add_biguint(&self_biguint, &rhs_biguint); + + let mut limbs: [U32Target; num_limbs::<$ty>()] = Self::zero(builder).limbs; + for i in 0..num_limbs::<$ty>() { + limbs[i] = sum_biguint.limbs[i].into(); + } + + Self { limbs } + } + } + + impl, const D: usize> Sub for $ident { + type Output = Self; + + fn sub(self, rhs: $ident, builder: &mut CircuitBuilder) -> Self::Output { + let self_biguint = BigUintTarget { + limbs: self.limbs.to_vec(), + }; + let rhs_biguint = BigUintTarget { + limbs: rhs.limbs.to_vec(), + }; + let sub_biguint = builder.sub_biguint(&self_biguint, &rhs_biguint); + + let mut limbs: [U32Target; num_limbs::<$ty>()] = Self::zero(builder).limbs; + for i in 0..num_limbs::<$ty>() { + limbs[i] = sub_biguint.limbs[i].into(); + } + + Self { limbs } + } + } + + impl, const D: usize> Div for $ident { + type Output = Self; + + fn div(self, rhs: $ident, builder: &mut CircuitBuilder) -> Self::Output { + let self_biguint = BigUintTarget { + limbs: self.limbs.to_vec(), + }; + let rhs_biguint = BigUintTarget { + limbs: rhs.limbs.to_vec(), + }; + let quotient_biguint = builder.div_biguint(&self_biguint, &rhs_biguint); + + let mut limbs: [U32Target; num_limbs::<$ty>()] = Self::zero(builder).limbs; + for i in 0..quotient_biguint.num_limbs() { + limbs[i] = quotient_biguint.limbs[i].into(); + } + + Self { limbs } + } + } + + impl, const D: usize> Mul for $ident { + type Output = Self; + + fn mul(self, rhs: $ident, builder: &mut CircuitBuilder) -> Self::Output { + let self_biguint = BigUintTarget { + limbs: self.limbs.to_vec(), + }; + let rhs_biguint = BigUintTarget { + limbs: rhs.limbs.to_vec(), + }; + let product_biguint = builder.mul_biguint(&self_biguint, &rhs_biguint); + + let mut limbs: [U32Target; num_limbs::<$ty>()] = Self::zero(builder).limbs; + for i in 0..num_limbs::<$ty>() { + limbs[i] = product_biguint.limbs[i].into(); + } + + Self { limbs } + } + } + + impl, const D: usize> Rem for $ident { + type Output = Self; + + fn rem(self, rhs: $ident, builder: &mut CircuitBuilder) -> Self::Output { + let self_biguint = BigUintTarget { + limbs: self.limbs.to_vec(), + }; + let rhs_biguint = BigUintTarget { + limbs: rhs.limbs.to_vec(), + }; + let rem_biguint = builder.rem_biguint(&self_biguint, &rhs_biguint); + + let mut limbs: [U32Target; num_limbs::<$ty>()] = Self::zero(builder).limbs; + for i in 0..num_limbs::<$ty>() { + limbs[i] = rem_biguint.limbs[i].into(); + } + + Self { limbs } + } + } + + impl, const D: usize> LessThanOrEqual for $ident { + #[must_use] + fn lte(self, rhs: Self, builder: &mut CircuitBuilder) -> BoolTarget { + let self_biguint = BigUintTarget { + limbs: self.limbs.to_vec(), + }; + let rhs_biguint = BigUintTarget { + limbs: rhs.limbs.to_vec(), + }; + builder.cmp_biguint(&self_biguint, &rhs_biguint) + } + } + + impl, const D: usize> EqualTo for $ident { + #[must_use] + fn equal_to(self, rhs: Self, builder: &mut CircuitBuilder) -> BoolTarget { + let mut result = builder._true(); + + for i in 0..num_limbs::<$ty>() { + let limbs_are_equal = builder.is_equal(self.limbs[i].0, rhs.limbs[i].0); + result = builder.and(result, limbs_are_equal); + } + + result + } + } + + impl, const D: usize> Comparison for $ident {} + }; +} diff --git a/beacon-light-client/plonky2/crates/circuit/src/targets/uint/mod.rs b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/mod.rs new file mode 100644 index 000000000..714493703 --- /dev/null +++ b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/mod.rs @@ -0,0 +1,56 @@ +use crate::{ + self as circuit, + circuit_builder_extensions::CircuitBuilderExtensions, + define_uint_target_type, + targets::uint::ops::{ + arithmetic::{Add, Div, Mul, One, Rem, Sub, Zero}, + comparison::{Comparison, EqualTo, LessThanOrEqual}, + }, + AddVirtualTarget, PublicInputsReadable, PublicInputsTargetReadable, SetWitness, + TargetPrimitive, ToTargets, +}; +use circuit_derive::SerdeCircuitTarget; +use itertools::Itertools; +use num_bigint::BigUint; +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::{ + target::{BoolTarget, Target}, + witness::PartialWitness, + }, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_crypto::{ + biguint::{BigUintTarget, CircuitBuilderBiguint}, + u32::{ + arithmetic_u32::{CircuitBuilderU32, U32Target}, + witness::WitnessU32, + }, +}; +use primitive_types::{U256, U512}; + +mod r#macro; +pub mod ops; + +define_uint_target_type!(Uint64Target, u64); +define_uint_target_type!(Uint128Target, u128); +define_uint_target_type!(Uint256Target, U256); +define_uint_target_type!(Uint512Target, U512); + +fn assert_limbs_are_valid, const D: usize>( + builder: &mut CircuitBuilder, + limbs: &[U32Target], +) { + for &limb in limbs { + let upper_bound = builder.constant_biguint(&BigUint::from(2u64.pow(32) - 1)); + let limb_biguint = BigUintTarget { limbs: vec![limb] }; + let limb_is_valid = builder.cmp_biguint(&limb_biguint, &upper_bound); + builder.assert_true(limb_is_valid); + } +} + +const fn num_limbs() -> usize { + debug_assert!(std::mem::size_of::() % 4 == 0); + std::mem::size_of::() / 4 +} diff --git a/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/arithmetic.rs b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/arithmetic.rs new file mode 100644 index 000000000..b0ce70834 --- /dev/null +++ b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/arithmetic.rs @@ -0,0 +1,42 @@ +use plonky2::{ + field::extension::Extendable, hash::hash_types::RichField, + plonk::circuit_builder::CircuitBuilder, +}; + +pub trait Add, const D: usize, Rhs = Self> { + type Output; + + fn add(self, rhs: Rhs, builder: &mut CircuitBuilder) -> Self::Output; +} + +pub trait Sub, const D: usize, Rhs = Self> { + type Output; + + fn sub(self, rhs: Rhs, builder: &mut CircuitBuilder) -> Self::Output; +} + +pub trait Mul, const D: usize, Rhs = Self> { + type Output; + + fn mul(self, rhs: Rhs, builder: &mut CircuitBuilder) -> Self::Output; +} + +pub trait Div, const D: usize, Rhs = Self> { + type Output; + + fn div(self, rhs: Rhs, builder: &mut CircuitBuilder) -> Self::Output; +} + +pub trait Rem, const D: usize, Rhs = Self> { + type Output; + + fn rem(self, rhs: Rhs, builder: &mut CircuitBuilder) -> Self::Output; +} + +pub trait Zero, const D: usize> { + fn zero(builder: &mut CircuitBuilder) -> Self; +} + +pub trait One, const D: usize> { + fn one(builder: &mut CircuitBuilder) -> Self; +} diff --git a/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/comparison.rs b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/comparison.rs new file mode 100644 index 000000000..3823f7f3f --- /dev/null +++ b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/comparison.rs @@ -0,0 +1,59 @@ +use plonky2::{ + field::extension::Extendable, hash::hash_types::RichField, iop::target::BoolTarget, + plonk::circuit_builder::CircuitBuilder, +}; + +pub trait LessThanOrEqual, const D: usize, Rhs = Self> { + #[must_use] + fn lte(self, rhs: Rhs, builder: &mut CircuitBuilder) -> BoolTarget; +} + +pub trait EqualTo, const D: usize, Rhs = Self> { + #[must_use] + fn equal_to(self, rhs: Rhs, builder: &mut CircuitBuilder) -> BoolTarget; +} + +pub trait Comparison, const D: usize, Rhs = Self>: + LessThanOrEqual + EqualTo +{ + #[must_use] + fn lt(self, rhs: Rhs, builder: &mut CircuitBuilder) -> BoolTarget + where + Self: Sized + Copy, + Rhs: Copy, + { + let are_equal = self.equal_to(rhs, builder); + let are_not_equal = builder.not(are_equal); + let lte = self.lte(rhs, builder); + builder.and(lte, are_not_equal) + } + + #[must_use] + fn gt(self, rhs: Rhs, builder: &mut CircuitBuilder) -> BoolTarget + where + Self: Sized + Copy, + { + let lte = self.lte(rhs, builder); + builder.not(lte) + } + + #[must_use] + fn gte(self, rhs: Rhs, builder: &mut CircuitBuilder) -> BoolTarget + where + Self: Sized + Copy, + Rhs: Copy, + { + let are_equal = self.equal_to(rhs, builder); + let gt = self.gt(rhs, builder); + builder.or(gt, are_equal) + } + + #[must_use] + fn not_equal_to(self, rhs: Rhs, builder: &mut CircuitBuilder) -> BoolTarget + where + Self: Sized, + { + let are_equal = self.equal_to(rhs, builder); + builder.not(are_equal) + } +} diff --git a/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/mod.rs b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/mod.rs new file mode 100644 index 000000000..8d5db7c3f --- /dev/null +++ b/beacon-light-client/plonky2/crates/circuit/src/targets/uint/ops/mod.rs @@ -0,0 +1,2 @@ +pub mod arithmetic; +pub mod comparison; diff --git a/beacon-light-client/plonky2/crates/circuits/src/common_targets.rs b/beacon-light-client/plonky2/crates/circuits/src/common_targets.rs index d31a65626..4b5ea92a3 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/common_targets.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/common_targets.rs @@ -1,7 +1,5 @@ -use crate::serializers::{ - biguint_to_str, parse_biguint, serde_bool_array_to_hex_string, - serde_bool_array_to_hex_string_nested, -}; +use crate::serializers::{serde_bool_array_to_hex_string, serde_bool_array_to_hex_string_nested}; +use circuit::{serde::serde_u64_str, targets::uint::Uint64Target}; use circuit_derive::{ AddVirtualTarget, CircuitTarget, PublicInputsReadable, SerdeCircuitTarget, SetWitness, TargetPrimitive, @@ -10,7 +8,6 @@ use plonky2::{ hash::hash_types::HashOutTarget, iop::target::BoolTarget, plonk::proof::ProofWithPublicInputsTarget, }; -use plonky2_crypto::biguint::BigUintTarget; pub type Sha256Target = [BoolTarget; 256]; pub type SSZTarget = [BoolTarget; 256]; @@ -42,22 +39,22 @@ pub struct ValidatorTarget { #[serde(with = "serde_bool_array_to_hex_string")] pub withdrawal_credentials: Sha256Target, - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub effective_balance: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub effective_balance: Uint64Target, pub slashed: BoolTarget, - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub activation_eligibility_epoch: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub activation_eligibility_epoch: Uint64Target, - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub activation_epoch: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub activation_epoch: Uint64Target, - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub exit_epoch: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub exit_epoch: Uint64Target, - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub withdrawable_epoch: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub withdrawable_epoch: Uint64Target, } #[derive(TargetPrimitive, PublicInputsReadable)] @@ -100,8 +97,8 @@ pub struct MerklelizedValidatorTarget { pub struct DepositTargets { #[serde(with = "serde_bool_array_to_hex_string")] pub pubkey: PubkeyTarget, - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub deposit_index: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub deposit_index: Uint64Target, #[serde(with = "serde_bool_array_to_hex_string")] pub deposit_message_root: Sha256Target, #[serde(with = "serde_bool_array_to_hex_string")] diff --git a/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/final_layer.rs b/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/final_layer.rs index 0046369c1..85e71781a 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/final_layer.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/final_layer.rs @@ -1,17 +1,14 @@ use crate::{ common_targets::{PoseidonMerkleBranchTarget, Sha256MerkleBranchTarget}, pubkey_commitment_mapper::first_level::PubkeyCommitmentMapperFL, - serializers::{ - biguint_to_str, parse_biguint, serde_bool_array_to_hex_string, - serde_bool_array_to_hex_string_nested, - }, + serializers::{serde_bool_array_to_hex_string, serde_bool_array_to_hex_string_nested}, utils::circuit::{ assert_slot_is_in_epoch::assert_slot_is_in_epoch, - biguint_to_bits_target, bits_to_bytes_target, + bits_to_bytes_target, hashing::{ merkle::{ poseidon::assert_merkle_proof_is_valid_const_poseidon, - sha256::assert_merkle_proof_is_valid_const_sha256, ssz::ssz_num_to_bits, + sha256::assert_merkle_proof_is_valid_const_sha256, }, sha256::sha256, }, @@ -19,7 +16,10 @@ use crate::{ }, validators_commitment_mapper::first_level::ValidatorsCommitmentMapperFirstLevel, }; -use circuit::{Circuit, CircuitInputTarget, CircuitOutputTarget}; +use circuit::{ + serde::serde_u64_str, targets::uint::Uint64Target, Circuit, CircuitInputTarget, + CircuitOutputTarget, SSZHashTreeRoot, +}; use circuit_derive::{CircuitTarget, SerdeCircuitTarget}; use plonky2::{ field::{extension::Extendable, goldilocks_field::GoldilocksField}, @@ -32,7 +32,6 @@ use plonky2::{ proof::ProofWithPublicInputsTarget, }, }; -use plonky2_crypto::biguint::BigUintTarget; use crate::common_targets::Sha256Target; @@ -68,16 +67,16 @@ pub struct DepositAccumulatorBalanceAggregatorDivaFinalLayerTarget { // Public input #[target(in)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub execution_block_number: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub execution_block_number: Uint64Target, #[target(in)] #[serde(with = "serde_bool_array_to_hex_string_nested")] pub execution_block_number_branch: Sha256MerkleBranchTarget<10>, // Public input #[target(in)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub slot: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub slot: Uint64Target, #[target(in)] #[serde(with = "serde_bool_array_to_hex_string_nested")] pub slot_branch: Sha256MerkleBranchTarget<5>, @@ -169,7 +168,7 @@ impl Circuit for DepositAccumulatorBalanceAggregatorDivaFinalLayer { &validators_commitment_mapper_root_pis.sha256_hash_tree_root, ); - assert_slot_is_in_epoch(builder, &input.slot, &balance_aggregation_pis.current_epoch); + assert_slot_is_in_epoch(builder, input.slot, balance_aggregation_pis.current_epoch); let mut public_inputs_hash = hash_public_inputs( builder, @@ -236,7 +235,7 @@ fn validate_data_against_block_root, const D: usize 5767168, ); - let slot_ssz = ssz_num_to_bits(builder, &input.slot, 64); + let slot_ssz = input.slot.ssz_hash_tree_root(builder); assert_merkle_proof_is_valid_const_sha256( builder, @@ -246,7 +245,7 @@ fn validate_data_against_block_root, const D: usize 34, ); - let block_number_ssz = ssz_num_to_bits(builder, &input.execution_block_number, 64); + let block_number_ssz = input.execution_block_number.ssz_hash_tree_root(builder); assert_merkle_proof_is_valid_const_sha256( builder, @@ -265,10 +264,12 @@ fn hash_public_inputs, const D: usize>( >, pubkey_commitment_mapper_pis: &CircuitOutputTarget, ) -> Sha256Target { - let balance_bits = - biguint_to_bits_target(builder, &balance_aggregation_pis.accumulated_data.balance); + let balance_bits = balance_aggregation_pis + .accumulated_data + .balance + .to_be_bits(builder); - let block_number_bits = biguint_to_bits_target(builder, &input.execution_block_number); + let block_number_bits = input.execution_block_number.to_be_bits(builder); let number_of_non_activated_validators_bits = target_to_be_bits( builder, diff --git a/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/first_level.rs b/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/first_level.rs index 01df5b27b..850adbd9c 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/first_level.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/first_level.rs @@ -1,10 +1,7 @@ use crate::{ common_targets::{PubkeyTarget, Sha256MerkleBranchTarget}, deposits_accumulator_balance_aggregator::common_targets::ValidatorStatusStatsTarget, - serializers::{ - biguint_to_str, parse_biguint, serde_bool_array_to_hex_string, - serde_bool_array_to_hex_string_nested, - }, + serializers::{serde_bool_array_to_hex_string, serde_bool_array_to_hex_string_nested}, utils::circuit::{ assert_bool_arrays_are_equal, get_balance_from_leaf, hashing::{ @@ -14,13 +11,19 @@ use crate::{ }, poseidon::poseidon_or_zeroes, }, - select_biguint, validator_status::{get_validator_relevance, get_validator_status}, }, }; -use circuit::{circuit_builder_extensions::CircuitBuilderExtensions, Circuit, ToTargets}; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, + serde::serde_u64_str, + targets::uint::{ + ops::arithmetic::{Div, Rem, Zero}, + Uint64Target, + }, + Circuit, ToTargets, +}; use circuit_derive::{CircuitTarget, PublicInputsReadable, SerdeCircuitTarget, TargetPrimitive}; -use num::{BigUint, FromPrimitive}; use plonky2::{ field::goldilocks_field::GoldilocksField, hash::hash_types::HashOutTarget, @@ -30,7 +33,6 @@ use plonky2::{ config::PoseidonGoldilocksConfig, }, }; -use plonky2_crypto::biguint::{BigUintTarget, CircuitBuilderBiguint}; use crate::common_targets::{PoseidonMerkleBranchTarget, Sha256Target, ValidatorTarget}; @@ -39,8 +41,8 @@ pub struct DepositAccumulatorBalanceAggregatorDivaFirstLevel {} #[derive(Clone, Debug, TargetPrimitive, PublicInputsReadable, SerdeCircuitTarget)] #[serde(rename_all = "camelCase")] pub struct DivaAccumulatedDataTarget { - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub balance: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub balance: Uint64Target, pub validator_status_stats: ValidatorStatusStatsTarget, } @@ -54,8 +56,8 @@ pub struct DepositAccumulatorBalanceAggregatorDivaFirstLevelTarget { pub validators_commitment_mapper_branch: PoseidonMerkleBranchTarget<24>, #[target(in)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub validator_gindex: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub validator_gindex: Uint64Target, #[target(in)] #[serde(with = "serde_bool_array_to_hex_string")] @@ -73,8 +75,8 @@ pub struct DepositAccumulatorBalanceAggregatorDivaFirstLevelTarget { pub is_dummy: BoolTarget, #[target(in, out)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub current_epoch: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub current_epoch: Uint64Target, #[target(in, out)] pub validators_commitment_mapper_root: HashOutTarget, @@ -117,33 +119,33 @@ impl Circuit for DepositAccumulatorBalanceAggregatorDivaFirstLevel { &validator_hash_tree_root, &input.validators_commitment_mapper_root, &input.validators_commitment_mapper_branch, - &input.validator_gindex, + input.validator_gindex, ); builder.assert_implication(deposit_is_real, validator_proof_is_valid); assert_bool_arrays_are_equal(builder, &input.validator.pubkey, &input.deposit_pubkey); - let four = builder.constant_biguint(&BigUint::from_u64(4u64).unwrap()); - let balance_inner_index = builder.rem_biguint(&input.validator_gindex, &four); + let four = Uint64Target::constant(4, builder); + let balance_inner_index = input.validator_gindex.rem(four, builder); let balance = get_balance_from_leaf(builder, &input.balance_leaf, balance_inner_index); - let balance_gindex = builder.div_biguint(&input.validator_gindex, &four); + let balance_gindex = input.validator_gindex.div(four, builder); let balance_proof_is_valid = validate_merkle_proof_sha256( builder, &input.balance_leaf, &input.balances_root, &input.balance_branch, - &balance_gindex, + balance_gindex, ); builder.assert_implication(deposit_is_real, balance_proof_is_valid); let (is_non_activated, is_active, is_exited) = get_validator_status( builder, - &input.validator.activation_epoch, - &input.current_epoch, - &input.validator.exit_epoch, + input.validator.activation_epoch, + input.current_epoch, + input.validator.exit_epoch, ); let zero_validator_status_stats: ValidatorStatusStatsTarget = builder.zero_init(); @@ -161,13 +163,13 @@ impl Circuit for DepositAccumulatorBalanceAggregatorDivaFirstLevel { let is_relevant = get_validator_relevance( builder, - &input.validator.activation_epoch, - &input.current_epoch, - &input.validator.withdrawable_epoch, + input.validator.activation_epoch, + input.current_epoch, + input.validator.withdrawable_epoch, ); - let zero_biguint = builder.zero_biguint(); - let validator_balance = select_biguint(builder, is_relevant, &balance, &zero_biguint); + let zero_u64 = Uint64Target::zero(builder); + let validator_balance = builder.select_target(is_relevant, &balance, &zero_u64); let zero_accumulated_data: DivaAccumulatedDataTarget = builder.zero_init(); let mut accumulated_data = DivaAccumulatedDataTarget { @@ -204,7 +206,6 @@ mod test { }; use circuit::{Circuit, CircuitInput, SetWitness}; - use num::{BigUint, FromPrimitive}; use plonky2::{field::goldilocks_field::GoldilocksField, iop::witness::PartialWitness}; use crate::utils::bytes_to_bits; @@ -238,7 +239,7 @@ mod test { &proof.public_inputs, ); - assert_eq!(result.current_epoch, BigUint::from_u64(158342).unwrap()); + assert_eq!(result.current_epoch, 158342); assert_eq!( result.validators_commitment_mapper_root.0, [ @@ -257,10 +258,7 @@ mod test { .unwrap(); assert_eq!(result.balances_root.0, balance_root_bools); - assert_eq!( - result.accumulated_data.balance, - BigUint::from_u64(31035128496).unwrap() - ); + assert_eq!(result.accumulated_data.balance, 31035128496); assert_eq!( result @@ -377,7 +375,7 @@ mod test { >(&json_str) .unwrap(); - json_input.validator.activation_epoch = BigUint::from_u64(817).unwrap(); + json_input.validator.activation_epoch = 817; let s = Instant::now(); println!("Stared building circuit"); @@ -405,7 +403,7 @@ mod test { >(&json_str) .unwrap(); - json_input.validator_gindex = BigUint::from_u64(817).unwrap(); + json_input.validator_gindex = 817; let s = Instant::now(); println!("Stared building circuit"); @@ -451,7 +449,7 @@ mod test { &proof.public_inputs, ); - assert_eq!(result.current_epoch, BigUint::from_u64(158342).unwrap()); + assert_eq!(result.current_epoch, 158342); assert_eq!( result.validators_commitment_mapper_root.0, [ @@ -470,10 +468,7 @@ mod test { .unwrap(); assert_eq!(result.balances_root.0, balance_root_bools); - assert_eq!( - result.accumulated_data.balance, - BigUint::from_u64(0).unwrap() - ); + assert_eq!(result.accumulated_data.balance, 0); assert_eq!( result diff --git a/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/inner_level.rs b/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/inner_level.rs index 0b16f388b..7fb51077c 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/inner_level.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/deposit_accumulator_balance_aggregator_diva/inner_level.rs @@ -5,7 +5,10 @@ use crate::{ assert_bool_arrays_are_equal, hashing::poseidon::poseidon_pair, verify_proof, }, }; -use circuit::{Circuit, CircuitOutputTarget}; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, targets::uint::ops::arithmetic::Add, + Circuit, CircuitOutputTarget, +}; use plonky2::{ field::{extension::Extendable, goldilocks_field::GoldilocksField}, hash::hash_types::RichField, @@ -15,7 +18,6 @@ use plonky2::{ config::PoseidonGoldilocksConfig, }, }; -use plonky2_crypto::biguint::CircuitBuilderBiguint; use super::first_level::{ DepositAccumulatorBalanceAggregatorDivaFirstLevel, DivaAccumulatedDataTarget, @@ -80,16 +82,11 @@ fn accumulate_data, const D: usize>( left_range: &CircuitOutputTarget, right_range: &CircuitOutputTarget, ) -> DivaAccumulatedDataTarget { - let mut balance = builder.add_biguint( - &left_range.accumulated_data.balance, - &right_range.accumulated_data.balance, - ); - - // pop carry - balance.limbs.pop(); - DivaAccumulatedDataTarget { - balance, + balance: left_range + .accumulated_data + .balance + .add(right_range.accumulated_data.balance, builder), validator_status_stats: accumulate_validator_stats( builder, &left_range.accumulated_data.validator_status_stats, @@ -116,7 +113,7 @@ fn connect_pass_through_data, const D: usize>( l_input: &CircuitOutputTarget, r_input: &CircuitOutputTarget, ) { - builder.connect_biguint(&l_input.current_epoch, &r_input.current_epoch); + builder.assert_targets_are_equal(&l_input.current_epoch, &r_input.current_epoch); builder.connect_hashes( l_input.validators_commitment_mapper_root, r_input.validators_commitment_mapper_root, diff --git a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/common_targets.rs b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/common_targets.rs index 4f503daa0..817e3a13f 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/common_targets.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/common_targets.rs @@ -1,7 +1,7 @@ -use crate::serializers::{biguint_to_str, parse_biguint, serde_bool_array_to_hex_string}; +use crate::serializers::serde_bool_array_to_hex_string; +use circuit::{serde::serde_u64_str, targets::uint::Uint64Target}; use circuit_derive::{PublicInputsReadable, SerdeCircuitTarget, TargetPrimitive}; use plonky2::iop::target::{BoolTarget, Target}; -use plonky2_crypto::biguint::BigUintTarget; use crate::common_targets::PubkeyTarget; @@ -17,8 +17,8 @@ pub struct ValidatorStatusStatsTarget { #[derive(Clone, Debug, TargetPrimitive, PublicInputsReadable, SerdeCircuitTarget)] #[serde(rename_all = "camelCase")] pub struct AccumulatedDataTarget { - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub balance: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub balance: Uint64Target, pub deposits_count: Target, pub validator_status_stats: ValidatorStatusStatsTarget, } @@ -26,8 +26,8 @@ pub struct AccumulatedDataTarget { #[derive(Clone, Debug, TargetPrimitive, PublicInputsReadable, SerdeCircuitTarget)] #[serde(rename_all = "camelCase")] pub struct ValidatorDataTarget { - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub balance: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub balance: Uint64Target, pub is_non_activated: BoolTarget, pub is_active: BoolTarget, @@ -41,8 +41,8 @@ pub struct DepositDataTarget { #[serde(with = "serde_bool_array_to_hex_string")] pub pubkey: PubkeyTarget, pub validator: ValidatorDataTarget, - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub deposit_index: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub deposit_index: Uint64Target, pub is_counted: BoolTarget, pub is_dummy: BoolTarget, } diff --git a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/final_layer.rs b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/final_layer.rs index a7601b236..889392788 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/final_layer.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/final_layer.rs @@ -1,23 +1,20 @@ use crate::{ - common_targets::Sha256MerkleBranchTarget, + common_targets::{Sha256MerkleBranchTarget, Sha256Target}, deposits_accumulator_balance_aggregator::first_level::DepositAccumulatorBalanceAggregatorFirstLevel, deposits_accumulator_commitment_mapper::first_level::DepositsCommitmentMapperFirstLevel, - serializers::{ - biguint_to_str, parse_biguint, serde_bool_array_to_hex_string, - serde_bool_array_to_hex_string_nested, - }, + serializers::{serde_bool_array_to_hex_string, serde_bool_array_to_hex_string_nested}, utils::circuit::{ assert_slot_is_in_epoch::assert_slot_is_in_epoch, - biguint_to_bits_target, bits_to_bytes_target, - hashing::{ - merkle::{sha256::assert_merkle_proof_is_valid_const_sha256, ssz::ssz_num_to_bits}, - sha256::sha256, - }, + bits_to_bytes_target, + hashing::{merkle::sha256::assert_merkle_proof_is_valid_const_sha256, sha256::sha256}, target_to_be_bits, verify_proof, }, validators_commitment_mapper::first_level::ValidatorsCommitmentMapperFirstLevel, }; -use circuit::{Circuit, CircuitInputTarget, CircuitOutputTarget}; +use circuit::{ + serde::serde_u64_str, targets::uint::Uint64Target, Circuit, CircuitInputTarget, + CircuitOutputTarget, SSZHashTreeRoot, +}; use circuit_derive::CircuitTarget; use plonky2::{ field::{extension::Extendable, goldilocks_field::GoldilocksField}, @@ -29,9 +26,6 @@ use plonky2::{ proof::ProofWithPublicInputsTarget, }, }; -use plonky2_crypto::biguint::BigUintTarget; - -use crate::common_targets::Sha256Target; #[derive(CircuitTarget)] #[serde(rename_all = "camelCase")] @@ -62,16 +56,16 @@ pub struct DepositAccumulatorBalanceAggregatorFinalLayerTargets { // Public input #[target(in)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub execution_block_number: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub execution_block_number: Uint64Target, #[target(in)] #[serde(with = "serde_bool_array_to_hex_string_nested")] pub execution_block_number_branch: Sha256MerkleBranchTarget<10>, // Public input #[target(in)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub slot: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub slot: Uint64Target, #[target(in)] #[serde(with = "serde_bool_array_to_hex_string_nested")] pub slot_branch: Sha256MerkleBranchTarget<5>, @@ -145,10 +139,10 @@ impl Circuit for DepositAccumulatorBalanceAggregatorFinalLayer { &input, &balance_aggregation_pis.balances_root, &validators_commitment_mapper_pis.sha256_hash_tree_root, - &balance_aggregation_pis.eth1_deposit_index, + balance_aggregation_pis.eth1_deposit_index, ); - assert_slot_is_in_epoch(builder, &input.slot, &balance_aggregation_pis.current_epoch); + assert_slot_is_in_epoch(builder, input.slot, balance_aggregation_pis.current_epoch); let mut public_inputs_hash = hash_public_inputs( builder, @@ -188,7 +182,7 @@ fn validate_data_against_block_root, const D: usize input: &CircuitInputTarget, balances_root_level_22: &Sha256Target, validators_root_left: &Sha256Target, - eth1_deposit_index: &BigUintTarget, + eth1_deposit_index: Uint64Target, ) { assert_merkle_proof_is_valid_const_sha256( builder, @@ -214,7 +208,7 @@ fn validate_data_against_block_root, const D: usize 5767168, ); - let slot_ssz = ssz_num_to_bits(builder, &input.slot, 64); + let slot_ssz = input.slot.ssz_hash_tree_root(builder); assert_merkle_proof_is_valid_const_sha256( builder, @@ -224,7 +218,7 @@ fn validate_data_against_block_root, const D: usize 34, ); - let block_number_ssz = ssz_num_to_bits(builder, &input.execution_block_number, 64); + let block_number_ssz = input.execution_block_number.ssz_hash_tree_root(builder); assert_merkle_proof_is_valid_const_sha256( builder, @@ -234,7 +228,7 @@ fn validate_data_against_block_root, const D: usize 1798, ); - let eth1_deposit_index_ssz = ssz_num_to_bits(builder, eth1_deposit_index, 64); + let eth1_deposit_index_ssz = eth1_deposit_index.ssz_hash_tree_root(builder); assert_merkle_proof_is_valid_const_sha256( builder, @@ -251,10 +245,12 @@ fn hash_public_inputs, const D: usize>( balance_aggregation_pis: &CircuitOutputTarget, deposits_commitment_mapper_pis: &CircuitOutputTarget, ) -> Sha256Target { - let balance_bits = - biguint_to_bits_target(builder, &balance_aggregation_pis.accumulated_data.balance); + let balance_bits = balance_aggregation_pis + .accumulated_data + .balance + .to_be_bits(builder); - let block_number_bits = biguint_to_bits_target(builder, &input.execution_block_number); + let block_number_bits = input.execution_block_number.to_be_bits(builder); let deposits_count_bits = target_to_be_bits( builder, diff --git a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/first_level.rs b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/first_level.rs index 0c74e9e66..b97041b87 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/first_level.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/first_level.rs @@ -4,10 +4,7 @@ use crate::{ deposits_accumulator_balance_aggregator::common_targets::{ AccumulatedDataTarget, DepositDataTarget, ValidatorStatusStatsTarget, }, - serializers::{ - biguint_to_str, parse_biguint, serde_bool_array_to_hex_string, - serde_bool_array_to_hex_string_nested, - }, + serializers::{serde_bool_array_to_hex_string, serde_bool_array_to_hex_string_nested}, utils::circuit::{ assert_arrays_are_equal, assert_bool_arrays_are_equal, bits_to_bytes_target, get_balance_from_leaf, @@ -19,16 +16,23 @@ use crate::{ poseidon::poseidon, sha256::sha256_pair, }, - select_biguint, validator_status::{get_validator_relevance, get_validator_status}, verify_proof, }, }; use circuit::{ - circuit_builder_extensions::CircuitBuilderExtensions, Circuit, CircuitInputTarget, ToTargets, + circuit_builder_extensions::CircuitBuilderExtensions, + serde::serde_u64_str, + targets::uint::{ + ops::{ + arithmetic::{Div, Rem, Zero}, + comparison::LessThanOrEqual, + }, + Uint64Target, + }, + Circuit, CircuitInputTarget, ToTargets, }; use circuit_derive::{CircuitTarget, SerdeCircuitTarget}; -use num::{BigUint, FromPrimitive}; use plonky2::{ field::{extension::Extendable, goldilocks_field::GoldilocksField}, hash::hash_types::{HashOutTarget, RichField}, @@ -40,7 +44,6 @@ use plonky2::{ proof::ProofWithPublicInputsTarget, }, }; -use plonky2_crypto::biguint::{BigUintTarget, CircuitBuilderBiguint}; use crate::common_targets::{ DepositTargets, PoseidonMerkleBranchTarget, Sha256Target, ValidatorTarget, @@ -60,8 +63,8 @@ pub struct DepositAccumulatorBalanceAggregatorFirstLevelTargets { pub commitment_mapper_proof: PoseidonMerkleBranchTarget<40>, #[target(in)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub validator_gindex: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub validator_gindex: Uint64Target, #[target(in)] pub deposit: DepositTargets, @@ -70,8 +73,8 @@ pub struct DepositAccumulatorBalanceAggregatorFirstLevelTargets { pub validator_deposit_proof: PoseidonMerkleBranchTarget<32>, #[target(in)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub validator_deposit_gindex: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub validator_deposit_gindex: Uint64Target, #[target(in)] #[serde(with = "serde_bool_array_to_hex_string")] @@ -85,12 +88,12 @@ pub struct DepositAccumulatorBalanceAggregatorFirstLevelTargets { pub is_dummy: BoolTarget, #[target(in, out)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub current_epoch: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub current_epoch: Uint64Target, #[target(in, out)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub eth1_deposit_index: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub eth1_deposit_index: Uint64Target, #[target(in, out)] pub commitment_mapper_root: HashOutTarget, @@ -144,7 +147,7 @@ impl Circuit for DepositAccumulatorBalanceAggregatorFirstLevel { &deposit_hash_tree_root, &input.deposits_commitment_mapper_root, &input.validator_deposit_proof, - &input.validator_deposit_gindex, + input.validator_deposit_gindex, ); builder.assert_implication(deposit_is_real, is_valid); @@ -152,8 +155,10 @@ impl Circuit for DepositAccumulatorBalanceAggregatorFirstLevel { let (bls_verification_proof, signature_is_valid) = verify_bls_signature(builder, &input, &bls_circuit_data); - let deposit_is_processed = - builder.cmp_biguint(&input.deposit.deposit_index, &input.eth1_deposit_index); + let deposit_is_processed = input + .deposit + .deposit_index + .lte(input.eth1_deposit_index, builder); let validator_is_on_chain = builder.and(deposit_is_processed, signature_is_valid); let deposit_is_real_and_validator_is_on_chain = @@ -166,7 +171,7 @@ impl Circuit for DepositAccumulatorBalanceAggregatorFirstLevel { &validator_hash_tree_root, &input.commitment_mapper_root, &input.commitment_mapper_proof, - &input.validator_gindex, + input.validator_gindex, ); builder.assert_implication( @@ -176,17 +181,17 @@ impl Circuit for DepositAccumulatorBalanceAggregatorFirstLevel { assert_bool_arrays_are_equal(builder, &input.validator.pubkey, &input.deposit.pubkey); - let four = builder.constant_biguint(&BigUint::from_u64(4u64).unwrap()); - let balance_inner_index = builder.rem_biguint(&input.validator_gindex, &four); + let four = Uint64Target::constant(4, builder); + let balance_inner_index = input.validator_gindex.rem(four, builder); let balance = get_balance_from_leaf(builder, &input.balance_leaf, balance_inner_index); - let balance_gindex = builder.div_biguint(&input.validator_gindex, &four); + let balance_gindex = input.validator_gindex.div(four, builder); let balances_proof_is_valid = validate_merkle_proof_sha256( builder, &input.balance_leaf, &input.balances_root, &input.balance_proof, - &balance_gindex, + balance_gindex, ); builder.assert_implication( @@ -196,9 +201,9 @@ impl Circuit for DepositAccumulatorBalanceAggregatorFirstLevel { let (is_non_activated, is_active, is_exited) = get_validator_status( builder, - &input.validator.activation_epoch, - &input.current_epoch, - &input.validator.exit_epoch, + input.validator.activation_epoch, + input.current_epoch, + input.validator.exit_epoch, ); let zero_validator_status_stats: ValidatorStatusStatsTarget = builder.zero_init(); @@ -216,15 +221,15 @@ impl Circuit for DepositAccumulatorBalanceAggregatorFirstLevel { let mut is_relevant = get_validator_relevance( builder, - &input.validator.activation_epoch, - &input.current_epoch, - &input.validator.withdrawable_epoch, + input.validator.activation_epoch, + input.current_epoch, + input.validator.withdrawable_epoch, ); is_relevant = builder.and(is_relevant, deposit_is_real_and_validator_is_on_chain); - let zero_biguint = builder.zero_biguint(); - let validator_balance = select_biguint(builder, is_relevant, &balance, &zero_biguint); + let zero_u64 = Uint64Target::zero(builder); + let validator_balance = builder.select_target(is_relevant, &balance, &zero_u64); let deposit_data = DepositDataTarget { pubkey: input.deposit.pubkey, @@ -235,7 +240,7 @@ impl Circuit for DepositAccumulatorBalanceAggregatorFirstLevel { is_exited, is_slashed: input.validator.slashed, }, - deposit_index: input.deposit.deposit_index.clone(), + deposit_index: input.deposit.deposit_index, is_counted: deposit_is_real_and_validator_is_on_chain, is_dummy: input.is_dummy, }; diff --git a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/inner_level.rs b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/inner_level.rs index 207907958..2e301f217 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/inner_level.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_balance_aggregator/inner_level.rs @@ -1,4 +1,11 @@ -use circuit::{circuit_builder_extensions::CircuitBuilderExtensions, Circuit, CircuitOutputTarget}; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, + targets::uint::ops::{ + arithmetic::{Add, Sub}, + comparison::Comparison, + }, + Circuit, CircuitOutputTarget, +}; use plonky2::{ field::{extension::Extendable, goldilocks_field::GoldilocksField}, hash::hash_types::RichField, @@ -15,8 +22,8 @@ use crate::{ common_targets::{BasicRecursiveInnerCircuitTarget, PubkeyTarget}, deposits_accumulator_balance_aggregator::first_level::DepositAccumulatorBalanceAggregatorFirstLevel, utils::circuit::{ - assert_bool_arrays_are_equal, biguint_is_equal, bits_to_biguint_target, - bool_arrays_are_equal, verify_proof, + assert_bool_arrays_are_equal, biguint_target_from_le_bits, bool_arrays_are_equal, + verify_proof, }, }; @@ -96,11 +103,12 @@ fn connect_pass_through_data, const D: usize>( left_range: &CircuitOutputTarget, right_range: &CircuitOutputTarget, ) { - builder.connect_biguint(&left_range.current_epoch, &right_range.current_epoch); - builder.connect_biguint( + builder.assert_targets_are_equal(&left_range.current_epoch, &right_range.current_epoch); + builder.assert_targets_are_equal( &left_range.eth1_deposit_index, &right_range.eth1_deposit_index, ); + builder.connect_hashes( left_range.commitment_mapper_root, right_range.commitment_mapper_root, @@ -127,8 +135,8 @@ fn cmp_pubkey, const D: usize>( pk1: PubkeyTarget, pk2: PubkeyTarget, ) -> BoolTarget { - let pk1_bu = bits_to_biguint_target(builder, pk1.to_vec()); - let pk2_bu = bits_to_biguint_target(builder, pk2.to_vec()); + let pk1_bu = biguint_target_from_le_bits(builder, &pk1); + let pk2_bu = biguint_target_from_le_bits(builder, &pk2); builder.cmp_biguint(&pk1_bu, &pk2_bu) } @@ -226,10 +234,10 @@ fn accumulate_data, const D: usize>( right_range: &CircuitOutputTarget, ) -> AccumulatedDataTarget { AccumulatedDataTarget { - balance: builder.add_biguint( - &left_range.accumulated_data.balance, - &right_range.accumulated_data.balance, - ), + balance: left_range + .accumulated_data + .balance + .add(right_range.accumulated_data.balance, builder), deposits_count: builder.add( left_range.accumulated_data.deposits_count, right_range.accumulated_data.deposits_count, @@ -272,10 +280,9 @@ fn account_for_double_counting, const D: usize>( right_range: &CircuitOutputTarget, ) -> AccumulatedDataTarget { let new_accumulated_data = AccumulatedDataTarget { - balance: builder.sub_biguint( - &accumulated_data.balance, - &left_range.accumulated_data.balance, - ), + balance: accumulated_data + .balance + .sub(left_range.accumulated_data.balance, builder), deposits_count: accumulated_data.deposits_count, validator_status_stats: ValidatorStatusStatsTarget { non_activated_count: builder.sub( @@ -331,21 +338,10 @@ fn assert_deposits_are_sorted, const D: usize>( &right_range.leftmost_deposit.pubkey, ); - let deposits_are_same = biguint_is_equal( - builder, - &left_range.rightmost_deposit.deposit_index, - &right_range.leftmost_deposit.deposit_index, - ); - - let deposits_are_different = builder.not(deposits_are_same); - - let deposits_are_increasing = builder.cmp_biguint( - &left_range.rightmost_deposit.deposit_index, - &right_range.leftmost_deposit.deposit_index, - ); - - let deposits_are_strictly_increasing = - builder.and(deposits_are_increasing, deposits_are_different); + let deposits_are_strictly_increasing = left_range + .rightmost_deposit + .deposit_index + .lt(right_range.leftmost_deposit.deposit_index, builder); let if_pks_are_same_then_deposits_are_strictly_increasing = builder.imply(pks_are_same, deposits_are_strictly_increasing); diff --git a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_commitment_mapper/first_level.rs b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_commitment_mapper/first_level.rs index 83006dc86..e0f7f40f4 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_commitment_mapper/first_level.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/deposits_accumulator_commitment_mapper/first_level.rs @@ -1,9 +1,7 @@ use crate::{ serializers::serde_bool_array_to_hex_string, - utils::circuit::{ - biguint_to_bits_target, - hashing::{merkle::poseidon::hash_tree_root_poseidon, poseidon::poseidon, sha256::sha256}, - reverse_endianness, + utils::circuit::hashing::{ + merkle::poseidon::hash_tree_root_poseidon, poseidon::poseidon, sha256::sha256, }, }; use circuit::{Circuit, ToTargets}; @@ -85,10 +83,7 @@ impl Circuit for DepositsCommitmentMapperFirstLevel { ) -> Self::Target { let input = Self::read_circuit_input_target(builder); - let deposit_index_bits = reverse_endianness(&biguint_to_bits_target( - builder, - &input.deposit.deposit_index, - )); + let deposit_index_bits = &input.deposit.deposit_index.to_le_bytes(builder); let sha256_hash_tree_root = sha256( builder, diff --git a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/assert_slot_is_in_epoch.rs b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/assert_slot_is_in_epoch.rs index d5b35d263..f062dd3c9 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/assert_slot_is_in_epoch.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/assert_slot_is_in_epoch.rs @@ -1,23 +1,26 @@ -use num::{BigUint, FromPrimitive}; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, + targets::uint::{ops::arithmetic::Div, Uint64Target}, +}; use plonky2::{ field::extension::Extendable, hash::hash_types::RichField, plonk::circuit_builder::CircuitBuilder, }; -use plonky2_crypto::biguint::{BigUintTarget, CircuitBuilderBiguint}; pub fn assert_slot_is_in_epoch, const D: usize>( builder: &mut CircuitBuilder, - slot: &BigUintTarget, - current_epoch: &BigUintTarget, -) -> () { - let slots_per_epoch = builder.constant_biguint(&BigUint::from_u32(32).unwrap()); - let slot_epoch = builder.div_biguint(slot, &slots_per_epoch); - builder.connect_biguint(&slot_epoch, current_epoch); + slot: Uint64Target, + current_epoch: Uint64Target, +) { + let slots_per_epoch = Uint64Target::constant(32, builder); + let slot_epoch = slot.div(slots_per_epoch, builder); + builder.assert_targets_are_equal(&slot_epoch, ¤t_epoch); } #[cfg(test)] mod test_assert_slot_is_in_epoch { - use num::{BigUint, FromPrimitive}; + use circuit::{serde::serde_u64_str, targets::uint::Uint64Target, Circuit, SetWitness}; + use circuit_derive::CircuitTarget; use plonky2::{ field::goldilocks_field::GoldilocksField, iop::witness::PartialWitness, @@ -26,104 +29,80 @@ mod test_assert_slot_is_in_epoch { config::PoseidonGoldilocksConfig, }, }; - use plonky2_crypto::biguint::{CircuitBuilderBiguint, WitnessBigUint}; + use serde_json::json; use crate::utils::circuit::assert_slot_is_in_epoch::assert_slot_is_in_epoch; - #[test] - fn test_assert_slot_is_in_epoch() -> std::result::Result<(), anyhow::Error> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = GoldilocksField; + #[derive(CircuitTarget)] + struct SlotIsInEpochTestCircuitTarget { + #[target(in)] + #[serde(with = "serde_u64_str")] + pub slot: Uint64Target, - let mut pw = PartialWitness::new(); + #[target(in)] + #[serde(with = "serde_u64_str")] + pub epoch: Uint64Target, + } - let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); + struct AssertSlotIsInEpochTestCircuit; - let slot_target = builder.add_virtual_biguint_target(2); - let current_epoch = builder.add_virtual_biguint_target(2); + impl Circuit for AssertSlotIsInEpochTestCircuit { + type F = GoldilocksField; + type C = PoseidonGoldilocksConfig; + const CIRCUIT_CONFIG: CircuitConfig = CircuitConfig::standard_recursion_config(); - assert_slot_is_in_epoch(&mut builder, &slot_target, ¤t_epoch); + type Target = SlotIsInEpochTestCircuitTarget; - pw.set_biguint_target(&slot_target, &BigUint::from_u64(6953401).unwrap()); - pw.set_biguint_target(¤t_epoch, &BigUint::from_u64(217293).unwrap()); + fn define(builder: &mut CircuitBuilder, _: &Self::Params) -> Self::Target { + let input = Self::read_circuit_input_target(builder); - let data = builder.build::(); - let proof = data.prove(pw)?; + assert_slot_is_in_epoch(builder, input.slot, input.epoch); - data.verify(proof) + Self::Target { + slot: input.slot, + epoch: input.epoch, + } + } } - #[test] - fn test_assert_slot_is_in_epoch_slot_in_epoch() -> std::result::Result<(), anyhow::Error> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = GoldilocksField; + fn run_test_case(slot: u64, epoch: u64) { + let (target, data) = AssertSlotIsInEpochTestCircuit::build(&()); let mut pw = PartialWitness::new(); + target.set_witness( + &mut pw, + &serde_json::from_str( + &json!({ + "slot": slot.to_string(), + "epoch": epoch.to_string() + }) + .to_string(), + ) + .unwrap(), + ); - let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); - - let slot_target = builder.add_virtual_biguint_target(2); - let current_epoch = builder.add_virtual_biguint_target(2); - - assert_slot_is_in_epoch(&mut builder, &slot_target, ¤t_epoch); - - pw.set_biguint_target(&slot_target, &BigUint::from_u64(7314752).unwrap()); - pw.set_biguint_target(¤t_epoch, &BigUint::from_u64(228586).unwrap()); - - let data = builder.build::(); - let proof = data.prove(pw)?; - - data.verify(proof) + let proof = data.prove(pw).unwrap(); + data.verify(proof).unwrap(); } #[test] - fn test_assert_slot_is_in_epoch_last_slot_in_epoch() -> std::result::Result<(), anyhow::Error> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = GoldilocksField; - - let mut pw = PartialWitness::new(); - - let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); - - let slot_target = builder.add_virtual_biguint_target(2); - let current_epoch = builder.add_virtual_biguint_target(2); - - assert_slot_is_in_epoch(&mut builder, &slot_target, ¤t_epoch); - - pw.set_biguint_target(&slot_target, &BigUint::from_u64(7314751).unwrap()); - pw.set_biguint_target(¤t_epoch, &BigUint::from_u64(228585).unwrap()); + fn test_assert_slot_is_in_epoch() { + run_test_case(6953401, 217293); + } - let data = builder.build::(); - let proof = data.prove(pw)?; + #[test] + fn test_assert_slot_is_in_epoch_slot_in_epoch() { + run_test_case(7314752, 228586); + } - data.verify(proof) + #[test] + fn test_assert_slot_is_in_epoch_last_slot_in_epoch() { + run_test_case(7314751, 228585); } #[test] #[should_panic] - fn test_assert_slot_is_not_in_epoch() -> () { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = GoldilocksField; - - let mut pw = PartialWitness::new(); - - let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); - - let slot_target = builder.add_virtual_biguint_target(2); - let current_epoch = builder.add_virtual_biguint_target(2); - - assert_slot_is_in_epoch(&mut builder, &slot_target, ¤t_epoch); - - pw.set_biguint_target(&slot_target, &BigUint::from_u64(7314751).unwrap()); - pw.set_biguint_target(¤t_epoch, &BigUint::from_u64(228586).unwrap()); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - data.verify(proof).unwrap(); + fn test_assert_slot_is_not_in_epoch() { + run_test_case(7314751, 228586); } } diff --git a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/mod.rs b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/mod.rs index dd7c58de3..822d65400 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/mod.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/mod.rs @@ -8,7 +8,6 @@ use crate::common_targets::Sha256Target; pub mod poseidon; pub mod sha256; -pub mod ssz; pub fn pick_left_and_right_hash, const D: usize>( builder: &mut CircuitBuilder, diff --git a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/poseidon.rs b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/poseidon.rs index 1ceb890d2..16d02c2fe 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/poseidon.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/poseidon.rs @@ -1,20 +1,17 @@ -use circuit::{circuit_builder_extensions::CircuitBuilderExtensions, ToTargets}; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, targets::uint::Uint64Target, ToTargets, +}; use itertools::Itertools; -use num::BigUint; use plonky2::{ field::extension::Extendable, hash::hash_types::{HashOutTarget, RichField, NUM_HASH_OUT_ELTS}, iop::target::BoolTarget, plonk::circuit_builder::CircuitBuilder, }; -use plonky2_crypto::biguint::{BigUintTarget, CircuitBuilderBiguint}; use crate::{ common_targets::{PoseidonMerkleBranchTarget, ValidatorTarget}, - utils::circuit::{ - biguint_to_le_bits_target, - hashing::poseidon::{poseidon, poseidon_pair}, - }, + utils::circuit::hashing::poseidon::{poseidon, poseidon_pair}, }; pub fn hash_tree_root_poseidon, const D: usize>( @@ -123,9 +120,9 @@ pub fn restore_merkle_root_poseidon< builder: &mut CircuitBuilder, leaf: &HashOutTarget, branch: &PoseidonMerkleBranchTarget, - gindex: &BigUintTarget, + gindex: Uint64Target, ) -> HashOutTarget { - let bits = biguint_to_le_bits_target(builder, &gindex); + let bits = gindex.to_le_bits(builder); let mut current = leaf.clone(); for level in 0..DEPTH { @@ -148,8 +145,8 @@ pub fn validate_merkle_proof_const_poseidon< branch: &PoseidonMerkleBranchTarget, gindex: u64, ) -> BoolTarget { - let gindex_target = builder.constant_biguint(&BigUint::from(gindex)); - let restored_root = restore_merkle_root_poseidon(builder, leaf, branch, &gindex_target); + let gindex_target = Uint64Target::constant(gindex, builder); + let restored_root = restore_merkle_root_poseidon(builder, leaf, branch, gindex_target); hash_outs_are_equal(builder, &restored_root, root) } @@ -162,7 +159,7 @@ pub fn validate_merkle_proof_poseidon< leaf: &HashOutTarget, root: &HashOutTarget, branch: &PoseidonMerkleBranchTarget, - gindex: &BigUintTarget, + gindex: Uint64Target, ) -> BoolTarget { let restored_root = restore_merkle_root_poseidon(builder, leaf, branch, gindex); hash_outs_are_equal(builder, &restored_root, root) @@ -177,7 +174,7 @@ pub fn assert_merkle_proof_is_valid_poseidon< leaf: &HashOutTarget, root: &HashOutTarget, branch: &PoseidonMerkleBranchTarget, - gindex: &BigUintTarget, + gindex: Uint64Target, ) { let is_valid = validate_merkle_proof_poseidon(builder, leaf, root, branch, gindex); builder.assert_true(is_valid); @@ -194,7 +191,6 @@ pub fn assert_merkle_proof_is_valid_const_poseidon< branch: &PoseidonMerkleBranchTarget, gindex: u64, ) { - let gindex_target = builder.constant_biguint(&BigUint::from(gindex)); - let is_valid = validate_merkle_proof_poseidon(builder, leaf, root, branch, &gindex_target); - builder.assert_true(is_valid); + let gindex_target = Uint64Target::constant(gindex, builder); + assert_merkle_proof_is_valid_poseidon(builder, leaf, root, branch, gindex_target); } diff --git a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/sha256.rs b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/sha256.rs index 03737a83d..a49ab077c 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/sha256.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/sha256.rs @@ -1,26 +1,22 @@ -use circuit::circuit_builder_extensions::CircuitBuilderExtensions; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, targets::uint::Uint64Target, + SSZHashTreeRoot, +}; use itertools::Itertools; -use num_bigint::BigUint; use plonky2::{ field::extension::Extendable, hash::hash_types::RichField, iop::target::BoolTarget, plonk::circuit_builder::CircuitBuilder, }; -use plonky2_crypto::biguint::{BigUintTarget, CircuitBuilderBiguint}; use crate::{ common_targets::{ MerklelizedValidatorTarget, SSZTarget, Sha256MerkleBranchTarget, Sha256Target, ValidatorTarget, }, - utils::circuit::{ - biguint_to_le_bits_target, bool_arrays_are_equal, hashing::sha256::sha256_pair, - }, + utils::circuit::{bool_arrays_are_equal, hashing::sha256::sha256_pair}, }; -use super::{ - pick_left_and_right_hash, - ssz::{ssz_merklelize_bool, ssz_num_to_bits}, -}; +use super::pick_left_and_right_hash; pub fn restore_merkle_root_sha256< const DEPTH: usize, @@ -30,9 +26,9 @@ pub fn restore_merkle_root_sha256< builder: &mut CircuitBuilder, leaf: &Sha256Target, branch: &Sha256MerkleBranchTarget, - gindex: &BigUintTarget, + gindex: Uint64Target, ) -> Sha256Target { - let bits = biguint_to_le_bits_target(builder, &gindex); + let bits = gindex.to_le_bits(builder); let mut current = leaf.clone(); for level in 0..DEPTH { @@ -53,7 +49,7 @@ pub fn validate_merkle_proof_sha256< leaf: &Sha256Target, root: &Sha256Target, branch: &Sha256MerkleBranchTarget, - gindex: &BigUintTarget, + gindex: Uint64Target, ) -> BoolTarget { let restored_root = restore_merkle_root_sha256(builder, leaf, branch, gindex); bool_arrays_are_equal(builder, root, &restored_root) @@ -68,7 +64,7 @@ pub fn assert_merkle_proof_is_valid_sha256< leaf: &Sha256Target, root: &Sha256Target, branch: &Sha256MerkleBranchTarget, - gindex: &BigUintTarget, + gindex: Uint64Target, ) { let is_valid = validate_merkle_proof_sha256(builder, leaf, root, branch, gindex); builder.assert_true(is_valid); @@ -85,8 +81,8 @@ pub fn validate_merkle_proof_const_sha256< branch: &Sha256MerkleBranchTarget, gindex: u64, ) -> BoolTarget { - let gindex_target = builder.constant_biguint(&BigUint::from(gindex)); - let restored_root = restore_merkle_root_sha256(builder, leaf, branch, &gindex_target); + let gindex_target = Uint64Target::constant(gindex, builder); + let restored_root = restore_merkle_root_sha256(builder, leaf, branch, gindex_target); bool_arrays_are_equal(builder, root, &restored_root) } @@ -166,15 +162,13 @@ pub fn merklelize_validator_target, const D: usize> MerklelizedValidatorTarget { pubkey: [first_pubkey_leaf, second_pubkey_leaf], withdrawal_credentials: validator.withdrawal_credentials, - effective_balance: ssz_num_to_bits(builder, &validator.effective_balance, 64), - slashed: ssz_merklelize_bool(builder, validator.slashed), - activation_eligibility_epoch: ssz_num_to_bits( - builder, - &validator.activation_eligibility_epoch, - 64, - ), - activation_epoch: ssz_num_to_bits(builder, &validator.activation_epoch, 64), - exit_epoch: ssz_num_to_bits(builder, &validator.exit_epoch, 64), - withdrawable_epoch: ssz_num_to_bits(builder, &validator.withdrawable_epoch, 64), + effective_balance: validator.effective_balance.ssz_hash_tree_root(builder), + slashed: validator.slashed.ssz_hash_tree_root(builder), + activation_eligibility_epoch: validator + .activation_eligibility_epoch + .ssz_hash_tree_root(builder), + activation_epoch: validator.activation_epoch.ssz_hash_tree_root(builder), + exit_epoch: validator.exit_epoch.ssz_hash_tree_root(builder), + withdrawable_epoch: validator.withdrawable_epoch.ssz_hash_tree_root(builder), } } diff --git a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/ssz.rs b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/ssz.rs deleted file mode 100644 index d55a87d75..000000000 --- a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/hashing/merkle/ssz.rs +++ /dev/null @@ -1,37 +0,0 @@ -use plonky2::{ - field::extension::Extendable, hash::hash_types::RichField, iop::target::BoolTarget, - plonk::circuit_builder::CircuitBuilder, -}; -use plonky2_crypto::biguint::BigUintTarget; - -use crate::{ - common_targets::SSZTarget, - utils::circuit::{biguint_to_bits_target, bits_to_biguint_target, reverse_endianness}, -}; - -pub fn ssz_merklelize_bool, const D: usize>( - builder: &mut CircuitBuilder, - bool_target: BoolTarget, -) -> SSZTarget { - let mut ssz_leaf = [BoolTarget::new_unsafe(builder.zero()); 256]; - ssz_leaf[7] = bool_target; - ssz_leaf -} -pub fn ssz_num_to_bits, const D: usize>( - builder: &mut CircuitBuilder, - num: &BigUintTarget, - bit_len: usize, -) -> SSZTarget { - assert!(bit_len <= 256); - - let mut bits = reverse_endianness(&biguint_to_bits_target(builder, num)); - bits.extend((bit_len..256).map(|_| builder._false())); - - bits.try_into().unwrap() -} -pub fn ssz_num_from_bits, const D: usize>( - builder: &mut CircuitBuilder, - bits: &[BoolTarget], -) -> BigUintTarget { - bits_to_biguint_target(builder, reverse_endianness(bits)) -} diff --git a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/mod.rs b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/mod.rs index 40f961184..af658666d 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/mod.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/mod.rs @@ -1,6 +1,11 @@ -use circuit::circuit_builder_extensions::CircuitBuilderExtensions; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, + targets::uint::{ + ops::{arithmetic::Zero, comparison::EqualTo}, + Uint64Target, + }, +}; use itertools::Itertools; -use num::BigUint; use plonky2::{ field::extension::Extendable, hash::hash_types::RichField, @@ -12,15 +17,10 @@ use plonky2::{ proof::ProofWithPublicInputsTarget, }, }; -use plonky2_crypto::{ - biguint::{BigUintTarget, CircuitBuilderBiguint}, - u32::arithmetic_u32::U32Target, -}; +use plonky2_crypto::{biguint::BigUintTarget, u32::arithmetic_u32::U32Target}; use crate::common_targets::SSZTarget; -use self::hashing::merkle::ssz::ssz_num_from_bits; - pub mod assert_slot_is_in_epoch; pub mod hashing; pub mod validator_status; @@ -115,48 +115,23 @@ pub fn arrays_are_equal, const D: usize>( result } -pub fn bits_to_biguint_target, const D: usize>( +pub fn biguint_target_from_le_bits, const D: usize>( builder: &mut CircuitBuilder, - bits_target: Vec, + bits: &[BoolTarget], ) -> BigUintTarget { - let bit_len = bits_target.len(); + let bit_len = bits.len(); assert_eq!(bit_len % 32, 0); let mut u32_targets = Vec::new(); for i in 0..bit_len / 32 { u32_targets.push(U32Target( - builder.le_sum(bits_target[i * 32..(i + 1) * 32].iter().rev()), + builder.le_sum(bits[i * 32..(i + 1) * 32].iter().rev()), )); } u32_targets.reverse(); BigUintTarget { limbs: u32_targets } } -pub fn biguint_to_bits_target, const D: usize>( - builder: &mut CircuitBuilder, - a: &BigUintTarget, -) -> Vec { - let mut res = Vec::new(); - for i in (0..a.num_limbs()).rev() { - let bit_targets = builder.split_le_base::<2>(a.get_limb(i).0, 32); - for j in (0..32).rev() { - res.push(BoolTarget::new_unsafe(bit_targets[j])); - } - } - - res -} - -pub fn biguint_to_le_bits_target, const D: usize>( - builder: &mut CircuitBuilder, - a: &BigUintTarget, -) -> Vec { - biguint_to_bits_target(builder, a) - .into_iter() - .rev() - .collect_vec() -} - pub fn bits_to_bytes_target, const D: usize>( builder: &mut CircuitBuilder, bits: &[BoolTarget], @@ -167,30 +142,6 @@ pub fn bits_to_bytes_target, const D: usize>( .collect_vec() } -pub fn reverse_endianness(bits: &[BoolTarget]) -> Vec { - bits.chunks(8).rev().flatten().cloned().collect() -} - -pub fn select_biguint, const D: usize>( - builder: &mut CircuitBuilder, - b: BoolTarget, - x: &BigUintTarget, - y: &BigUintTarget, -) -> BigUintTarget { - let not_b = builder.not(b); - - let maybe_x = builder.mul_biguint_by_bool(x, b); - - let maybe_y = builder.mul_biguint_by_bool(y, not_b); - - let mut result = builder.add_biguint(&maybe_y, &maybe_x); - - // trim the carry - result.limbs.pop(); - - result -} - pub fn target_to_be_bits, const D: usize>( builder: &mut CircuitBuilder, number: Target, @@ -203,42 +154,8 @@ pub fn target_to_be_bits, const D: usize>( .try_into() .unwrap() } -pub fn is_equal_u32, const D: usize>( - builder: &mut CircuitBuilder, - x: U32Target, - y: U32Target, -) -> BoolTarget { - builder.is_equal(x.0, y.0) -} - -pub fn biguint_is_equal_non_equal_limbs, const D: usize>( - builder: &mut CircuitBuilder, - a: &BigUintTarget, - b: &BigUintTarget, -) -> BoolTarget { - let mut ret = builder._true(); - let false_t = builder._false().target; - - let min_limbs = a.num_limbs().min(b.num_limbs()); - for i in 0..min_limbs { - let limb_equal = is_equal_u32(builder, a.get_limb(i), b.get_limb(i)); - ret = BoolTarget::new_unsafe(builder.select(limb_equal, ret.target, false_t)); - } - let zero_u32 = U32Target(builder.zero()); - for i in min_limbs..a.num_limbs() { - let is_zero = is_equal_u32(builder, a.get_limb(i), zero_u32); - ret = BoolTarget::new_unsafe(builder.select(is_zero, ret.target, false_t)); - } - for i in min_limbs..b.num_limbs() { - let is_zero = is_equal_u32(builder, b.get_limb(i), zero_u32); - ret = BoolTarget::new_unsafe(builder.select(is_zero, ret.target, false_t)); - } - - ret -} - -pub fn split_into_chunks(leaf: &[BoolTarget; 256]) -> [[BoolTarget; 64]; 4] { +fn split_into_chunks(leaf: &[BoolTarget; 256]) -> [[BoolTarget; 64]; 4] { let mut chunks = Vec::new(); for i in 0..4 { @@ -248,56 +165,37 @@ pub fn split_into_chunks(leaf: &[BoolTarget; 256]) -> [[BoolTarget; 64]; 4] { chunks.try_into().unwrap() } +/// `balance_index` must be in the range [0, 3]. pub fn get_balance_from_leaf, const D: usize>( builder: &mut CircuitBuilder, leaf: &SSZTarget, - balance_index: BigUintTarget, -) -> BigUintTarget { + balance_index: Uint64Target, +) -> Uint64Target { let balances_in_leaf = split_into_chunks(leaf); - let mut accumulator = ssz_num_from_bits(builder, &balances_in_leaf[0].clone()); - for i in 1..balances_in_leaf.len() { - let current_index_t = builder.constant_biguint(&BigUint::from(i as u32)); - let current_balance_in_leaf = ssz_num_from_bits(builder, &balances_in_leaf[i].clone()); - - let selector_enabled = - biguint_is_equal_non_equal_limbs(builder, ¤t_index_t, &balance_index); - accumulator = select_biguint( - builder, - selector_enabled, - ¤t_balance_in_leaf, - &accumulator, - ); - } + let mut accumulator = Uint64Target::zero(builder); + for i in 0..balances_in_leaf.len() { + let current_index_t = Uint64Target::constant(i as u64, builder); + let current_balance_in_leaf = Uint64Target::from_le_bytes(&balances_in_leaf[i], builder); - accumulator -} - -pub fn biguint_target_from_limbs(limbs: &[Target]) -> BigUintTarget { - BigUintTarget { - limbs: limbs.iter().cloned().map(|x| U32Target(x)).collect_vec(), - } -} - -pub fn biguint_is_equal, const D: usize>( - builder: &mut CircuitBuilder, - a: &BigUintTarget, - b: &BigUintTarget, -) -> BoolTarget { - assert!(a.limbs.len() == b.limbs.len()); + let selector_enabled = current_index_t.equal_to(balance_index, builder); - let mut all_equal = builder._true(); - - for i in 0..a.limbs.len() { - let equal = builder.is_equal(a.limbs[i].0, b.limbs[i].0); - all_equal = builder.and(all_equal, equal); + accumulator = + builder.select_target(selector_enabled, ¤t_balance_in_leaf, &accumulator); } - all_equal + accumulator } #[cfg(test)] mod test_ssz_num_from_bits { use anyhow::Result; + use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, + targets::uint::{ + ops::{arithmetic::Zero, comparison::EqualTo}, + Uint64Target, + }, + }; use itertools::Itertools; use num::{BigUint, Num}; use plonky2::{ @@ -311,12 +209,9 @@ mod test_ssz_num_from_bits { config::PoseidonGoldilocksConfig, }, }; - use plonky2_crypto::biguint::CircuitBuilderBiguint; use serde::Deserialize; use std::{fs, iter::repeat, println}; - use crate::utils::circuit::hashing::merkle::ssz::ssz_num_from_bits; - use super::get_balance_from_leaf; #[derive(Debug, Default, Deserialize)] @@ -382,8 +277,8 @@ mod test_ssz_num_from_bits { .parse::() .unwrap(); - if num_bits % 32 != 0 { - // For now lets test only multiples of 32 + if num_bits != 64 { + // For now lets test only test 64 bits continue; } @@ -402,9 +297,9 @@ mod test_ssz_num_from_bits { .map(|_| builder.add_virtual_bool_target_safe()) .collect::>(); - let target = ssz_num_from_bits(&mut builder, &bits); + let target = Uint64Target::from_le_bytes(&bits, &mut builder); - let value = test_case.value.parse::().expect( + let value = test_case.value.parse::().expect( format!( "Unable to parse value: {}_{}", test_case.r#type, test_case.tags[2] @@ -412,9 +307,9 @@ mod test_ssz_num_from_bits { .as_str(), ); - let expected_target = builder.constant_biguint(&value); - - builder.connect_biguint(&target, &expected_target); + let expected_target = Uint64Target::constant(value, &mut builder); + let values_are_equal = target.equal_to(expected_target, &mut builder); + builder.assert_true(values_are_equal); let data = builder.build::(); @@ -478,10 +373,11 @@ mod test_ssz_num_from_bits { .try_into() .unwrap(); - let balance_index_0 = builder.zero_biguint(); - let balance_index_1 = builder.constant_biguint(&BigUint::from(1 as u32)); - let balance_index_2 = builder.constant_biguint(&BigUint::from(2 as u32)); - let balance_index_3 = builder.constant_biguint(&BigUint::from(3 as u32)); + let balance_index_0 = Uint64Target::zero(&mut builder); + let balance_index_1 = Uint64Target::constant(1, &mut builder); + let balance_index_2 = Uint64Target::constant(2, &mut builder); + let balance_index_3 = Uint64Target::constant(3, &mut builder); + let balance_from_leaf_at_index_0 = get_balance_from_leaf(&mut builder, &leaf, balance_index_0); let balance_from_leaf_at_index_1 = @@ -491,19 +387,19 @@ mod test_ssz_num_from_bits { let balance_from_leaf_at_index_3 = get_balance_from_leaf(&mut builder, &leaf, balance_index_3); - let expected_balance_at_index_0 = - builder.constant_biguint(&BigUint::from(32000579388 as u64)); - let expected_balance_at_index_1 = - builder.constant_biguint(&BigUint::from(32000574671 as u64)); - let expected_balance_at_index_2 = - builder.constant_biguint(&BigUint::from(32000579312 as u64)); - let expected_balance_at_index_3 = - builder.constant_biguint(&BigUint::from(32000581683 as u64)); - - builder.connect_biguint(&balance_from_leaf_at_index_0, &expected_balance_at_index_0); - builder.connect_biguint(&balance_from_leaf_at_index_1, &expected_balance_at_index_1); - builder.connect_biguint(&balance_from_leaf_at_index_2, &expected_balance_at_index_2); - builder.connect_biguint(&balance_from_leaf_at_index_3, &expected_balance_at_index_3); + let expected_balance_at_index_0 = Uint64Target::constant(32000579388, &mut builder); + let expected_balance_at_index_1 = Uint64Target::constant(32000574671, &mut builder); + let expected_balance_at_index_2 = Uint64Target::constant(32000579312, &mut builder); + let expected_balance_at_index_3 = Uint64Target::constant(32000581683, &mut builder); + + builder + .assert_targets_are_equal(&balance_from_leaf_at_index_0, &expected_balance_at_index_0); + builder + .assert_targets_are_equal(&balance_from_leaf_at_index_1, &expected_balance_at_index_1); + builder + .assert_targets_are_equal(&balance_from_leaf_at_index_2, &expected_balance_at_index_2); + builder + .assert_targets_are_equal(&balance_from_leaf_at_index_3, &expected_balance_at_index_3); let pw = PartialWitness::new(); let data = builder.build::(); diff --git a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/validator_status.rs b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/validator_status.rs index d5bcd0f15..4164e0e4f 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/validator_status.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/utils/circuit/validator_status.rs @@ -1,27 +1,22 @@ +use circuit::targets::uint::{ + ops::comparison::{Comparison, LessThanOrEqual}, + Uint64Target, +}; use plonky2::{ field::extension::Extendable, hash::hash_types::RichField, iop::target::BoolTarget, plonk::circuit_builder::CircuitBuilder, }; -use plonky2_crypto::biguint::{BigUintTarget, CircuitBuilderBiguint}; - -use crate::utils::circuit::biguint_is_equal; pub fn get_validator_status, const D: usize>( builder: &mut CircuitBuilder, - activation_epoch: &BigUintTarget, - current_epoch: &BigUintTarget, - exit_epoch: &BigUintTarget, + activation_epoch: Uint64Target, + current_epoch: Uint64Target, + exit_epoch: Uint64Target, ) -> (BoolTarget, BoolTarget, BoolTarget) { - let activation_epoch_le_current_epoch = builder.cmp_biguint(&activation_epoch, ¤t_epoch); - - let current_epoch_le_exit_epoch = builder.cmp_biguint(¤t_epoch, &exit_epoch); - - let is_equal = biguint_is_equal(builder, current_epoch, exit_epoch); - let not_equal = builder.not(is_equal); - - let current_epoch_lt_exit_epoch = builder.and(current_epoch_le_exit_epoch, not_equal); + let is_not_activated = current_epoch.lt(activation_epoch, builder); - let is_not_activated = builder.not(activation_epoch_le_current_epoch); + let activation_epoch_le_current_epoch = activation_epoch.lte(current_epoch, builder); + let current_epoch_lt_exit_epoch = current_epoch.lt(exit_epoch, builder); let is_valid_validator = builder.and( activation_epoch_le_current_epoch, @@ -35,12 +30,12 @@ pub fn get_validator_status, const D: usize>( pub fn get_validator_relevance, const D: usize>( builder: &mut CircuitBuilder, - activation_epoch: &BigUintTarget, - current_epoch: &BigUintTarget, - withdrawable_epoch: &BigUintTarget, + activation_epoch: Uint64Target, + current_epoch: Uint64Target, + withdrawable_epoch: Uint64Target, ) -> BoolTarget { - let current_le_withdrawable_epoch = builder.cmp_biguint(¤t_epoch, &withdrawable_epoch); - let activation_epoch_le_current_epoch = builder.cmp_biguint(&activation_epoch, ¤t_epoch); + let current_le_withdrawable_epoch = current_epoch.lte(withdrawable_epoch, builder); + let activation_epoch_le_current_epoch = activation_epoch.lte(current_epoch, builder); builder.and( current_le_withdrawable_epoch, @@ -51,8 +46,10 @@ pub fn get_validator_relevance, const D: usize>( #[cfg(test)] mod test { use anyhow::Result; - use num::FromPrimitive; - use num_bigint::BigUint; + use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, targets::uint::Uint64Target, + AddVirtualTarget, SetWitness, + }; use plonky2::{ field::goldilocks_field::GoldilocksField, iop::witness::PartialWitness, @@ -61,7 +58,6 @@ mod test { config::PoseidonGoldilocksConfig, }, }; - use plonky2_crypto::biguint::{CircuitBuilderBiguint, WitnessBigUint}; use crate::utils::circuit::validator_status::get_validator_status; @@ -71,17 +67,19 @@ mod test { fn test_get_validator_relevance() -> Result<()> { let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); - let activation_epoch = builder.constant_biguint(&BigUint::from(28551 as u32)); - let current_epoch = builder.constant_biguint(&BigUint::from(285512 as u32)); - let withdrawable_epoch = builder.constant_biguint(&BigUint::from(2855125512 as u32)); + + let activation_epoch = Uint64Target::constant(28551, &mut builder); + let current_epoch = Uint64Target::constant(285512, &mut builder); + let withdrawable_epoch = Uint64Target::constant(2855125512, &mut builder); + let is_validator_relevant = get_validator_relevance( &mut builder, - &activation_epoch, - ¤t_epoch, - &withdrawable_epoch, + activation_epoch, + current_epoch, + withdrawable_epoch, ); - builder.assert_one(is_validator_relevant.target); + builder.assert_true(is_validator_relevant); let pw = PartialWitness::new(); let data = builder.build::(); @@ -100,28 +98,14 @@ mod test { type C = PoseidonGoldilocksConfig; type F = GoldilocksField; - let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); - let activation_epoch = builder.add_virtual_biguint_target(2); - let current_epoch = builder.add_virtual_biguint_target(2); - let exit_epoch = builder.add_virtual_biguint_target(2); + let activation_epoch = ::add_virtual_target(&mut builder); + let current_epoch = ::add_virtual_target(&mut builder); + let exit_epoch = ::add_virtual_target(&mut builder); let (is_non_activated_validator, is_valid_validator, is_exited_validator) = - get_validator_status(&mut builder, &activation_epoch, ¤t_epoch, &exit_epoch); - - pw.set_biguint_target( - &activation_epoch, - &BigUint::from_u64(activation_epoch_value).unwrap(), - ); - - pw.set_biguint_target( - ¤t_epoch, - &BigUint::from_u64(current_epoch_value).unwrap(), - ); - - pw.set_biguint_target(&exit_epoch, &BigUint::from_u64(exit_epoch_value).unwrap()); + get_validator_status(&mut builder, activation_epoch, current_epoch, exit_epoch); if assert_result.0 { builder.assert_one(is_non_activated_validator.target); @@ -142,8 +126,13 @@ mod test { } let data = builder.build::(); - let proof = data.prove(pw).unwrap(); + let mut pw = PartialWitness::new(); + activation_epoch.set_witness(&mut pw, &activation_epoch_value); + current_epoch.set_witness(&mut pw, ¤t_epoch_value); + exit_epoch.set_witness(&mut pw, &exit_epoch_value); + + let proof = data.prove(pw).unwrap(); data.verify(proof) } diff --git a/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/final_layer.rs b/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/final_layer.rs index c53b3dcbd..2f4923027 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/final_layer.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/final_layer.rs @@ -1,22 +1,18 @@ use crate::{ common_targets::{Sha256MerkleBranchTarget, Sha256Target}, - serializers::{ - biguint_to_str, parse_biguint, serde_bool_array_to_hex_string, - serde_bool_array_to_hex_string_nested, - }, + serializers::{serde_bool_array_to_hex_string, serde_bool_array_to_hex_string_nested}, utils::circuit::{ assert_slot_is_in_epoch::assert_slot_is_in_epoch, - biguint_to_bits_target, bits_to_bytes_target, - hashing::{ - merkle::{sha256::assert_merkle_proof_is_valid_const_sha256, ssz::ssz_num_to_bits}, - sha256::sha256, - }, + bits_to_bytes_target, + hashing::{merkle::sha256::assert_merkle_proof_is_valid_const_sha256, sha256::sha256}, target_to_be_bits, verify_proof, }, validators_commitment_mapper::first_level::ValidatorsCommitmentMapperFirstLevel, withdrawal_credentials_balance_aggregator::first_level::WithdrawalCredentialsBalanceAggregatorFirstLevel, }; -use circuit::{Circuit, CircuitInputTarget}; +use circuit::{ + serde::serde_u64_str, targets::uint::Uint64Target, Circuit, CircuitInputTarget, SSZHashTreeRoot, +}; use circuit_derive::CircuitTarget; use itertools::Itertools; use plonky2::{ @@ -30,7 +26,6 @@ use plonky2::{ proof::ProofWithPublicInputsTarget, }, }; -use plonky2_crypto::biguint::BigUintTarget; const D: usize = 2; @@ -38,8 +33,8 @@ const D: usize = 2; #[serde(rename_all = "camelCase")] pub struct FinalCircuitTargets { #[target(in)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub slot: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub slot: Uint64Target, #[target(in)] #[serde(with = "serde_bool_array_to_hex_string_nested")] @@ -124,10 +119,11 @@ impl Circuit &validators_commitment_mapper_pi.sha256_hash_tree_root, ); - assert_slot_is_in_epoch(builder, &input.slot, &balance_verification_pi.current_epoch); + assert_slot_is_in_epoch(builder, input.slot, balance_verification_pi.current_epoch); - let accumulated_balance_bits = - biguint_to_bits_target(builder, &balance_verification_pi.range_total_value); + let accumulated_balance_bits = balance_verification_pi + .range_total_value + .to_be_bits(builder); let flattened_withdrawal_credentials = balance_verification_pi .withdrawal_credentials @@ -221,7 +217,7 @@ fn validate_input_against_block_root< 88, ); - let slot_ssz = ssz_num_to_bits(builder, &input.slot, 64); + let slot_ssz = input.slot.ssz_hash_tree_root(builder); assert_merkle_proof_is_valid_const_sha256( builder, diff --git a/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/first_level.rs b/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/first_level.rs index 3568ef3f7..afe335631 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/first_level.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/first_level.rs @@ -6,13 +6,19 @@ use crate::{ hashing::merkle::{ poseidon::{hash_tree_root_poseidon, hash_validator_poseidon_or_zeroes}, sha256::hash_tree_root_sha256, - ssz::ssz_num_from_bits, }, - select_biguint, validator_status::get_validator_status, }, }; -use circuit::Circuit; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, + serde::serde_u64_str, + targets::uint::{ + ops::arithmetic::{Add, Zero}, + Uint64Target, + }, + Circuit, +}; use circuit_derive::{CircuitTarget, SerdeCircuitTarget}; use itertools::Itertools; @@ -25,12 +31,8 @@ use plonky2::{ config::PoseidonGoldilocksConfig, }, }; -use plonky2_crypto::biguint::{BigUintTarget, CircuitBuilderBiguint}; -use crate::{ - common_targets::Sha256Target, - serializers::{biguint_to_str, parse_biguint}, -}; +use crate::common_targets::Sha256Target; #[derive(CircuitTarget, SerdeCircuitTarget)] #[serde(rename_all = "camelCase")] @@ -55,12 +57,12 @@ pub struct ValidatorBalanceVerificationTargets< pub withdrawal_credentials: [Sha256Target; WITHDRAWAL_CREDENTIALS_COUNT], #[target(in, out)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub current_epoch: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub current_epoch: Uint64Target, #[target(out)] - #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] - pub range_total_value: BigUintTarget, + #[serde(with = "serde_u64_str")] + pub range_total_value: Uint64Target, #[target(out)] #[serde(with = "serde_bool_array_to_hex_string")] @@ -128,7 +130,7 @@ where let validators_hash_tree_root_poseidon = hash_tree_root_poseidon(builder, &validators_leaves); - let mut range_total_value = builder.zero_biguint(); + let mut range_total_value = Uint64Target::zero(builder); let mut number_of_non_activated_validators = builder.zero(); let mut number_of_active_validators = builder.zero(); let mut number_of_exited_validators = builder.zero(); @@ -147,26 +149,26 @@ where validator_is_considered = builder.or(is_equal_inner, validator_is_considered); } - let balance = ssz_num_from_bits( - builder, + let balance = Uint64Target::from_le_bytes( &input.balances_leaves[i / 4][((i % 4) * 64)..(((i % 4) * 64) + 64)], + builder, ); - let zero = builder.zero_biguint(); + let zero_u64 = Uint64Target::zero(builder); let (is_non_activated_validator, is_valid_validator, is_exited_validator) = get_validator_status( builder, - &input.validators[i].activation_epoch, - &input.current_epoch, - &input.validators[i].exit_epoch, + input.validators[i].activation_epoch, + input.current_epoch, + input.validators[i].exit_epoch, ); let will_be_counted = builder.and(validator_is_considered, is_valid_validator); - let current = select_biguint(builder, will_be_counted, &balance, &zero); + let current = builder.select_target(will_be_counted, &balance, &zero_u64); - range_total_value = builder.add_biguint(&range_total_value, ¤t); + range_total_value = range_total_value.add(current, builder); number_of_active_validators = builder.add(number_of_active_validators, will_be_counted.target); @@ -187,8 +189,6 @@ where number_of_slashed_validators, validator_is_considered_and_is_slashed.target, ); - - range_total_value.limbs.pop(); } Self::Target { diff --git a/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/inner_level.rs b/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/inner_level.rs index 1a2295019..0bcc648ee 100644 --- a/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/inner_level.rs +++ b/beacon-light-client/plonky2/crates/circuits/src/withdrawal_credentials_balance_aggregator/inner_level.rs @@ -7,7 +7,10 @@ use crate::{ }, withdrawal_credentials_balance_aggregator::first_level::WithdrawalCredentialsBalanceAggregatorFirstLevel, }; -use circuit::{Circuit, CircuitOutputTarget}; +use circuit::{ + circuit_builder_extensions::CircuitBuilderExtensions, targets::uint::ops::arithmetic::Add, + Circuit, CircuitOutputTarget, +}; use plonky2::{ field::goldilocks_field::GoldilocksField, plonk::{ @@ -16,7 +19,6 @@ use plonky2::{ config::PoseidonGoldilocksConfig, }, }; -use plonky2_crypto::biguint::CircuitBuilderBiguint; pub struct WithdrawalCredentialsBalanceAggregatorInnerLevel< const VALIDATORS_COUNT: usize, @@ -92,11 +94,9 @@ where r_input.number_of_slashed_validators, ); - let mut range_total_value = - builder.add_biguint(&l_input.range_total_value, &r_input.range_total_value); - - // pop carry - range_total_value.limbs.pop(); + let range_total_value = l_input + .range_total_value + .add(r_input.range_total_value, builder); for i in 0..WITHDRAWAL_CREDENTIALS_COUNT { connect_bool_arrays( @@ -106,7 +106,7 @@ where ); } - builder.connect_biguint(&l_input.current_epoch, &r_input.current_epoch); + builder.assert_targets_are_equal(&l_input.current_epoch, &r_input.current_epoch); let output_target = CircuitOutputTarget::< WithdrawalCredentialsBalanceAggregatorFirstLevel<