Skip to main content

ark_ec/hashing/
map_to_curve_hasher.rs

1use crate::{
2    hashing::{HashToCurve, HashToCurveError},
3    AffineRepr, CurveGroup,
4};
5use ark_ff::field_hashers::HashToField;
6use ark_std::marker::PhantomData;
7
8/// Trait for mapping a random field element to a random curve point.
9pub trait MapToCurve<T: CurveGroup>: Sized {
10    /// Checks whether supplied parameters represent a valid map.
11    fn check_parameters() -> Result<(), HashToCurveError>;
12
13    /// Map an arbitrary field element to a corresponding curve point.
14    fn map_to_curve(point: T::BaseField) -> Result<T::Affine, HashToCurveError>;
15}
16
17/// A helper struct used to construct elements on an elliptic curve
18/// from arbitrary messages.
19///
20/// The process works in two stages:
21///
22/// 1. First, the message is hashed into a field element.
23/// 2. Then, the resulting field element is mapped to the elliptic curve
24///    defined over that field.
25pub struct MapToCurveBasedHasher<T, H2F, M2C>
26where
27    T: CurveGroup,
28    H2F: HashToField<T::BaseField>,
29    M2C: MapToCurve<T>,
30{
31    field_hasher: H2F,
32    _phantom: PhantomData<(T, M2C)>,
33}
34
35impl<T, H2F, M2C> HashToCurve<T> for MapToCurveBasedHasher<T, H2F, M2C>
36where
37    T: CurveGroup,
38    H2F: HashToField<T::BaseField>,
39    M2C: MapToCurve<T>,
40{
41    fn new(domain: &[u8]) -> Result<Self, HashToCurveError> {
42        #[cfg(test)]
43        M2C::check_parameters()?;
44        Ok(Self {
45            field_hasher: H2F::new(domain),
46            _phantom: PhantomData,
47        })
48    }
49
50    /// Produce a hash of the message, using the hash to field and map to curve
51    /// traits. This uses the IETF hash to curve's specification for Random
52    /// oracle encoding (hash_to_curve) defined by combining these components.
53    /// See <https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-09#section-3>
54    fn hash(&self, msg: &[u8]) -> Result<T::Affine, HashToCurveError> {
55        // IETF spec of hash_to_curve, from hash_to_field and map_to_curve
56        // sub-components
57        // 1. u = hash_to_field(msg, 2)
58        // 2. Q0 = map_to_curve(u[0])
59        // 3. Q1 = map_to_curve(u[1])
60        // 4. R = Q0 + Q1              # Point addition
61        // 5. P = clear_cofactor(R)
62        // 6. return P
63
64        let rand_field_elems = self.field_hasher.hash_to_field::<2>(msg);
65
66        let rand_curve_elem_0 = M2C::map_to_curve(rand_field_elems[0])?;
67        let rand_curve_elem_1 = M2C::map_to_curve(rand_field_elems[1])?;
68
69        let rand_curve_elem = (rand_curve_elem_0 + rand_curve_elem_1).into();
70        let rand_subgroup_elem = rand_curve_elem.clear_cofactor();
71
72        Ok(rand_subgroup_elem)
73    }
74}