franklin_crypto/plonk/circuit/
multieq.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::bellman::pairing::Engine;

use crate::bellman::pairing::ff::{BitIterator, Field, PrimeField, PrimeFieldRepr};

use crate::bellman::SynthesisError;

use crate::bellman::plonk::better_better_cs::cs::{
    ArithmeticTerm, Coefficient, ConstraintSystem, Gate, GateInternal, LinearCombinationOfTerms, MainGate, MainGateTerm, PolynomialInConstraint, PolynomialMultiplicativeTerm, TimeDilation, Variable,
    Width4MainGateWithDNext,
};

use crate::plonk::circuit::Assignment;

use super::allocated_num::AllocatedNum;

use super::linear_combination::LinearCombination;

pub struct MultiEq<'a, E: Engine, CS: ConstraintSystem<E> + 'a> {
    cs: &'a mut CS,
    ops: usize,
    bits_used: usize,
    lhs: LinearCombination<E>,
    rhs: LinearCombination<E>,
}

impl<'a, E: Engine, CS: ConstraintSystem<E> + 'a> MultiEq<'a, E, CS> {
    pub fn new(cs: &'a mut CS) -> Self {
        MultiEq {
            cs: cs,
            ops: 0,
            bits_used: 0,
            lhs: LinearCombination::<E>::zero(),
            rhs: LinearCombination::<E>::zero(),
        }
    }

    pub fn as_cs(&mut self) -> &mut CS {
        &mut self.cs
    }

    fn accumulate(&mut self) {
        let mut lhs = self.lhs.clone();
        let mut rhs = self.rhs.clone();
        let mut minus_one = E::Fr::one();
        minus_one.negate();
        rhs.scale(&minus_one);

        lhs.add_assign(&rhs);

        lhs.enforce_zero(self.cs).expect("must enforce");

        self.lhs = LinearCombination::<E>::zero();
        self.rhs = LinearCombination::<E>::zero();
        self.bits_used = 0;
        self.ops += 1;
    }

    pub fn enforce_equal(&mut self, num_bits: usize, lhs: &LinearCombination<E>, rhs: &LinearCombination<E>) {
        // Check if we will exceed the capacity
        if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) {
            self.accumulate();
        }

        assert!((E::Fr::CAPACITY as usize) > (self.bits_used + num_bits));

        let coeff = E::Fr::from_str("2").unwrap().pow(&[self.bits_used as u64]);
        let mut scaled_lhs = lhs.clone();
        scaled_lhs.scale(&coeff);

        let mut scaled_rhs = rhs.clone();
        scaled_rhs.scale(&coeff);

        self.lhs.add_assign(&scaled_lhs);
        self.rhs.add_assign(&scaled_rhs);

        self.bits_used += num_bits;
    }
}

impl<'a, E: Engine, CS: ConstraintSystem<E> + 'a> Drop for MultiEq<'a, E, CS> {
    fn drop(&mut self) {
        if self.bits_used > 0 {
            self.accumulate();
        }
    }
}

pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
    bytes.iter().flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)).collect()
}

pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool> {
    bytes.iter().flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)).collect()
}

pub fn compute_multipacking<E: Engine>(bits: &[bool]) -> Vec<E::Fr> {
    let mut result = vec![];

    for bits in bits.chunks(E::Fr::CAPACITY as usize) {
        let mut cur = E::Fr::zero();
        let mut coeff = E::Fr::one();

        for bit in bits {
            if *bit {
                cur.add_assign(&coeff);
            }

            coeff.double();
        }

        result.push(cur);
    }

    result
}