Skip to content

Commit

Permalink
Merge branch 'IrreducibleOSS:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurpaulino authored Jan 28, 2025
2 parents b57727d + 3a58b90 commit f8b8c87
Show file tree
Hide file tree
Showing 86 changed files with 1,579 additions and 998 deletions.
71 changes: 71 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,77 @@ version = "0.2.0"
edition = "2021"
authors = ["Irreducible Team <[email protected]>"]

[workspace.lints.clippy]
# These are some of clippy's nursery (i.e., experimental) lints that we like.
# By default, nursery lints are allowed. Some of the lints below have made good
# suggestions which we fixed. The others didn't have any findings, so we can
# assume they don't have that many false positives. Let's enable them to
# prevent future problems.
borrow_as_ptr = "warn"
branches_sharing_code = "warn"
clear_with_drain = "warn"
cloned_instead_of_copied = "warn"
collection_is_never_read = "warn"
dbg_macro = "warn"
derive_partial_eq_without_eq = "warn"
empty_line_after_doc_comments = "warn"
empty_line_after_outer_attr = "warn"
enum_glob_use = "warn"
equatable_if_let = "warn"
explicit_into_iter_loop = "warn"
explicit_iter_loop = "warn"
flat_map_option = "warn"
from_iter_instead_of_collect = "warn"
if_not_else = "warn"
if_then_some_else_none = "warn"
implicit_clone = "warn"
imprecise_flops = "warn"
iter_on_empty_collections = "warn"
iter_on_single_items = "warn"
iter_with_drain = "warn"
iter_without_into_iter = "warn"
large_stack_frames = "warn"
manual_assert = "warn"
manual_clamp = "warn"
manual_is_variant_and = "warn"
manual_string_new = "warn"
match_same_arms = "warn"
missing_const_for_fn = "warn"
mutex_integer = "warn"
naive_bytecount = "warn"
needless_bitwise_bool = "warn"
needless_continue = "warn"
needless_for_each = "warn"
needless_pass_by_ref_mut = "warn"
nonstandard_macro_braces = "warn"
option_as_ref_cloned = "warn"
or_fun_call = "warn"
path_buf_push_overwrite = "warn"
read_zero_byte_vec = "warn"
redundant_clone = "warn"
redundant_else = "warn"
single_char_pattern = "warn"
string_lit_as_bytes = "warn"
string_lit_chars_any = "warn"
suboptimal_flops = "warn"
suspicious_operation_groupings = "warn"
trailing_empty_array = "warn"
trait_duplication_in_bounds = "warn"
transmute_undefined_repr = "warn"
trivial_regex = "warn"
tuple_array_conversions = "warn"
type_repetition_in_bounds = "warn"
uninhabited_references = "warn"
unnecessary_self_imports = "warn"
unnecessary_struct_initialization = "warn"
unnested_or_patterns = "warn"
unused_peekable = "warn"
unused_rounding = "warn"
use_self = "warn"
useless_let_if_seq = "warn"
while_float = "warn"
zero_sized_map_values = "warn"

[workspace.dependencies]
anyhow = "1.0.81"
assert_matches = "1.5.0"
Expand Down
85 changes: 84 additions & 1 deletion crates/circuits/src/arithmetic/u32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,73 @@ where
Ok(zout)
}

pub fn sub<U, F>(
builder: &mut ConstraintSystemBuilder<U, F>,
name: impl ToString,
zin: OracleId,
yin: OracleId,
flags: super::Flags,
) -> Result<OracleId, anyhow::Error>
where
U: PackScalar<F> + PackScalar<BinaryField1b> + Pod,
F: TowerField,
{
builder.push_namespace(name);
let log_rows = builder.log_rows([zin, yin])?;
let cout = builder.add_committed("cout", log_rows, BinaryField1b::TOWER_LEVEL);
let cin = builder.add_shifted("cin", cout, 1, 5, ShiftVariant::LogicalLeft)?;
let xout = builder.add_committed("xin", log_rows, BinaryField1b::TOWER_LEVEL);

if let Some(witness) = builder.witness() {
(
witness.get::<BinaryField1b>(zin)?.as_slice::<u32>(),
witness.get::<BinaryField1b>(yin)?.as_slice::<u32>(),
witness
.new_column::<BinaryField1b>(xout)
.as_mut_slice::<u32>(),
witness
.new_column::<BinaryField1b>(cout)
.as_mut_slice::<u32>(),
witness
.new_column::<BinaryField1b>(cin)
.as_mut_slice::<u32>(),
)
.into_par_iter()
.for_each(|(zout, yin, xin, cout, cin)| {
let carry;
(*xin, carry) = (*zout).overflowing_sub(*yin);
*cin = (*xin) ^ (*yin) ^ (*zout);
*cout = ((carry as u32) << 31) | (*cin >> 1);
});
}

builder.assert_zero(
"sum",
[xout, yin, cin, zin],
arith_expr!([xout, yin, cin, zin] = xout + yin + cin - zin).convert_field(),
);

builder.assert_zero(
"carry",
[xout, yin, cin, cout],
arith_expr!([xout, yin, cin, cout] = (xout + cin) * (yin + cin) + cin - cout)
.convert_field(),
);

// Underflow checking
if matches!(flags, super::Flags::Checked) {
let last_cout = select_bit(builder, "last_cout", cout, 31)?;
builder.assert_zero(
"underflow",
[last_cout],
arith_expr!([last_cout] = last_cout).convert_field(),
);
}

builder.pop_namespace();
Ok(xout)
}

