alloy_eips/eip4844/
utils.rs1use crate::eip4844::{Blob, FIELD_ELEMENT_BYTES_USIZE, USABLE_BITS_PER_FIELD_ELEMENT};
7
8pub const fn fits_in_fe(data: &[u8]) -> bool {
10 const FIELD_ELEMENT_BYTES_USIZE_PLUS_ONE: usize = FIELD_ELEMENT_BYTES_USIZE + 1;
11
12 match data.len() {
13 FIELD_ELEMENT_BYTES_USIZE_PLUS_ONE.. => false,
14 FIELD_ELEMENT_BYTES_USIZE => data[0] & 0b1100_0000 == 0, _ => true,
16 }
17}
18
19pub const fn minimum_fe_for_bytes(bytes: usize) -> usize {
22 (bytes * 8).div_ceil(USABLE_BITS_PER_FIELD_ELEMENT)
23}
24
25pub const fn minimum_fe(data: &[u8]) -> usize {
27 minimum_fe_for_bytes(data.len())
28}
29
30#[cfg(feature = "kzg")]
34pub fn bytes_to_blob<B: AsRef<[u8]>>(blob: B) -> Result<Blob, c_kzg::Error> {
35 let b_ref = blob.as_ref();
36 Blob::try_from(b_ref).map_err(|_| {
37 c_kzg::Error::InvalidBytesLength(format!(
39 "Invalid byte length. Expected {} got {}",
40 crate::eip4844::BYTES_PER_BLOB,
41 b_ref.len(),
42 ))
43 })
44}
45
46#[cfg(feature = "kzg")]
50pub fn hex_to_blob<B: AsRef<str>>(blob: B) -> Result<Blob, c_kzg::Error> {
51 let b_ref = blob.as_ref();
52 alloy_primitives::hex::decode(b_ref)
53 .map_err(|e| c_kzg::Error::InvalidHexFormat(format!("Failed to decode hex: {}", e)))
54 .and_then(bytes_to_blob)
55}
56
57#[derive(Clone, Copy, Debug)]
59pub struct WholeFe<'a>(&'a [u8]);
60
61impl<'a> WholeFe<'a> {
62 pub(crate) const fn new_unchecked(data: &'a [u8]) -> Self {
63 Self(data)
64 }
65
66 pub const fn new(data: &'a [u8]) -> Option<Self> {
69 if data.len() == FIELD_ELEMENT_BYTES_USIZE && fits_in_fe(data) {
70 Some(Self::new_unchecked(data))
71 } else {
72 None
73 }
74 }
75}
76
77impl AsRef<[u8]> for WholeFe<'_> {
78 fn as_ref(&self) -> &[u8] {
79 self.0
80 }
81}
82
83#[cfg(test)]
84mod test {
85 use crate::eip4844::{FIELD_ELEMENTS_PER_BLOB, USABLE_BYTES_PER_BLOB};
86
87 use super::*;
88 #[test]
89 fn calc_required_fe() {
90 assert_eq!(minimum_fe(&[0u8; 32]), 2);
91 assert_eq!(minimum_fe(&[0u8; 31]), 1);
92 assert_eq!(minimum_fe(&[0u8; 33]), 2);
93 assert_eq!(minimum_fe(&[0u8; 64]), 3);
94 assert_eq!(minimum_fe(&[0u8; 65]), 3);
95 assert_eq!(minimum_fe_for_bytes(USABLE_BYTES_PER_BLOB), FIELD_ELEMENTS_PER_BLOB as usize);
96 }
97
98 #[test]
99 fn calc_is_valid_field_element() {
100 assert!(fits_in_fe(&[0u8; 32]));
101 assert!(!fits_in_fe(&[0u8; 33]));
102
103 assert!(WholeFe::new(&[0u8; 32]).is_some());
104 assert!(WholeFe::new(&[0u8; 33]).is_none());
105 assert!(WholeFe::new(&[0u8; 31]).is_none());
106 }
107}