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