pub fn half<U, F>(
builder: &mut ConstraintSystemBuilder<U, F>,
name: impl ToString,
Expand Down Expand Up @@ -296,7 +363,7 @@ mod tests {
use binius_core::constraint_system::validate::validate_witness;
use binius_field::{arch::OptimalUnderlier, BinaryField128b, BinaryField1b, TowerField};

use crate::{arithmetic, builder::ConstraintSystemBuilder};
use crate::{arithmetic, builder::ConstraintSystemBuilder, unconstrained::unconstrained};

type U = OptimalUnderlier;
type F = BinaryField128b;
Expand All @@ -323,4 +390,20 @@ mod tests {
let boundaries = vec![];
validate_witness(&constraint_system, &boundaries, &witness).unwrap();
}

#[test]
fn test_sub() {
let allocator = bumpalo::Bump::new();
let mut builder = ConstraintSystemBuilder::<U, F>::new_with_witness(&allocator);

let a = unconstrained::<U, F, BinaryField1b>(&mut builder, "a", 7).unwrap();
let b = unconstrained::<U, F, BinaryField1b>(&mut builder, "a", 7).unwrap();
let _c =
arithmetic::u32::sub(&mut builder, "c", a, b, arithmetic::Flags::Unchecked).unwrap();

let witness = builder.take_witness().unwrap();
let constraint_system = builder.build().unwrap();
let boundaries = vec![];
validate_witness(&constraint_system, &boundaries, &witness).unwrap();
}
}
184 changes: 152 additions & 32 deletions crates/core/benches/prodcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,185 @@ use std::iter::repeat_with;
use binius_core::{
fiat_shamir::HasherChallenger,
protocols::gkr_gpa::{self, GrandProductClaim, GrandProductWitness},
transcript::TranscriptWriter,
transcript::ProverTranscript,
};
use binius_field::{
arch::packed_polyval_128::PackedBinaryPolyval1x128b, BinaryField128b, BinaryField128bPolyval,
PackedField,
arch::OptimalUnderlier,
as_packed_field::PackScalar,
linear_transformation::{PackedTransformationFactory, Transformation},
BinaryField128b, BinaryField128bPolyval, PackedField, PackedFieldIndexable, TowerField,
BINARY_TO_POLYVAL_TRANSFORMATION,
};
use binius_hal::make_portable_backend;
use binius_hal::{make_portable_backend, CpuBackend};
use binius_math::{IsomorphicEvaluationDomainFactory, MultilinearExtension};
use binius_maybe_rayon::iter::{IntoParallelIterator, ParallelIterator};
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use groestl_crypto::Groestl256;
use rand::{rngs::StdRng, SeedableRng};

// Creates T(x), a multilinear with evaluations over the n-dimensional boolean hypercube
fn create_numerator<P: PackedField>(n_vars: usize) -> MultilinearExtension<P> {
fn create_numerator<P: PackedField>(n_vars: usize) -> Vec<P> {
let mut rng = StdRng::seed_from_u64(0);
let values = repeat_with(|| P::random(&mut rng))
.take(1 << n_vars)
.collect::<Vec<P>>();
repeat_with(|| P::random(&mut rng))
.take(1 << (n_vars - P::LOG_WIDTH))
.collect()
}

MultilinearExtension::from_values(values).unwrap()
fn apply_transformation<IP, OP>(
input: &[IP],
transformation: &impl Transformation<IP, OP>,
) -> Vec<OP> {
input.iter().map(|x| transformation.transform(x)).collect()
}

fn bench_polyval(c: &mut Criterion) {
type FDomain = BinaryField128b;
const N_VARS: [usize; 3] = [12, 16, 20];
const N_CLAIMS: usize = 20;
type FDomain = BinaryField128b;

type P = PackedBinaryPolyval1x128b;
type FW = BinaryField128bPolyval;
let mut group = c.benchmark_group("prodcheck");
fn bench_gpa_generic<U, F, R, BenchFn>(name: &str, c: &mut Criterion, bench_fn: &BenchFn)
where
U: PackScalar<F, Packed: PackedFieldIndexable>,
F: TowerField + From<BinaryField128b>,
BenchFn: Fn(
usize,
&mut ProverTranscript<HasherChallenger<Groestl256>>,
&[U::Packed],
&IsomorphicEvaluationDomainFactory<FDomain>,
&CpuBackend,
) -> R,
{
let mut group = c.benchmark_group(name);
let domain_factory = IsomorphicEvaluationDomainFactory::<FDomain>::default();

for n in [12, 16, 20] {
for n_vars in N_VARS {
group.throughput(Throughput::Bytes(
((1 << n) * std::mem::size_of::<BinaryField128b>()) as u64,
((1 << n_vars) * std::mem::size_of::<F>() * N_CLAIMS) as u64,
));
group.bench_function(format!("n_vars={n}"), |bench| {
group.bench_function(format!("n_vars={n_vars}"), |bench| {
// Setup witness
let numerator = create_numerator::<P>(n);

let gpa_witness =
GrandProductWitness::<P>::new(numerator.specialize_arc_dyn()).unwrap();
let numerator = create_numerator::<U::Packed>(n_vars);

let product: FW = FW::from(gpa_witness.grand_product_evaluation());
let gpa_claim = GrandProductClaim { n_vars: n, product };
let backend = make_portable_backend();

let mut prover_transcript = TranscriptWriter::<HasherChallenger<Groestl256>>::default();
let mut prover_transcript = ProverTranscript::<HasherChallenger<Groestl256>>::default();
bench.iter(|| {
gkr_gpa::batch_prove::<FW, P, FW, _, _>(
[gpa_witness.clone()],
&[gpa_claim.clone()],
domain_factory.clone(),
&mut prover_transcript,
&backend,
)
bench_fn(n_vars, &mut prover_transcript, &numerator, &domain_factory, &backend)
});
});
}
group.finish()
}

fn bench_gpa<U, F>(name: &str, c: &mut Criterion)
where
U: PackScalar<F, Packed: PackedFieldIndexable>,
F: TowerField + From<BinaryField128b>,
{
bench_gpa_generic::<U, F, _, _>(
name,
c,
&|n_vars, prover_transcript, numerator, domain_factory, backend| {
let (gpa_witnesses, gpa_claims): (Vec<_>, Vec<_>) = (0..N_CLAIMS)
.into_par_iter()
.map(|_| {
let numerator =
MultilinearExtension::<U::Packed, &[U::Packed]>::from_values_generic(
numerator,
)
.unwrap();
let gpa_witness = GrandProductWitness::<<U as PackScalar<F>>::Packed>::new(
numerator.specialize_arc_dyn(),
)
.unwrap();

let product = gpa_witness.grand_product_evaluation();

(gpa_witness, GrandProductClaim { n_vars, product })
})
.collect::<Vec<_>>()
.into_iter()
.unzip();

gkr_gpa::batch_prove::<F, U::Packed, F, _, _>(
gpa_witnesses,
&gpa_claims,
domain_factory.clone(),
prover_transcript,
backend,
)
},
);
}

fn bench_gpa_isomorphic<U>(name: &str, c: &mut Criterion)
where
U: PackScalar<
BinaryField128b,
Packed: PackedFieldIndexable
+ PackedTransformationFactory<<U as PackScalar<BinaryField128bPolyval>>::Packed>,
>,
U: PackScalar<
BinaryField128bPolyval,
Packed: PackedFieldIndexable
+ PackedTransformationFactory<<U as PackScalar<BinaryField128b>>::Packed>,
>,
{
let transform_to_polyval =
<U as PackScalar<BinaryField128b>>::Packed::make_packed_transformation(
BINARY_TO_POLYVAL_TRANSFORMATION,
);

bench_gpa_generic::<U, BinaryField128b, _, _>(
name,
c,
&|n_vars, prover_transcript, numerator, domain_factory, backend| {
let (gpa_witnesses, gpa_claims): (Vec<_>, Vec<_>) = (0..N_CLAIMS)
.into_par_iter()
.map(|_| {
let transformed_values = apply_transformation(numerator, &transform_to_polyval);
let numerator = MultilinearExtension::from_values(transformed_values).unwrap();

let gpa_witness = GrandProductWitness::<
<U as PackScalar<BinaryField128bPolyval>>::Packed,
>::new(numerator.specialize_arc_dyn())
.unwrap();

let product = gpa_witness.grand_product_evaluation();

(gpa_witness, GrandProductClaim { n_vars, product })
})
.collect::<Vec<_>>()
.into_iter()
.unzip();

gkr_gpa::batch_prove::<
BinaryField128bPolyval,
<U as PackScalar<BinaryField128bPolyval>>::Packed,
BinaryField128bPolyval,
_,
_,
>(
gpa_witnesses.clone(),
&gpa_claims,
domain_factory.clone(),
prover_transcript,
&backend,
)
},
);
}

fn bench_polyval(c: &mut Criterion) {
bench_gpa::<OptimalUnderlier, BinaryField128bPolyval>("polyval", c);
}

fn bench_binary(c: &mut Criterion) {
bench_gpa::<OptimalUnderlier, BinaryField128b>("binary_128b", c);
}

fn bench_binary_isomorphic(c: &mut Criterion) {
bench_gpa_isomorphic::<OptimalUnderlier>("binary_128b_isomorphic", c);
}

criterion_main!(prodcheck);
criterion_group!(prodcheck, bench_polyval);
criterion_group!(prodcheck, bench_polyval, bench_binary, bench_binary_isomorphic);
Loading

0 comments on commit f8b8c87

Please sign in to comment.