Skip to content

Commit

Permalink
examples: Transparent columns usage (part 2) (#9)
Browse files Browse the repository at this point in the history
* 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
storojs72 committed Feb 25, 2025
1 parent 98d1776 commit be6150b
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 0 deletions.
25 changes: 25 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ binius_hash = { path = "../crates/hash" }
binius_macros = { path = "../crates/macros" }
binius_math = { path = "../crates/math" }
binius_utils = { path = "../crates/utils", default-features = false }
bytemuck.workspace = true
bumpalo.workspace = true
bytesize.workspace = true
clap = { version = "4.5.20", features = ["derive"] }
Expand Down Expand Up @@ -116,6 +117,30 @@ path = "acc-disjoint-product.rs"
name = "acc-eq-ind-partial-eval"
path = "acc-eq-ind-partial-eval.rs"

[[example]]
name = "acc-multilinear-extension-transparent"
path = "acc-multilinear-extension-transparent.rs"

[[example]]
name = "acc-select-row"
path = "acc-select-row.rs"

[[example]]
name = "acc-shift-ind-partial-eq"
path = "acc-shift-ind-partial-eq.rs"

[[example]]
name = "acc-step-down"
path = "acc-step-down.rs"

[[example]]
name = "acc-step-up"
path = "acc-step-up.rs"

[[example]]
name = "acc-tower-basis"
path = "acc-tower-basis.rs"

[lints.clippy]
needless_range_loop = "allow"

Expand Down
95 changes: 95 additions & 0 deletions examples/acc-multilinear-extension-transparent.rs
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()
}
35 changes: 35 additions & 0 deletions examples/acc-select-row.rs
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();
}
93 changes: 93 additions & 0 deletions examples/acc-shift-ind-partial-eq.rs
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,
}
}
34 changes: 34 additions & 0 deletions examples/acc-step-down.rs
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();
}
32 changes: 32 additions & 0 deletions examples/acc-step-up.rs
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();
}
60 changes: 60 additions & 0 deletions examples/acc-tower-basis.rs
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
}

0 comments on commit be6150b

Please sign in to comment.