snark_verifier/
loader.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
//! Abstraction of field element and elliptic curve point for generic verifier
//! implementation.

use crate::util::{
    arithmetic::{CurveAffine, FieldOps, PrimeField},
    Itertools,
};
use std::{borrow::Cow, fmt::Debug, iter, ops::Deref};

/// Native (cpu) loader
pub mod native;

#[cfg(feature = "loader_evm")]
/// EVM loader
pub mod evm;

#[cfg(feature = "loader_halo2")]
/// Halo2 loader
pub mod halo2;

/// Loaded elliptic curve point.
pub trait LoadedEcPoint<C: CurveAffine>: Clone + Debug + PartialEq {
    /// [`Loader`].
    type Loader: Loader<C, LoadedEcPoint = Self>;

    /// Returns [`Loader`].
    fn loader(&self) -> &Self::Loader;
}

/// Loaded field element.
pub trait LoadedScalar<F: PrimeField>: Clone + Debug + PartialEq + FieldOps {
    /// [`Loader`].
    type Loader: ScalarLoader<F, LoadedScalar = Self>;

    /// Returns [`Loader`].
    fn loader(&self) -> &Self::Loader;

    /// Returns square.
    fn square(&self) -> Self {
        self.clone() * self
    }

    /// Returns inverse if any.
    fn invert(&self) -> Option<Self> {
        FieldOps::invert(self)
    }

    /// Returns power to exponent.
    fn pow_const(&self, mut exp: u64) -> Self {
        assert!(exp > 0);

        let mut base = self.clone();

        while exp & 1 == 0 {
            base = base.square();
            exp >>= 1;
        }

        let mut acc = base.clone();
        while exp > 1 {
            exp >>= 1;
            base = base.square();
            if exp & 1 == 1 {
                acc *= &base;
            }
        }
        acc
    }

    /// Returns power to exponent, where exponent is also [`LoadedScalar`].
    /// If `Loader` is for Halo2, then `exp` must have at most `exp_max_bits` bits (otherwise constraints will fail).
    ///
    /// Currently **unimplemented** for EvmLoader
    fn pow_var(&self, exp: &Self, exp_max_bits: usize) -> Self;

    /// Returns powers up to exponent `n-1`.
    fn powers(&self, n: usize) -> Vec<Self> {
        iter::once(self.loader().load_one())
            .chain(
                iter::successors(Some(self.clone()), |power| Some(power.clone() * self))
                    .take(n - 1),
            )
            .collect_vec()
    }
}

/// Elliptic curve point loader.
pub trait EcPointLoader<C: CurveAffine> {
    /// [`LoadedEcPoint`].
    type LoadedEcPoint: LoadedEcPoint<C, Loader = Self>;

    /// Load a constant elliptic curve point.
    fn ec_point_load_const(&self, value: &C) -> Self::LoadedEcPoint;

    /// Load `identity` as constant.
    fn ec_point_load_zero(&self) -> Self::LoadedEcPoint {
        self.ec_point_load_const(&C::identity())
    }

    /// Load `generator` as constant.
    fn ec_point_load_one(&self) -> Self::LoadedEcPoint {
        self.ec_point_load_const(&C::generator())
    }

    /// Assert lhs and rhs elliptic curve points are equal.
    fn ec_point_assert_eq(
        &self,
        annotation: &str,
        lhs: &Self::LoadedEcPoint,
        rhs: &Self::LoadedEcPoint,
    );

    /// Perform multi-scalar multiplication.
    fn multi_scalar_multiplication(
        pairs: &[(&Self::LoadedScalar, &Self::LoadedEcPoint)],
    ) -> Self::LoadedEcPoint
    where
        Self: ScalarLoader<C::ScalarExt>;
}

/// Field element loader.
pub trait ScalarLoader<F: PrimeField> {
    /// [`LoadedScalar`].
    type LoadedScalar: LoadedScalar<F, Loader = Self>;

    /// Load a constant field element.
    fn load_const(&self, value: &F) -> Self::LoadedScalar;

    /// Load `zero` as constant.
    fn load_zero(&self) -> Self::LoadedScalar {
        self.load_const(&F::ZERO)
    }

    /// Load `one` as constant.
    fn load_one(&self) -> Self::LoadedScalar {
        self.load_const(&F::ONE)
    }

    /// Assert lhs and rhs field elements are equal.
    fn assert_eq(&self, annotation: &str, lhs: &Self::LoadedScalar, rhs: &Self::LoadedScalar);

