monero_generators/
hash_to_point.rs1use subtle::ConditionallySelectable;
2
3use curve25519_dalek::edwards::EdwardsPoint;
4
5use group::ff::{Field, PrimeField};
6use dalek_ff_group::FieldElement;
7
8use monero_io::decompress_point;
9
10use crate::keccak256;
11
12pub fn hash_to_point(bytes: [u8; 32]) -> EdwardsPoint {
14 #[allow(non_snake_case)]
15 let A = FieldElement::from(486662u64);
16
17 let v = FieldElement::from_square(keccak256(&bytes)).double();
18 let w = v + FieldElement::ONE;
19 let x = w.square() + (-A.square() * v);
20
21 #[allow(non_snake_case)]
25 let X = {
26 let u = w;
27 let v = x;
28 let v3 = v * v * v;
29 let uv3 = u * v3;
30 let v7 = v3 * v3 * v;
31 let uv7 = u * v7;
32 uv3 *
33 uv7.pow(
34 (-FieldElement::from(5u8)) *
35 FieldElement::from(8u8).invert().expect("eight was coprime with the prime 2^{255}-19"),
36 )
37 };
38 let x = X.square() * x;
39
40 let y = w - x;
41 let non_zero_0 = !y.is_zero();
42 let y_if_non_zero_0 = w + x;
43 let sign = non_zero_0 & (!y_if_non_zero_0.is_zero());
44
45 let mut z = -A;
46 z *= FieldElement::conditional_select(&v, &FieldElement::from(1u8), sign);
47 #[allow(non_snake_case)]
48 let Z = z + w;
49 #[allow(non_snake_case)]
50 let mut Y = z - w;
51
52 Y *= Z.invert().expect("if sign, v was 486661. if !sign, v was 486661^{-1}");
67 let mut bytes = Y.to_repr();
68 bytes[31] |= sign.unwrap_u8() << 7;
69
70 decompress_point(bytes).expect("point from hash-to-curve wasn't on-curve").mul_by_cofactor()
71}