Skip to content

Commit

Permalink
feat: Packable trait
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Jan 14, 2025
1 parent c107b6b commit 2083683
Showing 1 changed file with 78 additions and 0 deletions.
78 changes: 78 additions & 0 deletions noir-projects/noir-protocol-circuits/crates/types/src/traits.nr
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,35 @@ impl FromField for U128 {
}

// docs:start:serialize
/// Trait for serializing Noir types into arrays of Fields in a constraint-efficient manner.
///
/// This trait prioritizes minimal constraint costs during serialization, even if it
/// results in larger array sizes. Each value is typically converted directly into one
/// or more Fields without any packing or compression. This trait (and Deserialize) are
/// typically used to communicate between Noir and TypeScript (via oracles and function
/// arguments).
///
/// # Type Parameters
/// * `N` - The length of the output Field array, known at compile time
///
/// # Implementation Notes
/// - Focus on simple, direct conversions to minimize constraints
/// - Each component of a type typically maps to its own Field
/// - Do not attempt to pack or compress values (use Packable trait for that)
///
/// # Example
/// ```
/// impl<let N: u32> Serialize<N> for str<N> {
/// fn serialize(self) -> [Field; N] {
/// let bytes = self.as_bytes();
/// let mut fields = [0; N];
/// for i in 0..bytes.len() {
/// fields[i] = bytes[i] as Field; // Each byte gets its own Field
/// }
/// fields
/// }
/// }
/// ```
#[derive_via(derive_serialize)]
pub trait Serialize<let N: u32> {
fn serialize(self) -> [Field; N];
Expand All @@ -173,6 +202,30 @@ impl<let N: u32> Serialize<N> for str<N> {
}

// docs:start:deserialize
/// Trait for deserializing Noir types from arrays of Fields in a constraint-efficient manner.
///
/// This trait prioritizes minimal constraint costs during deserialization, even if it
/// results in larger array sizes. Each Field is typically converted directly into one
/// or more values without any packing or compression. This trait (and Serialize) are
/// typically used to communicate between Noir and TypeScript (via oracles and function
/// arguments).
///
/// # Type Parameters
/// * `N` - The length of the input Field array, known at compile time
///
/// # Implementation Notes
/// - Focus on simple, direct conversions to minimize constraints
/// - Each Field typically maps to its own component of a type
/// - Do not attempt to unpack or decompress values (use Packable trait for that)
///
/// # Example
/// ```
/// impl<let N: u32> Deserialize<N> for str<N> {
/// fn deserialize(fields: [Field; N]) -> Self {
/// str<N>::from(fields.map(|value| value as u8))
/// }
/// }
/// ```
#[derive_via(derive_deserialize)]
pub trait Deserialize<let N: u32> {
fn deserialize(fields: [Field; N]) -> Self;
Expand All @@ -184,3 +237,28 @@ impl<let N: u32> Deserialize<N> for str<N> {
str<N>::from(fields.map(|value| value as u8))
}
}

/// Trait for efficiently packing and unpacking Noir types into and from arrays of Fields.
///
/// The `Packable` trait allows types to be serialized and deserialized with a focus on
/// minimizing the size of the resulting Field array, even at the cost of additional
/// constraints. This is in contrast to the `Serialize` and `Deserialize` traits, which
/// prioritize minimizing constraint costs but may result in larger arrays.
///
/// Packing and unpacking often involve compression or aggregation of values, enabling
/// more compact representations of complex types.
///
/// # Type Parameters
/// * `N` - The length of the Field array, known at compile time.
///
/// # Implementation Notes
/// - Use efficient algorithms to reduce the size of the Field array during packing.
/// - Ensure data integrity and correctness during both packing and unpacking.
/// - This trait is useful for cases where storage efficiency is critical.
pub trait Packable<let N: u32> {
/// Packs the current value into a compact array of `Field` elements.
fn pack(self) -> [Field; N];

/// Unpacks a compact array of `Field` elements into the original value.
fn unpack(fields: [Field; N]) -> Self;
}

0 comments on commit 2083683

Please sign in to comment.