1#![no_std]
23#![deny(unsafe_code)]
24#![deny(clippy::all)]
25#![deny(clippy::pedantic)]
26#![deny(clippy::nursery)]
27
28extern crate alloc;
29
30use alloc::vec::Vec;
31use ark_ec::short_weierstrass::SWCurveConfig;
32use ark_ff::{Field, One, Zero};
33
34pub trait GroupMap<F> {
35 fn setup() -> Self;
36 fn to_group(&self, u: F) -> (F, F);
37 fn batch_to_group_x(&self, ts: Vec<F>) -> Vec<[F; 3]>;
38}
39
40#[derive(Clone, Copy)]
41pub struct BWParameters<G: SWCurveConfig> {
42 pub u: G::BaseField,
43 pub fu: G::BaseField,
44 pub sqrt_neg_three_u_squared_minus_u_over_2: G::BaseField,
45 pub sqrt_neg_three_u_squared: G::BaseField,
46 pub inv_three_u_squared: G::BaseField,
47}
48
49fn curve_eqn<G: SWCurveConfig>(x: G::BaseField) -> G::BaseField {
51 let mut res = x;
52 res *= &x; res += &G::COEFF_A; res *= &x; res += &G::COEFF_B; res
58}
59
60fn find_first<A, K: Field, F: Fn(K) -> Option<A>>(start: K, f: F) -> A {
62 let mut i = start;
63 loop {
64 match f(i) {
65 Some(x) => return x,
66 None => {
67 i += K::one();
68 }
69 }
70 }
71}
72
73fn potential_xs_helper<G: SWCurveConfig>(
75 params: &BWParameters<G>,
76 t2: G::BaseField,
77 alpha: G::BaseField,
78) -> [G::BaseField; 3] {
79 let x1 = {
80 let mut temp = t2;
81 temp.square_in_place(); temp *= α temp *= ¶ms.sqrt_neg_three_u_squared; params.sqrt_neg_three_u_squared_minus_u_over_2 - temp };
86
87 let x2 = -params.u - x1;
88
89 let x3 = {
90 let t2_plus_fu = t2 + params.fu;
91 let t2_inv = alpha * t2_plus_fu;
92 let mut temp = t2_plus_fu.square();
93 temp *= &t2_inv;
94 temp *= ¶ms.inv_three_u_squared;
95 params.u - temp
96 };
97
98 [x1, x2, x3]
99}
100
101fn potential_xs<G: SWCurveConfig>(params: &BWParameters<G>, t: G::BaseField) -> [G::BaseField; 3] {
103 let t2 = t.square();
104 let mut alpha_inv = t2;
105 alpha_inv += ¶ms.fu;
106 alpha_inv *= &t2;
107
108 let alpha = alpha_inv.inverse().unwrap_or_else(G::BaseField::zero);
109
110 potential_xs_helper(params, t2, alpha)
111}
112
113pub fn get_y<G: SWCurveConfig>(x: G::BaseField) -> Option<G::BaseField> {
116 let fx = curve_eqn::<G>(x);
117 fx.sqrt()
118}
119
120fn get_xy<G: SWCurveConfig>(
121 params: &BWParameters<G>,
122 t: G::BaseField,
123) -> (G::BaseField, G::BaseField) {
124 let xvec = potential_xs(params, t);
125 for x in &xvec {
126 if let Some(y) = get_y::<G>(*x) {
127 return (*x, y);
128 }
129 }
130 panic!("get_xy")
131}
132
133impl<G: SWCurveConfig> GroupMap<G::BaseField> for BWParameters<G> {
134 fn setup() -> Self {
135 assert!(G::COEFF_A.is_zero());
136
137 let (u, fu) = find_first(G::BaseField::one(), |u| {
139 let fu: G::BaseField = curve_eqn::<G>(u);
140 if fu.is_zero() {
141 None
142 } else {
143 Some((u, fu))
144 }
145 });
146
147 let two = G::BaseField::one() + G::BaseField::one();
148 let three = two + G::BaseField::one();
149
150 let three_u_squared = u.square() * three; let inv_three_u_squared = three_u_squared.inverse().unwrap(); let sqrt_neg_three_u_squared = (-three_u_squared).sqrt().unwrap();
153 let two_inv = two.inverse().unwrap();
154 let sqrt_neg_three_u_squared_minus_u_over_2 = (sqrt_neg_three_u_squared - u) * two_inv;
155
156 Self {
157 u,
158 fu,
159 sqrt_neg_three_u_squared_minus_u_over_2,
160 sqrt_neg_three_u_squared,
161 inv_three_u_squared,
162 }
163 }
164
165 fn batch_to_group_x(&self, ts: Vec<G::BaseField>) -> Vec<[G::BaseField; 3]> {
166 let t2_alpha_invs: Vec<_> = ts
167 .iter()
168 .map(|t| {
169 let t2 = t.square();
170 let mut alpha_inv = t2;
171 alpha_inv += &self.fu;
172 alpha_inv *= &t2;
173 (t2, alpha_inv)
174 })
175 .collect();
176
177 let mut alphas: Vec<G::BaseField> = t2_alpha_invs.iter().map(|(_, a)| *a).collect();
178 ark_ff::batch_inversion::<G::BaseField>(&mut alphas);
179
180 let potential_xs = t2_alpha_invs
181 .iter()
182 .zip(alphas)
183 .map(|((t2, _), alpha)| potential_xs_helper(self, *t2, alpha));
184 potential_xs.collect()
185 }
186
187 fn to_group(&self, t: G::BaseField) -> (G::BaseField, G::BaseField) {
188 get_xy(self, t)
189 }
190}