Skip to content

Commit

Permalink
style!: issue14 - cleanup blob api
Browse files Browse the repository at this point in the history
  • Loading branch information
samlaf committed Jan 3, 2025
1 parent cd193ca commit 17050bf
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 205 deletions.
6 changes: 3 additions & 3 deletions benches/bench_kzg_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn bench_kzg_commit(c: &mut Criterion) {

c.bench_function("bench_kzg_commit_10000", |b| {
let random_blob: Vec<u8> = (0..10000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand All @@ -28,7 +28,7 @@ fn bench_kzg_commit(c: &mut Criterion) {

c.bench_function("bench_kzg_commit_30000", |b| {
let random_blob: Vec<u8> = (0..30000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand All @@ -39,7 +39,7 @@ fn bench_kzg_commit(c: &mut Criterion) {

c.bench_function("bench_kzg_commit_50000", |b| {
let random_blob: Vec<u8> = (0..50000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand Down
4 changes: 2 additions & 2 deletions benches/bench_kzg_commit_large_blobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn bench_kzg_commit(c: &mut Criterion) {
let random_blob: Vec<u8> = (0..8000000)
.map(|_| rng.gen_range(32..=126) as u8)
.collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand All @@ -32,7 +32,7 @@ fn bench_kzg_commit(c: &mut Criterion) {
let random_blob: Vec<u8> = (0..16_252_000)
.map(|_| rng.gen_range(32..=126) as u8)
.collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand Down
4 changes: 2 additions & 2 deletions benches/bench_kzg_commit_with_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn bench_kzg_commit_with_cache(c: &mut Criterion) {
let random_blob: Vec<u8> = (0..8000000)
.map(|_| rng.gen_range(32..=126) as u8)
.collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand All @@ -33,7 +33,7 @@ fn bench_kzg_commit_with_cache(c: &mut Criterion) {
let random_blob: Vec<u8> = (0..16000000)
.map(|_| rng.gen_range(32..=126) as u8)
.collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand Down
6 changes: 3 additions & 3 deletions benches/bench_kzg_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn bench_kzg_proof(c: &mut Criterion) {

c.bench_function("bench_kzg_proof_10000", |b| {
let random_blob: Vec<u8> = (0..10000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand All @@ -33,7 +33,7 @@ fn bench_kzg_proof(c: &mut Criterion) {

c.bench_function("bench_kzg_proof_30000", |b| {
let random_blob: Vec<u8> = (0..30000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand All @@ -49,7 +49,7 @@ fn bench_kzg_proof(c: &mut Criterion) {

c.bench_function("bench_kzg_proof_50000", |b| {
let random_blob: Vec<u8> = (0..50000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand Down
6 changes: 3 additions & 3 deletions benches/bench_kzg_verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn bench_kzg_verify(c: &mut Criterion) {

c.bench_function("bench_kzg_verify_10000", |b| {
let random_blob: Vec<u8> = (0..10000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand All @@ -36,7 +36,7 @@ fn bench_kzg_verify(c: &mut Criterion) {

c.bench_function("bench_kzg_verify_30000", |b| {
let random_blob: Vec<u8> = (0..30000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand All @@ -55,7 +55,7 @@ fn bench_kzg_verify(c: &mut Criterion) {

c.bench_function("bench_kzg_verify_50000", |b| {
let random_blob: Vec<u8> = (0..50000).map(|_| rng.gen_range(32..=126) as u8).collect();
let input = Blob::from_bytes_and_pad(&random_blob);
let input = Blob::from_raw_data(&random_blob);
let input_poly = input
.to_polynomial(PolynomialFormat::InCoefficientForm)
.unwrap();
Expand Down
111 changes: 38 additions & 73 deletions src/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,45 @@ use crate::{
};

/// A blob which is Eigen DA spec aligned.
/// TODO: we should probably move to a transparent repr like
/// https://docs.rs/alloy-primitives/latest/alloy_primitives/struct.FixedBytes.html
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Blob {
blob_data: Vec<u8>,
is_padded: bool,
length_after_padding: usize,
}

impl Blob {
/// Creates a new `Blob` from the given data.
pub fn new(blob_data: Vec<u8>) -> Self {
/// Creates a new `Blob` from the given blob_data.
/// blob_data should already be padded according to DA specs, meaning
/// that it contains bn254 field elements. Otherwise, use [`Blob::from_raw_data`].
///
/// WARNING: This function does not check if the bytes are modulo bn254
/// if the data has 32 byte segments exceeding the modulo of the field
/// then the bytes will be modded by the order of the field and the data
/// will be transformed incorrectly.
/// TODO: we should check that the bytes are correct and return an error instead of
/// relying on the users reading this documentation.
pub fn new(blob_data: &[u8]) -> Self {
Blob {
blob_data,
is_padded: false,
length_after_padding: 0,
blob_data: blob_data.to_vec(),
}
}

pub fn get_length_after_padding(&self) -> usize {
self.length_after_padding
}

/// Creates a new `Blob` from the given data.
pub fn is_padded(&self) -> bool {
self.is_padded
}

/// Creates a new `Blob` from the provided byte slice and pads it according
/// to DA specs.
pub fn from_bytes_and_pad(input: &[u8]) -> Self {
let padded_input = helpers::convert_by_padding_empty_byte(input);
let length_after_padding = padded_input.len();
Blob {
blob_data: padded_input,
is_padded: true,
length_after_padding,
}
/// Creates a new `Blob` from the provided raw_data byte slice and pads it according
/// to DA specs. If the data is already padded, use [`Blob::new`] instead.
pub fn from_raw_data(raw_data: &[u8]) -> Self {
let blob_data = helpers::convert_by_padding_empty_byte(raw_data);
Blob { blob_data }
}

/// Creates a new `Blob` from the provided byte slice and assumes it's
/// already padded according to DA specs.
/// WARNING: This function does not check if the bytes are modulo bn254
/// if the data has 32 byte segments exceeding the modulo of the field
/// then the bytes will be modded by the order of the field and the data
/// will be transformed incorrectly
pub fn from_padded_bytes_unchecked(input: &[u8]) -> Self {
let length_after_padding = input.len();

Blob {
blob_data: input.to_vec(),
is_padded: true,
length_after_padding,
}
/// Returns the raw data of the blob, removing any padding added by [`Blob::from_raw_data`].
pub fn to_raw_data(&self) -> Vec<u8> {
helpers::remove_empty_byte_from_padded_bytes_unchecked(&self.blob_data)
}

/// Returns the blob data
pub fn get_blob_data(&self) -> Vec<u8> {
self.blob_data.clone()
pub fn data(&self) -> &[u8] {
&self.blob_data
}

/// Returns the length of the data in the blob.
Expand All @@ -74,40 +56,23 @@ impl Blob {
self.blob_data.is_empty()
}

/// Pads the blob data in-place if it is not already padded.
pub fn pad_data(&mut self) -> Result<(), BlobError> {
if self.is_padded {
Err(BlobError::AlreadyPaddedError)
} else {
self.blob_data = helpers::convert_by_padding_empty_byte(&self.blob_data);
self.is_padded = true;
self.length_after_padding = self.blob_data.len();
Ok(())
}
/// Converts the blob data to a `Polynomial` if the data is padded.
pub fn to_polynomial(&self, form: PolynomialFormat) -> Result<Polynomial, BlobError> {
let fr_vec = helpers::to_fr_array(&self.blob_data);
let poly = Polynomial::new(&fr_vec, self.len(), form)
.map_err(|err| BlobError::GenericError(err.to_string()))?;
Ok(poly)
}
}

/// Removes padding from the blob data if it is padded.
pub fn remove_padding(&mut self) -> Result<(), BlobError> {
if !self.is_padded {
Err(BlobError::NotPaddedError)
} else {
self.blob_data =
helpers::remove_empty_byte_from_padded_bytes_unchecked(&self.blob_data);
self.is_padded = false;
self.length_after_padding = 0;
Ok(())
}
impl From<Vec<u8>> for Blob {
fn from(blob_data: Vec<u8>) -> Self {
Blob { blob_data }
}
}

/// Converts the blob data to a `Polynomial` if the data is padded.
pub fn to_polynomial(&self, form: PolynomialFormat) -> Result<Polynomial, BlobError> {
if !self.is_padded {
Err(BlobError::NotPaddedError)
} else {
let fr_vec = helpers::to_fr_array(&self.blob_data);
let poly = Polynomial::new(&fr_vec, self.length_after_padding, form)
.map_err(|err| BlobError::GenericError(err.to_string()))?;
Ok(poly)
}
impl From<Blob> for Vec<u8> {
fn from(blob: Blob) -> Self {
blob.blob_data
}
}
4 changes: 0 additions & 4 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@ use std::{error::Error, fmt};

#[derive(Clone, Debug, PartialEq)]
pub enum BlobError {
NotPaddedError,
AlreadyPaddedError,
GenericError(String),
}

impl fmt::Display for BlobError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
BlobError::NotPaddedError => write!(f, "tried to execute on non padded blob"),
BlobError::AlreadyPaddedError => write!(f, "tried to execute on already padded blob"),
BlobError::GenericError(ref msg) => write!(f, "generic error: {}", msg),
}
}
Expand Down
67 changes: 14 additions & 53 deletions tests/blob_test.rs
Original file line number Diff line number Diff line change
@@ -1,56 +1,29 @@
#[cfg(test)]
mod tests {
use rust_kzg_bn254::{blob::Blob, errors::BlobError, polynomial::PolynomialFormat};
use rust_kzg_bn254::blob::Blob;
const GETTYSBURG_ADDRESS_BYTES: &[u8] = "Fourscore and seven years ago our fathers brought forth, on this continent, a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived, and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting-place for those who here gave their lives, that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we cannot dedicate, we cannot consecrate—we cannot hallow—this ground. The brave men, living and dead, who struggled here, have consecrated it far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us—that from these honored dead we take increased devotion to that cause for which they here gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain—that this nation, under God, shall have a new birth of freedom, and that government of the people, by the people, for the people, shall not perish from the earth.".as_bytes();

#[test]
fn test_already_padded() {
let mut blob = Blob::from_bytes_and_pad("hi".as_bytes());
let mut result = blob.pad_data();
assert_eq!(result, Err(BlobError::AlreadyPaddedError));
blob.remove_padding().unwrap();
result = blob.remove_padding();
assert_eq!(result, Err(BlobError::NotPaddedError));
assert_eq!(
blob.to_polynomial(PolynomialFormat::InCoefficientForm),
Err(BlobError::NotPaddedError)
);
}

#[test]
fn test_is_empty() {
let blob_empty = Blob::from_bytes_and_pad("".as_bytes());
let blob_empty = Blob::from_raw_data("".as_bytes());
assert!(blob_empty.is_empty(), "blob should be empty");

let blob = Blob::from_bytes_and_pad("hi".as_bytes());
let blob = Blob::from_raw_data("hi".as_bytes());
assert!(!blob.is_empty(), "blob should not be empty");
}

#[test]
fn test_from_padded_bytes_unchecked() {
let blob = Blob::from_bytes_and_pad("hi".as_bytes());
let blob_unchecked = Blob::from_padded_bytes_unchecked(blob.get_blob_data().as_slice());
let blob = Blob::from_raw_data("hi".as_bytes());
let blob_unchecked = Blob::new(blob.data());

assert_eq!(blob, blob_unchecked, "blob should be equal");
}

#[test]
fn test_convert_by_padding_empty_byte() {
let mut blob = Blob::from_bytes_and_pad("hi".as_bytes());
assert_eq!(
blob.get_blob_data(),
vec![0, 104, 105],
"testing adding padding"
);
assert!(blob.is_padded(), "has to be padded");

blob.remove_padding().unwrap();
assert_eq!(
blob.get_blob_data(),
vec![104, 105],
"testing removing padding"
);
assert!(!blob.is_padded(), "cannot be padded");
let mut blob = Blob::from_raw_data("hi".as_bytes());
assert_eq!(blob.data(), &[0, 104, 105], "testing adding padding");

let result: Vec<u8> = vec![
0, 70, 111, 117, 114, 115, 99, 111, 114, 101, 32, 97, 110, 100, 32, 115, 101, 118, 101,
Expand Down Expand Up @@ -137,28 +110,16 @@ mod tests {
97, 114, 116, 104, 46,
];

blob = Blob::from_bytes_and_pad(GETTYSBURG_ADDRESS_BYTES);
assert_eq!(blob.get_blob_data(), result, "testing adding padding");
assert!(blob.is_padded(), "has to be padded");
assert_eq!(blob.get_length_after_padding(), 1515);

blob.remove_padding().unwrap();
assert!(!blob.is_padded(), "cannot be padded");
assert_eq!(
blob.get_blob_data(),
GETTYSBURG_ADDRESS_BYTES,
"testing removing padding"
);
blob = Blob::from_raw_data(GETTYSBURG_ADDRESS_BYTES);
assert_eq!(blob.data(), result, "testing adding padding");
assert_eq!(blob.len(), 1515);
}

#[test]
fn test_new_blob_creation() {
let blob_from = Blob::from_bytes_and_pad(GETTYSBURG_ADDRESS_BYTES);
let mut blob_raw = Blob::new(GETTYSBURG_ADDRESS_BYTES.to_vec());
fn test_blob_creation() {
let blob = Blob::from_raw_data(GETTYSBURG_ADDRESS_BYTES);
let raw_data = blob.to_raw_data();

blob_raw.pad_data().unwrap();
assert_eq!(blob_raw, blob_from, "testing adding padding");
assert!(blob_raw.is_padded(), "has to be padded");
assert!(blob_from.is_padded(), "has to be padded");
assert_eq!(GETTYSBURG_ADDRESS_BYTES, &raw_data);
}
}
Loading

0 comments on commit 17050bf

Please sign in to comment.