binius_circuits/
bitwise.rs1use 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}