bellperson_nonnative/util/
bit.rs

1// (mostly from franklin-crypto)
2use bellperson::gadgets::boolean::Boolean;
3use bellperson::{ConstraintSystem, LinearCombination, SynthesisError};
4use ff::PrimeField;
5
6use std::fmt::{self, Display, Formatter};
7
8use crate::OptionExt;
9
10#[derive(Clone)]
11/// A representation of a bit
12pub struct Bit<Scalar: PrimeField> {
13    /// The linear combination which constrain the value of the bit
14    pub bit: LinearCombination<Scalar>,
15    /// The value of the bit (filled at witness-time)
16    pub value: Option<bool>,
17}
18
19#[derive(Clone)]
20/// A representation of a bit-vector
21pub struct Bitvector<Scalar: PrimeField> {
22    /// The linear combination which constrain the values of the bits
23    pub bits: Vec<LinearCombination<Scalar>>,
24    /// The value of the bits (filled at witness-time)
25    pub values: Option<Vec<bool>>,
26    /// Allocated bit variables
27    pub allocations: Vec<Bit<Scalar>>,
28}
29
30impl<Scalar: PrimeField> Bitvector<Scalar> {
31    /// Reverse the order of the bits
32    pub fn reversed(mut self) -> Self {
33        self.values.as_mut().map(|v| v.reverse());
34        self.bits.reverse();
35        self
36    }
37    /// Keep only the first `n` bits.
38    pub fn truncate(mut self, n: usize) -> Self {
39        self.values.as_mut().map(|v| v.truncate(n));
40        self.bits.truncate(n);
41        self
42    }
43
44    pub fn get(&self, i: usize) -> Option<Bit<Scalar>> {
45        self.bits.get(i).map(|lc| Bit {
46            bit: lc.clone(),
47            value: self.values.as_ref().map(|vs| vs[i].clone()),
48        })
49    }
50
51    pub fn shr(mut self, i: usize) -> Self {
52        self.values.as_mut().map(|v| {
53            v.drain(0..i);
54        });
55        self.bits.drain(0..i);
56        self
57    }
58
59    pub fn shl(mut self, i: usize) -> Self {
60        self.values.as_mut().map(|v| {
61            v.splice(0..0, std::iter::repeat(false).take(i));
62        });
63        self.bits
64            .splice(0..0, std::iter::repeat(LinearCombination::zero()).take(i));
65        self
66    }
67
68    pub fn pop(&mut self) -> Option<Bit<Scalar>> {
69        if self.bits.len() > 0 {
70            Some(Bit::new(
71                self.bits.pop().unwrap(),
72                self.values.as_mut().map(|vs| vs.pop().unwrap()),
73            ))
74        } else {
75            None
76        }
77    }
78
79    pub fn push(&mut self, mut b: Bit<Scalar>) {
80        self.values
81            .as_mut()
82            .map(|vs| b.value.take().map(|v| vs.push(v)));
83        self.bits.push(b.bit);
84    }
85
86    pub fn insert(&mut self, i: usize, mut b: Bit<Scalar>) {
87        self.values
88            .as_mut()
89            .map(|vs| b.value.take().map(|v| vs.insert(i, v)));
90        self.bits.insert(i, b.bit);
91    }
92
93    pub fn append(&mut self, mut other: Self) {
94        let ovs = other.values.take();
95        self.bits.extend(other.bits.into_iter());
96        self.values
97            .as_mut()
98            .map(|vs| ovs.map(|ovs| vs.extend(ovs.into_iter())));
99    }
100
101    pub fn into_bits(mut self) -> Vec<Bit<Scalar>> {
102        let vs = self.values.take();
103        self.bits
104            .into_iter()
105            .enumerate()
106            .map(|(i, b)| Bit {
107                bit: b,
108                value: vs.as_ref().map(|vs| vs[i]),
109            })
110            .collect()
111    }
112
113    pub fn from_bits(bs: Vec<Bit<Scalar>>) -> Self {
114        let mut bits = Vec::new();
115        let mut values = Some(Vec::new());
116        for mut b in bs.clone() {
117            let v = b.value.take();
118            bits.push(b.bit);
119            values = values.take().and_then(|mut vs| {
120                v.map(|v| {
121                    vs.push(v);
122                    vs
123                })
124            });
125        }
126        Self {
127            bits,
128            values,
129            allocations: bs,
130        }
131    }
132}
133
134impl<Scalar: PrimeField> Bit<Scalar> {
135    /// Allocate a variable in the constraint system which can only be a
136    /// boolean value.
137    pub fn alloc<CS>(mut cs: CS, value: Option<bool>) -> Result<Self, SynthesisError>
138    where
139        CS: ConstraintSystem<Scalar>,
140    {
141        let var = cs.alloc(
142            || "boolean",
143            || {
144                if *value.grab()? {
145                    Ok(Scalar::one())
146                } else {
147                    Ok(Scalar::zero())
148                }
149            },
150        )?;
151
152        // Constrain: (1 - a) * a = 0
153        // This constrains a to be either 0 or 1.
154        cs.enforce(
155            || "boolean constraint",
156            |lc| lc + CS::one() - var,
157            |lc| lc + var,
158            |lc| lc,
159        );
160
161        Ok(Self {
162            bit: LinearCombination::zero() + var,
163            value,
164        })
165    }
166
167    pub fn constrain_value<CS>(&self, mut cs: CS, value: bool)
168    where
169        CS: ConstraintSystem<Scalar>,
170    {
171        cs.enforce(
172            || format!("is {}", value),
173            |lc| lc,
174            |lc| lc,
175            |lc| {
176                if value {
177                    lc + &self.bit - CS::one()
178                } else {
179                    lc + &self.bit
180                }
181            },
182        );
183    }
184
185    pub fn new(bit: LinearCombination<Scalar>, value: Option<bool>) -> Self {
186        Self { bit, value }
187    }
188
189    pub fn from_sapling<CS: ConstraintSystem<Scalar>>(b: Boolean) -> Self {
190        Self::new(b.lc(CS::one(), Scalar::one()), b.get_value())
191    }
192
193    pub fn not<CS: ConstraintSystem<Scalar>>(&self) -> Self {
194        Self::new(
195            LinearCombination::zero() + CS::one() - &self.bit,
196            self.value.clone().map(|b| !b),
197        )
198    }
199
200    pub fn new_false<CS: ConstraintSystem<Scalar>>() -> Self {
201        Self::new(LinearCombination::zero(), Some(false))
202    }
203
204    pub fn new_true<CS: ConstraintSystem<Scalar>>() -> Self {
205        Self::new(LinearCombination::zero() + CS::one(), Some(true))
206    }
207
208    pub fn new_value<CS: ConstraintSystem<Scalar>>(v: bool) -> Self {
209        if v {
210            Self::new_true::<CS>()
211        } else {
212            Self::new_false::<CS>()
213        }
214    }
215}
216
217impl<Scalar: PrimeField> Display for Bitvector<Scalar> {
218    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
219        match self.values.as_ref() {
220            Some(vs) => write!(
221                f,
222                "Bitvector({})",
223                vs.into_iter()
224                    .map(|b| if *b { "1" } else { "0" })
225                    .collect::<Vec<_>>()
226                    .concat()
227            ),
228            None => write!(f, "Bitvector(len {})", self.bits.len()),
229        }
230    }
231}