    /// Sum field elements with coefficients and constant.
    fn sum_with_coeff_and_const(
        &self,
        values: &[(F, &Self::LoadedScalar)],
        constant: F,
    ) -> Self::LoadedScalar {
        if values.is_empty() {
            return self.load_const(&constant);
        }

        let loader = values.first().unwrap().1.loader();
        iter::empty()
            .chain(if constant == F::ZERO {
                None
            } else {
                Some(Cow::Owned(loader.load_const(&constant)))
            })
            .chain(values.iter().map(|&(coeff, value)| {
                if coeff == F::ONE {
                    Cow::Borrowed(value)
                } else {
                    Cow::Owned(loader.load_const(&coeff) * value)
                }
            }))
            .reduce(|acc, term| Cow::Owned(acc.into_owned() + term.deref()))
            .unwrap()
            .into_owned()
    }

    /// Sum product of field elements with coefficients and constant.
    fn sum_products_with_coeff_and_const(
        &self,
        values: &[(F, &Self::LoadedScalar, &Self::LoadedScalar)],
        constant: F,
    ) -> Self::LoadedScalar {
        if values.is_empty() {
            return self.load_const(&constant);
        }

        let loader = values.first().unwrap().1.loader();
        iter::empty()
            .chain(if constant == F::ZERO { None } else { Some(loader.load_const(&constant)) })
            .chain(values.iter().map(|&(coeff, lhs, rhs)| {
                if coeff == F::ONE {
                    lhs.clone() * rhs
                } else {
                    loader.load_const(&coeff) * lhs * rhs
                }
            }))
            .reduce(|acc, term| acc + term)
            .unwrap()
    }

    /// Sum field elements with coefficients.
    fn sum_with_coeff(&self, values: &[(F, &Self::LoadedScalar)]) -> Self::LoadedScalar {
        self.sum_with_coeff_and_const(values, F::ZERO)
    }

    /// Sum field elements and constant.
    fn sum_with_const(&self, values: &[&Self::LoadedScalar], constant: F) -> Self::LoadedScalar {
        self.sum_with_coeff_and_const(
            &values.iter().map(|&value| (F::ONE, value)).collect_vec(),
            constant,
        )
    }

    /// Sum field elements.
    fn sum(&self, values: &[&Self::LoadedScalar]) -> Self::LoadedScalar {
        self.sum_with_const(values, F::ZERO)
    }

    /// Sum product of field elements with coefficients.
    fn sum_products_with_coeff(
        &self,
        values: &[(F, &Self::LoadedScalar, &Self::LoadedScalar)],
    ) -> Self::LoadedScalar {
        self.sum_products_with_coeff_and_const(values, F::ZERO)
    }

    /// Sum product of field elements and constant.
    fn sum_products_with_const(
        &self,
        values: &[(&Self::LoadedScalar, &Self::LoadedScalar)],
        constant: F,
    ) -> Self::LoadedScalar {
        self.sum_products_with_coeff_and_const(
            &values.iter().map(|&(lhs, rhs)| (F::ONE, lhs, rhs)).collect_vec(),
            constant,
        )
    }

    /// Sum product of field elements.
    fn sum_products(
        &self,
        values: &[(&Self::LoadedScalar, &Self::LoadedScalar)],
    ) -> Self::LoadedScalar {
        self.sum_products_with_const(values, F::ZERO)
    }

    /// Product of field elements.
    fn product(&self, values: &[&Self::LoadedScalar]) -> Self::LoadedScalar {
        values.iter().fold(self.load_one(), |acc, value| acc * *value)
    }

    /// Batch invert field elements.
    fn batch_invert<'a>(values: impl IntoIterator<Item = &'a mut Self::LoadedScalar>)
    where
        Self::LoadedScalar: 'a,
    {
        values
            .into_iter()
            .for_each(|value| *value = LoadedScalar::invert(value).unwrap_or_else(|| value.clone()))
    }
}

/// [`EcPointLoader`] and [`ScalarLoader`] with some helper methods.
pub trait Loader<C: CurveAffine>:
    EcPointLoader<C> + ScalarLoader<C::ScalarExt> + Clone + Debug
{
    /// Start cost metering with an `identifier`.
    fn start_cost_metering(&self, _identifier: &str) {}

    /// End latest started cost metering.
    fn end_cost_metering(&self) {}
}