-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add VariableByteArray * fix: correct type in panic msg * feat: make MAX_VAR_LEN const generic * feat: add `SafeBool` and `SafeByte` types These are very common so we have separate wrapper to avoid the extra length 1 vector heap allocation. * wip: add VarLenBytes * Refactor VarLenBytes Add VarLenBytesVec and FixLenBytes Fix tests * Add unsafe methods for bytes Address NITs --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Co-authored-by: Xinding Wei <xinding@intrinsictech.xyz>
- Loading branch information
1 parent
a7b5433
commit f724c9b
Showing
8 changed files
with
488 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#![allow(clippy::len_without_is_empty)] | ||
use crate::AssignedValue; | ||
|
||
use super::{SafeByte, ScalarField}; | ||
|
||
use getset::Getters; | ||
|
||
/// Represents a variable length byte array in circuit. | ||
/// | ||
/// Each element is guaranteed to be a byte, given by type [`SafeByte`]. | ||
/// To represent a variable length array, we must know the maximum possible length `MAX_LEN` the array could be -- this is some additional context the user must provide. | ||
/// Then we right pad the array with 0s to the maximum length (we do **not** constrain that these paddings must be 0s). | ||
#[derive(Debug, Clone, Getters)] | ||
pub struct VarLenBytes<F: ScalarField, const MAX_LEN: usize> { | ||
/// The byte array, right padded | ||
#[getset(get = "pub")] | ||
bytes: [SafeByte<F>; MAX_LEN], | ||
/// Witness representing the actual length of the byte array. Upon construction, this is range checked to be at most `MAX_LEN` | ||
#[getset(get = "pub")] | ||
len: AssignedValue<F>, | ||
} | ||
|
||
impl<F: ScalarField, const MAX_LEN: usize> VarLenBytes<F, MAX_LEN> { | ||
// VarLenBytes can be only created by SafeChip. | ||
pub(super) fn new(bytes: [SafeByte<F>; MAX_LEN], len: AssignedValue<F>) -> Self { | ||
assert!( | ||
len.value().le(&F::from(MAX_LEN as u64)), | ||
"Invalid length which exceeds MAX_LEN {MAX_LEN}", | ||
); | ||
Self { bytes, len } | ||
} | ||
|
||
/// Returns the maximum length of the byte array. | ||
pub fn max_len(&self) -> usize { | ||
MAX_LEN | ||
} | ||
} | ||
|
||
/// Represents a variable length byte array in circuit. Not encouraged to use because `MAX_LEN` cannot be verified at compile time. | ||
/// | ||
/// Each element is guaranteed to be a byte, given by type [`SafeByte`]. | ||
/// To represent a variable length array, we must know the maximum possible length `MAX_LEN` the array could be -- this is provided when constructing and `bytes.len()` == `MAX_LEN` is enforced. | ||
/// Then we right pad the array with 0s to the maximum length (we do **not** constrain that these paddings must be 0s). | ||
#[derive(Debug, Clone, Getters)] | ||
pub struct VarLenBytesVec<F: ScalarField> { | ||
/// The byte array, right padded | ||
#[getset(get = "pub")] | ||
bytes: Vec<SafeByte<F>>, | ||
/// Witness representing the actual length of the byte array. Upon construction, this is range checked to be at most `MAX_LEN` | ||
#[getset(get = "pub")] | ||
len: AssignedValue<F>, | ||
} | ||
|
||
impl<F: ScalarField> VarLenBytesVec<F> { | ||
// VarLenBytesVec can be only created by SafeChip. | ||
pub(super) fn new(bytes: Vec<SafeByte<F>>, len: AssignedValue<F>, max_len: usize) -> Self { | ||
assert!( | ||
len.value().le(&F::from_u128(max_len as u128)), | ||
"Invalid length which exceeds MAX_LEN {}", | ||
max_len | ||
); | ||
assert!(bytes.len() == max_len, "bytes is not padded correctly"); | ||
Self { bytes, len } | ||
} | ||
|
||
/// Returns the maximum length of the byte array. | ||
pub fn max_len(&self) -> usize { | ||
self.bytes.len() | ||
} | ||
} | ||
|
||
/// Represents a fixed length byte array in circuit. | ||
#[derive(Debug, Clone, Getters)] | ||
pub struct FixLenBytes<F: ScalarField, const LEN: usize> { | ||
/// The byte array | ||
#[getset(get = "pub")] | ||
bytes: [SafeByte<F>; LEN], | ||
} | ||
|
||
impl<F: ScalarField, const LEN: usize> FixLenBytes<F, LEN> { | ||
// FixLenBytes can be only created by SafeChip. | ||
pub(super) fn new(bytes: [SafeByte<F>; LEN]) -> Self { | ||
Self { bytes } | ||
} | ||
|
||
/// Returns the length of the byte array. | ||
pub fn len(&self) -> usize { | ||
LEN | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use super::*; | ||
/// SafeType for bool (1 bit). | ||
/// | ||
/// This is a separate struct from [`CompactSafeType`] with the same behavior. Because | ||
/// we know only one [`AssignedValue`] is needed to hold the boolean value, we avoid | ||
/// using [`CompactSafeType`] to avoid the additional heap allocation from a length 1 vector. | ||
#[derive(Clone, Copy, Debug)] | ||
pub struct SafeBool<F: ScalarField>(pub(super) AssignedValue<F>); | ||
|
||
/// SafeType for byte (8 bits). | ||
/// | ||
/// This is a separate struct from [`CompactSafeType`] with the same behavior. Because | ||
/// we know only one [`AssignedValue`] is needed to hold the boolean value, we avoid | ||
/// using [`CompactSafeType`] to avoid the additional heap allocation from a length 1 vector. | ||
#[derive(Clone, Copy, Debug)] | ||
pub struct SafeByte<F: ScalarField>(pub(super) AssignedValue<F>); | ||
|
||
macro_rules! safe_primitive_impls { | ||
($SafePrimitive:ty) => { | ||
impl<F: ScalarField> AsRef<AssignedValue<F>> for $SafePrimitive { | ||
fn as_ref(&self) -> &AssignedValue<F> { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl<F: ScalarField> AsMut<AssignedValue<F>> for $SafePrimitive { | ||
fn as_mut(&mut self) -> &mut AssignedValue<F> { | ||
&mut self.0 | ||
} | ||
} | ||
|
||
impl<F: ScalarField> Borrow<AssignedValue<F>> for $SafePrimitive { | ||
fn borrow(&self) -> &AssignedValue<F> { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl<F: ScalarField> BorrowMut<AssignedValue<F>> for $SafePrimitive { | ||
fn borrow_mut(&mut self) -> &mut AssignedValue<F> { | ||
&mut self.0 | ||
} | ||
} | ||
}; | ||
} | ||
|
||
safe_primitive_impls!(SafeBool<F>); | ||
safe_primitive_impls!(SafeByte<F>); |
Oops, something went wrong.