binius_circuits/
bitwise.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use binius_core::oracle::OracleId;
4use binius_field::{BinaryField1b, Field, TowerField};
5use binius_macros::arith_expr;
6use binius_maybe_rayon::prelude::*;
7
8use crate::builder::ConstraintSystemBuilder;
9
10pub fn and(
11	builder: &mut ConstraintSystemBuilder,
12	name: impl ToString,
13	xin: OracleId,
14	yin: OracleId,
15) -> Result<OracleId, anyhow::Error> {
16	builder.push_namespace(name);
17	let log_rows = builder.log_rows([xin, yin])?;
18	let zout = builder.add_committed("zout", log_rows, BinaryField1b::TOWER_LEVEL);
19	if let Some(witness) = builder.witness() {
20		(
21			witness.get::<BinaryField1b>(xin)?.as_slice::<u32>(),
22			witness.get::<BinaryField1b>(yin)?.as_slice::<u32>(),
23			witness
24				.new_column::<BinaryField1b>(zout)
25				.as_mut_slice::<u32>(),
26		)
27			.into_par_iter()
28			.for_each(|(xin, yin, zout)| {
29				*zout = (*xin) & (*yin);
30			});
31	}
32	builder.assert_zero(
33		"bitwise_and",
34		[xin, yin, zout],
35		arith_expr!([x, y, z] = x * y - z).convert_field(),
36	);
37	builder.pop_namespace();
38	Ok(zout)
39}
40
41pub fn xor(
42	builder: &mut ConstraintSystemBuilder,
43	name: impl ToString,
44	xin: OracleId,
45	yin: OracleId,
46) -> Result<OracleId, anyhow::Error> {
47	builder.push_namespace(name);
48	let log_rows = builder.log_rows([xin, yin])?;
49	let zout =
50		builder.add_linear_combination("zout", log_rows, [(xin, Field::ONE), (yin, Field::ONE)])?;
51	if let Some(witness) = builder.witness() {
52		(
53			witness.get::<BinaryField1b>(xin)?.as_slice::<u32>(),
54			witness.get::<BinaryField1b>(yin)?.as_slice::<u32>(),
55			witness
56				.new_column::<BinaryField1b>(zout)
57				.as_mut_slice::<u32>(),
58		)
59			.into_par_iter()
60			.for_each(|(xin, yin, zout)| {
61				*zout = (*xin) ^ (*yin);
62			});
63	}
64	builder.pop_namespace();
65	Ok(zout)
66}
67
68pub fn or(
69	builder: &mut ConstraintSystemBuilder,
70	name: impl ToString,
71	xin: OracleId,
72	yin: OracleId,
73) -> Result<OracleId, anyhow::Error> {
74	builder.push_namespace(name);
75	let log_rows = builder.log_rows([xin, yin])?;
76	let zout = builder.add_committed("zout", log_rows, BinaryField1b::TOWER_LEVEL);
77	if let Some(witness) = builder.witness() {
78		(
79			witness.get::<BinaryField1b>(xin)?.as_slice::<u32>(),
80			witness.get::<BinaryField1b>(yin)?.as_slice::<u32>(),
81			witness
82				.new_column::<BinaryField1b>(zout)
83				.as_mut_slice::<u32>(),
84		)
85			.into_par_iter()
86			.for_each(|(xin, yin, zout)| {
87				*zout = (*xin) | (*yin);
88			});
89	}
90	builder.assert_zero(
91		"bitwise_or",
92		[xin, yin, zout],
93		arith_expr!([x, y, z] = (x + y) + (x * y) - z).convert_field(),
94	);
95	builder.pop_namespace();
96	Ok(zout)
97}
98
99#[cfg(test)]
100mod tests {
101	use binius_field::BinaryField1b;
102
103	use crate::{builder::test_utils::test_circuit, unconstrained::unconstrained};
104
105	#[test]
106	fn test_bitwise() {
107		test_circuit(|builder| {
108			let log_size = 6;
109			let a = unconstrained::<BinaryField1b>(builder, "a", log_size)?;
110			let b = unconstrained::<BinaryField1b>(builder, "b", log_size)?;
111			let _and = super::and(builder, "and", a, b)?;
112			let _xor = super::xor(builder, "xor", a, b)?;
113			let _or = super::or(builder, "or", a, b)?;
114			Ok(vec![])
115		})
116		.unwrap();
117	}
118}