Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples: Transparent columns usage (part 2) #9

Merged
merged 6 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -120,6 +121,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
}