diff --git a/espressocrypto/lib/espresso-crypto-helper/src/bytes.rs b/espressocrypto/lib/espresso-crypto-helper/src/bytes.rs deleted file mode 100644 index 5859c871d7..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/bytes.rs +++ /dev/null @@ -1,160 +0,0 @@ -//! Convenient serialization for binary blobs. - -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use base64::{engine::general_purpose::STANDARD as BASE64, Engine}; -use derive_more::{From, Into}; -use serde::{ - de::{Deserialize, Deserializer, Error}, - ser::{Serialize, Serializer}, -}; -use std::{ - ops::{Deref, DerefMut}, - slice::SliceIndex, -}; - -/// An unstructured byte array with smart serialization. -/// -/// [`Bytes`] mostly acts as a simple byte array, `Vec`. It can easily be converted to and from -/// a `Vec`, and it implements many of the same traits as [`Vec`]. In fact internally it merely -/// wraps a `Vec`. -/// -/// The only difference is in how it serializes. `Vec` serializes very efficiently using -/// `bincode`, but using `serde_json`, it serializes as a JSON array of integers, which is -/// unconventional and inefficient. It is better, in JSON, to serialize binary data as a -/// base64-encoded string. [`Bytes`] uses the [`is_human_readable`](Serializer::is_human_readable) -/// property of a [`Serializer`] to detect whether we are serializing for a compact binary format -/// (like `bincode`) or a human-readable format (like JSON). In the former cases, it serializes -/// directly as an array of bytes. In the latter case, it serializes as a string using base 64. -#[derive( - Clone, - Debug, - Default, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - From, - Into, - CanonicalSerialize, - CanonicalDeserialize, -)] -pub struct Bytes(Vec); - -impl Bytes { - pub fn get(&self, index: I) -> Option<&I::Output> - where - I: SliceIndex<[u8]>, - { - self.0.get(index) - } -} - -impl Serialize for Bytes { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - BASE64.encode(self).serialize(s) - } else { - self.0.serialize(s) - } - } -} - -impl<'a> Deserialize<'a> for Bytes { - fn deserialize>(d: D) -> Result { - if d.is_human_readable() { - Ok(Self(BASE64.decode(String::deserialize(d)?).map_err( - |err| D::Error::custom(format!("invalid base64: {err}")), - )?)) - } else { - Ok(Self(Vec::deserialize(d)?)) - } - } -} - -impl From<&[u8]> for Bytes { - fn from(bytes: &[u8]) -> Self { - Self(bytes.into()) - } -} - -impl From<[u8; N]> for Bytes { - fn from(bytes: [u8; N]) -> Self { - Self(bytes.into()) - } -} - -impl From<&[u8; N]> for Bytes { - fn from(bytes: &[u8; N]) -> Self { - Self((*bytes).into()) - } -} - -impl FromIterator for Bytes { - fn from_iter>(iter: I) -> Self { - Self(iter.into_iter().collect()) - } -} - -impl AsRef<[u8]> for Bytes { - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } -} - -impl AsMut<[u8]> for Bytes { - fn as_mut(&mut self) -> &mut [u8] { - self.0.as_mut() - } -} - -impl Deref for Bytes { - type Target = [u8]; - - fn deref(&self) -> &[u8] { - self.as_ref() - } -} - -impl DerefMut for Bytes { - fn deref_mut(&mut self) -> &mut [u8] { - self.as_mut() - } -} - -impl PartialEq<[u8]> for Bytes { - fn eq(&self, other: &[u8]) -> bool { - self.as_ref() == other - } -} - -impl PartialEq<[u8; N]> for Bytes { - fn eq(&self, other: &[u8; N]) -> bool { - self.as_ref() == other - } -} - -impl PartialEq> for Bytes { - fn eq(&self, other: &Vec) -> bool { - self.0 == *other - } -} - -impl Extend for Bytes -where - Vec: Extend, -{ - fn extend>(&mut self, iter: I) { - self.0.extend(iter); - } -} - -#[macro_export] -macro_rules! bytes { - [$($elem:expr),* $(,)?] => { - $crate::bytes::Bytes::from(vec![$($elem),*]) - }; - [$elem:expr; $size:expr] => { - $crate::bytes::Bytes::from(vec![$elem; $size]) - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/full_payload.rs b/espressocrypto/lib/espresso-crypto-helper/src/full_payload.rs deleted file mode 100644 index dba15e03c3..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/full_payload.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod ns_proof; -mod ns_table; -mod payload; - -pub use ns_proof::NsProof; -pub use ns_table::{NsIndex, NsTable}; - -pub use payload::PayloadByteLen; diff --git a/espressocrypto/lib/espresso-crypto-helper/src/full_payload/ns_proof.rs b/espressocrypto/lib/espresso-crypto-helper/src/full_payload/ns_proof.rs deleted file mode 100644 index a263ca935d..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/full_payload/ns_proof.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::hotshot_types::{ - vid_scheme, LargeRangeProofType, VidCommitment, VidCommon, VidSchemeType, -}; -use crate::{ - full_payload::{NsIndex, NsTable, PayloadByteLen}, - namespace_payload::NsPayloadOwned, - NamespaceId, Transaction, -}; -use jf_vid::{ - payload_prover::{PayloadProver, Statement}, - VidScheme, -}; -use serde::{Deserialize, Serialize}; - -/// Proof of correctness for namespace payload bytes in a block. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct NsProof { - ns_index: NsIndex, - ns_payload: NsPayloadOwned, - ns_proof: Option, // `None` if ns_payload is empty -} - -impl NsProof { - /// Verify a [`NsProof`] against a payload commitment. Returns `None` on - /// error or if verification fails. - /// - /// There is no [`NsPayload`](crate::block::namespace_payload::NsPayload) - /// arg because this data is already included in the [`NsProof`]. See - /// [`NsProof::new`] for discussion. - /// - /// If verification is successful then return `(Vec, - /// NamespaceId)` obtained by post-processing the underlying - /// [`NsPayload`](crate::block::namespace_payload::NsPayload). Why? This - /// method might be run by a client in a WASM environment who might be - /// running non-Rust code, in which case the client is unable to perform - /// this post-processing himself. - pub fn verify( - &self, - ns_table: &NsTable, - commit: &VidCommitment, - common: &VidCommon, - ) -> Option<(Vec, NamespaceId)> { - VidSchemeType::is_consistent(commit, common).ok()?; - if !ns_table.in_bounds(&self.ns_index) { - return None; // error: index out of bounds - } - - let range = ns_table - .ns_range(&self.ns_index, &PayloadByteLen::from_vid_common(common)) - .as_block_range(); - - match (&self.ns_proof, range.is_empty()) { - (Some(proof), false) => { - // TODO vid_scheme() arg should be u32 to match get_num_storage_nodes - // https://github.com/EspressoSystems/HotShot/issues/3298 - let vid = vid_scheme( - VidSchemeType::get_num_storage_nodes(common) - .try_into() - .ok()?, // error: failure to convert u32 to usize - ); - - vid.payload_verify( - Statement { - payload_subslice: self.ns_payload.as_bytes_slice(), - range, - commit, - common, - }, - proof, - ) - .ok()? // error: internal to payload_verify() - .ok()?; // verification failure - } - (None, true) => {} // 0-length namespace, nothing to verify - (None, false) => { - return None; - } - (Some(_), true) => { - return None; - } - } - - // verification succeeded, return some data - let ns_id = ns_table.read_ns_id_unchecked(&self.ns_index); - Some((self.ns_payload.export_all_txs(&ns_id), ns_id)) - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/full_payload/ns_table.rs b/espressocrypto/lib/espresso-crypto-helper/src/full_payload/ns_table.rs deleted file mode 100644 index c6fae5ce80..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/full_payload/ns_table.rs +++ /dev/null @@ -1,277 +0,0 @@ -//! Types related to a namespace table. -//! -//! All code that needs to know the binary format of a namespace table is -//! restricted to this file. -//! -//! See [`NsTable`] for a full specification of the binary format of a namespace -//! table. -use crate::{ - full_payload::payload::PayloadByteLen, - namespace_payload::NsPayloadRange, - uint_bytes::{bytes_serde_impl, u32_from_bytes, usize_from_bytes, usize_to_bytes}, - NamespaceId, -}; -use committable::{Commitment, Committable, RawCommitmentBuilder}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::{collections::HashSet, sync::Arc}; - -/// Byte lengths for the different items that could appear in a namespace table. -const NUM_NSS_BYTE_LEN: usize = 4; -const NS_OFFSET_BYTE_LEN: usize = 4; - -// TODO prefer [`NS_ID_BYTE_LEN`] set to `8` because [`NamespaceId`] is a `u64` -// but we need to maintain serialization compatibility. -// https://github.com/EspressoSystems/espresso-sequencer/issues/1574 -const NS_ID_BYTE_LEN: usize = 4; - -/// Raw binary data for a namespace table. -/// -/// Any sequence of bytes is a valid [`NsTable`]. -/// -/// # Binary format of a namespace table -/// -/// Byte lengths for the different items that could appear in a namespace table -/// are specified in local private constants [`NUM_NSS_BYTE_LEN`], -/// [`NS_OFFSET_BYTE_LEN`], [`NS_ID_BYTE_LEN`]. -/// -/// ## Number of entries in the namespace table -/// -/// The first [`NUM_NSS_BYTE_LEN`] bytes of the namespace table indicate the -/// number `n` of entries in the table as a little-endian unsigned integer. If -/// the entire table length is smaller than [`NUM_NSS_BYTE_LEN`] then the -/// missing bytes are zero-padded. -/// -/// The bytes in the namespace table beyond the first [`NUM_NSS_BYTE_LEN`] bytes -/// encode table entries. Each entry consumes exactly [`NS_ID_BYTE_LEN`] `+` -/// [`NS_OFFSET_BYTE_LEN`] bytes. -/// -/// The number `n` could be anything, including a number much larger than the -/// number of entries that could fit in the namespace table. As such, the actual -/// number of entries in the table is defined as the minimum of `n` and the -/// maximum number of whole entries that could fit in the table. -/// -/// See [`Self::in_bounds`] for clarification. -/// -/// ## Namespace table entry -/// -/// ### Namespace ID -/// -/// The first [`NS_ID_BYTE_LEN`] bytes of each table entry indicate the -/// [`NamespaceId`] for this namespace. Any table entry whose [`NamespaceId`] is -/// a duplicate of a previous entry is ignored. A correct count of the number of -/// *unique* (non-ignored) entries is given by `NsTable::iter().count()`. -/// -/// ### Namespace offset -/// -/// The next [`NS_OFFSET_BYTE_LEN`] bytes of each table entry indicate the -/// end-index of a namespace in the block payload bytes -/// [`Payload`](super::payload::Payload). This end-index is a little-endian -/// unsigned integer. -/// -/// # How to deduce a namespace's byte range -/// -/// In order to extract the payload bytes of a single namespace `N` from the -/// block payload one needs both the start- and end-indices for `N`. -/// -/// See [`Self::ns_range`] for clarification. What follows is a description of -/// what's implemented in [`Self::ns_range`]. -/// -/// If `N` occupies the `i`th entry in the namespace table for `i>0` then the -/// start-index for `N` is defined as the end-index of the `(i-1)`th entry in -/// the table. -/// -/// Even if the `(i-1)`the entry would otherwise be ignored (due to a duplicate -/// [`NamespaceId`] or any other reason), that entry's end-index still defines -/// the start-index of `N`. This rule guarantees that both start- and -/// end-indices for any namespace `N` can be read from a constant-size byte -/// range in the namespace table, and it eliminates the need to traverse an -/// unbounded number of previous entries of the namespace table looking for a -/// previous non-ignored entry. -/// -/// The start-index of the 0th entry in the table is implicitly defined to be -/// `0`. -/// -/// The start- and end-indices `(declared_start, declared_end)` declared in the -/// namespace table could be anything. As such, the actual start- and -/// end-indices `(start, end)` are defined so as to ensure that the byte range -/// is well-defined and in-bounds for the block payload: -/// ```ignore -/// end = min(declared_end, block_payload_byte_length) -/// start = min(declared_start, end) -/// ``` -/// -/// In a "honestly-prepared" namespace table the end-index of the final -/// namespace equals the byte length of the block payload. (Otherwise the block -/// payload might have bytes that are not included in any namespace.) -/// -/// It is possible that a namespace table could indicate two distinct namespaces -/// whose byte ranges overlap, though no "honestly-prepared" namespace table -/// would do this. -/// -/// TODO prefer [`NsTable`] to be a newtype like this -/// ```ignore -/// #[repr(transparent)] -/// #[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)] -/// #[serde(transparent)] -/// pub struct NsTable(#[serde(with = "base64_bytes")] Vec); -/// ``` -/// but we need to maintain serialization compatibility. -/// -#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct NsTable { - #[serde(with = "base64_bytes")] - pub bytes: Vec, -} - -impl NsTable { - /// Search the namespace table for the ns_index belonging to `ns_id`. - pub fn find_ns_id(&self, ns_id: &NamespaceId) -> Option { - self.iter() - .find(|index| self.read_ns_id_unchecked(index) == *ns_id) - } - - /// Iterator over all unique namespaces in the namespace table. - pub fn iter(&self) -> impl Iterator + '_ { - NsIter::new(self) - } - - /// Read the namespace id from the `index`th entry from the namespace table. - /// Returns `None` if `index` is out of bounds. - /// - /// TODO I want to restrict visibility to `pub(crate)` or lower but this - /// method is currently used in `nasty-client`. - pub fn read_ns_id(&self, index: &NsIndex) -> Option { - if !self.in_bounds(index) { - None - } else { - Some(self.read_ns_id_unchecked(index)) - } - } - - /// Like [`Self::read_ns_id`] except `index` is not checked. Use [`Self::in_bounds`] as needed. - pub fn read_ns_id_unchecked(&self, index: &NsIndex) -> NamespaceId { - let start = index.0 * (NS_ID_BYTE_LEN + NS_OFFSET_BYTE_LEN) + NUM_NSS_BYTE_LEN; - - // TODO hack to deserialize `NamespaceId` from `NS_ID_BYTE_LEN` bytes - // https://github.com/EspressoSystems/espresso-sequencer/issues/1574 - NamespaceId::from(u32_from_bytes::( - &self.bytes[start..start + NS_ID_BYTE_LEN], - )) - } - - /// Does the `index`th entry exist in the namespace table? - pub fn in_bounds(&self, index: &NsIndex) -> bool { - // The number of entries in the namespace table, including all duplicate - // namespace IDs. - let num_nss_with_duplicates = std::cmp::min( - // Number of namespaces declared in the ns table - self.read_num_nss(), - // Max number of entries that could fit in the namespace table - self.bytes.len().saturating_sub(NUM_NSS_BYTE_LEN) - / NS_ID_BYTE_LEN.saturating_add(NS_OFFSET_BYTE_LEN), - ); - - index.0 < num_nss_with_duplicates - } - - // CRATE-VISIBLE HELPERS START HERE - - /// Read subslice range for the `index`th namespace from the namespace - /// table. - pub fn ns_range(&self, index: &NsIndex, payload_byte_len: &PayloadByteLen) -> NsPayloadRange { - let end = self.read_ns_offset(index).min(payload_byte_len.as_usize()); - let start = if index.0 == 0 { - 0 - } else { - self.read_ns_offset(&NsIndex(index.0 - 1)) - } - .min(end); - NsPayloadRange::new(start, end) - } - - // PRIVATE HELPERS START HERE - - /// Read the number of namespaces declared in the namespace table. This - /// quantity might exceed the number of entries that could fit in the - /// namespace table. - /// - /// For a correct count of the number of unique namespaces in this - /// namespace table use `iter().count()`. - fn read_num_nss(&self) -> usize { - let num_nss_byte_len = NUM_NSS_BYTE_LEN.min(self.bytes.len()); - usize_from_bytes::(&self.bytes[..num_nss_byte_len]) - } - - /// Read the namespace offset from the `index`th entry from the namespace table. - fn read_ns_offset(&self, index: &NsIndex) -> usize { - let start = - index.0 * (NS_ID_BYTE_LEN + NS_OFFSET_BYTE_LEN) + NUM_NSS_BYTE_LEN + NS_ID_BYTE_LEN; - usize_from_bytes::(&self.bytes[start..start + NS_OFFSET_BYTE_LEN]) - } - - pub fn encode(&self) -> Arc<[u8]> { - Arc::from(self.bytes.as_ref()) - } -} - -impl Committable for NsTable { - fn commit(&self) -> Commitment { - RawCommitmentBuilder::new(&Self::tag()) - .var_size_bytes(&self.bytes) - .finalize() - } - - fn tag() -> String { - "NSTABLE".into() - } -} - -/// Index for an entry in a ns table. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct NsIndex(usize); -bytes_serde_impl!(NsIndex, to_bytes, [u8; NUM_NSS_BYTE_LEN], from_bytes); - -impl NsIndex { - pub fn to_bytes(&self) -> [u8; NUM_NSS_BYTE_LEN] { - usize_to_bytes::(self.0) - } - fn from_bytes(bytes: &[u8]) -> Self { - Self(usize_from_bytes::(bytes)) - } -} - -/// Return type for [`Payload::ns_iter`]. -pub struct NsIter<'a> { - cur_index: usize, - repeat_nss: HashSet, - ns_table: &'a NsTable, -} - -impl<'a> NsIter<'a> { - pub fn new(ns_table: &'a NsTable) -> Self { - Self { - cur_index: 0, - repeat_nss: HashSet::new(), - ns_table, - } - } -} - -impl<'a> Iterator for NsIter<'a> { - type Item = NsIndex; - - fn next(&mut self) -> Option { - loop { - let candidate_result = NsIndex(self.cur_index); - let ns_id = self.ns_table.read_ns_id(&candidate_result)?; - self.cur_index += 1; - - // skip duplicate namespace IDs - if !self.repeat_nss.insert(ns_id) { - continue; - } - - break Some(candidate_result); - } - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/full_payload/payload.rs b/espressocrypto/lib/espresso-crypto-helper/src/full_payload/payload.rs deleted file mode 100644 index 43080bc60c..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/full_payload/payload.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::full_payload::ns_table::NsTable; -use crate::hotshot_types::{VidCommon, VidSchemeType}; -use jf_vid::VidScheme; -use serde::{Deserialize, Serialize}; -use std::fmt::Display; - -/// Raw payload data for an entire block. -/// -/// A block consists of two sequences of arbitrary bytes: -/// - `ns_table`: namespace table -/// - `ns_payloads`: namespace payloads -/// -/// Any sequence of bytes is a valid `ns_table`. Any sequence of bytes is a -/// valid `ns_payloads`. The contents of `ns_table` determine how to interpret -/// `ns_payload`. -/// -/// # Namespace table -/// -/// See [`NsTable`] for the format of a namespace table. -/// -/// # Namespace payloads -/// -/// A concatenation of payload bytes for multiple individual namespaces. -/// Namespace boundaries are dictated by `ns_table`. See [`NsPayload`] for the -/// format of a namespace payload. -#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct Payload { - // Concatenated payload bytes for each namespace - #[serde(with = "base64_bytes")] - ns_payloads: Vec, - - ns_table: NsTable, -} - -impl Display for Payload { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{self:#?}") - } -} - -/// Byte length of a block payload, which includes all namespaces but *not* the -/// namespace table. -pub struct PayloadByteLen(usize); - -impl PayloadByteLen { - /// Extract payload byte length from a [`VidCommon`] and construct a new [`Self`] from it. - pub fn from_vid_common(common: &VidCommon) -> Self { - Self(usize::try_from(VidSchemeType::get_payload_byte_len(common)).unwrap()) - } - - /// Is the payload byte length declared in a [`VidCommon`] equal [`Self`]? - pub fn is_consistent(&self, common: &VidCommon) -> Result<(), ()> { - // failure to convert to usize implies that `common` cannot be - // consistent with `self`. - let expected = - usize::try_from(VidSchemeType::get_payload_byte_len(common)).map_err(|_| ())?; - - (self.0 == expected).then_some(()).ok_or(()) - } - - pub fn as_usize(&self) -> usize { - self.0 - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/hotshot_types.rs b/espressocrypto/lib/espresso-crypto-helper/src/hotshot_types.rs deleted file mode 100644 index 5ee3bcfc81..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/hotshot_types.rs +++ /dev/null @@ -1,264 +0,0 @@ -use committable::{Commitment, Committable, RawCommitmentBuilder}; -use std::ops::Range; -use tagged_base64::tagged; - -use ark_bn254::Bn254; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use digest::OutputSizeUser; -use jf_pcs::{ - prelude::UnivariateUniversalParams, univariate_kzg::UnivariateKzgPCS, - PolynomialCommitmentScheme, -}; -use jf_vid::advz::payload_prover::{LargeRangeProof, SmallRangeProof}; -use jf_vid::{ - advz, - payload_prover::{PayloadProver, Statement}, - precomputable::Precomputable, - VidDisperse, VidResult, VidScheme, -}; -use lazy_static::lazy_static; -use serde::{Deserialize, Serialize}; -use sha2::Sha256; -use typenum::Unsigned; - -/// Private type alias for the EC pairing type parameter for [`Advz`]. -type E = Bn254; -/// Private type alias for the hash type parameter for [`Advz`]. -type H = Sha256; - -type Advz = advz::Advz; - -pub type VidCommitment = ::Commit; -pub type VidCommon = ::Common; -type Sha256Digest = [u8; ::OutputSize::USIZE]; - -#[tagged("BUILDER_COMMITMENT")] -#[derive(Clone, Debug, Hash, PartialEq, Eq, CanonicalDeserialize, CanonicalSerialize)] -/// Commitment that builders use to sign block options. -/// A thin wrapper around a Sha256 digest. -pub struct BuilderCommitment(Sha256Digest); - -impl AsRef for BuilderCommitment { - fn as_ref(&self) -> &Sha256Digest { - &self.0 - } -} - -/// Type-safe wrapper around `u64` so we know the thing we're talking about is a view number. -#[derive( - Copy, - Clone, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Serialize, - Deserialize, - CanonicalSerialize, - CanonicalDeserialize, -)] -pub struct ViewNumber(pub u64); - -impl Committable for ViewNumber { - fn commit(&self) -> Commitment { - let builder = RawCommitmentBuilder::new("View Number Commitment"); - builder.u64(self.0).finalize() - } -} - -pub struct VidSchemeType(Advz); - -impl VidScheme for VidSchemeType { - type Commit = ::Commit; - type Share = ::Share; - type Common = ::Common; - - fn commit_only(&mut self, payload: B) -> VidResult - where - B: AsRef<[u8]>, - { - self.0.commit_only(payload) - } - - fn disperse(&mut self, payload: B) -> VidResult> - where - B: AsRef<[u8]>, - { - self.0.disperse(payload).map(vid_disperse_conversion) - } - - fn verify_share( - &self, - share: &Self::Share, - common: &Self::Common, - commit: &Self::Commit, - ) -> VidResult> { - self.0.verify_share(share, common, commit) - } - - fn recover_payload(&self, shares: &[Self::Share], common: &Self::Common) -> VidResult> { - self.0.recover_payload(shares, common) - } - - fn is_consistent(commit: &Self::Commit, common: &Self::Common) -> VidResult<()> { - ::is_consistent(commit, common) - } - - fn get_payload_byte_len(common: &Self::Common) -> u32 { - ::get_payload_byte_len(common) - } - - fn get_num_storage_nodes(common: &Self::Common) -> u32 { - ::get_num_storage_nodes(common) - } - - fn get_multiplicity(common: &Self::Common) -> u32 { - ::get_multiplicity(common) - } -} - -impl PayloadProver for VidSchemeType { - fn payload_proof(&self, payload: B, range: Range) -> VidResult - where - B: AsRef<[u8]>, - { - self.0 - .payload_proof(payload, range) - .map(SmallRangeProofType) - } - - fn payload_verify( - &self, - stmt: Statement<'_, Self>, - proof: &SmallRangeProofType, - ) -> VidResult> { - self.0.payload_verify(stmt_conversion(stmt), &proof.0) - } -} - -impl PayloadProver for VidSchemeType { - fn payload_proof(&self, payload: B, range: Range) -> VidResult - where - B: AsRef<[u8]>, - { - self.0 - .payload_proof(payload, range) - .map(LargeRangeProofType) - } - - fn payload_verify( - &self, - stmt: Statement<'_, Self>, - proof: &LargeRangeProofType, - ) -> VidResult> { - self.0.payload_verify(stmt_conversion(stmt), &proof.0) - } -} - -impl Precomputable for VidSchemeType { - type PrecomputeData = ::PrecomputeData; - - fn commit_only_precompute( - &self, - payload: B, - ) -> VidResult<(Self::Commit, Self::PrecomputeData)> - where - B: AsRef<[u8]>, - { - self.0.commit_only_precompute(payload) - } - - fn disperse_precompute( - &self, - payload: B, - data: &Self::PrecomputeData, - ) -> VidResult> - where - B: AsRef<[u8]>, - { - self.0 - .disperse_precompute(payload, data) - .map(vid_disperse_conversion) - } -} - -lazy_static! { - // Initialize the byte array from JSON content - pub static ref KZG_SRS: UnivariateUniversalParams = { - let json_content = include_str!("../vid_srs.json"); - let s: Vec = serde_json::from_str(json_content).expect("Failed to deserialize"); - UnivariateUniversalParams::::deserialize_uncompressed_unchecked(s.as_slice()) - .unwrap() - }; -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct LargeRangeProofType( - // # Type complexity - // - // Jellyfish's `LargeRangeProof` type has a prime field generic parameter `F`. - // This `F` is determined by the type parameter `E` for `Advz`. - // Jellyfish needs a more ergonomic way for downstream users to refer to this type. - // - // There is a `KzgEval` type alias in jellyfish that helps a little, but it's currently private: - // - // If it were public then we could instead use - // `LargeRangeProof>` - // but that's still pretty crufty. - LargeRangeProof< as PolynomialCommitmentScheme>::Evaluation>, -); - -/// Newtype wrapper for a small payload range proof. -/// -/// Useful for transaction proofs. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct SmallRangeProofType( - // # Type complexity - // - // Similar to the comments in `LargeRangeProofType`. - SmallRangeProof< as PolynomialCommitmentScheme>::Proof>, -); - -#[must_use] -pub fn vid_scheme(num_storage_nodes: usize) -> VidSchemeType { - // recovery_threshold is currently num_storage_nodes rounded down to a power of two - // TODO recovery_threshold should be a function of the desired erasure code rate - // https://github.com/EspressoSystems/HotShot/issues/2152 - let recovery_threshold = 1 << num_storage_nodes.ilog2(); - - #[allow(clippy::panic)] - let num_storage_nodes = u32::try_from(num_storage_nodes).unwrap_or_else(|err| { - panic!( - "num_storage_nodes {num_storage_nodes} should fit into u32; \ - error: {err}" - ) - }); - - // TODO panic, return `Result`, or make `new` infallible upstream (eg. by panicking)? - #[allow(clippy::panic)] - VidSchemeType( - Advz::new(num_storage_nodes, recovery_threshold, &*KZG_SRS).unwrap_or_else(|err| { - panic!("advz construction failure: (num_storage nodes,recovery_threshold)=({num_storage_nodes},{recovery_threshold}); \ - error: {err}") - }) - ) -} - -fn stmt_conversion(stmt: Statement<'_, VidSchemeType>) -> Statement<'_, Advz> { - Statement { - payload_subslice: stmt.payload_subslice, - range: stmt.range, - commit: stmt.commit, - common: stmt.common, - } -} - -fn vid_disperse_conversion(vid_disperse: VidDisperse) -> VidDisperse { - VidDisperse { - shares: vid_disperse.shares, - common: vid_disperse.common, - commit: vid_disperse.commit, - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/mock_data/header.json b/espressocrypto/lib/espresso-crypto-helper/src/mock_data/header.json deleted file mode 100644 index 78ffc95fbf..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/mock_data/header.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "block_merkle_tree_root": "MERKLE_COMM~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAQA", - "builder_commitment": "BUILDER_COMMITMENT~PfISPEAHYbCXqJ08RqlK74d9aSrtrZkKHdnoX7crymG5", - "builder_signature": { - "r": "0xca39647d5e159ebf62e0efd163ddb2b7946f437948e6c31accdb5360a9f2da17", - "s": "0x610e51dced89ede20e3dcc5e9e26fff580738e785371df53389f2f84dadbdb87", - "v": 28 - }, - "chain_config": { - "chain_config": { - "Left": { - "base_fee": "0", - "chain_id": "35353", - "fee_contract": "0x0000000000000000000000000000000000000000", - "fee_recipient": "0x0000000000000000000000000000000000000000", - "max_block_size": "10240" - } - } - }, - "fee_info": { - "account": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", - "amount": "0" - }, - "fee_merkle_tree_root": "MERKLE_COMM~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAKA", - "height": 42, - "l1_finalized": { - "hash": "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", - "number": 123, - "timestamp": "0x456" - }, - "l1_head": 124, - "ns_table": { - "bytes": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - }, - "payload_commitment": "HASH~AazstQer_ho1SqgGT0r10_Gs0BnjfbPBHJdSO3HHbp29", - "timestamp": 789 -} \ No newline at end of file diff --git a/espressocrypto/lib/espresso-crypto-helper/src/mock_data/test_header.json b/espressocrypto/lib/espresso-crypto-helper/src/mock_data/test_header.json deleted file mode 100644 index 6def47976b..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/mock_data/test_header.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "chain_config": { - "chain_config": { - "Right": "CHAIN_CONFIG~E_LT4O8oRs3FoSL7pVT1iVaN9Y2XAHNYnKmJuHcz2mXE" - } - }, - "height": 1, - "timestamp": 1714012810, - "l1_head": 40, - "l1_finalized": { - "number": 32, - "timestamp": "0x6629c282", - "hash": "0x086c2d889dfc549acffa6ecd53b4df088e770ac87e26e3726d09f849c17db536" - }, - "payload_commitment": "HASH~CcLCyX4_jMHMT_UXK_FsGF8Shvw7pgFj5Og2mjW2y7ao", - "builder_commitment": "BUILDER_COMMITMENT~qfiL_spBvy7D19-v1bjtjhB_Yg1oH84s5xE1A5YgMn42", - "ns_table": { - "bytes": "CgAAABgnAACUCAAAGScAAG4TAAASJwAAcx4AABQnAADQIgAAECcAAOAmAAAWJwAARy8AABMnAABTLwAAEScAALsyAAAXJwAATjoAABonAAAJRQAA" - }, - "block_merkle_tree_root": "MERKLE_COMM~Y9ufYrqN9PnWxV7sGibwrfdNKXkgGzmL2TZDrLZgo1AgAAAAAAAAAAEAAAAAAAAAJA", - "fee_merkle_tree_root": "MERKLE_COMM~bYMmugVZtniEfwFcBGTEbMpBnkPHHWmt8YAW5ygWSKAUAAAAAAAAAAYAAAAAAAAAvQ", - "builder_signature": { - "r": "0x95824a15bb9e854bfbbab2b4ea27c82102078691281b1dc24fb5d63bb2deb663", - "s": "0x4419db237be39bfc44cb37f2f69ed78cd1709fe4b01ec15c0bbd08ddd309d7b8", - "v": 27 - }, - "fee_info": { - "account": "0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097", - "amount": "0" - } -} \ No newline at end of file diff --git a/espressocrypto/lib/espresso-crypto-helper/src/mock_data/test_merkle_path.json b/espressocrypto/lib/espresso-crypto-helper/src/mock_data/test_merkle_path.json deleted file mode 100644 index 5e2bf3a4c2..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/mock_data/test_merkle_path.json +++ /dev/null @@ -1,461 +0,0 @@ -[ - { - "Leaf": { - "value": "FIELD~6VQrizdRaPzfmROuCvnc0QOwBdhcwKY_3EPHynjDyILQ", - "pos": "FIELD~AQAAAAAAAADo", - "elem": "FIELD~RSru5Twf7bIO0OjFSgP51vzmoK0F-8hRzT2PupCj0tMI" - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~xscaz6FruKxsBoKEACvNF1wnTW6V0rH0j29ig-bAbUwd" - } - }, - { - "ForgettenSubtree": { - "value": "FIELD~6VQrizdRaPzfmROuCvnc0QOwBdhcwKY_3EPHynjDyILQ" - } - }, - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~pQJi6QyIJsBp2QjXewKEnmX69AlAUDcJn91qDQOBu0d5" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~xVk0KVx9gGlqJezxTFWJb5VY0W5HR0fGOpU4jA7jCZZK" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~gl-2rVZixvayTCL9oF_JqaGLaa_wE_mbFOqFZjqPCzZA" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~xL0xIv0h68mYL11kWao6rYmSTEWi3fRbyQWHfPyEn_iE" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~h-cXbgHjUsA5UdjCKElfotbH_sFojDsr-Yi1OCZfJqt6" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~5szgmqzQUFqVqv-KMC23Lge1V4VX283P7AL4TzccF7Nj" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~sFf1-LCN8CKAqF1_qiJtg_2C8vUQ4Hsqc234C4114Fcv" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~oSrlsy2v9cJ-JSq2S5C-vFmLLhU65TwQ3NCyfbYdtqT6" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~0peohqKgYojAT6KNF1bBsRNmlygaKQzLaw07j6Z2PMRv" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~z9CXaMo00duLJpu-oy9wRt3E8CO1pous0G8cF9RaK9H7" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~jta1zsZ3wwspHq6kPdlLJnUuq6OZLQXfpVcTBFIwrP33" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~M_1B3DZvnKF-pCIWkA1EPaAJ9fbKvXATbuVKfFaViMUR" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~FvTrLXCDsQsXcSaw0dXXI6IGZvgERzlICbYOrIg9HDc5" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~i5GrTe_LAyQ-l9xC1-Z8PNRVGLQlvtlOXkDPXsC8uPzS" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~hflM-xcou4mbpNssmyi0psXcmLsdKHYbNIsOUwfq-kX9" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~k8zu7RN20jkn1HZhC8rZs4Blg4m4ot2UHYOKPFqVsrmv" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~aVOpFFV-GDvlEMuccVQs58g5OLC1Yh8m6mjRwRVWKZ-i" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~qsrtaYOIFWg45Xm9Gjy8a9OdjIn4lKv3RSN3AtxBsik0" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~7xmzCbMCAbgamlgx05_WjSlxB477ITa-pZb2bL2raPYH" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~SOiYDaqzZK2_F6Gf9lTzhVG_4StGIRSPIBiMFhe-RQG1" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~TSDISEgvVqX6tmEkvDtvH-fYVIPdA7XuQ2MwotMdzArQ" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~lMFy8dCVMzxI1ZW1mzrHRlTw3tMwAbGKROTYwEMLwSkA" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~pgXvTrhjfZeoviD2eaU2V2Fw_ChA2wX8kcQo0957y389" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~FjM7j4P8ceGWUnHI6Yj6HBfJKund6Ydpp9cjoC3j1a8P" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~YK-KU5izKQQesnWJ-e_0BDqlHQRcU_SF7GHF7W0KRK01" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~TClCNKKoFWIqeb0vgib8Ec0b6rZuYspnsfpuss8qRgqA" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~d2r9j_P8ej-NZioHkgplpNr2e8cIWqUUvdTHV5LSimuL" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~7f4ZkitmDas3uutCpjF7KBKWIugwSM9lCfw0UOaIV2er" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~Atx2Q-bXGa4dUQ2z3vf5TDixMjTyHelLEwdCoNu-cXjr" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~YJRraa2xh7phTgoIDWDxN5UVIYRpUlQy_FhhCHrsPKqX" - } - }, - "Empty", - "Empty" - ] - } - }, - { - "Branch": { - "value": "FIELD~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-", - "children": [ - { - "ForgettenSubtree": { - "value": "FIELD~Y-tbmH2qO7bCByGa0XidyQJKeC1-ZYrtnn_AIPEzTnBW" - } - }, - "Empty", - "Empty" - ] - } - } -] \ No newline at end of file diff --git a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload.rs b/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload.rs deleted file mode 100644 index 222cabc3ff..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod iter; -mod ns_payload; -mod ns_payload_range; -mod tx_proof; -mod types; - -pub use ns_payload::NsPayloadOwned; -pub use ns_payload_range::NsPayloadRange; diff --git a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/iter.rs b/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/iter.rs deleted file mode 100644 index 572e2c518d..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/iter.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::{full_payload::NsIndex, namespace_payload::types::TxIndex}; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct Index { - ns_index: NsIndex, - tx_index: TxIndex, -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/ns_payload.rs b/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/ns_payload.rs deleted file mode 100644 index 77dd322a4e..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/ns_payload.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::{ - namespace_payload::types::{ - FromNsPayloadBytes, NsPayloadByteLen, NsPayloadBytesRange, NumTxs, NumTxsRange, - NumTxsUnchecked, TxIndex, TxIter, TxPayloadRange, TxTableEntriesRange, - }, - NamespaceId, Transaction, -}; -use serde::{Deserialize, Serialize}; - -/// Raw binary data for a single namespace's payload. -/// -/// Any sequence of bytes is a valid [`NsPayload`]. -/// -/// See module-level documentation [`types`](super::types) for a full -/// specification of the binary format of a namespace. -pub struct NsPayload([u8]); - -impl NsPayload { - pub fn as_bytes_slice(&self) -> &[u8] { - &self.0 - } - pub fn byte_len(&self) -> NsPayloadByteLen { - NsPayloadByteLen::from_usize(self.0.len()) - } - - /// Read and parse bytes from the ns payload. - /// - /// Arg `range: &R` is convertible into a `Range` via - /// [`NsPayloadBytesRange`]. The payload bytes are parsed into a `R::Output` - /// via [`FromNsPayloadBytes`]. - pub fn read<'a, R>(&'a self, range: &R) -> R::Output - where - R: NsPayloadBytesRange<'a>, - { - >::from_payload_bytes(&self.0[range.ns_payload_range()]) - } - - /// Return all transactions in this namespace. The namespace ID for each - /// returned [`Transaction`] is set to `ns_id`. - pub fn export_all_txs(&self, ns_id: &NamespaceId) -> Vec { - let num_txs = self.read_num_txs(); - self.iter_from_num_txs(&num_txs) - .map(|i| self.tx_from_num_txs(ns_id, &i, &num_txs)) - .collect() - } - - /// Private helper. (Could be pub if desired.) - fn read_num_txs(&self) -> NumTxsUnchecked { - self.read(&NumTxsRange::new(&self.byte_len())) - } - - /// Private helper - fn iter_from_num_txs(&self, num_txs: &NumTxsUnchecked) -> TxIter { - let num_txs = NumTxs::new(num_txs, &self.byte_len()); - TxIter::new(&num_txs) - } - - /// Private helper - fn tx_from_num_txs( - &self, - ns_id: &NamespaceId, - index: &TxIndex, - num_txs_unchecked: &NumTxsUnchecked, - ) -> Transaction { - let tx_table_entries = self.read(&TxTableEntriesRange::new(index)); - let tx_range = TxPayloadRange::new(num_txs_unchecked, &tx_table_entries, &self.byte_len()); - - // TODO don't copy the tx bytes into the return value - // https://github.com/EspressoSystems/hotshot-query-service/issues/267 - let tx_payload = self.read(&tx_range).to_payload_bytes().to_vec(); - Transaction::new(*ns_id, tx_payload) - } -} - -#[repr(transparent)] -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -#[serde(transparent)] -pub struct NsPayloadOwned(#[serde(with = "base64_bytes")] Vec); - -/// Crazy boilerplate code to make it so that [`NsPayloadOwned`] is to -/// [`NsPayload`] as [`Vec`] is to `[T]`. See [How can I create newtypes for -/// an unsized type and its owned counterpart (like `str` and `String`) in safe -/// Rust? - Stack Overflow](https://stackoverflow.com/q/64977525) -mod ns_payload_owned { - use super::{NsPayload, NsPayloadOwned}; - use std::borrow::Borrow; - use std::ops::Deref; - - impl NsPayload { - // pub(super) because I want it visible everywhere in this file but I - // also want this boilerplate code quarrantined in `ns_payload_owned`. - pub(super) fn new_private(p: &[u8]) -> &NsPayload { - unsafe { &*(p as *const [u8] as *const NsPayload) } - } - } - - impl Deref for NsPayloadOwned { - type Target = NsPayload; - fn deref(&self) -> &NsPayload { - NsPayload::new_private(&self.0) - } - } - - impl Borrow for NsPayloadOwned { - fn borrow(&self) -> &NsPayload { - self.deref() - } - } - - impl ToOwned for NsPayload { - type Owned = NsPayloadOwned; - fn to_owned(&self) -> NsPayloadOwned { - NsPayloadOwned(self.0.to_owned()) - } - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/ns_payload_range.rs b/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/ns_payload_range.rs deleted file mode 100644 index 3846223839..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/ns_payload_range.rs +++ /dev/null @@ -1,34 +0,0 @@ -use super::types::{NsPayloadByteLen, NsPayloadBytesRange}; -use std::ops::Range; - -/// Index range for a namespace payload inside a block payload. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct NsPayloadRange(Range); - -impl NsPayloadRange { - /// TODO restrict visibility? - pub fn new(start: usize, end: usize) -> Self { - Self(start..end) - } - - /// Access the underlying index range for this namespace inside a block - /// payload. - pub fn as_block_range(&self) -> Range { - self.0.clone() - } - - /// Return the byte length of this namespace. - pub fn byte_len(&self) -> NsPayloadByteLen { - NsPayloadByteLen::from_usize(self.0.len()) - } - - /// Convert a [`NsPayloadBytesRange`] into a range that's relative to the - /// entire block payload. - pub fn block_range<'a, R>(&self, range: &R) -> Range - where - R: NsPayloadBytesRange<'a>, - { - let range = range.ns_payload_range(); - range.start + self.0.start..range.end + self.0.start - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/tx_proof.rs b/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/tx_proof.rs deleted file mode 100644 index 5c066f8e21..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/tx_proof.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::hotshot_types::SmallRangeProofType; -use crate::namespace_payload::types::{NumTxsUnchecked, TxIndex, TxTableEntries}; -use serde::{Deserialize, Serialize}; - -/// Proof of correctness for transaction bytes in a block. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct TxProof { - // Naming conventions for this struct's fields: - // - `payload_x`: bytes from the payload - // - `payload_proof_x`: a proof of those bytes from the payload - tx_index: TxIndex, - - // Number of txs declared in the tx table - payload_num_txs: NumTxsUnchecked, - payload_proof_num_txs: SmallRangeProofType, - - // Tx table entries for this tx - payload_tx_table_entries: TxTableEntries, - payload_proof_tx_table_entries: SmallRangeProofType, - - // This tx's payload bytes. - // `None` if this tx has zero length. - payload_proof_tx: Option, -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/types.rs b/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/types.rs deleted file mode 100644 index 8c21e02759..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/namespace_payload/types.rs +++ /dev/null @@ -1,382 +0,0 @@ -//! Types related to a namespace payload and its transaction table. -//! -//! All code that needs to know the binary format of a namespace payload and its -//! transaction table is restricted to this file. -//! -//! There are many newtypes in this file to facilitate transaction proofs. -//! -//! # Binary format of a namespace payload -//! -//! Any sequence of bytes is a valid [`NsPayload`]. -//! -//! A namespace payload consists of two concatenated byte sequences: -//! - `tx_table`: transaction table -//! - `tx_payloads`: transaction payloads -//! -//! # Transaction table -//! -//! Byte lengths for the different items that could appear in a `tx_table` are -//! specified in local private constants [`NUM_TXS_BYTE_LEN`], -//! [`TX_OFFSET_BYTE_LEN`]. -//! -//! ## Number of entries in the transaction table -//! -//! The first [`NUM_TXS_BYTE_LEN`] bytes of the `tx_table` indicate the number -//! `n` of entries in the table as a little-endian unsigned integer. If the -//! entire namespace payload byte length is smaller than [`NUM_TXS_BYTE_LEN`] -//! then the missing bytes are zero-padded. -//! -//! The bytes in the namespace payload beyond the first [`NUM_TXS_BYTE_LEN`] -//! bytes encode entries in the `tx_table`. Each entry consumes exactly -//! [`TX_OFFSET_BYTE_LEN`] bytes. -//! -//! The number `n` could be anything, including a number much larger than the -//! number of entries that could fit in the namespace payload. As such, the -//! actual number of entries in the `tx_table` is defined as the minimum of `n` -//! and the maximum number of whole `tx_table` entries that could fit in the -//! namespace payload. -//! -//! The `tx_payloads` consist of any bytes in the namespace payload beyond the -//! `tx_table`. -//! -//! ## Transaction table entry -//! -//! Each entry in the `tx_table` is exactly [`TX_OFFSET_BYTE_LEN`] bytes. These -//! bytes indicate the end-index of a transaction in the namespace payload -//! bytes. This end-index is a little-endian unsigned integer. -//! -//! This offset is relative to the end of the `tx_table` within the current -//! namespace. -//! -//! ### Example -//! -//! Suppose a block payload has 3000 bytes and 3 namespaces of 1000 bytes each. -//! Suppose the `tx_table` for final namespace in the block has byte length 100, -//! and suppose an entry in that `tx_table` indicates an end-index of `10`. The -//! actual end-index of that transaction relative to the current namespace is -//! `110`: `10` bytes for the offset plus `100` bytes for the `tx_table`. -//! Relative to the entire block payload, the end-index of that transaction is -//! `2110`: `10` bytes for the offset plus `100` bytes for the `tx_table` plus -//! `2000` bytes for this namespace. -//! -//! # How to deduce a transaction's byte range -//! -//! In order to extract the payload bytes of a single transaction `T` from the -//! namespace payload one needs both the start- and end-indices for `T`. -//! -//! See [`TxPayloadRange::new`] for clarification. What follows is a description -//! of what's implemented in [`TxPayloadRange::new`]. -//! -//! If `T` occupies the `i`th entry in the `tx_table` for `i>0` then the -//! start-index for `T` is defined as the end-index of the `(i-1)`th entry in -//! the table. -//! -//! Thus, both start- and end-indices for any transaction `T` can be read from a -//! contiguous, constant-size byte range in the `tx_table`. This property -//! facilitates transaction proofs. -//! -//! The start-index of the 0th entry in the table is implicitly defined to be -//! `0`. -//! -//! The start- and end-indices `(declared_start, declared_end)` declared in the -//! `tx_table` could be anything. As such, the actual start- and end-indices -//! `(start, end)` are defined so as to ensure that the byte range is -//! well-defined and in-bounds for the namespace payload: -//! ```ignore -//! end = min(declared_end, namespace_payload_byte_length) -//! start = min(declared_start, end) -//! ``` -//! -//! To get the byte range for `T` relative to the current namespace, the above -//! range is translated by the byte length of the `tx_table` *as declared in the -//! `tx_table` itself*, suitably truncated to fit within the current namespace. -//! -//! In particular, if the `tx_table` declares a huge number `n` of entries that -//! cannot fit into the namespace payload then all transactions in this -//! namespace have a zero-length byte range whose start- and end-indices are -//! both `namespace_payload_byte_length`. -//! -//! In a "honestly-prepared" `tx_table` the end-index of the final transaction -//! equals the byte length of the namespace payload minus the byte length of the -//! `tx_table`. (Otherwise the namespace payload might have bytes that are not -//! included in any transaction.) -//! -//! It is possible that a `tx_table` table could indicate two distinct -//! transactions whose byte ranges overlap, though no "honestly-prepared" -//! `tx_table` would do this. -use crate::uint_bytes::{bytes_serde_impl, usize_from_bytes, usize_to_bytes}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::ops::Range; - -/// Byte lengths for the different items that could appear in a tx table. -const NUM_TXS_BYTE_LEN: usize = 4; -const TX_OFFSET_BYTE_LEN: usize = 4; - -/// Data that can be deserialized from a subslice of namespace payload bytes. -/// -/// Companion trait for [`NsPayloadBytesRange`], which specifies the subslice of -/// namespace payload bytes to read. -pub trait FromNsPayloadBytes<'a> { - /// Deserialize `Self` from namespace payload bytes. - fn from_payload_bytes(bytes: &'a [u8]) -> Self; -} - -/// Specifies a subslice of namespace payload bytes to read. -/// -/// Companion trait for [`FromNsPayloadBytes`], which holds data that can be -/// deserialized from that subslice of bytes. -pub trait NsPayloadBytesRange<'a> { - type Output: FromNsPayloadBytes<'a>; - - /// Range relative to this ns payload - fn ns_payload_range(&self) -> Range; -} - -/// Number of txs in a namespace. -/// -/// Like [`NumTxsUnchecked`] but checked against a [`NsPayloadByteLen`]. -pub struct NumTxs(usize); - -impl NumTxs { - /// Returns the minimum of: - /// - `num_txs` - /// - The maximum number of tx table entries that could fit in a namespace - /// whose byte length is `byte_len`. - pub fn new(num_txs: &NumTxsUnchecked, byte_len: &NsPayloadByteLen) -> Self { - Self(std::cmp::min( - // Number of txs declared in the tx table - num_txs.0, - // Max number of tx table entries that could fit in the namespace payload - byte_len.0.saturating_sub(NUM_TXS_BYTE_LEN) / TX_OFFSET_BYTE_LEN, - )) - } -} - -/// Byte length of a namespace payload. -pub struct NsPayloadByteLen(usize); - -impl NsPayloadByteLen { - // TODO restrict visibility? - pub fn from_usize(n: usize) -> Self { - Self(n) - } -} - -/// The part of a tx table that declares the number of txs in the payload. -/// -/// "Unchecked" because this quantity might exceed the number of tx table -/// entries that could fit into the namespace that contains it. -/// -/// Use [`NumTxs`] for the actual number of txs in this namespace. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct NumTxsUnchecked(usize); -bytes_serde_impl!( - NumTxsUnchecked, - to_payload_bytes, - [u8; NUM_TXS_BYTE_LEN], - from_payload_bytes -); - -impl NumTxsUnchecked { - pub fn to_payload_bytes(&self) -> [u8; NUM_TXS_BYTE_LEN] { - usize_to_bytes::(self.0) - } -} - -impl FromNsPayloadBytes<'_> for NumTxsUnchecked { - fn from_payload_bytes(bytes: &[u8]) -> Self { - Self(usize_from_bytes::(bytes)) - } -} - -/// Byte range for the part of a tx table that declares the number of txs in the -/// payload. -pub struct NumTxsRange(Range); - -impl NumTxsRange { - pub fn new(byte_len: &NsPayloadByteLen) -> Self { - Self(0..NUM_TXS_BYTE_LEN.min(byte_len.0)) - } -} - -impl NsPayloadBytesRange<'_> for NumTxsRange { - type Output = NumTxsUnchecked; - - fn ns_payload_range(&self) -> Range { - self.0.clone() - } -} - -/// Entries from a tx table in a namespace for use in a transaction proof. -/// -/// Contains either one or two entries according to whether it was derived from -/// the first transaction in the namespace. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct TxTableEntries { - cur: usize, - prev: Option, // `None` if derived from the first transaction -} - -// This serde impl uses Vec. We could save space by using an array of -// length `TWO_ENTRIES_BYTE_LEN`, but then we need a way to distinguish -// `prev=Some(0)` from `prev=None`. -bytes_serde_impl!( - TxTableEntries, - to_payload_bytes, - Vec, - from_payload_bytes -); - -impl TxTableEntries { - const TWO_ENTRIES_BYTE_LEN: usize = 2 * TX_OFFSET_BYTE_LEN; - - pub fn to_payload_bytes(&self) -> Vec { - let mut bytes = Vec::with_capacity(Self::TWO_ENTRIES_BYTE_LEN); - if let Some(prev) = self.prev { - bytes.extend(usize_to_bytes::(prev)); - } - bytes.extend(usize_to_bytes::(self.cur)); - bytes - } -} - -impl FromNsPayloadBytes<'_> for TxTableEntries { - fn from_payload_bytes(bytes: &[u8]) -> Self { - match bytes.len() { - TX_OFFSET_BYTE_LEN => Self { - cur: usize_from_bytes::(bytes), - prev: None, - }, - Self::TWO_ENTRIES_BYTE_LEN => Self { - cur: usize_from_bytes::(&bytes[TX_OFFSET_BYTE_LEN..]), - prev: Some(usize_from_bytes::( - &bytes[..TX_OFFSET_BYTE_LEN], - )), - }, - len => panic!( - "unexpected bytes len {} should be either {} or {}", - len, - TX_OFFSET_BYTE_LEN, - Self::TWO_ENTRIES_BYTE_LEN - ), - } - } -} - -/// Byte range for entries from a tx table for use in a transaction proof. -/// -/// This range covers either one or two entries from a tx table according to -/// whether it was derived from the first transaction in the namespace. -pub struct TxTableEntriesRange(Range); - -impl TxTableEntriesRange { - pub fn new(index: &TxIndex) -> Self { - let start = if index.0 == 0 { - // Special case: the desired range includes only one entry from - // the tx table: the first entry. This entry starts immediately - // following the bytes that encode the tx table length. - NUM_TXS_BYTE_LEN - } else { - // The desired range starts at the beginning of the previous tx - // table entry. - (index.0 - 1) - .saturating_mul(TX_OFFSET_BYTE_LEN) - .saturating_add(NUM_TXS_BYTE_LEN) - }; - // The desired range ends at the end of this transaction's tx table entry - let end = index - .0 - .saturating_add(1) - .saturating_mul(TX_OFFSET_BYTE_LEN) - .saturating_add(NUM_TXS_BYTE_LEN); - Self(start..end) - } -} - -impl NsPayloadBytesRange<'_> for TxTableEntriesRange { - type Output = TxTableEntries; - - fn ns_payload_range(&self) -> Range { - self.0.clone() - } -} - -/// A transaction's payload data. -pub struct TxPayload<'a>(&'a [u8]); - -impl<'a> TxPayload<'a> { - pub fn to_payload_bytes(&self) -> &'a [u8] { - self.0 - } -} - -impl<'a> FromNsPayloadBytes<'a> for TxPayload<'a> { - fn from_payload_bytes(bytes: &'a [u8]) -> Self { - Self(bytes) - } -} - -/// Byte range for a transaction's payload data. -pub struct TxPayloadRange(Range); - -impl TxPayloadRange { - pub fn new( - num_txs: &NumTxsUnchecked, - tx_table_entries: &TxTableEntries, - byte_len: &NsPayloadByteLen, - ) -> Self { - let tx_table_byte_len = num_txs - .0 - .saturating_mul(TX_OFFSET_BYTE_LEN) - .saturating_add(NUM_TXS_BYTE_LEN); - let end = tx_table_entries - .cur - .saturating_add(tx_table_byte_len) - .min(byte_len.0); - let start = tx_table_entries - .prev - .unwrap_or(0) - .saturating_add(tx_table_byte_len) - .min(end); - Self(start..end) - } -} - -impl<'a> NsPayloadBytesRange<'a> for TxPayloadRange { - type Output = TxPayload<'a>; - - fn ns_payload_range(&self) -> Range { - self.0.clone() - } -} - -/// Index for an entry in a tx table. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct TxIndex(usize); -bytes_serde_impl!(TxIndex, to_bytes, [u8; NUM_TXS_BYTE_LEN], from_bytes); - -impl TxIndex { - pub fn to_bytes(&self) -> [u8; NUM_TXS_BYTE_LEN] { - usize_to_bytes::(self.0) - } - fn from_bytes(bytes: &[u8]) -> Self { - Self(usize_from_bytes::(bytes)) - } -} - -pub struct TxIter(Range); - -impl TxIter { - pub fn new(num_txs: &NumTxs) -> Self { - Self(0..num_txs.0) - } -} - -// Simple `impl Iterator` delegates to `Range`. -impl Iterator for TxIter { - type Item = TxIndex; - - fn next(&mut self) -> Option { - self.0.next().map(TxIndex) - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/sequencer_data_structures.rs b/espressocrypto/lib/espresso-crypto-helper/src/sequencer_data_structures.rs deleted file mode 100644 index 19ed706eb5..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/sequencer_data_structures.rs +++ /dev/null @@ -1,797 +0,0 @@ -// TODO import from sequencer: https://github.com/EspressoSystems/nitro-espresso-integration/issues/87 -// This module is essentially copy and pasted VID logic from the sequencer repo. It is an unfortunate workaround -// until the VID portion of the sequencer repo is WASM-compatible. -use ark_ff::{BigInteger, PrimeField}; -use ark_serialize::{ - CanonicalDeserialize, CanonicalSerialize, Compress, Read, SerializationError, Valid, Validate, -}; -use bytesize::ByteSize; -use committable::{Commitment, Committable, RawCommitmentBuilder}; -use derive_more::Deref; -use derive_more::{Add, Display, From, Into, Sub}; -use digest::OutputSizeUser; -use either::Either; -use ethers_core::{ - types::{Address, Signature, H256, U256}, - utils::{parse_units, ParseUnits}, -}; -use jf_merkle_tree::{ - prelude::{LightWeightSHA3MerkleTree, Sha3Digest, Sha3Node}, - universal_merkle_tree::UniversalMerkleTree, - MerkleTreeScheme, ToTraversalPath, -}; -use num_traits::PrimInt; -use serde::Serializer; -use serde::{ - de::{self, MapAccess, SeqAccess, Visitor}, - Deserialize, Deserializer, Serialize, -}; -use serde_json::{Map, Value}; -use std::{default::Default, fmt, str::FromStr}; -use tagged_base64::tagged; -use trait_set::trait_set; -use typenum::Unsigned; - -use crate::v0_3; -use crate::{full_payload::NsTable, hotshot_types::VidCommitment}; -use crate::{ - utils::{impl_serde_from_string_or_integer, Err, FromStringOrInteger}, - NamespaceId, -}; - -trait_set! { - pub trait TableWordTraits = CanonicalSerialize - + CanonicalDeserialize - + TryFrom - + TryInto - + Default - + PrimInt - + std::marker::Sync; - - // Note: this trait is not used yet as for now the Payload structs are only parametrized with the TableWord parameter. - pub trait OffsetTraits = CanonicalSerialize - + CanonicalDeserialize - + TryFrom - + TryInto - + Default - + std::marker::Sync; - - // Note: this trait is not used yet as for now the Payload structs are only parametrized with the TableWord parameter. - pub trait NsIdTraits =CanonicalSerialize + CanonicalDeserialize + Default + std::marker::Sync; -} - -pub struct Transaction { - pub _namespace: NamespaceId, - pub payload: Vec, -} - -impl Transaction { - pub fn new(namespace: NamespaceId, payload: Vec) -> Self { - Self { - _namespace: namespace, - payload, - } - } -} - -#[derive(Default, Hash, Copy, Clone, Debug, PartialEq, Eq, From, Into, Display)] -#[display(fmt = "{_0}")] - -pub struct ChainId(U256); - -impl From for ChainId { - fn from(id: u64) -> Self { - Self(id.into()) - } -} - -impl FromStringOrInteger for ChainId { - type Binary = U256; - type Integer = u64; - - fn from_binary(b: Self::Binary) -> Result { - Ok(Self(b)) - } - - fn from_integer(i: Self::Integer) -> Result { - Ok(i.into()) - } - - fn from_string(s: String) -> Result { - if s.starts_with("0x") { - Ok(Self(U256::from_str(&s).unwrap())) - } else { - Ok(Self(U256::from_dec_str(&s).unwrap())) - } - } - - fn to_binary(&self) -> Result { - Ok(self.0) - } - - fn to_string(&self) -> Result { - Ok(format!("{self}")) - } -} - -macro_rules! impl_to_fixed_bytes { - ($struct_name:ident, $type:ty) => { - impl $struct_name { - pub(crate) fn to_fixed_bytes(self) -> [u8; core::mem::size_of::<$type>()] { - let mut bytes = [0u8; core::mem::size_of::<$type>()]; - self.0.to_little_endian(&mut bytes); - bytes - } - } - }; -} - -impl_serde_from_string_or_integer!(ChainId); -impl_to_fixed_bytes!(ChainId, U256); - -impl From for ChainId { - fn from(id: u16) -> Self { - Self(id.into()) - } -} - -#[derive(Hash, Copy, Clone, Debug, Default, Display, PartialEq, Eq, From, Into, Deref)] -#[display(fmt = "{_0}")] -pub struct BlockSize(u64); - -impl_serde_from_string_or_integer!(BlockSize); - -impl FromStringOrInteger for BlockSize { - type Binary = u64; - type Integer = u64; - - fn from_binary(b: Self::Binary) -> Result { - Ok(Self(b)) - } - - fn from_integer(i: Self::Integer) -> Result { - Ok(Self(i)) - } - - fn from_string(s: String) -> Result { - Ok(BlockSize(s.parse::().unwrap().0)) - } - - fn to_binary(&self) -> Result { - Ok(self.0) - } - - fn to_string(&self) -> Result { - Ok(format!("{self}")) - } -} - -/// Global variables for an Espresso blockchain. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct ChainConfig { - /// Espresso chain ID - chain_id: ChainId, - /// Maximum size in bytes of a block - max_block_size: BlockSize, - /// Minimum fee in WEI per byte of payload - base_fee: FeeAmount, - fee_contract: Option
, - fee_recipient: FeeAccount, -} - -impl Committable for ChainConfig { - fn tag() -> String { - "CHAIN_CONFIG".to_string() - } - - fn commit(&self) -> Commitment { - let comm = committable::RawCommitmentBuilder::new(&Self::tag()) - .fixed_size_field("chain_id", &self.chain_id.to_fixed_bytes()) - .u64_field("max_block_size", self.max_block_size.0) - .fixed_size_field("base_fee", &self.base_fee.to_fixed_bytes()) - .fixed_size_field("fee_recipient", &self.fee_recipient.to_fixed_bytes()); - let comm = if let Some(addr) = self.fee_contract { - comm.u64_field("fee_contract", 1).fixed_size_bytes(&addr.0) - } else { - comm.u64_field("fee_contract", 0) - }; - comm.finalize() - } -} - -#[derive(Clone, Debug, Copy, PartialEq, Deserialize, Serialize, Eq, Hash)] -pub struct ResolvableChainConfig { - chain_config: Either>, -} - -impl ResolvableChainConfig { - pub fn commit(&self) -> Commitment { - match self.chain_config { - Either::Left(config) => config.commit(), - Either::Right(commitment) => commitment, - } - } - pub fn resolve(self) -> Option { - match self.chain_config { - Either::Left(config) => Some(config), - Either::Right(_) => None, - } - } -} - -impl From> for ResolvableChainConfig { - fn from(value: Commitment) -> Self { - Self { - chain_config: Either::Right(value), - } - } -} - -impl From for ResolvableChainConfig { - fn from(value: ChainConfig) -> Self { - Self { - chain_config: Either::Left(value), - } - } -} - -pub type BlockMerkleTree = LightWeightSHA3MerkleTree>; -pub type BlockMerkleCommitment = ::Commitment; - -#[tagged("BUILDER_COMMITMENT")] -#[derive(Clone, Debug, Hash, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)] -/// Commitment that builders use to sign block options. -/// A thin wrapper around a Sha256 digest. -pub struct BuilderCommitment(Sha256Digest); - -impl AsRef for BuilderCommitment { - fn as_ref(&self) -> &Sha256Digest { - &self.0 - } -} - -pub enum Header { - V1(Header0_1), - V2(Header0_1), - V3(v0_3::Header), -} - -impl Header { - pub fn height(&self) -> u64 { - match self { - Header::V1(header0_1) => header0_1.height, - Header::V2(header0_1) => header0_1.height, - Header::V3(header) => header.height, - } - } -} - -impl<'de> Deserialize<'de> for Header { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct HeaderVisitor; - - impl<'de> Visitor<'de> for HeaderVisitor { - type Value = Header; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Header") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let chain_config_or_version: EitherOrVersion = seq - .next_element()? - .ok_or_else(|| de::Error::missing_field("chain_config"))?; - - match chain_config_or_version { - // For v0.1, the first field in the sequence of fields is the first field of the struct, so we call a function to get the rest of - // the fields from the sequence and pack them into the struct. - EitherOrVersion::Left(cfg) => Ok(Header::V1( - Header0_1::deserialize_with_chain_config(cfg.into(), seq)?, - )), - EitherOrVersion::Right(commit) => Ok(Header::V1( - Header0_1::deserialize_with_chain_config(commit.into(), seq)?, - )), - // For all versions > 0.1, the first "field" is not actually part of the `Header` struct. - // We just delegate directly to the derived deserialization impl for the appropriate version. - EitherOrVersion::Version(Version { major: 0, minor: 2 }) => Ok(Header::V2( - seq.next_element()? - .ok_or_else(|| de::Error::missing_field("fields"))?, - )), - EitherOrVersion::Version(Version { major: 0, minor: 3 }) => Ok(Header::V3( - seq.next_element()? - .ok_or_else(|| de::Error::missing_field("fields"))?, - )), - EitherOrVersion::Version(v) => { - Err(serde::de::Error::custom(format!("invalid version {v:?}"))) - } - } - } - - fn visit_map(self, mut map: V) -> Result - where - V: MapAccess<'de>, - { - // insert all the fields in the serde_map as the map may have out of order fields. - let mut serde_map: Map = Map::new(); - - while let Some(key) = map.next_key::()? { - serde_map.insert(key.trim().to_owned(), map.next_value()?); - } - - if let Some(v) = serde_map.get("version") { - let fields = serde_map - .get("fields") - .ok_or_else(|| de::Error::missing_field("fields"))?; - - let version = serde_json::from_value::(v.clone()) - .map_err(de::Error::custom)?; - let result = match version { - EitherOrVersion::Version(Version { major: 0, minor: 2 }) => Ok(Header::V2( - serde_json::from_value(fields.clone()).map_err(de::Error::custom)?, - )), - EitherOrVersion::Version(Version { major: 0, minor: 3 }) => Ok(Header::V3( - serde_json::from_value(fields.clone()).map_err(de::Error::custom)?, - )), - EitherOrVersion::Version(v) => { - Err(de::Error::custom(format!("invalid version {v:?}"))) - } - chain_config => Err(de::Error::custom(format!( - "expected version, found chain_config {chain_config:?}" - ))), - }; - return result; - } - - Ok(Header::V1( - serde_json::from_value(serde_map.into()).map_err(de::Error::custom)?, - )) - } - } - - // List of all possible fields of all versions of the `Header`. - // serde's `deserialize_struct` works by deserializing to a struct with a specific list of fields. - // The length of the fields list we provide is always going to be greater than the length of the target struct. - // In our case, we are deserializing to either a V1 Header or a VersionedHeader for versions > 0.1. - // We use serde_json and bincode serialization in the sequencer. - // Fortunately, serde_json ignores fields parameter and only cares about our Visitor implementation. - // - https://docs.rs/serde_json/1.0.120/serde_json/struct.Deserializer.html#method.deserialize_struct - // Bincode uses the length of the fields list, but the bincode deserialization only cares that the length of the fields - // is an upper bound of the target struct's fields length. - // - https://docs.rs/bincode/1.3.3/src/bincode/de/mod.rs.html#313 - // This works because the bincode deserializer only consumes the next field when `next_element` is called, - // and our visitor calls it the correct number of times. - // This would, however, break if the bincode deserializer implementation required an exact match of the field's length, - // consuming one element for each field. - let fields: &[&str] = &[ - "fields", - "chain_config", - "version", - "height", - "timestamp", - "l1_head", - "l1_finalized", - "payload_commitment", - "builder_commitment", - "ns_table", - "block_merkle_tree_root", - "fee_merkle_tree_root", - "fee_info", - "builder_signature", - ]; - - deserializer.deserialize_struct("Header", fields, HeaderVisitor) - } -} - -impl Committable for Header { - fn commit(&self) -> Commitment { - match self { - Self::V1(header) => header.commit(), - Self::V2(fields) => RawCommitmentBuilder::new(&Self::tag()) - .u64_field("version_major", 0) - .u64_field("version_minor", 2) - .field("fields", fields.commit()) - .finalize(), - Self::V3(fields) => RawCommitmentBuilder::new(&Self::tag()) - .u64_field("version_major", 0) - .u64_field("version_minor", 3) - .field("fields", fields.commit()) - .finalize(), - } - } - - fn tag() -> String { - // We use the tag "BLOCK" since blocks are identified by the hash of their header. This will - // thus be more intuitive to users than "HEADER". - "BLOCK".into() - } -} - -impl Serialize for Header { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Self::V1(header) => header.serialize(serializer), - Self::V2(fields) => VersionedHeader { - version: EitherOrVersion::Version(Version { major: 0, minor: 2 }), - fields: fields.clone(), - } - .serialize(serializer), - Self::V3(fields) => VersionedHeader { - version: EitherOrVersion::Version(Version { major: 0, minor: 3 }), - fields: fields.clone(), - } - .serialize(serializer), - } - } -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct VersionedHeader { - pub(crate) version: EitherOrVersion, - pub(crate) fields: Fields, -} - -#[derive(Deserialize, Serialize, Debug)] -pub enum EitherOrVersion { - Left(ChainConfig), - Right(Commitment), - Version(Version), -} - -// Header values -#[derive(Clone, Debug, Deserialize, Serialize, Hash, PartialEq, Eq)] -pub struct Header0_1 { - pub chain_config: ResolvableChainConfig, - pub height: u64, - pub timestamp: u64, - pub l1_head: u64, - pub l1_finalized: Option, - pub payload_commitment: VidCommitment, - pub builder_commitment: BuilderCommitment, - pub ns_table: NsTable, - pub block_merkle_tree_root: BlockMerkleCommitment, - pub fee_merkle_tree_root: FeeMerkleCommitment, - pub builder_signature: Option, - pub fee_info: FeeInfo, -} - -impl Header0_1 { - fn commit(&self) -> Commitment
{ - let mut bmt_bytes = vec![]; - self.block_merkle_tree_root - .serialize_with_mode(&mut bmt_bytes, ark_serialize::Compress::Yes) - .unwrap(); - let mut fmt_bytes = vec![]; - self.fee_merkle_tree_root - .serialize_with_mode(&mut fmt_bytes, ark_serialize::Compress::Yes) - .unwrap(); - - RawCommitmentBuilder::new(&Self::tag()) - .field("chain_config", self.chain_config.commit()) - .u64_field("height", self.height) - .u64_field("timestamp", self.timestamp) - .u64_field("l1_head", self.l1_head) - .optional("l1_finalized", &self.l1_finalized) - .constant_str("payload_commitment") - .fixed_size_bytes(self.payload_commitment.as_ref().as_ref()) - .constant_str("builder_commitment") - .fixed_size_bytes(self.builder_commitment.as_ref()) - .field("ns_table", self.ns_table.commit()) - .var_size_field("block_merkle_tree_root", &bmt_bytes) - .var_size_field("fee_merkle_tree_root", &fmt_bytes) - .field("fee_info", self.fee_info.commit()) - .finalize() - } - - fn tag() -> String { - // We use the tag "BLOCK" since blocks are identified by the hash of their header. This will - // thus be more intuitive to users than "HEADER". - "BLOCK".into() - } -} - -impl Header0_1 { - pub fn deserialize_with_chain_config<'de, A>( - chain_config: ResolvableChainConfig, - mut seq: A, - ) -> Result - where - A: SeqAccess<'de>, - { - macro_rules! element { - ($seq:expr, $field:ident) => { - $seq.next_element()? - .ok_or_else(|| de::Error::missing_field(stringify!($field)))? - }; - } - let height = element!(seq, height); - let timestamp = element!(seq, timestamp); - let l1_head = element!(seq, l1_head); - let l1_finalized = element!(seq, l1_finalized); - let payload_commitment = element!(seq, payload_commitment); - let builder_commitment = element!(seq, builder_commitment); - let ns_table = element!(seq, ns_table); - let block_merkle_tree_root = element!(seq, block_merkle_tree_root); - let fee_merkle_tree_root = element!(seq, fee_merkle_tree_root); - let fee_info = element!(seq, fee_info); - let builder_signature = element!(seq, builder_signature); - - Ok(Self { - chain_config, - height, - timestamp, - l1_head, - l1_finalized, - payload_commitment, - builder_commitment, - ns_table, - block_merkle_tree_root, - fee_merkle_tree_root, - fee_info, - builder_signature, - }) - } -} - -/// Type for protocol version number -#[derive(Deserialize, Serialize, Debug)] -pub struct Version { - /// major version number - pub major: u16, - /// minor version number - pub minor: u16, -} - -pub type FeeMerkleTree = UniversalMerkleTree; -pub type FeeMerkleCommitment = ::Commitment; - -/// Type alias for byte array of SHA256 digest length -type Sha256Digest = [u8; ::OutputSize::USIZE]; - -#[derive(Default, Hash, Copy, Clone, Debug, PartialEq, Eq, Add, Sub, From, Into, Display)] -#[display(fmt = "{_0}")] -pub struct FeeAmount(U256); - -impl FromStringOrInteger for FeeAmount { - type Binary = U256; - type Integer = u64; - - fn from_binary(b: Self::Binary) -> Result { - Ok(Self(b)) - } - - fn from_integer(i: Self::Integer) -> Result { - Ok(i.into()) - } - - fn from_string(s: String) -> Result { - // For backwards compatibility, we have an ad hoc parser for WEI amounts represented as hex - // strings. - if let Some(s) = s.strip_prefix("0x") { - return Ok(Self(s.parse().unwrap())); - } - - // Strip an optional non-numeric suffix, which will be interpreted as a unit. - let (base, unit) = s - .split_once(char::is_whitespace) - .unwrap_or((s.as_str(), "wei")); - match parse_units(base, unit).unwrap() { - ParseUnits::U256(n) => Ok(Self(n)), - ParseUnits::I256(_) => panic!("amount cannot be negative"), - } - } - - fn to_binary(&self) -> Result { - Ok(self.0) - } - - fn to_string(&self) -> Result { - Ok(format!("{self}")) - } -} - -impl_serde_from_string_or_integer!(FeeAmount); -impl_to_fixed_bytes!(FeeAmount, U256); - -impl From for FeeAmount { - fn from(amt: u64) -> Self { - Self(amt.into()) - } -} - -impl CanonicalSerialize for FeeAmount { - fn serialize_with_mode( - &self, - mut writer: W, - _compress: Compress, - ) -> Result<(), SerializationError> { - Ok(writer.write_all(&self.to_fixed_bytes())?) - } - - fn serialized_size(&self, _compress: Compress) -> usize { - core::mem::size_of::() - } -} -impl CanonicalDeserialize for FeeAmount { - fn deserialize_with_mode( - mut reader: R, - _compress: Compress, - _validate: Validate, - ) -> Result { - let mut bytes = [0u8; core::mem::size_of::()]; - reader.read_exact(&mut bytes)?; - let value = U256::from_little_endian(&bytes); - Ok(Self(value)) - } -} - -impl CanonicalSerialize for FeeAccount { - fn serialize_with_mode( - &self, - mut writer: W, - _compress: Compress, - ) -> Result<(), SerializationError> { - Ok(writer.write_all(&self.0.to_fixed_bytes())?) - } - - fn serialized_size(&self, _compress: Compress) -> usize { - core::mem::size_of::
() - } -} - -impl CanonicalDeserialize for FeeAccount { - fn deserialize_with_mode( - mut reader: R, - _compress: Compress, - _validate: Validate, - ) -> Result { - let mut bytes = [0u8; core::mem::size_of::
()]; - reader.read_exact(&mut bytes)?; - let value = Address::from_slice(&bytes); - Ok(Self(value)) - } -} - -#[derive( - Default, - Hash, - Copy, - Clone, - Debug, - Display, - Deserialize, - Serialize, - PartialEq, - Eq, - PartialOrd, - Ord, - From, - Into, -)] -#[display(fmt = "{_0:x}")] -pub struct FeeAccount(Address); - -impl FeeAccount { - /// Return inner `Address` - pub fn address(&self) -> Address { - self.0 - } - /// Return byte slice representation of inner `Address` type - pub fn as_bytes(&self) -> &[u8] { - self.0.as_bytes() - } - /// Return array containing underlying bytes of inner `Address` type - pub fn to_fixed_bytes(self) -> [u8; 20] { - self.0.to_fixed_bytes() - } -} - -impl ToTraversalPath<256> for FeeAccount { - fn to_traversal_path(&self, height: usize) -> Vec { - self.0 - .to_fixed_bytes() - .into_iter() - .take(height) - .map(|i| i as usize) - .collect() - } -} - -impl Valid for FeeAmount { - fn check(&self) -> Result<(), SerializationError> { - Ok(()) - } -} - -impl Valid for FeeAccount { - fn check(&self) -> Result<(), SerializationError> { - Ok(()) - } -} - -#[derive( - Hash, - Copy, - Clone, - Debug, - Deserialize, - Serialize, - PartialEq, - Eq, - CanonicalSerialize, - CanonicalDeserialize, -)] -pub struct FeeInfo { - account: FeeAccount, - amount: FeeAmount, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, Hash, PartialEq, Eq)] -pub struct L1BlockInfo { - pub number: u64, - pub timestamp: U256, - pub hash: H256, -} - -impl Committable for L1BlockInfo { - fn commit(&self) -> Commitment { - let mut timestamp = [0u8; 32]; - self.timestamp.to_little_endian(&mut timestamp); - - RawCommitmentBuilder::new(&Self::tag()) - .u64_field("number", self.number) - // `RawCommitmentBuilder` doesn't have a `u256_field` method, so we simulate it: - .constant_str("timestamp") - .fixed_size_bytes(×tamp) - .constant_str("hash") - .fixed_size_bytes(&self.hash.0) - .finalize() - } - - fn tag() -> String { - "L1BLOCK".into() - } -} - -impl Committable for FeeInfo { - fn commit(&self) -> Commitment { - RawCommitmentBuilder::new(&Self::tag()) - .fixed_size_field("account", &self.account.to_fixed_bytes()) - .fixed_size_field("amount", &self.amount.to_fixed_bytes()) - .finalize() - } - fn tag() -> String { - "FEE_INFO".into() - } -} - -pub fn field_to_u256(f: F) -> U256 { - if F::MODULUS_BIT_SIZE > 256 { - panic!("Shouldn't convert a >256-bit field to U256"); - } - U256::from_little_endian(&f.into_bigint().to_bytes_le()) -} - -#[cfg(test)] -mod tests { - - use super::Header0_1; - - #[test] - fn header_test() { - let header_str = include_str!("./mock_data/header.json"); - let header = serde_json::from_str::(&header_str).unwrap(); - // Copied from espresso sequencer reference test - let expected = "BLOCK~6Ol30XYkdKaNFXw0QAkcif18Lk8V8qkC4M81qTlwL707"; - assert_eq!(header.commit().to_string(), expected); - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/uint_bytes.rs b/espressocrypto/lib/espresso-crypto-helper/src/uint_bytes.rs deleted file mode 100644 index a1bd0ea49d..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/uint_bytes.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! Serialization (and deserialization) of primitive unsigned integer types to -//! (and from) an arbitrary fixed-length byte array. -//! -use paste::paste; -use std::mem::size_of; - -// Use an ugly macro because it's difficult or impossible to be generic over -// primitive types such as `usize`, `u64`. -macro_rules! uint_bytes_impl { - ($T:ty) => { - paste! { - /// Serialize `n` into `BYTE_LEN` bytes in little-endian form, padding with - /// 0 as needed. - /// - /// # Panics - /// If `n` cannot fit into `BYTE_LEN` bytes. - #[allow(dead_code)] - pub fn [<$T _to_bytes>](n: $T) -> [u8; BYTE_LEN] { - if size_of::<$T>() > BYTE_LEN { - assert!( - [<$T _fits>](n, BYTE_LEN), - "n {n} cannot fit into {BYTE_LEN} bytes" - ); - n.to_le_bytes()[..BYTE_LEN].try_into().unwrap() // panic is impossible - } else { - // convert `n` to bytes and pad with 0 - let mut result = [0; BYTE_LEN]; - result[..size_of::<$T>()].copy_from_slice(&n.to_le_bytes()[..]); - result - } - } - - /// Deserialize `bytes` in little-endian form into a `$T`, padding with 0 - /// as needed. - /// - /// # Panics - /// If `bytes.len()` is too large to fit into a `$T`. - pub fn [<$T _from_bytes>](bytes: &[u8]) -> $T { - assert!(bytes.len() <= BYTE_LEN, "bytes len {} exceeds BYTE_LEN {BYTE_LEN}", bytes.len()); - assert!( - BYTE_LEN <= size_of::<$T>(), - "BYTE_LEN {BYTE_LEN} cannot fit into {}", - stringify!($T) - ); - let mut [<$T _bytes>] = [0; size_of::<$T>()]; - [<$T _bytes>][..bytes.len()].copy_from_slice(bytes); - $T::from_le_bytes([<$T _bytes>]) - } - - /// Return the largest `$T` value that can fit into `byte_len` bytes. - pub const fn [<$T _max_from_byte_len>](byte_len: usize) -> $T { - if byte_len >= size_of::<$T>() { - $T::MAX - } else { - // overflow cannot occur because `byte_len < size_of::<$T>()` - (1 << (byte_len * 8)) - 1 - } - } - - /// Can `n` fit into `byte_len` bytes? - pub const fn [<$T _fits>](n: $T, byte_len: usize) -> bool { - n <= [<$T _max_from_byte_len>](byte_len) - } - } - }; - } - -uint_bytes_impl!(usize); -uint_bytes_impl!(u32); - -/// Impl [`serde`] for type `$T` with methods named `$to_bytes`, `$from_bytes` -/// of the form -/// ```ignore -/// $T::$to_bytes(&self) -> $B -/// $T::$from_bytes(bytes: &[u8]) -> Self -/// ``` -/// where `$B` is any type that impls [`serde::Deserialize`] and has a method -/// `as_ref` of the form -/// ```ignore -/// $B::as_ref(&self) -> &[u8] -/// ``` -/// Typical examples of `$B` include array `[u8; N]`, slice `&[u8]`, or -/// `Vec`. -macro_rules! bytes_serde_impl { - ($T:ty, $to_bytes:ident, $B:ty, $from_bytes:ident) => { - impl Serialize for $T { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.$to_bytes().serialize(serializer) - } - } - - impl<'de> Deserialize<'de> for $T { - fn deserialize(deserializer: D) -> Result<$T, D::Error> - where - D: Deserializer<'de>, - { - <$B as Deserialize>::deserialize(deserializer) - .map(|bytes| <$T>::$from_bytes(bytes.as_ref())) - } - } - }; -} - -pub(super) use bytes_serde_impl; diff --git a/espressocrypto/lib/espresso-crypto-helper/src/utils.rs b/espressocrypto/lib/espresso-crypto-helper/src/utils.rs deleted file mode 100644 index 23bd000055..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/utils.rs +++ /dev/null @@ -1,75 +0,0 @@ -use serde::{ - de::{DeserializeOwned, Deserializer, Error as _}, - ser::Serializer, - Deserialize, Serialize, -}; - -pub type Err = u8; - -/// Basically copied from sequencer repo. Just removed the error types to avoid introducing other crate -pub trait FromStringOrInteger: Sized { - type Binary: Serialize + DeserializeOwned; - type Integer: Serialize + DeserializeOwned; - - fn from_binary(b: Self::Binary) -> Result; - fn from_string(s: String) -> Result; - fn from_integer(i: Self::Integer) -> Result; - - fn to_binary(&self) -> Result; - fn to_string(&self) -> Result; -} - -#[macro_export] -macro_rules! impl_serde_from_string_or_integer { - ($t:ty) => { - impl serde::Serialize for $t { - fn serialize(&self, s: S) -> Result { - $crate::utils::string_or_integer::serialize(self, s) - } - } - - impl<'de> serde::Deserialize<'de> for $t { - fn deserialize>(d: D) -> Result { - $crate::utils::string_or_integer::deserialize(d) - } - } - }; -} - -pub use crate::impl_serde_from_string_or_integer; - -pub mod string_or_integer { - - use super::*; - - #[derive(Debug, Deserialize)] - #[serde(untagged)] - enum StringOrInteger { - String(String), - Integer(I), - } - - pub fn serialize( - t: &T, - s: S, - ) -> Result { - if s.is_human_readable() { - t.to_string().unwrap().serialize(s) - } else { - t.to_binary().unwrap().serialize(s) - } - } - - pub fn deserialize<'a, T: FromStringOrInteger, D: Deserializer<'a>>( - d: D, - ) -> Result { - if d.is_human_readable() { - match StringOrInteger::deserialize(d)? { - StringOrInteger::String(s) => T::from_string(s).map_err(D::Error::custom), - StringOrInteger::Integer(i) => T::from_integer(i).map_err(D::Error::custom), - } - } else { - T::from_binary(T::Binary::deserialize(d)?).map_err(D::Error::custom) - } - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/v0_3/auction.rs b/espressocrypto/lib/espresso-crypto-helper/src/v0_3/auction.rs deleted file mode 100644 index 9c3209c89e..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/v0_3/auction.rs +++ /dev/null @@ -1,130 +0,0 @@ -use super::super::hotshot_types::ViewNumber; -use super::{FeeAccount, FeeAmount}; -use crate::NamespaceId; -use committable::{Commitment, Committable}; -use ethers_core::types::Signature; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)] -/// Wrapper enum for Full Network Transactions. Each transaction type -/// will be a variant of this enum. -pub enum FullNetworkTx { - Bid(BidTx), -} - -#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)] -/// A transaction to bid for the sequencing rights of a namespace. It -/// is the `signed` form of `BidTxBody`. Expected usage is *build* -/// it by calling `signed` on `BidTxBody`. -pub struct BidTx { - pub(crate) body: BidTxBody, - pub(crate) signature: Signature, -} - -/// A transaction body holding data required for bid submission. -#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)] -pub struct BidTxBody { - /// Account responsible for the signature - pub(crate) account: FeeAccount, - /// Fee to be sequenced in the network. Different than the bid_amount fee - // FULL_NETWORK_GAS * MINIMUM_GAS_PRICE - pub(crate) gas_price: FeeAmount, - /// The bid amount designated in Wei. This is different than - /// the sequencing fee (gas price) for this transaction - pub(crate) bid_amount: FeeAmount, - /// The URL the HotShot leader will use to request a bundle - /// from this sequencer if they win the auction - pub(crate) url: String, - /// The slot this bid is for - pub(crate) view: ViewNumber, - /// The set of namespace ids the sequencer is bidding for - pub(crate) namespaces: Vec, -} - -/// The results of an Auction -#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)] -pub struct SolverAuctionResults { - /// view number the results are for - pub(crate) view_number: ViewNumber, - /// A list of the bid txs that won - pub(crate) winning_bids: Vec, - /// A list of reserve sequencers being used - pub(crate) reserve_bids: Vec<(NamespaceId, String)>, -} - -impl Committable for SolverAuctionResults { - fn tag() -> String { - "SOLVER_AUCTION_RESULTS".to_string() - } - - fn commit(&self) -> Commitment { - let comm = committable::RawCommitmentBuilder::new(&Self::tag()) - .fixed_size_field("view_number", &self.view_number.commit().into()) - .array_field( - "winning_bids", - &self - .winning_bids - .iter() - .map(Committable::commit) - .collect::>(), - ) - .array_field( - "reserve_bids", - &self - .reserve_bids - .iter() - .map(|(nsid, url)| { - // Set a phantom type to make the compiler happy - committable::RawCommitmentBuilder::::new( - "RESERVE_BID", - ) - .u64(nsid.0) - .constant_str(url.as_str()) - .finalize() - }) - .collect::>(), - ); - comm.finalize() - } -} - -impl Committable for BidTx { - fn tag() -> String { - "BID_TX".to_string() - } - - fn commit(&self) -> Commitment { - let comm = committable::RawCommitmentBuilder::new(&Self::tag()) - .field("body", self.body.commit()) - .fixed_size_field("signature", &self.signature.into()); - comm.finalize() - } -} - -impl Committable for BidTxBody { - fn tag() -> String { - "BID_TX_BODY".to_string() - } - - fn commit(&self) -> Commitment { - let comm = committable::RawCommitmentBuilder::new(&Self::tag()) - .fixed_size_field("account", &self.account.to_fixed_bytes()) - .fixed_size_field("gas_price", &self.gas_price.to_fixed_bytes()) - .fixed_size_field("bid_amount", &self.bid_amount.to_fixed_bytes()) - .var_size_field("url", self.url.as_str().as_ref()) - .u64_field("view", self.view.0) - .array_field( - "namespaces", - &self - .namespaces - .iter() - .map(|e| { - committable::RawCommitmentBuilder::::new("namespace") - .u64(e.0) - .finalize() - }) - .collect::>(), - ); - comm.finalize() - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/v0_3/chain_config.rs b/espressocrypto/lib/espresso-crypto-helper/src/v0_3/chain_config.rs deleted file mode 100644 index 47198d6115..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/v0_3/chain_config.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::{BlockSize, ChainId, FeeAccount, FeeAmount}; -use committable::{Commitment, Committable}; -use ethers_core::types::{Address, U256}; -use itertools::Either; -use serde::{Deserialize, Serialize}; - -/// Global variables for an Espresso blockchain. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct ChainConfig { - /// Espresso chain ID - pub chain_id: ChainId, - - /// Maximum size in bytes of a block - pub max_block_size: BlockSize, - - /// Minimum fee in WEI per byte of payload - pub base_fee: FeeAmount, - - /// Fee contract address on L1. - /// - /// This is optional so that fees can easily be toggled on/off, with no need to deploy a - /// contract when they are off. In a future release, after fees are switched on and thoroughly - /// tested, this may be made mandatory. - pub fee_contract: Option
, - - /// Account that receives sequencing fees. - /// - /// This account in the Espresso fee ledger will always receive every fee paid in Espresso, - /// regardless of whether or not their is a `fee_contract` deployed. Once deployed, the fee - /// contract can decide what to do with tokens locked in this account in Espresso. - pub fee_recipient: FeeAccount, - - /// Account that receives sequencing bids. - pub bid_recipient: Option, -} - -#[derive(Clone, Debug, Copy, PartialEq, Deserialize, Serialize, Eq, Hash)] -/// A commitment to a ChainConfig or a full ChainConfig. -pub struct ResolvableChainConfig { - pub(crate) chain_config: Either>, -} - -impl Committable for ChainConfig { - fn tag() -> String { - "CHAIN_CONFIG".to_string() - } - - fn commit(&self) -> Commitment { - let comm = committable::RawCommitmentBuilder::new(&Self::tag()) - .fixed_size_field("chain_id", &self.chain_id.to_fixed_bytes()) - .u64_field("max_block_size", *self.max_block_size) - .fixed_size_field("base_fee", &self.base_fee.to_fixed_bytes()) - .fixed_size_field("fee_recipient", &self.fee_recipient.to_fixed_bytes()); - let comm = if let Some(addr) = self.fee_contract { - comm.u64_field("fee_contract", 1).fixed_size_bytes(&addr.0) - } else { - comm.u64_field("fee_contract", 0) - }; - - // With `ChainConfig` upgrades we want commitments w/out - // fields added >= v0_3 to have the same commitment as <= v0_3 - // commitment. Therefore `None` values are simply ignored. - let comm = if let Some(bid_recipient) = self.bid_recipient { - comm.fixed_size_field("bid_recipient", &bid_recipient.to_fixed_bytes()) - } else { - comm - }; - - comm.finalize() - } -} - -impl ResolvableChainConfig { - pub fn commit(&self) -> Commitment { - match self.chain_config { - Either::Left(config) => config.commit(), - Either::Right(commitment) => commitment, - } - } -} - -impl From> for ResolvableChainConfig { - fn from(value: Commitment) -> Self { - Self { - chain_config: Either::Right(value), - } - } -} - -impl From for ResolvableChainConfig { - fn from(value: ChainConfig) -> Self { - Self { - chain_config: Either::Left(value), - } - } -} - -impl Default for ChainConfig { - fn default() -> Self { - Self { - chain_id: U256::from(35353).into(), // arbitrarily chosen chain ID - max_block_size: 30720.into(), - base_fee: 0.into(), - fee_contract: None, - fee_recipient: Default::default(), - bid_recipient: None, - } - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/v0_3/header.rs b/espressocrypto/lib/espresso-crypto-helper/src/v0_3/header.rs deleted file mode 100644 index ef88bb666a..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/v0_3/header.rs +++ /dev/null @@ -1,70 +0,0 @@ -use super::{ - BlockMerkleCommitment, FeeInfo, FeeMerkleCommitment, L1BlockInfo, ResolvableChainConfig, - SolverAuctionResults, -}; -use crate::hotshot_types::{BuilderCommitment, VidCommitment}; -use crate::NsTable; -use ark_serialize::CanonicalSerialize; -use committable::{Commitment, Committable, RawCommitmentBuilder}; -use ethers_core::types::Signature as BuilderSignature; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Deserialize, Serialize, Hash, PartialEq, Eq)] -/// A header is like a [`Block`] with the body replaced by a digest. -pub struct Header { - /// A commitment to a ChainConfig or a full ChainConfig. - pub(crate) chain_config: ResolvableChainConfig, - pub(crate) height: u64, - pub(crate) timestamp: u64, - pub(crate) l1_head: u64, - pub(crate) l1_finalized: Option, - pub(crate) payload_commitment: VidCommitment, - pub(crate) builder_commitment: BuilderCommitment, - pub(crate) ns_table: NsTable, - pub(crate) block_merkle_tree_root: BlockMerkleCommitment, - pub(crate) fee_merkle_tree_root: FeeMerkleCommitment, - pub(crate) fee_info: Vec, - pub(crate) builder_signature: Vec, - pub(crate) auction_results: SolverAuctionResults, -} - -impl Committable for Header { - fn commit(&self) -> Commitment { - let mut bmt_bytes = vec![]; - self.block_merkle_tree_root - .serialize_with_mode(&mut bmt_bytes, ark_serialize::Compress::Yes) - .unwrap(); - let mut fmt_bytes = vec![]; - self.fee_merkle_tree_root - .serialize_with_mode(&mut fmt_bytes, ark_serialize::Compress::Yes) - .unwrap(); - - RawCommitmentBuilder::new(&Self::tag()) - .field("chain_config", self.chain_config.commit()) - .u64_field("height", self.height) - .u64_field("timestamp", self.timestamp) - .u64_field("l1_head", self.l1_head) - .optional("l1_finalized", &self.l1_finalized) - .constant_str("payload_commitment") - .fixed_size_bytes(self.payload_commitment.as_ref().as_ref()) - .constant_str("builder_commitment") - .fixed_size_bytes(self.builder_commitment.as_ref()) - .field("ns_table", self.ns_table.commit()) - .var_size_field("block_merkle_tree_root", &bmt_bytes) - .var_size_field("fee_merkle_tree_root", &fmt_bytes) - .array_field( - "fee_info", - &self - .fee_info - .iter() - .map(Committable::commit) - .collect::>(), - ) - .field("auction_results", self.auction_results.commit()) - .finalize() - } - - fn tag() -> String { - "BLOCK".into() - } -} diff --git a/espressocrypto/lib/espresso-crypto-helper/src/v0_3/mod.rs b/espressocrypto/lib/espresso-crypto-helper/src/v0_3/mod.rs deleted file mode 100644 index e568b23500..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/src/v0_3/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Re-export types which haven't changed since the last minor version. -pub use super::sequencer_data_structures::{ - BlockMerkleCommitment, BlockSize, ChainId, FeeAccount, FeeAmount, FeeInfo, FeeMerkleCommitment, - L1BlockInfo, -}; - -mod auction; -mod chain_config; -mod header; - -pub use auction::SolverAuctionResults; -pub use chain_config::*; -pub use header::Header; diff --git a/espressocrypto/lib/espresso-crypto-helper/vid_srs.json b/espressocrypto/lib/espresso-crypto-helper/vid_srs.json deleted file mode 100644 index aa0532dceb..0000000000 --- a/espressocrypto/lib/espresso-crypto-helper/vid_srs.json +++ /dev/null @@ -1 +0,0 @@ -[5,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,230,49,207,189,34,111,38,253,239,131,186,97,251,231,171,98,78,190,123,168,209,107,255,67,249,159,40,40,6,54,45,170,10,112,5,212,123,240,59,100,176,247,78,203,61,211,248,240,162,236,254,231,204,82,130,244,195,99,229,121,42,185,166,219,137,228,207,21,151,128,212,130,59,138,190,25,73,54,189,135,81,200,124,137,67,158,163,166,72,205,60,228,214,10,2,67,69,158,23,152,197,51,106,108,140,24,44,111,20,97,192,10,96,210,7,20,82,156,180,146,61,234,226,186,158,167,161,118,140,215,125,138,226,57,182,7,222,71,91,232,103,156,194,54,190,135,208,45,8,92,144,114,46,122,185,203,237,11,33,101,226,121,255,196,55,110,254,210,246,234,12,28,192,114,52,238,47,69,188,187,4,105,47,171,163,58,184,49,228,209,152,214,96,132,233,17,76,177,73,144,41,127,136,58,178,129,238,30,130,27,98,71,103,194,185,19,190,176,246,65,206,86,42,124,44,239,166,174,161,44,209,192,86,134,199,56,99,125,130,213,222,37,231,228,109,143,125,84,218,221,227,45,143,169,154,237,246,146,217,92,189,222,70,221,218,94,247,212,34,67,103,121,68,92,94,102,0,106,66,118,30,31,18,239,222,0,24,194,18,243,174,183,133,228,151,18,231,169,53,51,73,170,241,37,93,251,49,183,191,96,114,58,72,13,146,147,147,142,25,170,125,250,102,1,204,230,76,123,211,67,12,105,231,209,227,143,64,203,141,128,113,171,74,235,109,140,219,165,94,200,18,91,151,34,209,220,218,172,85,243,142,179,112,51,49,75,188,149,51,12,105,173,153,158,236,117,240,95,88,208,137,6,9,176,131,136,147,236,31,35,126,139,7,50,59,7,68,89,159,78,151,181,152,179,181,137,188,194,188,55,184,213,196,24,1,193,131,147,192,250,48,254,78,139,3,142,53,122,216,81,234,232,222,145,7,88,78,255,231,199,241,246,81,178,1,14,38,85,94,204,218,212,135,74,133,162,206,230,150,63,221,230,17,94,97,229,20,66,91,71,86,42,99,192,192,163,189,254,34,228,95,106,218,128,60,65,238,164,155,249,65,70,160,242,156,133,114,154,187,193,86,81,210,227,15,17,247,105,99,252,4,2,0,0,0,0,0,0,0,237,246,146,217,92,189,222,70,221,218,94,247,212,34,67,103,121,68,92,94,102,0,106,66,118,30,31,18,239,222,0,24,194,18,243,174,183,133,228,151,18,231,169,53,51,73,170,241,37,93,251,49,183,191,96,114,58,72,13,146,147,147,142,25,170,125,250,102,1,204,230,76,123,211,67,12,105,231,209,227,143,64,203,141,128,113,171,74,235,109,140,219,165,94,200,18,91,151,34,209,220,218,172,85,243,142,179,112,51,49,75,188,149,51,12,105,173,153,158,236,117,240,95,88,208,137,6,9,176,131,136,147,236,31,35,126,139,7,50,59,7,68,89,159,78,151,181,152,179,181,137,188,194,188,55,184,213,196,24,1,193,131,147,192,250,48,254,78,139,3,142,53,122,216,81,234,232,222,145,7,88,78,255,231,199,241,246,81,178,1,14,38,85,94,204,218,212,135,74,133,162,206,230,150,63,221,230,17,94,97,229,20,66,91,71,86,42,99,192,192,163,189,254,34,228,95,106,218,128,60,65,238,164,155,249,65,70,160,242,156,133,114,154,187,193,86,81,210,227,15,17,247,105,99,252,4] \ No newline at end of file