diff --git a/Cargo.lock b/Cargo.lock index 07f969855..89d8ecf87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2210,26 +2210,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" -[[package]] -name = "jemalloc-sys" -version = "0.5.4+5.3.0-patched" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c1946e1cea1788cbfde01c993b52a10e2da07f4bac608228d1bed20bfebf2" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "jemallocator" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0de374a9f8e63150e6f5e8a60cc14c668226d7a347d8aee1a45766e3c4dd3bc" -dependencies = [ - "jemalloc-sys", - "libc", -] - [[package]] name = "jobserver" version = "0.1.26" @@ -2983,7 +2963,6 @@ dependencies = [ "futures", "hex", "itertools 0.10.5", - "jemallocator", "lazy_static", "log", "num", diff --git a/plonky2x/core/Cargo.toml b/plonky2x/core/Cargo.toml index 395ac5996..ccede3afb 100644 --- a/plonky2x/core/Cargo.toml +++ b/plonky2x/core/Cargo.toml @@ -21,9 +21,7 @@ num = { version = "0.4", default-features = false } sha2 = "0.10.7" curve25519-dalek = { git = "https://github.com/succinctlabs/curve25519-dalek.git", branch = "feature/edwards-point-getters" } ff = { package = "ff", version = "0.13", features = ["derive"] } - ethers = { version = "2.0" } - hex = "0.4.3" log = { version = "0.4.14", default-features = false } rand = { version = "0.8.4", package = "rand" } @@ -47,14 +45,11 @@ serde_with = "3.3.0" bincode = "1.3.3" uuid = { version = "1.4.1", features = ["serde"] } serde_plain = "1.0.2" -jemallocator = "0.5.0" ed25519-consensus = "2.1.0" async-trait = "0.1.73" digest = "0.10.7" sha256 = "1.4.0" [dev-dependencies] -plonky2 = { git = "https://github.com/mir-protocol/plonky2.git", features = [ - "gate_testing", -] } +plonky2 = { git = "https://github.com/mir-protocol/plonky2.git", features = ["gate_testing"] } env_logger = "0.10.0" diff --git a/plonky2x/core/src/backend/circuit/serialization/hints.rs b/plonky2x/core/src/backend/circuit/serialization/hints.rs index ad53965ef..3fe79eb0d 100644 --- a/plonky2x/core/src/backend/circuit/serialization/hints.rs +++ b/plonky2x/core/src/backend/circuit/serialization/hints.rs @@ -49,15 +49,16 @@ use crate::frontend::curta::hash::sha::sha256::hint::Sha256ProofHint; use crate::frontend::ecc::ed25519::field::ed25519_base::Ed25519Base; use crate::frontend::eth::beacon::generators::{ BeaconAllWithdrawalsHint, BeaconBalanceBatchWitnessHint, BeaconBalanceGenerator, - BeaconBalanceWitnessHint, BeaconBalancesGenerator, BeaconExecutionPayloadHint, - BeaconHeaderHint, BeaconHistoricalBlockGenerator, BeaconPartialBalancesHint, + BeaconBalanceWitnessHint, BeaconBalancesGenerator, BeaconBlockRootsHint, + BeaconExecutionPayloadHint, BeaconGraffitiHint, BeaconHeaderHint, + BeaconHeadersFromOffsetRangeHint, BeaconHistoricalBlockGenerator, BeaconPartialBalancesHint, BeaconPartialValidatorsHint, BeaconValidatorBatchHint, BeaconValidatorGenerator, BeaconValidatorsGenerator, BeaconValidatorsHint, BeaconWithdrawalGenerator, BeaconWithdrawalsGenerator, CompressedBeaconValidatorBatchHint, Eth1BlockToSlotHint, }; use crate::frontend::eth::beacon::vars::{ - BeaconBalancesVariable, BeaconValidatorVariable, BeaconValidatorsVariable, - BeaconWithdrawalVariable, BeaconWithdrawalsVariable, + BeaconBalancesVariable, BeaconHeaderVariable, BeaconValidatorVariable, + BeaconValidatorsVariable, BeaconWithdrawalVariable, BeaconWithdrawalsVariable, }; use crate::frontend::eth::mpt::generators::LteGenerator; use crate::frontend::eth::storage::generators::{ @@ -84,7 +85,7 @@ use crate::frontend::num::u32::gates::range_check_u32::U32RangeCheckGenerator; use crate::frontend::num::u32::gates::subtraction_u32::U32SubtractionGenerator; use crate::frontend::uint::uint64::U64Variable; use crate::frontend::vars::{Bytes32Variable, SubArrayExtractorHint, U256Variable}; -use crate::prelude::{BoolVariable, U32Variable, Variable}; +use crate::prelude::{ArrayVariable, BoolVariable, U32Variable, Variable}; pub trait HintSerializer, const D: usize>: WitnessGeneratorSerializer @@ -463,6 +464,12 @@ where r.register_hint::(); + r.register_hint::(); + + r.register_hint::(); + + register_powers_of_two!(r, BeaconHeadersFromOffsetRangeHint); + register_watch_generator!( r, L, @@ -477,7 +484,9 @@ where BeaconBalancesVariable, BeaconWithdrawalsVariable, BeaconWithdrawalVariable, - BeaconValidatorVariable + BeaconValidatorVariable, + BeaconHeaderVariable, + ArrayVariable ); r diff --git a/plonky2x/core/src/frontend/builder/mod.rs b/plonky2x/core/src/frontend/builder/mod.rs index 4338d3629..7883e2cdf 100644 --- a/plonky2x/core/src/frontend/builder/mod.rs +++ b/plonky2x/core/src/frontend/builder/mod.rs @@ -1,5 +1,6 @@ mod boolean; pub mod io; +pub mod permutation; mod proof; pub mod watch; diff --git a/plonky2x/core/src/frontend/builder/permutation.rs b/plonky2x/core/src/frontend/builder/permutation.rs new file mode 100644 index 000000000..44dc8e6f8 --- /dev/null +++ b/plonky2x/core/src/frontend/builder/permutation.rs @@ -0,0 +1,149 @@ +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use serde::{Deserialize, Serialize}; + +use super::CircuitBuilder; +use crate::frontend::hint::simple::hint::Hint; +use crate::frontend::uint::uint32::U32Variable; +use crate::frontend::vars::{EvmVariable, ValueStream, VariableStream}; +use crate::prelude::{ArrayVariable, PlonkParameters, Variable}; +use crate::utils::hash::sha256; + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct RandomPermutationHint; + +impl, const D: usize, const B: usize> Hint + for RandomPermutationHint +{ + fn hint(&self, input_stream: &mut ValueStream, output_stream: &mut ValueStream) { + let inputs = input_stream.read_value::>(); + let dummy = input_stream.read_value::(); + let nonce = input_stream.read_value::(); + + let mut filtered_inputs = Vec::new(); + for i in 0..inputs.len() { + if inputs[i] != dummy { + filtered_inputs.push(inputs[i]); + } + } + + filtered_inputs.sort_by_key(|x| { + let mut bytes = Vec::new(); + bytes.extend(x.to_be_bytes()); + bytes.extend(nonce.to_be_bytes()); + u32::from_be_bytes(sha256(&bytes)[0..4].try_into().unwrap()) + }); + filtered_inputs.resize(B, dummy); + + output_stream.write_value::>(filtered_inputs); + } +} + +impl, const D: usize> CircuitBuilder { + pub fn permute_with_dummy( + &mut self, + inputs: ArrayVariable, + dummy: U32Variable, + gamma: Variable, + nonce: U32Variable, + ) -> ArrayVariable + where + <>::Config as GenericConfig>::Hasher: + AlgebraicHasher<>::Field>, + { + // Compute the filtered accumulator. + let mut filtered_acc = self.one::(); + for i in 0..inputs.len() { + let is_dummy = self.is_equal(inputs[i], dummy); + let term = self.sub(gamma, inputs[i].0); + let acc = self.mul(filtered_acc, term); + filtered_acc = self.select(is_dummy, filtered_acc, acc); + } + + // Get the permuted inputs. + let mut input_stream = VariableStream::new(); + input_stream.write(&inputs); + input_stream.write(&dummy); + input_stream.write(&nonce); + let output_stream = self.hint(input_stream, RandomPermutationHint:: {}); + let permuted_inputs = output_stream.read::>(self); + + // Compute the permtued filtered accumulator. + let mut permuted_filtered_acc = self.one::(); + for i in 0..inputs.len() { + let is_dummy = self.is_equal(permuted_inputs[i], dummy); + let term = self.sub(gamma, permuted_inputs[i].0); + let acc = self.mul(permuted_filtered_acc, term); + permuted_filtered_acc = self.select(is_dummy, permuted_filtered_acc, acc); + } + + // Assert that the permuted filtered accumulator is the same as the filtered accumulator. + self.assert_is_equal(permuted_filtered_acc, filtered_acc); + + // Check the metric ordering. + let mut metrics = Vec::new(); + for i in 0..permuted_inputs.len() { + let mut bytes = Vec::new(); + bytes.extend(permuted_inputs[i].encode(self)); + bytes.extend(nonce.encode(self)); + let h = self.curta_sha256(&bytes); + let metric = U32Variable::decode(self, &h.0[0..4]); + metrics.push(metric); + } + + let t = self._true(); + let f = self._false(); + let mut seen_dummy = self._false(); + for i in 0..metrics.len() - 1 { + // If the next is dummy and we've seen one, panic. + let next_is_dummy = self.is_equal(permuted_inputs[i + 1], dummy); + let not_next_is_dummy = self.not(next_is_dummy); + let seen_dummy_and_not_next_is_dummy = self.and(seen_dummy, not_next_is_dummy); + self.assert_is_equal(seen_dummy_and_not_next_is_dummy, f); + + // The next metric should be less than or equal to or the next is valid. + let lte = self.lte(metrics[i], metrics[i + 1]); + let valid = self.or(lte, next_is_dummy); + self.assert_is_equal(valid, t); + + // If the next thing is a dummy, we've seen a dummy. + seen_dummy = self.select(next_is_dummy, t, seen_dummy); + } + + permuted_inputs + } +} + +#[cfg(test)] +pub(crate) mod tests { + + use plonky2::field::types::Field; + + use crate::frontend::uint::uint32::U32Variable; + use crate::prelude::*; + use crate::utils; + + #[test] + fn test_simple_circuit_with_field_io() { + utils::setup_logger(); + let mut builder = DefaultBuilder::new(); + + let inputs = builder.constant::>(vec![0, 1, 2, 3, 4]); + let dummy = builder.constant::(0); + let gamma = builder.constant::(GoldilocksField::from_canonical_u64(3)); + let nonce = builder.constant::(1); + + let permuted_inputs = builder.permute_with_dummy(inputs, dummy, gamma, nonce); + for i in 0..permuted_inputs.len() { + builder.watch( + &permuted_inputs[i], + format!("permuted_inputs[{}]", i).as_str(), + ); + } + + let circuit = builder.build(); + + let input = circuit.input(); + let (proof, output) = circuit.prove(&input); + circuit.verify(&proof, &input, &output); + } +} diff --git a/plonky2x/core/src/frontend/eth/beacon/builder.rs b/plonky2x/core/src/frontend/eth/beacon/builder.rs index 5961f3a05..e24728044 100644 --- a/plonky2x/core/src/frontend/eth/beacon/builder.rs +++ b/plonky2x/core/src/frontend/eth/beacon/builder.rs @@ -3,8 +3,9 @@ use ethers::types::{H256, U256}; use super::generators::{ BeaconAllWithdrawalsHint, BeaconBalanceBatchWitnessHint, BeaconBalanceGenerator, - BeaconBalanceWitnessHint, BeaconBalancesGenerator, BeaconExecutionPayloadHint, - BeaconHeaderHint, BeaconHistoricalBlockGenerator, BeaconPartialBalancesHint, + BeaconBalanceWitnessHint, BeaconBalancesGenerator, BeaconBlockRootsHint, + BeaconExecutionPayloadHint, BeaconGraffitiHint, BeaconHeaderHint, + BeaconHeadersFromOffsetRangeHint, BeaconHistoricalBlockGenerator, BeaconPartialBalancesHint, BeaconPartialValidatorsHint, BeaconValidatorBatchHint, BeaconValidatorGenerator, BeaconValidatorsHint, BeaconWithdrawalGenerator, BeaconWithdrawalsGenerator, CompressedBeaconValidatorBatchHint, Eth1BlockToSlotHint, @@ -61,20 +62,34 @@ const EXECUTION_PAYLOAD_BLOCK_NUMBER_GINDEX: u64 = 3222; /// The log2 of the validator registry limit. const VALIDATOR_REGISTRY_LIMIT_LOG2: usize = 40; -/// The depth of the proof from the blockRoot -> balancesRoot; +/// The depth of the proof from the blockRoot -> balancesRoot. const BALANCES_PROOF_DEPTH: usize = 8; +/// The depth of the proof from the blockRoot -> blockRoots. +const BLOCK_ROOTS_PROOF_DEPTH: usize = 8; + +/// The depth of the proof from blockRoot -> graffiti. +const GRAFFITI_PROOF_DEPTH: usize = 7; + +/// The gindex for stateRoot -> validators; const VALIDATORS_GINDEX: usize = 43; +/// The gindex for stateRoot -> balances; const BALANCES_GINDEX: usize = 44; +/// The gindex for blockRoot -> blockRoots. +const BLOCK_ROOTS_GINDEX: usize = 357; + +/// The gindex for blockRoot -> graffiti. +const GRAFFITI_GINDEX: usize = 194; + /// Beacon chain constant SLOTS_PER_EPOCH. const SLOTS_PER_EPOCH: u64 = 32; /// Beacon chain constant SLOTS_PER_HISTORICAL_ROOT. -const SLOTS_PER_HISTORICAL_ROOT: u64 = 8192; +const SLOTS_PER_HISTORICAL_ROOT: usize = 8192; -/// Beacon chain constant CAPELLA_FORK_EPOCH. (mainnet specific) +/// Beacon chain constant CAPELLA_FORK_EPOCH (mainnet specific). const CAPELLA_FORK_EPOCH: u64 = 194048; /// Beacon chain constant MAX_WITHDRAWALS_PER_PAYLOAD. @@ -519,7 +534,7 @@ impl, const D: usize> CircuitBuilder { // Use close slot logic if (source - target) < 8192 let source_slot = self.beacon_get_block_header(block_root).slot; let source_sub_target = self.sub(source_slot, target_slot); - let slots_per_historical = self.constant::(SLOTS_PER_HISTORICAL_ROOT); + let slots_per_historical = self.constant::(SLOTS_PER_HISTORICAL_ROOT as u64); let one_u64 = self.constant::(1); let slots_per_historical_sub_one = self.sub(slots_per_historical, one_u64); let is_close_slot = self.lte(source_sub_target, slots_per_historical_sub_one); @@ -575,6 +590,57 @@ impl, const D: usize> CircuitBuilder { generator.target_block_root } + pub fn beacon_get_block_roots( + &mut self, + block_root: Bytes32Variable, + ) -> ArrayVariable { + let mut input = VariableStream::new(); + input.write(&block_root); + let output = self.hint(input, BeaconBlockRootsHint {}); + let block_roots_root = output.read::(self); + let proof = output.read::>(self); + let block_roots = + output.read::>(self); + self.ssz_verify_proof_const( + block_root, + block_roots_root, + proof.as_slice(), + BLOCK_ROOTS_GINDEX as u64, + ); + let root = self.ssz_hash_leafs(block_roots.as_slice()); + self.assert_is_equal(root, block_roots_root); + block_roots + } + + pub fn beacon_get_graffiti(&mut self, block_root: Bytes32Variable) -> Bytes32Variable { + let mut input = VariableStream::new(); + input.write(&block_root); + let output = self.hint(input, BeaconGraffitiHint {}); + let graffiti = output.read::(self); + let proof = output.read::>(self); + self.ssz_verify_proof_const( + block_root, + graffiti, + proof.as_slice(), + GRAFFITI_GINDEX as u64, + ); + graffiti + } + + pub fn beacon_witness_headers_from_offset_range( + &mut self, + end_block_root: Bytes32Variable, + start_offset: U64Variable, + end_offset: U64Variable, + ) -> ArrayVariable { + let mut input = VariableStream::new(); + input.write(&end_block_root); + input.write(&start_offset); + input.write(&end_offset); + let output = self.hint(input, BeaconHeadersFromOffsetRangeHint:: {}); + output.read::>(self) + } + /// Verify a simple serialize (ssz) merkle proof with a dynamic index. #[allow(unused_variables)] pub fn ssz_verify_proof( @@ -995,6 +1061,86 @@ pub(crate) mod tests { circuit.test_default_serializers(); } + #[test] + #[cfg_attr(feature = "ci", ignore)] + fn test_beacon_get_block_roots() { + env_logger::try_init().unwrap_or_default(); + dotenv::dotenv().ok(); + + let consensus_rpc = env::var("CONSENSUS_RPC_1").unwrap(); + let client = BeaconClient::new(consensus_rpc); + let latest_block_root = client.get_finalized_block_root().unwrap(); + + let mut builder = CircuitBuilder::::new(); + builder.set_beacon_client(client); + + let block_root = builder.constant::(bytes32!(latest_block_root)); + let block_roots = builder.beacon_get_block_roots(block_root); + builder.watch(&block_roots, "block_roots"); + + let circuit = builder.build(); + let input = circuit.input(); + let (proof, output) = circuit.prove(&input); + circuit.verify(&proof, &input, &output); + circuit.test_default_serializers(); + } + + #[test] + #[cfg_attr(feature = "ci", ignore)] + fn test_beacon_get_graffiti() { + env_logger::try_init().unwrap_or_default(); + dotenv::dotenv().ok(); + + let consensus_rpc = env::var("CONSENSUS_RPC_1").unwrap(); + let client = BeaconClient::new(consensus_rpc); + let latest_block_root = client.get_finalized_block_root().unwrap(); + + let mut builder = CircuitBuilder::::new(); + builder.set_beacon_client(client); + + let block_root = builder.constant::(bytes32!(latest_block_root)); + let graffiti = builder.beacon_get_graffiti(block_root); + builder.watch(&graffiti, "graffiti"); + + let circuit = builder.build(); + let input = circuit.input(); + let (proof, output) = circuit.prove(&input); + circuit.verify(&proof, &input, &output); + circuit.test_default_serializers(); + } + + #[test] + #[cfg_attr(feature = "ci", ignore)] + fn test_beacon_witness_headers_from_offset_range() { + env_logger::try_init().unwrap_or_default(); + dotenv::dotenv().ok(); + + let consensus_rpc = env::var("CONSENSUS_RPC_1").unwrap(); + let client = BeaconClient::new(consensus_rpc); + let latest_block_root = client.get_finalized_block_root().unwrap(); + + let mut builder = CircuitBuilder::::new(); + builder.set_beacon_client(client); + + let block_root = builder.constant::(bytes32!(latest_block_root)); + let start_offset = builder.constant::(0); + let end_offset = builder.constant::(15); + let block_roots = builder.beacon_witness_headers_from_offset_range::<16>( + block_root, + start_offset, + end_offset, + ); + for i in 0..block_roots.len() { + builder.watch(&block_roots[i], "block_roots"); + } + + let circuit = builder.build(); + let input = circuit.input(); + let (proof, output) = circuit.prove(&input); + circuit.verify(&proof, &input, &output); + circuit.test_default_serializers(); + } + #[test] #[cfg_attr(feature = "ci", ignore)] fn test_ssz_restore_merkle_root_equal() { diff --git a/plonky2x/core/src/frontend/eth/beacon/generators/block_roots.rs b/plonky2x/core/src/frontend/eth/beacon/generators/block_roots.rs new file mode 100644 index 000000000..575b2fa93 --- /dev/null +++ b/plonky2x/core/src/frontend/eth/beacon/generators/block_roots.rs @@ -0,0 +1,36 @@ +use std::env; + +use itertools::Itertools; +use serde::{Deserialize, Serialize}; + +use crate::backend::circuit::PlonkParameters; +use crate::frontend::hint::simple::hint::Hint; +use crate::frontend::vars::{Bytes32Variable, ValueStream}; +use crate::prelude::ArrayVariable; +use crate::utils::eth::beacon::BeaconClient; +use crate::utils::{bytes32, hex}; + +const NB_BLOCK_ROOTS: usize = 8192; +const DEPTH: usize = 8; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BeaconBlockRootsHint; + +impl, const D: usize> Hint for BeaconBlockRootsHint { + fn hint(&self, input_stream: &mut ValueStream, output_stream: &mut ValueStream) { + let client = BeaconClient::new(env::var("CONSENSUS_RPC_1").unwrap()); + let header_root = input_stream.read_value::(); + let response = client.get_block_roots(hex!(header_root)).unwrap(); + output_stream.write_value::(bytes32!(response.block_roots_root)); + output_stream.write_value::>( + response.proof.iter().map(|p| bytes32!(p)).collect_vec(), + ); + output_stream.write_value::>( + response + .block_roots + .iter() + .map(|p| bytes32!(p)) + .collect_vec(), + ); + } +} diff --git a/plonky2x/core/src/frontend/eth/beacon/generators/graffiti.rs b/plonky2x/core/src/frontend/eth/beacon/generators/graffiti.rs new file mode 100644 index 000000000..6b56d0218 --- /dev/null +++ b/plonky2x/core/src/frontend/eth/beacon/generators/graffiti.rs @@ -0,0 +1,28 @@ +use std::env; + +use itertools::Itertools; +use serde::{Deserialize, Serialize}; + +use crate::backend::circuit::PlonkParameters; +use crate::frontend::hint::simple::hint::Hint; +use crate::frontend::vars::{Bytes32Variable, ValueStream}; +use crate::prelude::ArrayVariable; +use crate::utils::eth::beacon::BeaconClient; +use crate::utils::{bytes32, hex}; + +const DEPTH: usize = 7; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BeaconGraffitiHint; + +impl, const D: usize> Hint for BeaconGraffitiHint { + fn hint(&self, input_stream: &mut ValueStream, output_stream: &mut ValueStream) { + let client = BeaconClient::new(env::var("CONSENSUS_RPC_1").unwrap()); + let header_root = input_stream.read_value::(); + let response = client.get_graffiti(hex!(header_root)).unwrap(); + output_stream.write_value::(bytes32!(response.graffiti)); + output_stream.write_value::>( + response.proof.iter().map(|p| bytes32!(p)).collect_vec(), + ); + } +} diff --git a/plonky2x/core/src/frontend/eth/beacon/generators/headers.rs b/plonky2x/core/src/frontend/eth/beacon/generators/headers.rs new file mode 100644 index 000000000..cd96b0cd6 --- /dev/null +++ b/plonky2x/core/src/frontend/eth/beacon/generators/headers.rs @@ -0,0 +1,32 @@ +use std::env; + +use itertools::Itertools; +use serde::{Deserialize, Serialize}; + +use crate::backend::circuit::PlonkParameters; +use crate::frontend::hint::simple::hint::Hint; +use crate::frontend::uint::uint64::U64Variable; +use crate::frontend::vars::{Bytes32Variable, ValueStream}; +use crate::prelude::ArrayVariable; +use crate::utils::eth::beacon::BeaconClient; +use crate::utils::{bytes32, hex}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BeaconHeadersFromOffsetRangeHint; + +impl, const D: usize, const B: usize> Hint + for BeaconHeadersFromOffsetRangeHint +{ + fn hint(&self, input_stream: &mut ValueStream, output_stream: &mut ValueStream) { + let client = BeaconClient::new(env::var("CONSENSUS_RPC_1").unwrap()); + let header_root = input_stream.read_value::(); + let start_offset = input_stream.read_value::(); + let end_offset = input_stream.read_value::(); + let response = client + .get_headers_from_offset_range(hex!(header_root), start_offset, end_offset) + .unwrap(); + output_stream.write_value::>( + response.headers.iter().map(|h| bytes32!(h)).collect_vec(), + ); + } +} diff --git a/plonky2x/core/src/frontend/eth/beacon/generators/mod.rs b/plonky2x/core/src/frontend/eth/beacon/generators/mod.rs index 17ff35e7d..f57a4c91f 100644 --- a/plonky2x/core/src/frontend/eth/beacon/generators/mod.rs +++ b/plonky2x/core/src/frontend/eth/beacon/generators/mod.rs @@ -2,8 +2,11 @@ mod all_withdrawals; mod balance; mod balance_witness; mod balances; +mod block_roots; mod eth1_block; +mod graffiti; mod header; +mod headers; mod historical; mod partial_balances; mod partial_validators; @@ -12,13 +15,15 @@ mod validator_witness; mod validators; mod withdrawal; mod withdrawals; - pub use all_withdrawals::BeaconAllWithdrawalsHint; pub use balance::BeaconBalanceGenerator; pub use balance_witness::{BeaconBalanceBatchWitnessHint, BeaconBalanceWitnessHint}; pub use balances::BeaconBalancesGenerator; +pub use block_roots::BeaconBlockRootsHint; pub use eth1_block::{BeaconExecutionPayloadHint, Eth1BlockToSlotHint}; +pub use graffiti::BeaconGraffitiHint; pub use header::BeaconHeaderHint; +pub use headers::BeaconHeadersFromOffsetRangeHint; pub use historical::BeaconHistoricalBlockGenerator; pub use partial_balances::BeaconPartialBalancesHint; pub use partial_validators::BeaconPartialValidatorsHint; diff --git a/plonky2x/core/src/frontend/uint/uint32.rs b/plonky2x/core/src/frontend/uint/uint32.rs index 6f5694d2d..46d20f0b0 100644 --- a/plonky2x/core/src/frontend/uint/uint32.rs +++ b/plonky2x/core/src/frontend/uint/uint32.rs @@ -4,6 +4,7 @@ use itertools::Itertools; use plonky2::hash::hash_types::RichField; use plonky2::iop::target::BoolTarget; +use super::uint64::U64Variable; use crate::backend::circuit::PlonkParameters; use crate::frontend::builder::CircuitBuilder; use crate::frontend::num::biguint::{BigUintTarget, CircuitBuilderBiguint}; @@ -188,6 +189,24 @@ impl, const D: usize> Sub for U32Variable { } } +impl U32Variable { + pub fn to_u64, const D: usize>( + &self, + builder: &mut CircuitBuilder, + ) -> U64Variable { + let zero = builder.zero::(); + let result = builder.init::(); + for i in 0..result.limbs.len() { + if i == 0 { + builder.connect(*self, result.limbs[i]); + } else { + builder.connect(zero, result.limbs[i]); + } + } + result + } +} + #[cfg(test)] mod tests { use rand::Rng; diff --git a/plonky2x/core/src/frontend/vars/collections.rs b/plonky2x/core/src/frontend/vars/collections.rs index a8547913d..9a94a80c6 100644 --- a/plonky2x/core/src/frontend/vars/collections.rs +++ b/plonky2x/core/src/frontend/vars/collections.rs @@ -331,7 +331,8 @@ impl< ..V1::nb_elements() + V2::nb_elements() + V3::nb_elements()], ); let v4 = V4::from_variables_unsafe( - &variables[V1::nb_elements() + V2::nb_elements() + V3::nb_elements()..], + &variables[V1::nb_elements() + V2::nb_elements() + V3::nb_elements() + ..V1::nb_elements() + V2::nb_elements() + V3::nb_elements() + V4::nb_elements()], ); let v5 = V5::from_variables_unsafe( &variables diff --git a/plonky2x/core/src/frontend/vars/mod.rs b/plonky2x/core/src/frontend/vars/mod.rs index bdbb54868..52adb718d 100644 --- a/plonky2x/core/src/frontend/vars/mod.rs +++ b/plonky2x/core/src/frontend/vars/mod.rs @@ -4,6 +4,7 @@ mod byte; mod bytes; mod bytes32; mod collections; + mod stream; mod variable; use std::fmt::Debug; diff --git a/plonky2x/core/src/utils/eth/beacon/mod.rs b/plonky2x/core/src/utils/eth/beacon/mod.rs index ef5ae6296..ec921b363 100644 --- a/plonky2x/core/src/utils/eth/beacon/mod.rs +++ b/plonky2x/core/src/utils/eth/beacon/mod.rs @@ -305,6 +305,33 @@ pub struct GetBeaconSlotNumber { pub proof: Vec, } +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetBeaconBlockRoots { + pub block_roots_root: String, + pub block_roots: Vec, + #[serde(deserialize_with = "deserialize_bigint")] + pub gindex: BigInt, + pub depth: u64, + pub proof: Vec, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetBeaconGraffiti { + pub graffiti: String, + #[serde(deserialize_with = "deserialize_bigint")] + pub gindex: BigInt, + pub depth: u64, + pub proof: Vec, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetBeaconHeadersFromOffsetRange { + pub headers: Vec, +} + impl BeaconClient { /// Creates a new BeaconClient based on a rpc url. pub fn new(rpc_url: String) -> Self { @@ -649,6 +676,44 @@ impl BeaconClient { Ok(parsed.data.header.message) } + + pub fn get_block_roots(&self, beacon_id: String) -> Result { + let endpoint = format!("{}/api/beacon/proof/blockRoots/{}", self.rpc_url, beacon_id); + info!("{}", endpoint); + let client = Client::new(); + let response = client.get(endpoint).timeout(Duration::new(60, 0)).send()?; + let response: CustomResponse = response.json()?; + assert!(response.success); + Ok(response.result) + } + + pub fn get_graffiti(&self, beacon_id: String) -> Result { + let endpoint = format!("{}/api/beacon/proof/graffiti/{}", self.rpc_url, beacon_id); + info!("{}", endpoint); + let client = Client::new(); + let response = client.get(endpoint).timeout(Duration::new(60, 0)).send()?; + let response: CustomResponse = response.json()?; + assert!(response.success); + Ok(response.result) + } + + pub fn get_headers_from_offset_range( + &self, + beacon_id: String, + start_offset: u64, + end_offset: u64, + ) -> Result { + let endpoint = format!( + "{}/api/beacon/header/offset/{}/{}/{}", + self.rpc_url, beacon_id, start_offset, end_offset + ); + info!("{}", endpoint); + let client = Client::new(); + let response = client.get(endpoint).timeout(Duration::new(60, 0)).send()?; + let response: CustomResponse = response.json()?; + assert!(response.success); + Ok(response.result) + } } #[cfg(test)] @@ -730,4 +795,40 @@ mod tests { debug!("{:?}", result); Ok(()) } + + #[cfg_attr(feature = "ci", ignore)] + #[test] + fn test_get_block_roots() -> Result<()> { + utils::setup_logger(); + let rpc = env::var("CONSENSUS_RPC_1").unwrap(); + let client = BeaconClient::new(rpc.to_string()); + let slot = 7052735; + let result = client.get_block_roots(slot.to_string())?; + debug!("{:?}", result); + Ok(()) + } + + #[cfg_attr(feature = "ci", ignore)] + #[test] + fn test_get_graffiti() -> Result<()> { + utils::setup_logger(); + let rpc = env::var("CONSENSUS_RPC_1").unwrap(); + let client = BeaconClient::new(rpc.to_string()); + let slot = 7052735; + let result = client.get_graffiti(slot.to_string())?; + debug!("{:?}", result); + Ok(()) + } + + #[cfg_attr(feature = "ci", ignore)] + #[test] + fn test_get_headers_from_offset_range() -> Result<()> { + utils::setup_logger(); + let rpc = env::var("CONSENSUS_RPC_1").unwrap(); + let client = BeaconClient::new(rpc.to_string()); + let slot = 7052735; + let result = client.get_headers_from_offset_range(slot.to_string(), 0, 16)?; + debug!("{:?}", result); + Ok(()) + } }