ark_ec/hashing/curve_maps/
wb.rs1use core::marker::PhantomData;
2
3use crate::{models::short_weierstrass::SWCurveConfig, CurveConfig};
4use ark_ff::batch_inversion;
5use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, Polynomial};
6
7use crate::{
8 hashing::{map_to_curve_hasher::MapToCurve, HashToCurveError},
9 models::short_weierstrass::{Affine, Projective},
10 AffineRepr,
11};
12
13use super::swu::{SWUConfig, SWUMap};
14type BaseField<MP> = <MP as CurveConfig>::BaseField;
15
16pub struct IsogenyMap<
32 'a,
33 Domain: SWCurveConfig,
34 Codomain: SWCurveConfig<BaseField = BaseField<Domain>>,
35> {
36 pub x_map_numerator: &'a [BaseField<Domain>],
37 pub x_map_denominator: &'a [BaseField<Codomain>],
38
39 pub y_map_numerator: &'a [BaseField<Domain>],
40 pub y_map_denominator: &'a [BaseField<Codomain>],
41}
42
43impl<Domain, Codomain> IsogenyMap<'_, Domain, Codomain>
44where
45 Domain: SWCurveConfig,
46 Codomain: SWCurveConfig<BaseField = BaseField<Domain>>,
47{
48 fn apply(&self, domain_point: Affine<Domain>) -> Result<Affine<Codomain>, HashToCurveError> {
49 match domain_point.xy() {
50 Some((x, y)) => {
51 let x_num = DensePolynomial::from_coefficients_slice(self.x_map_numerator);
52 let x_den = DensePolynomial::from_coefficients_slice(self.x_map_denominator);
53
54 let y_num = DensePolynomial::from_coefficients_slice(self.y_map_numerator);
55 let y_den = DensePolynomial::from_coefficients_slice(self.y_map_denominator);
56
57 let mut v: [BaseField<Domain>; 2] = [x_den.evaluate(&x), y_den.evaluate(&x)];
58 batch_inversion(&mut v);
59 let img_x = x_num.evaluate(&x) * v[0];
60 let img_y = (y_num.evaluate(&x) * y) * v[1];
61 Ok(Affine::new_unchecked(img_x, img_y))
62 },
63 None => Ok(Affine::identity()),
64 }
65 }
66}
67
68pub trait WBConfig: SWCurveConfig + Sized {
79 type IsogenousCurve: SWUConfig<BaseField = BaseField<Self>>;
82
83 const ISOGENY_MAP: IsogenyMap<'static, Self::IsogenousCurve, Self>;
84}
85
86pub struct WBMap<P: WBConfig> {
87 swu_field_curve_hasher: PhantomData<SWUMap<P::IsogenousCurve>>,
88 curve_params: PhantomData<fn() -> P>,
89}
90
91impl<P: WBConfig> MapToCurve<Projective<P>> for WBMap<P> {
92 fn check_parameters() -> Result<(), HashToCurveError> {
94 match P::ISOGENY_MAP.apply(P::IsogenousCurve::GENERATOR) {
95 Ok(point_on_curve) => {
96 debug_assert!(point_on_curve.is_on_curve(),
97 "the isogeny maps the generator of its domain: {} into {} which does not belong to its codomain.",P::IsogenousCurve::GENERATOR, point_on_curve);
98 },
99 Err(e) => return Err(e),
100 }
101
102 SWUMap::<P::IsogenousCurve>::check_parameters().unwrap(); Ok(())
104 }
105
106 fn map_to_curve(
110 element: <Affine<P> as AffineRepr>::BaseField,
111 ) -> Result<Affine<P>, HashToCurveError> {
112 let point_on_isogenious_curve = SWUMap::map_to_curve(element).unwrap();
114 P::ISOGENY_MAP.apply(point_on_isogenious_curve)
115 }
116}
117
118#[cfg(test)]
119mod test {
120 use crate::{
121 hashing::{
122 curve_maps::{
123 swu::SWUConfig,
124 wb::{IsogenyMap, WBConfig, WBMap},
125 },
126 map_to_curve_hasher::MapToCurveBasedHasher,
127 HashToCurve,
128 },
129 models::short_weierstrass::SWCurveConfig,
130 short_weierstrass::{Affine, Projective},
131 CurveConfig,
132 };
133 use ark_ff::{field_hashers::DefaultFieldHasher, fields::Fp64, MontBackend, MontFp};
134
135 #[derive(ark_ff::MontConfig)]
136 #[modulus = "127"]
137 #[generator = "6"]
138 pub(crate) struct F127Config;
139 pub(crate) type F127 = Fp64<MontBackend<F127Config, 1>>;
140
141 const F127_ZERO: F127 = MontFp!("0");
142 const F127_ONE: F127 = MontFp!("1");
143
144 struct TestWBF127MapToCurveConfig;
146
147 impl CurveConfig for TestWBF127MapToCurveConfig {
148 const COFACTOR: &[u64] = &[1];
149
150 const COFACTOR_INV: F127 = F127_ONE;
151
152 type BaseField = F127;
153 type ScalarField = F127;
154 }
155
156 impl SWCurveConfig for TestWBF127MapToCurveConfig {
159 const COEFF_A: F127 = F127_ZERO;
161
162 const COEFF_B: F127 = MontFp!("3");
164
165 const GENERATOR: Affine<Self> = Affine::new_unchecked(MontFp!("62"), MontFp!("70"));
167
168 type ZeroFlag = ();
170 }
171
172 struct TestSWU127MapToIsogenousCurveConfig;
177
178 impl CurveConfig for TestSWU127MapToIsogenousCurveConfig {
182 const COFACTOR: &[u64] = &[1];
183
184 const COFACTOR_INV: F127 = F127_ONE;
185
186 type BaseField = F127;
187 type ScalarField = F127;
188 }
189
190 impl SWCurveConfig for TestSWU127MapToIsogenousCurveConfig {
193 const COEFF_A: F127 = MontFp!("109");
195
196 const COEFF_B: F127 = MontFp!("124");
198
199 const GENERATOR: Affine<Self> = Affine::new_unchecked(MontFp!("84"), MontFp!("2"));
201
202 type ZeroFlag = bool;
204 }
205
206 impl SWUConfig for TestSWU127MapToIsogenousCurveConfig {
208 const ZETA: F127 = MontFp!("-1");
210 }
211
212 const ISOGENY_MAP_TESTWBF127: IsogenyMap<
228 '_,
229 TestSWU127MapToIsogenousCurveConfig,
230 TestWBF127MapToCurveConfig,
231 > = IsogenyMap {
232 x_map_numerator: &[
233 MontFp!("4"),
234 MontFp!("63"),
235 MontFp!("23"),
236 MontFp!("39"),
237 MontFp!("-14"),
238 MontFp!("23"),
239 MontFp!("-32"),
240 MontFp!("32"),
241 MontFp!("-13"),
242 MontFp!("40"),
243 MontFp!("34"),
244 MontFp!("10"),
245 MontFp!("-21"),
246 MontFp!("-57"),
247 ],
248
249 x_map_denominator: &[
250 MontFp!("2"),
251 MontFp!("31"),
252 MontFp!("-10"),
253 MontFp!("-20"),
254 MontFp!("63"),
255 MontFp!("-44"),
256 MontFp!("34"),
257 MontFp!("30"),
258 MontFp!("-30"),
259 MontFp!("-33"),
260 MontFp!("11"),
261 MontFp!("-13"),
262 MontFp!("1"),
263 ],
264
265 y_map_numerator: &[
266 MontFp!("-34"),
267 MontFp!("-57"),
268 MontFp!("30"),
269 MontFp!("-18"),
270 MontFp!("-60"),
271 MontFp!("-43"),
272 MontFp!("-63"),
273 MontFp!("-18"),
274 MontFp!("-49"),
275 MontFp!("36"),
276 MontFp!("12"),
277 MontFp!("62"),
278 MontFp!("5"),
279 MontFp!("6"),
280 MontFp!("-7"),
281 MontFp!("48"),
282 MontFp!("41"),
283 MontFp!("59"),
284 MontFp!("10"),
285 ],
286
287 y_map_denominator: &[
288 MontFp!("32"),
289 MontFp!("-18"),
290 MontFp!("-24"),
291 MontFp!("23"),
292 MontFp!("18"),
293 MontFp!("-55"),
294 MontFp!("-16"),
295 MontFp!("-61"),
296 MontFp!("-46"),
297 MontFp!("-13"),
298 MontFp!("-42"),
299 MontFp!("11"),
300 MontFp!("-30"),
301 MontFp!("38"),
302 MontFp!("3"),
303 MontFp!("52"),
304 MontFp!("-63"),
305 MontFp!("44"),
306 MontFp!("1"),
307 ],
308 };
309 impl WBConfig for TestWBF127MapToCurveConfig {
310 type IsogenousCurve = TestSWU127MapToIsogenousCurveConfig;
311
312 const ISOGENY_MAP: super::IsogenyMap<'static, Self::IsogenousCurve, Self> =
313 ISOGENY_MAP_TESTWBF127;
314 }
315
316 #[test]
319 fn hash_arbitrary_string_to_curve_wb() {
320 use sha2::Sha256;
321 let test_wb_to_curve_hasher = MapToCurveBasedHasher::<
322 Projective<TestWBF127MapToCurveConfig>,
323 DefaultFieldHasher<Sha256, 128>,
324 WBMap<TestWBF127MapToCurveConfig>,
325 >::new(&[1])
326 .unwrap();
327
328 let hash_result = test_wb_to_curve_hasher.hash(b"if you stick a Babel fish in your ear you can instantly understand anything said to you in any form of language.").expect("fail to hash the string to curve");
329
330 assert!(
331 hash_result.x != F127_ZERO && hash_result.y != F127_ZERO,
332 "we assume that not both a and b coefficienst are zero for the test curve"
333 );
334
335 assert!(
336 hash_result.is_on_curve(),
337 "hash results into a point off the curve"
338 );
339 }
340}