libecvrf/
hash.rs

1use k256::{
2    elliptic_curve::{ff::PrimeField, group::GroupEncoding, sec1::FromEncodedPoint},
3    AffinePoint, EncodedPoint, ProjectivePoint, Scalar,
4};
5use tiny_keccak::{Hasher, Keccak};
6
7/// Try to generate a point on the curve based on hashes
8pub fn new_candidate_point(b: &[u8]) -> AffinePoint {
9    // X is a digest of field
10    let x = field_hash(b);
11    // Y is a coordinate point, corresponding to x
12    let mut y = y_squared(&x).square();
13
14    if y.is_odd().unwrap_u8() == 1 {
15        y = y.negate();
16    }
17
18    let x_bytes = x.to_bytes();
19    let y_bytes = y.to_bytes();
20    let encoded_point = EncodedPoint::from_affine_coordinates(&x_bytes, &y_bytes, false);
21
22    AffinePoint::from_encoded_point(&encoded_point).unwrap()
23}
24
25/// Hash bytes array to a field
26pub fn field_hash(b: &[u8]) -> Scalar {
27    let mut output = [0u8; 32];
28    let mut hasher = Keccak::v256();
29    hasher.update(b);
30    hasher.finalize(&mut output);
31
32    Scalar::from_repr(output.into()).unwrap()
33}
34
35/// Y squared, it was calculate by evaluate X
36pub fn y_squared(x: &Scalar) -> Scalar {
37    let t = *x;
38    // y^2 = x^3 + 7
39    t * t * t + Scalar::from_u128(7)
40}
41
42/// Hash to curve with prefix
43/// HASH_TO_CURVE_HASH_PREFIX = 1
44pub fn hash_to_curve_prefix(alpha: &Scalar, pk: &AffinePoint) -> AffinePoint {
45    let packed = [
46        // HASH_TO_CURVE_HASH_PREFIX = 1
47        Scalar::from_u128(1).to_bytes().as_slice(),
48        // pk
49        pk.to_bytes().as_slice(),
50        // seed
51        alpha.to_bytes().as_slice(),
52    ]
53    .concat();
54
55    new_candidate_point(&packed)
56}
57
58/// Hash point to Scalar
59pub fn hash_points(
60    g: &AffinePoint,
61    h: &AffinePoint,
62    pk: &AffinePoint,
63    gamma: &AffinePoint,
64    kg: &AffinePoint,
65    kh: &AffinePoint,
66) -> Scalar {
67    let mut output = [0u8; 32];
68    let mut hasher = Keccak::v256();
69    let all_points = [g, h, pk, gamma, kg, kh];
70    for point in all_points {
71        hasher.update(point.to_bytes().as_ref());
72    }
73    hasher.finalize(&mut output);
74    Scalar::from_repr(output.into()).unwrap()
75}
76
77/// Hash points with prefix
78/// SCALAR_FROM_CURVE_POINTS_HASH_PREFIX = 2
79pub fn hash_points_prefix(
80    hash: &AffinePoint,
81    pk: &AffinePoint,
82    gamma: &AffinePoint,
83    u_witness: &Scalar,
84    v: &AffinePoint,
85) -> Scalar {
86    let mut output = [0u8; 32];
87    let mut hasher = Keccak::v256();
88    let all_points = [hash, pk, gamma, v];
89    // SCALAR_FROM_CURVE_POINTS_HASH_PREFIX = 2
90    hasher.update(Scalar::from_u128(2).to_bytes().as_slice());
91    for point in all_points {
92        hasher.update(point.to_bytes().as_ref());
93    }
94    hasher.update(u_witness.to_bytes().as_ref());
95    hasher.finalize(&mut output);
96    Scalar::from_repr(output.into()).unwrap()
97}
98
99/// Hash to curve
100pub fn hash_to_curve(alpha: &Scalar, y: Option<&AffinePoint>) -> AffinePoint {
101    let mut r = ProjectivePoint::GENERATOR * alpha;
102
103    if let Some(y) = y {
104        r += ProjectivePoint::from(*y);
105    }
106
107    r.to_affine()
108}