frontend/components/digits.rs
1use shared_types::Field;
2
3use crate::{
4 abstract_expr::AbstractExpression,
5 layouter::builder::{CircuitBuilder, NodeRef},
6};
7
8/// Digits-related circuit components
9pub struct DigitComponents;
10
11impl DigitComponents {
12 /// Digital recomposition of an unsigned integer, i.e. deriving the number from its digits.
13 /// Each of the Nodes in `mles` specifies the digits for a different
14 /// "decimal place". Most significant digit comes first.
15 pub fn unsigned_recomposition<F: Field>(
16 builder_ref: &mut CircuitBuilder<F>,
17 mles: &[&NodeRef<F>],
18 base: u64,
19 ) -> NodeRef<F> {
20 let num_digits = mles.len();
21
22 let b_s_initial_acc = AbstractExpression::<F>::constant(F::ZERO);
23
24 let sector_expr = mles.iter().enumerate().fold(
25 b_s_initial_acc,
26 |acc_expr, (bit_idx, bin_decomp_node)| {
27 let power = F::from(base.pow((num_digits - (bit_idx + 1)) as u32));
28 acc_expr + *bin_decomp_node * power
29 },
30 );
31 builder_ref.add_sector(sector_expr)
32 }
33
34 /// Checks that the complementary decomposition of a signed
35 /// integer. To be used in conjunction with [Self::unsigned_recomposition]. See
36 /// [crate::digits::complementary_decomposition] and
37 /// [Notion](https://www.notion.so/Constraining-for-the-response-zero-case-using-the-complementary-representation-d77ddfe258a74a9ab949385cc6f7eda4).
38 /// Add self.sector to the circuit as an output layer to enforce this constraint.
39 /// Create a new ComplementaryDecompChecker. `values` are the original
40 /// values. `bits` are the bits of the complementary decomposition.
41 /// `unsigned_recomps` are the unsigned recompositions.
42 pub fn complementary_recomp_check<F: Field>(
43 builder_ref: &mut CircuitBuilder<F>,
44 values: &NodeRef<F>,
45 bits: &NodeRef<F>,
46 unsigned_recomps: &NodeRef<F>,
47 base: u64,
48 num_digits: usize,
49 ) -> NodeRef<F> {
50 let mut pow = F::from(1_u64);
51 for _ in 0..num_digits {
52 pow *= F::from(base);
53 }
54
55 builder_ref.add_sector(bits * pow - unsigned_recomps - values)
56 }
57
58 /// Ensures that each bit is either 0 or 1. Add self.sector to the circuit as an
59 /// output layer to enforce this constraint.
60 pub fn bits_are_binary<F: Field>(
61 builder_ref: &mut CircuitBuilder<F>,
62 values_node: &NodeRef<F>,
63 ) -> NodeRef<F> {
64 builder_ref.add_sector(values_node * values_node - values_node)
65 }
66
67 /// A component that concatenates all the separate digit MLEs (there is one for
68 /// each digital place) into a single MLE using a selector tree. (Necessary to
69 /// interact with logup).
70 pub fn digits_concatenator<F: Field>(
71 builder_ref: &mut CircuitBuilder<F>,
72 mles: &[&NodeRef<F>],
73 ) -> NodeRef<F> {
74 builder_ref.add_sector(AbstractExpression::binary_tree_selector(mles.to_vec()))
75 }
76}