arcis_compiler/core/circuits/boolean/
boolean_value.rs

1#[cfg(debug_assertions)]
2use crate::core::expressions::domain::Domain;
3use crate::{
4    core::{
5        actually_used_field::ActuallyUsedField,
6        bounds::{Bounds, IsBounds},
7        expressions::{
8            bit_expr::{BitExpr, RandomBitId},
9            expr::Expr,
10            other_expr::OtherExpr,
11        },
12        global_value::{
13            curve_value::CurveValue,
14            global_expr_store::with_global_expr_store_as_local,
15            value::FieldValue,
16        },
17        ir_builder::{ExprStore, IRBuilder},
18        mxe_input::{MxeBitInput, MxeInput},
19    },
20    traits::{GetBit, Keccak, RandomBit, Reveal, Select},
21    utils::{
22        elliptic_curve::ProjectiveEdwardsPoint,
23        field::{BaseField, ScalarField},
24    },
25};
26use core::panic;
27use rand::Rng;
28use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
29
30pub trait Boolean:
31    BitAnd<Output = Self>
32    + BitAndAssign
33    + BitXor<Output = Self>
34    + BitXorAssign
35    + Not<Output = Self>
36    + RandomBit
37    + Reveal
38    + Keccak
39    + Select<Self, Self, Self>
40    + Select<Vec<Self>, Vec<Self>, Vec<Self>>
41    + Copy
42    + From<bool>
43{
44}
45#[derive(Debug, Clone, Copy)]
46pub struct BooleanValue(usize);
47
48impl BooleanValue {
49    pub fn new(id: usize) -> Self {
50        #[cfg(debug_assertions)]
51        with_global_expr_store_as_local(|expr_store| {
52            let _ = bool::unwrap(*expr_store.get_bounds(id));
53        });
54
55        Self(id)
56    }
57
58    pub fn from_expr(expr: Expr<usize>) -> Self {
59        Self(with_global_expr_store_as_local(|expr_store| {
60            let id = expr_store.new_expr(expr);
61            #[cfg(debug_assertions)]
62            let _ = bool::unwrap(*expr_store.get_bounds(id));
63            id
64        }))
65    }
66
67    pub fn get_id(&self) -> usize {
68        self.0
69    }
70
71    pub fn expr(&self) -> Expr<usize> {
72        with_global_expr_store_as_local(|expr_store| expr_store.get_expr(self.0).clone())
73    }
74
75    pub fn is_plaintext(&self) -> bool {
76        with_global_expr_store_as_local(|expr_store| expr_store.get_is_plaintext(self.get_id()))
77    }
78
79    pub fn ed25519_secret_key(i: usize) -> Self {
80        Self::from_expr(Expr::Other(OtherExpr::MxeKey(MxeInput::Bit(
81            MxeBitInput::Ed25519SecretKey(i),
82        ))))
83    }
84
85    pub fn ed25519_signing_key_hash_prefix(i: usize) -> Self {
86        Self::from_expr(Expr::Other(OtherExpr::MxeKey(MxeInput::Bit(
87            MxeBitInput::Ed25519SigningKeyHashPrefix(i),
88        ))))
89    }
90
91    pub fn as_constant(&self) -> Option<bool> {
92        let Bounds::Bit(b) =
93            with_global_expr_store_as_local(|expr_store| *expr_store.get_bounds(self.get_id()))
94        else {
95            panic!("BooleanValue has non-boolean bounds.")
96        };
97        b.as_constant()
98    }
99}
100
101impl BitAnd for BooleanValue {
102    type Output = BooleanValue;
103
104    fn bitand(self, rhs: Self) -> Self::Output {
105        Self(with_global_expr_store_as_local(|expr_store| {
106            <IRBuilder as ExprStore<BaseField>>::push_bit(
107                expr_store,
108                BitExpr::And(self.0, rhs.get_id()),
109            )
110        }))
111    }
112}
113
114impl BitAndAssign for BooleanValue {
115    fn bitand_assign(&mut self, rhs: Self) {
116        *self = *self & rhs;
117    }
118}
119
120impl BitXor for BooleanValue {
121    type Output = BooleanValue;
122
123    fn bitxor(self, rhs: Self) -> Self::Output {
124        Self(with_global_expr_store_as_local(|expr_store| {
125            <IRBuilder as ExprStore<BaseField>>::push_bit(
126                expr_store,
127                BitExpr::Xor(self.0, rhs.get_id()),
128            )
129        }))
130    }
131}
132
133impl BitXorAssign for BooleanValue {
134    fn bitxor_assign(&mut self, rhs: Self) {
135        *self = *self ^ rhs;
136    }
137}
138
139impl BitOr for BooleanValue {
140    type Output = BooleanValue;
141
142    fn bitor(self, rhs: Self) -> Self::Output {
143        !(!self & !rhs)
144    }
145}
146
147impl BitOrAssign for BooleanValue {
148    fn bitor_assign(&mut self, rhs: Self) {
149        *self = *self | rhs;
150    }
151}
152
153impl Not for BooleanValue {
154    type Output = BooleanValue;
155
156    fn not(self) -> Self::Output {
157        Self(with_global_expr_store_as_local(|expr_store| {
158            <IRBuilder as ExprStore<BaseField>>::push_bit(expr_store, BitExpr::Not(self.0))
159        }))
160    }
161}
162
163impl RandomBit for BooleanValue {
164    fn random() -> Self {
165        Self(with_global_expr_store_as_local(|expr_store| {
166            let before_len = expr_store.len();
167            let res = expr_store.new_expr(Expr::Bit(BitExpr::Random(RandomBitId::new())));
168            let after_len = expr_store.len();
169            assert_eq!(after_len, before_len + 1, "Randomness was reused.");
170            assert_eq!(res, before_len, "Randomness was reused.");
171            res
172        }))
173    }
174}
175
176impl Reveal for BooleanValue {
177    fn reveal(self) -> Self {
178        Self(with_global_expr_store_as_local(|expr_store| {
179            expr_store.new_expr(Expr::Bit(BitExpr::Reveal(self.0)))
180        }))
181    }
182}
183
184impl Select<BooleanValue, BooleanValue, BooleanValue> for BooleanValue {
185    fn select(self, x: BooleanValue, y: BooleanValue) -> BooleanValue {
186        y ^ self & (x ^ y)
187    }
188}
189
190impl Select<Vec<BooleanValue>, Vec<BooleanValue>, Vec<BooleanValue>> for BooleanValue {
191    fn select(self, x: Vec<BooleanValue>, y: Vec<BooleanValue>) -> Vec<BooleanValue> {
192        assert_eq!(x.len(), y.len());
193        x.into_iter()
194            .zip(y)
195            .map(|(bit_x, bit_y)| self.select(bit_x, bit_y))
196            .collect::<Vec<BooleanValue>>()
197    }
198}
199
200impl<F: ActuallyUsedField> Select<FieldValue<F>, FieldValue<F>, FieldValue<F>> for BooleanValue {
201    fn select(self, x: FieldValue<F>, y: FieldValue<F>) -> FieldValue<F> {
202        FieldValue::<F>::from(self).select(x, y)
203    }
204}
205
206impl Select<CurveValue, CurveValue, CurveValue> for BooleanValue {
207    fn select(self, x: CurveValue, y: CurveValue) -> CurveValue {
208        y + FieldValue::<ScalarField>::from(self) * (x - y)
209    }
210}
211
212impl
213    Select<
214        ProjectiveEdwardsPoint<FieldValue<BaseField>>,
215        ProjectiveEdwardsPoint<FieldValue<BaseField>>,
216        ProjectiveEdwardsPoint<FieldValue<BaseField>>,
217    > for BooleanValue
218{
219    fn select(
220        self,
221        x: ProjectiveEdwardsPoint<FieldValue<BaseField>>,
222        y: ProjectiveEdwardsPoint<FieldValue<BaseField>>,
223    ) -> ProjectiveEdwardsPoint<FieldValue<BaseField>> {
224        ProjectiveEdwardsPoint::new(
225            (
226                self.select(x.X, y.X),
227                self.select(x.Y, y.Y),
228                self.select(x.Z, y.Z),
229            ),
230            x.is_on_curve && y.is_on_curve,
231            x.is_ell_torsion && y.is_ell_torsion,
232        )
233    }
234}
235
236impl From<bool> for BooleanValue {
237    fn from(val: bool) -> Self {
238        Self(with_global_expr_store_as_local(|expr_store| {
239            <IRBuilder as ExprStore<BaseField>>::push_bit(expr_store, BitExpr::Val(val))
240        }))
241    }
242}
243
244impl<F: ActuallyUsedField> From<FieldValue<F>> for BooleanValue {
245    fn from(val: FieldValue<F>) -> Self {
246        let bounds = val.bounds();
247        if !bounds.is_arithmetic_boolean() {
248            panic!("bounds must be boolean (found {:?})", bounds);
249        }
250        val.get_bit(0, false)
251    }
252}
253
254impl Boolean for BooleanValue {}
255
256impl RandomBit for bool {
257    fn random() -> Self {
258        let rng = &mut rand::thread_rng();
259        rng.gen_bool(0.5)
260    }
261}
262
263impl Reveal for bool {
264    fn reveal(self) -> Self {
265        self
266    }
267}
268
269impl<T> Select<T, T, T> for bool {
270    fn select(self, a: T, b: T) -> T {
271        if self {
272            a
273        } else {
274            b
275        }
276    }
277}
278
279impl Boolean for bool {}