ark_r1cs_std/groups/curves/short_weierstrass/bls12/
mod.rs1use ark_ec::{
2 bls12::{Bls12Config, G1Prepared, G2Prepared, TwistType},
3 short_weierstrass::Affine as GroupAffine,
4};
5use ark_ff::{BitIteratorBE, Field, One};
6use ark_relations::r1cs::{Namespace, SynthesisError};
7
8use crate::{
9 fields::{fp::FpVar, fp2::Fp2Var, FieldVar},
10 groups::curves::short_weierstrass::*,
11 Vec,
12};
13
14pub type G1Var<P> = ProjectiveVar<<P as Bls12Config>::G1Config, FpVar<<P as Bls12Config>::Fp>>;
16
17pub type G1AffineVar<P> = AffineVar<<P as Bls12Config>::G1Config, FpVar<<P as Bls12Config>::Fp>>;
21
22pub type G2Var<P> = ProjectiveVar<<P as Bls12Config>::G2Config, Fp2G<P>>;
24pub type G2AffineVar<P> = AffineVar<<P as Bls12Config>::G2Config, Fp2G<P>>;
28
29#[derive(Educe)]
32#[educe(Clone, Debug)]
33pub struct G1PreparedVar<P: Bls12Config>(pub AffineVar<P::G1Config, FpVar<P::Fp>>);
34
35impl<P: Bls12Config> G1PreparedVar<P> {
36 pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
39 let x = self.0.x.value()?;
40 let y = self.0.y.value()?;
41 let infinity = self.0.infinity.value()?;
42 let g = infinity
43 .then_some(GroupAffine::identity())
44 .unwrap_or(GroupAffine::new(x, y))
45 .into();
46 Ok(g)
47 }
48
49 pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
51 let g = q.to_affine()?;
52 Ok(Self(g))
53 }
54}
55
56impl<P: Bls12Config> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
57 fn new_variable<T: Borrow<G1Prepared<P>>>(
58 cs: impl Into<Namespace<P::Fp>>,
59 f: impl FnOnce() -> Result<T, SynthesisError>,
60 mode: AllocationMode,
61 ) -> Result<Self, SynthesisError> {
62 let ns = cs.into();
63 let cs = ns.cs();
64 let g1_prep = f().map(|b| b.borrow().0);
65
66 let x = FpVar::new_variable(ark_relations::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?;
67 let y = FpVar::new_variable(ark_relations::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?;
68 let infinity = Boolean::new_variable(
69 ark_relations::ns!(cs, "inf"),
70 || g1_prep.map(|g| g.infinity),
71 mode,
72 )?;
73 let g = AffineVar::new(x, y, infinity);
74 Ok(Self(g))
75 }
76}
77
78impl<P: Bls12Config> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
79 #[inline]
80 #[tracing::instrument(target = "r1cs")]
81 fn to_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
82 let mut bytes = self.0.x.to_bytes_le()?;
83 let y_bytes = self.0.y.to_bytes_le()?;
84 let inf_bytes = self.0.infinity.to_bytes_le()?;
85 bytes.extend_from_slice(&y_bytes);
86 bytes.extend_from_slice(&inf_bytes);
87 Ok(bytes)
88 }
89
90 #[tracing::instrument(target = "r1cs")]
91 fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
92 let mut bytes = self.0.x.to_non_unique_bytes_le()?;
93 let y_bytes = self.0.y.to_non_unique_bytes_le()?;
94 let inf_bytes = self.0.infinity.to_non_unique_bytes_le()?;
95 bytes.extend_from_slice(&y_bytes);
96 bytes.extend_from_slice(&inf_bytes);
97 Ok(bytes)
98 }
99}
100
101type Fp2G<P> = Fp2Var<<P as Bls12Config>::Fp2Config>;
102type LCoeff<P> = (Fp2G<P>, Fp2G<P>);
103#[derive(Educe)]
106#[educe(Clone, Debug)]
107pub struct G2PreparedVar<P: Bls12Config> {
108 #[doc(hidden)]
109 pub ell_coeffs: Vec<LCoeff<P>>,
110}
111
112impl<P: Bls12Config> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
113 #[tracing::instrument(target = "r1cs", skip(cs, f, mode))]
114 fn new_variable<T: Borrow<G2Prepared<P>>>(
115 cs: impl Into<Namespace<P::Fp>>,
116 f: impl FnOnce() -> Result<T, SynthesisError>,
117 mode: AllocationMode,
118 ) -> Result<Self, SynthesisError> {
119 let ns = cs.into();
120 let cs = ns.cs();
121 let g2_prep = f().map(|b| {
122 let projective_coeffs = &b.borrow().ell_coeffs;
123 match P::TWIST_TYPE {
124 TwistType::M => {
125 let mut z_s = projective_coeffs
126 .iter()
127 .map(|(_, _, z)| *z)
128 .collect::<Vec<_>>();
129 ark_ff::fields::batch_inversion(&mut z_s);
130 projective_coeffs
131 .iter()
132 .zip(z_s)
133 .map(|((x, y, _), z_inv)| (*x * &z_inv, *y * &z_inv))
134 .collect::<Vec<_>>()
135 },
136 TwistType::D => {
137 let mut z_s = projective_coeffs
138 .iter()
139 .map(|(z, ..)| *z)
140 .collect::<Vec<_>>();
141 ark_ff::fields::batch_inversion(&mut z_s);
142 projective_coeffs
143 .iter()
144 .zip(z_s)
145 .map(|((_, x, y), z_inv)| (*x * &z_inv, *y * &z_inv))
146 .collect::<Vec<_>>()
147 },
148 }
149 });
150
151 let l = Vec::new_variable(
152 ark_relations::ns!(cs, "l"),
153 || {
154 g2_prep
155 .clone()
156 .map(|c| c.iter().map(|(l, _)| *l).collect::<Vec<_>>())
157 },
158 mode,
159 )?;
160 let r = Vec::new_variable(
161 ark_relations::ns!(cs, "r"),
162 || g2_prep.map(|c| c.iter().map(|(_, r)| *r).collect::<Vec<_>>()),
163 mode,
164 )?;
165 let ell_coeffs = l.into_iter().zip(r).collect();
166 Ok(Self { ell_coeffs })
167 }
168}
169
170impl<P: Bls12Config> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
171 #[inline]
172 #[tracing::instrument(target = "r1cs")]
173 fn to_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
174 let mut bytes = Vec::new();
175 for coeffs in &self.ell_coeffs {
176 bytes.extend_from_slice(&coeffs.0.to_bytes_le()?);
177 bytes.extend_from_slice(&coeffs.1.to_bytes_le()?);
178 }
179 Ok(bytes)
180 }
181
182 #[tracing::instrument(target = "r1cs")]
183 fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
184 let mut bytes = Vec::new();
185 for coeffs in &self.ell_coeffs {
186 bytes.extend_from_slice(&coeffs.0.to_non_unique_bytes_le()?);
187 bytes.extend_from_slice(&coeffs.1.to_non_unique_bytes_le()?);
188 }
189 Ok(bytes)
190 }
191}
192
193impl<P: Bls12Config> G2PreparedVar<P> {
194 #[tracing::instrument(target = "r1cs")]
196 pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
197 let q = q.to_affine()?;
198 let two_inv = P::Fp::one().double().inverse().unwrap();
199 q.infinity.enforce_not_equal(&Boolean::TRUE)?;
201 let mut ell_coeffs = vec![];
202 let mut r = q.clone();
203
204 for i in BitIteratorBE::new(P::X).skip(1) {
205 ell_coeffs.push(Self::double(&mut r, &two_inv)?);
206
207 if i {
208 ell_coeffs.push(Self::add(&mut r, &q)?);
209 }
210 }
211
212 Ok(Self { ell_coeffs })
213 }
214
215 #[tracing::instrument(target = "r1cs")]
216 fn double(r: &mut G2AffineVar<P>, two_inv: &P::Fp) -> Result<LCoeff<P>, SynthesisError> {
217 let a = r.y.inverse()?;
218 let mut b = r.x.square()?;
219 let b_tmp = b.clone();
220 b.mul_assign_by_base_field_constant(*two_inv);
221 b += &b_tmp;
222
223 let c = &a * &b;
224 let d = r.x.double()?;
225 let x3 = c.square()? - &d;
226 let e = &c * &r.x - &r.y;
227 let c_x3 = &c * &x3;
228 let y3 = &e - &c_x3;
229 let mut f = c;
230 f.negate_in_place()?;
231 r.x = x3;
232 r.y = y3;
233 match P::TWIST_TYPE {
234 TwistType::M => Ok((e, f)),
235 TwistType::D => Ok((f, e)),
236 }
237 }
238
239 #[tracing::instrument(target = "r1cs")]
240 fn add(r: &mut G2AffineVar<P>, q: &G2AffineVar<P>) -> Result<LCoeff<P>, SynthesisError> {
241 let a = (&q.x - &r.x).inverse()?;
242 let b = &q.y - &r.y;
243 let c = &a * &b;
244 let d = &r.x + &q.x;
245 let x3 = c.square()? - &d;
246
247 let e = (&r.x - &x3) * &c;
248 let y3 = e - &r.y;
249 let g = &c * &r.x - &r.y;
250 let mut f = c;
251 f.negate_in_place()?;
252 r.x = x3;
253 r.y = y3;
254 match P::TWIST_TYPE {
255 TwistType::M => Ok((g, f)),
256 TwistType::D => Ok((f, g)),
257 }
258 }
259}