cyclone_msm/
preprocess.rs1use core::ops::{AddAssign, Neg, SubAssign};
4
5pub use ark_bls12_377::g1::Parameters;
6use ark_bls12_377::{Fq, G1Affine};
7use ark_ec::{
8 models::twisted_edwards::{Affine, Projective, TECurveConfig},
9 AffineRepr as _,
10};
11use ark_ff::Field as _;
12use ark_std::{One as _, Zero as _};
13use derivative::Derivative;
14
15use crate::bls12_377::G1PTEAffine;
16
17#[derive(Derivative)]
22#[derivative(Copy(bound = "P: TECurveConfig"), Clone(bound = "P: TECurveConfig"))]
23#[derive(Debug, Eq, Hash, PartialEq)]
25pub struct PreprocessedAffine<P: TECurveConfig> {
26 pub x: P::BaseField,
28 pub y: P::BaseField,
30 pub kt: P::BaseField,
32}
33
34impl<P: TECurveConfig> PreprocessedAffine<P> {
35 pub fn new(x: P::BaseField, y: P::BaseField) -> Self {
36 Self {
37 x,
38 y,
39 kt: (P::COEFF_D + P::COEFF_D) * x * y,
40 }
41 }
42
43 pub const fn zero() -> Self {
44 Self {
45 x: P::BaseField::ZERO,
46 y: P::BaseField::ONE,
47 kt: P::BaseField::ZERO,
48 }
49 }
50
51 pub fn is_zero(&self) -> bool {
52 self.x.is_zero() && self.y.is_one()
53 }
54}
55
56impl<P: TECurveConfig> From<Affine<P>> for PreprocessedAffine<P> {
57 fn from(affine: Affine<P>) -> PreprocessedAffine<P> {
58 Self::new(affine.x, affine.y)
59 }
60}
61
62impl<P: TECurveConfig> From<&Affine<P>> for PreprocessedAffine<P> {
63 fn from(affine: &Affine<P>) -> PreprocessedAffine<P> {
64 Self::new(affine.x, affine.y)
65 }
66}
67
68impl<P: TECurveConfig> From<PreprocessedAffine<P>> for Affine<P> {
69 fn from(pre: PreprocessedAffine<P>) -> Affine<P> {
70 Self::new(pre.x, pre.y)
71 }
72}
73
74impl<P: TECurveConfig> From<&PreprocessedAffine<P>> for Affine<P> {
75 fn from(pre: &PreprocessedAffine<P>) -> Affine<P> {
76 Self::new(pre.x, pre.y)
77 }
78}
79
80impl<'a, P: TECurveConfig> AddAssign<&'a PreprocessedAffine<P>> for Projective<P> {
81 fn add_assign(&mut self, other: &PreprocessedAffine<P>) {
82 if self.is_zero() {
83 self.x = other.x;
85 self.y = other.y;
86 self.t = other.x * other.y;
87 self.z = P::BaseField::one();
88 return;
89 }
90
91 let r1 = self.y - self.x;
126 let r2 = other.y - other.x;
127 let r3 = self.y + self.x;
128 let r4 = other.y + other.x;
129
130 let r5 = r1 * r2;
132 let r6 = r3 * r4;
133 let r7 = self.t * other.kt;
134 let r8 = self.z.double();
135
136 let r1b = r6 - r5;
142 let r2b = r8 - r7;
143 let r3b = r8 + r7;
144 let r4b = r6 + r5;
145
146 self.x = r1b * r2b;
148 self.y = r3b * r4b;
149 self.t = r1b * r4b;
150 self.z = r2b * r3b;
151 }
152}
153
154impl<'a, P: TECurveConfig> SubAssign<&'a PreprocessedAffine<P>> for Projective<P> {
155 fn sub_assign(&mut self, other: &'a PreprocessedAffine<P>) {
156 self.add_assign(&(-*other))
157 }
158}
159
160impl<P: TECurveConfig> Neg for PreprocessedAffine<P> {
161 type Output = Self;
162
163 fn neg(self) -> Self {
164 Self {
165 x: -self.x,
166 y: self.y,
167 kt: -self.kt,
168 }
169 }
170}
171
172pub fn batch_preprocess(a: &[G1Affine], b: &mut [G1PTEAffine]) {
174 use crate::bls12_377::{FQ_S, FQ_SQRT_MIN_A};
175
176 debug_assert!(a.len() == b.len());
177
178 let mut x = vec![Fq::ZERO; a.len()];
179 let mut y = vec![Fq::ZERO; a.len()];
180 let mut z = vec![Fq::ZERO; a.len()];
181
182 for (i, p) in a.iter().enumerate() {
183 if p.is_zero() {
184 x[i] = Fq::ZERO;
185 y[i] = Fq::ONE;
186 z[i] = Fq::ONE;
187 continue;
188 }
189
190 let xpo = p.x + Fq::ONE;
191 let sxpo = xpo * FQ_S;
192 let axpo = xpo * FQ_SQRT_MIN_A;
193 let syxpo = sxpo * p.y;
194
195 x[i] = (sxpo + Fq::ONE) * axpo;
196 y[i] = syxpo - p.y;
197 z[i] = syxpo + p.y;
198 }
199
200 ark_ff::batch_inversion(&mut z);
201
202 for i in 0..a.len() {
203 b[i] = G1PTEAffine::new(x[i] * z[i], y[i] * z[i]);
204 }
205}
206
207pub fn preprocess_points(points: &[G1Affine]) -> Vec<G1PTEAffine> {
232 let mut ppoints = vec![G1PTEAffine::zero(); points.len()];
233
234 const CHUNK: usize = 1 << 16;
235 for (chunk_in, chunk_out) in points
236 .chunks(CHUNK)
237 .zip(ppoints.as_mut_slice().chunks_mut(CHUNK))
238 {
239 crate::preprocess::batch_preprocess(chunk_in, chunk_out);
240 }
241 ppoints
242}