forked from IrreducibleOSS/binius
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
examples: Transparent columns usage (part 2) (#9)
* example: Add example of Transparent (MultilinearExtensionTransparent) column usage * example: Add example of Transparent (SelectRow) column usage * example: Add example of Transparent (ShiftIndPartialEval) column usage * example: Add example of Transparent (StepDown) column usage * example: Add example of Transparent (StepUp) column usage * example: Add example of Transparent (TowerBasis) column usage
- Loading branch information
Showing
7 changed files
with
374 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use binius_circuits::builder::ConstraintSystemBuilder; | ||
use binius_core::{ | ||
constraint_system::validate::validate_witness, transparent::MultilinearExtensionTransparent, | ||
}; | ||
use binius_field::{ | ||
arch::OptimalUnderlier, as_packed_field::PackedType, underlier::WithUnderlier, BinaryField128b, | ||
BinaryField1b, PackedField, | ||
}; | ||
use binius_utils::checked_arithmetics::log2_ceil_usize; | ||
use bytemuck::{pod_collect_to_vec, Pod}; | ||
|
||
type U = OptimalUnderlier; | ||
type F128 = BinaryField128b; | ||
type F1 = BinaryField1b; | ||
|
||
// From a perspective of circuits creation, MultilinearExtensionTransparent can be used naturally for decomposing integers to bits | ||
fn decompose_transparent_u64(builder: &mut ConstraintSystemBuilder<U, F128>, x: u64) { | ||
builder.push_namespace("decompose_transparent_u64"); | ||
|
||
let log_bits = log2_ceil_usize(64); | ||
|
||
let broadcasted = vec![x; 1 << (PackedType::<U, F1>::LOG_WIDTH.saturating_sub(log_bits))]; | ||
|
||
let broadcasted_decomposed = into_packed_vec::<PackedType<U, F1>>(&broadcasted); | ||
|
||
let transparent_id = builder | ||
.add_transparent( | ||
"transparent", | ||
MultilinearExtensionTransparent::<_, PackedType<U, F128>, _>::from_values( | ||
broadcasted_decomposed, | ||
) | ||
.unwrap(), | ||
) | ||
.unwrap(); | ||
|
||
if let Some(witness) = builder.witness() { | ||
let mut transparent_witness = witness.new_column::<F1>(transparent_id); | ||
let values = transparent_witness.as_mut_slice::<u64>(); | ||
values.fill(x); | ||
} | ||
|
||
builder.pop_namespace(); | ||
} | ||
|
||
fn decompose_transparent_u32(builder: &mut ConstraintSystemBuilder<U, F128>, x: u32) { | ||
builder.push_namespace("decompose_transparent_u32"); | ||
|
||
let log_bits = log2_ceil_usize(32); | ||
|
||
let broadcasted = vec![x; 1 << (PackedType::<U, F1>::LOG_WIDTH.saturating_sub(log_bits))]; | ||
|
||
let broadcasted_decomposed = into_packed_vec::<PackedType<U, F1>>(&broadcasted); | ||
|
||
let transparent_id = builder | ||
.add_transparent( | ||
"transparent", | ||
MultilinearExtensionTransparent::<_, PackedType<U, F128>, _>::from_values( | ||
broadcasted_decomposed, | ||
) | ||
.unwrap(), | ||
) | ||
.unwrap(); | ||
|
||
if let Some(witness) = builder.witness() { | ||
let mut transparent_witness = witness.new_column::<F1>(transparent_id); | ||
let values = transparent_witness.as_mut_slice::<u32>(); | ||
values.fill(x); | ||
} | ||
|
||
builder.pop_namespace(); | ||
} | ||
|
||
fn main() { | ||
let allocator = bumpalo::Bump::new(); | ||
let mut builder = ConstraintSystemBuilder::<U, F128>::new_with_witness(&allocator); | ||
|
||
decompose_transparent_u64(&mut builder, 0xff00ff00ff00ff00); | ||
decompose_transparent_u32(&mut builder, 0x00ff00ff); | ||
|
||
let witness = builder.take_witness().unwrap(); | ||
let constraints_system = builder.build().unwrap(); | ||
|
||
validate_witness(&constraints_system, &[], &witness).unwrap(); | ||
} | ||
|
||
fn into_packed_vec<P>(src: &[impl Pod]) -> Vec<P> | ||
where | ||
P: PackedField + WithUnderlier, | ||
P::Underlier: Pod, | ||
{ | ||
pod_collect_to_vec::<_, P::Underlier>(src) | ||
.into_iter() | ||
.map(P::from_underlier) | ||
.collect() | ||
} |
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,35 @@ | ||
use binius_circuits::builder::ConstraintSystemBuilder; | ||
use binius_core::{ | ||
constraint_system::validate::validate_witness, transparent::select_row::SelectRow, | ||
}; | ||
use binius_field::{arch::OptimalUnderlier, BinaryField128b, BinaryField8b}; | ||
|
||
type U = OptimalUnderlier; | ||
type F128 = BinaryField128b; | ||
type F8 = BinaryField8b; | ||
|
||
const LOG_SIZE: usize = 8; | ||
|
||
// SelectRow expects exactly one witness value at particular index to be set. | ||
fn main() { | ||
let allocator = bumpalo::Bump::new(); | ||
let mut builder = ConstraintSystemBuilder::<U, F128>::new_with_witness(&allocator); | ||
|
||
let index = 58; | ||
assert!(index < 1 << LOG_SIZE); | ||
|
||
let select_row = SelectRow::new(LOG_SIZE, index).unwrap(); | ||
let transparent = builder.add_transparent("select_row", select_row).unwrap(); | ||
|
||
if let Some(witness) = builder.witness() { | ||
let mut transparent_witness = witness.new_column::<F8>(transparent); | ||
let values = transparent_witness.as_mut_slice::<u8>(); | ||
|
||
values[index] = 0x01; | ||
} | ||
|
||
let witness = builder.take_witness().unwrap(); | ||
let constraints_system = builder.build().unwrap(); | ||
|
||
validate_witness(&constraints_system, &[], &witness).unwrap(); | ||
} |
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,93 @@ | ||
use binius_circuits::builder::ConstraintSystemBuilder; | ||
use binius_core::{ | ||
constraint_system::validate::validate_witness, oracle::ShiftVariant, | ||
transparent::shift_ind::ShiftIndPartialEval, | ||
}; | ||
use binius_field::{arch::OptimalUnderlier, util::eq, BinaryField128b, Field}; | ||
|
||
type U = OptimalUnderlier; | ||
type F128 = BinaryField128b; | ||
|
||
// ShiftIndPartialEval is a more elaborated version of EqIndPartialEval. Same idea with challenges, but a bit more | ||
// elaborated evaluation algorithm is used | ||
fn main() { | ||
let allocator = bumpalo::Bump::new(); | ||
let mut builder = ConstraintSystemBuilder::<U, F128>::new_with_witness(&allocator); | ||
|
||
let block_size = 3; | ||
let shift_offset = 4; | ||
// Challenges have to be F128, but actual values in the witness could be of smaller field | ||
let challenges = vec![ | ||
F128::new(0xff00ff00ff00ff00ff00ff00ff00ff00), | ||
F128::new(0x1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f), | ||
F128::new(0x2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f), | ||
]; | ||
let shift_variant = ShiftVariant::LogicalLeft; | ||
|
||
assert_eq!(block_size, challenges.len()); | ||
|
||
let shift_ind = | ||
ShiftIndPartialEval::new(block_size, shift_offset, shift_variant, challenges.clone()) | ||
.unwrap(); | ||
|
||
let transparent = builder.add_transparent("shift_ind", shift_ind).unwrap(); | ||
|
||
if let Some(witness) = builder.witness() { | ||
let mut transparent_witness = witness.new_column::<F128>(transparent); | ||
let values = transparent_witness.as_mut_slice::<u128>(); | ||
|
||
let lexicographical_order_x = [ | ||
vec![F128::new(0), F128::new(0), F128::new(0)], | ||
vec![F128::new(1), F128::new(0), F128::new(0)], | ||
vec![F128::new(0), F128::new(1), F128::new(0)], | ||
vec![F128::new(1), F128::new(1), F128::new(0)], | ||
vec![F128::new(0), F128::new(0), F128::new(1)], | ||
vec![F128::new(1), F128::new(0), F128::new(1)], | ||
vec![F128::new(0), F128::new(1), F128::new(1)], | ||
vec![F128::new(1), F128::new(1), F128::new(1)], | ||
]; | ||
|
||
assert_eq!(lexicographical_order_x.len(), 1 << block_size); | ||
|
||
for (val, x) in values.iter_mut().zip(lexicographical_order_x.into_iter()) { | ||
*val = compute(block_size, shift_offset, shift_variant, x, challenges.clone()).val(); | ||
} | ||
} | ||
|
||
let witness = builder.take_witness().unwrap(); | ||
let constraints_system = builder.build().unwrap(); | ||
|
||
validate_witness(&constraints_system, &[], &witness).unwrap(); | ||
} | ||
|
||
// Evaluation logic taken from ShiftIndPartialEval implementation | ||
fn compute( | ||
block_size: usize, | ||
shift_offset: usize, | ||
shift_variant: ShiftVariant, | ||
x: Vec<F128>, | ||
y: Vec<F128>, | ||
) -> F128 { | ||
let (mut s_ind_p, mut s_ind_pp) = (F128::ONE, F128::ZERO); | ||
let (mut temp_p, mut temp_pp) = (F128::default(), F128::default()); | ||
(0..block_size).for_each(|k| { | ||
let o_k = shift_offset >> k; | ||
let product = x[k] * y[k]; | ||
if o_k % 2 == 1 { | ||
temp_p = (y[k] - product) * s_ind_p; | ||
temp_pp = (x[k] - product) * s_ind_p + eq(x[k], y[k]) * s_ind_pp; | ||
} else { | ||
temp_p = eq(x[k], y[k]) * s_ind_p + (y[k] - product) * s_ind_pp; | ||
temp_pp = (x[k] - product) * s_ind_pp; | ||
} | ||
// roll over results | ||
s_ind_p = temp_p; | ||
s_ind_pp = temp_pp; | ||
}); | ||
|
||
match shift_variant { | ||
ShiftVariant::CircularLeft => s_ind_p + s_ind_pp, | ||
ShiftVariant::LogicalLeft => s_ind_p, | ||
ShiftVariant::LogicalRight => s_ind_pp, | ||
} | ||
} |
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,34 @@ | ||
use binius_circuits::builder::ConstraintSystemBuilder; | ||
use binius_core::{ | ||
constraint_system::validate::validate_witness, transparent::step_down::StepDown, | ||
}; | ||
use binius_field::{arch::OptimalUnderlier, BinaryField128b, BinaryField8b}; | ||
|
||
const LOG_SIZE: usize = 8; | ||
|
||
type U = OptimalUnderlier; | ||
type F128 = BinaryField128b; | ||
type F8 = BinaryField8b; | ||
|
||
// StepDown expects all bytes to be set before particular index specified as input | ||
fn main() { | ||
let allocator = bumpalo::Bump::new(); | ||
let mut builder = ConstraintSystemBuilder::<U, F128>::new_with_witness(&allocator); | ||
|
||
let index = 10; | ||
|
||
let step_down = StepDown::new(LOG_SIZE, index).unwrap(); | ||
let transparent = builder.add_transparent("step_down", step_down).unwrap(); | ||
|
||
if let Some(witness) = builder.witness() { | ||
let mut transparent_witness = witness.new_column::<F8>(transparent); | ||
let values = transparent_witness.as_mut_slice::<u8>(); | ||
|
||
values[0..index].fill(0x01); | ||
} | ||
|
||
let witness = builder.take_witness().unwrap(); | ||
let constraints_system = builder.build().unwrap(); | ||
|
||
validate_witness(&constraints_system, &[], &witness).unwrap(); | ||
} |
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,32 @@ | ||
use binius_circuits::builder::ConstraintSystemBuilder; | ||
use binius_core::{constraint_system::validate::validate_witness, transparent::step_up::StepUp}; | ||
use binius_field::{arch::OptimalUnderlier, BinaryField128b, BinaryField8b}; | ||
|
||
type U = OptimalUnderlier; | ||
type F128 = BinaryField128b; | ||
type F8 = BinaryField8b; | ||
|
||
const LOG_SIZE: usize = 8; | ||
|
||
// StepUp expects all bytes to be unset before particular index specified as input (opposite to StepDown) | ||
fn main() { | ||
let allocator = bumpalo::Bump::new(); | ||
let mut builder = ConstraintSystemBuilder::<U, F128>::new_with_witness(&allocator); | ||
|
||
let index = 10; | ||
|
||
let step_up = StepUp::new(LOG_SIZE, index).unwrap(); | ||
let transparent = builder.add_transparent("step_up", step_up).unwrap(); | ||
|
||
if let Some(witness) = builder.witness() { | ||
let mut transparent_witness = witness.new_column::<F8>(transparent); | ||
let values = transparent_witness.as_mut_slice::<u8>(); | ||
|
||
values[index..].fill(0x01); | ||
} | ||
|
||
let witness = builder.take_witness().unwrap(); | ||
let constraints_system = builder.build().unwrap(); | ||
|
||
validate_witness(&constraints_system, &[], &witness).unwrap(); | ||
} |
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,60 @@ | ||
use binius_circuits::builder::ConstraintSystemBuilder; | ||
use binius_core::{ | ||
constraint_system::validate::validate_witness, transparent::tower_basis::TowerBasis, | ||
}; | ||
use binius_field::{arch::OptimalUnderlier, BinaryField128b, Field, TowerField}; | ||
|
||
type U = OptimalUnderlier; | ||
type F128 = BinaryField128b; | ||
|
||
// TowerBasis expects actually basis vectors written to the witness. | ||
// The form of basis could vary depending on 'iota' and 'k' parameters | ||
fn main() { | ||
let allocator = bumpalo::Bump::new(); | ||
let mut builder = ConstraintSystemBuilder::<U, F128>::new_with_witness(&allocator); | ||
|
||
let k = 3usize; | ||
let iota = 4usize; | ||
|
||
assert!(k + iota < 8); | ||
|
||
let tower_basis = TowerBasis::new(k, iota).unwrap(); | ||
let transparent = builder.add_transparent("tower_basis", tower_basis).unwrap(); | ||
|
||
if let Some(witness) = builder.witness() { | ||
let mut transparent_witness = witness.new_column::<F128>(transparent); | ||
let values = transparent_witness.as_mut_slice::<u128>(); | ||
|
||
let lexicographic_query = [ | ||
vec![F128::new(0), F128::new(0), F128::new(0)], | ||
vec![F128::new(1), F128::new(0), F128::new(0)], | ||
vec![F128::new(0), F128::new(1), F128::new(0)], | ||
vec![F128::new(1), F128::new(1), F128::new(0)], | ||
vec![F128::new(0), F128::new(0), F128::new(1)], | ||
vec![F128::new(1), F128::new(0), F128::new(1)], | ||
vec![F128::new(0), F128::new(1), F128::new(1)], | ||
vec![F128::new(1), F128::new(1), F128::new(1)], | ||
]; | ||
|
||
assert_eq!(lexicographic_query.len(), 1 << k); | ||
|
||
for (val, query) in values.iter_mut().zip(lexicographic_query.into_iter()) { | ||
*val = compute(iota, query).val(); | ||
} | ||
} | ||
|
||
let witness = builder.take_witness().unwrap(); | ||
let constraints_system = builder.build().unwrap(); | ||
|
||
validate_witness(&constraints_system, &[], &witness).unwrap(); | ||
} | ||
|
||
fn compute(iota: usize, query: Vec<F128>) -> F128 { | ||
let mut result = F128::ONE; | ||
for (i, query_i) in query.iter().enumerate() { | ||
let r_comp = F128::ONE - query_i; | ||
let basis_elt = <F128 as TowerField>::basis(iota + i, 1).unwrap(); | ||
result *= r_comp + *query_i * basis_elt; | ||
} | ||
result | ||
} |