arcis_compiler/core/circuits/boolean/
boolean_value.rs1#[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 {}