elliptic_curve/hash2curve/
group_digest.rs

1//! Traits for handling hash to curve.
2
3use super::{hash_to_field, ExpandMsg, FromOkm, MapToCurve};
4use crate::{CurveArithmetic, ProjectivePoint, Result};
5use group::cofactor::CofactorGroup;
6
7/// Adds hashing arbitrary byte sequences to a valid group element
8pub trait GroupDigest: CurveArithmetic
9where
10    ProjectivePoint<Self>: CofactorGroup,
11{
12    /// The field element representation for a group value with multiple elements
13    type FieldElement: FromOkm + MapToCurve<Output = ProjectivePoint<Self>> + Default + Copy;
14
15    /// Computes the hash to curve routine.
16    ///
17    /// From <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html>:
18    ///
19    /// > Uniform encoding from byte strings to points in G.
20    /// > That is, the distribution of its output is statistically close
21    /// > to uniform in G.
22    /// > This function is suitable for most applications requiring a random
23    /// > oracle returning points in G assuming a cryptographically secure
24    /// > hash function is used.
25    ///
26    /// # Examples
27    ///
28    /// ## Using a fixed size hash function
29    ///
30    /// ```ignore
31    /// let pt = ProjectivePoint::hash_from_bytes::<ExpandMsgXmd<sha2::Sha256>>(b"test data", b"CURVE_XMD:SHA-256_SSWU_RO_");
32    /// ```
33    ///
34    /// ## Using an extendable output function
35    ///
36    /// ```ignore
37    /// let pt = ProjectivePoint::hash_from_bytes::<ExpandMsgXof<sha3::Shake256>>(b"test data", b"CURVE_XOF:SHAKE-256_SSWU_RO_");
38    /// ```
39    ///
40    /// # Errors
41    /// See implementors of [`ExpandMsg`] for errors:
42    /// - [`ExpandMsgXmd`]
43    /// - [`ExpandMsgXof`]
44    ///
45    /// `len_in_bytes = <Self::FieldElement as FromOkm>::Length * 2`
46    ///
47    /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd
48    /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof
49    fn hash_from_bytes<'a, X: ExpandMsg<'a>>(
50        msgs: &[&[u8]],
51        dsts: &'a [&'a [u8]],
52    ) -> Result<ProjectivePoint<Self>> {
53        let mut u = [Self::FieldElement::default(), Self::FieldElement::default()];
54        hash_to_field::<X, _>(msgs, dsts, &mut u)?;
55        let q0 = u[0].map_to_curve();
56        let q1 = u[1].map_to_curve();
57        // Ideally we could add and then clear cofactor once
58        // thus saving a call but the field elements may not
59        // add properly due to the underlying implementation
60        // which could result in an incorrect subgroup.
61        // This is caused curve coefficients being different than
62        // what is usually implemented.
63        // FieldElement expects the `a` and `b` to be the original values
64        // isogenies are different with curves like k256 and bls12-381.
65        // This problem doesn't manifest for curves with no isogeny like p256.
66        // For k256 and p256 clear_cofactor doesn't do anything anyway so it will be a no-op.
67        Ok(q0.clear_cofactor().into() + q1.clear_cofactor())
68    }
69
70    /// Computes the encode to curve routine.
71    ///
72    /// From <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html>:
73    ///
74    /// > Nonuniform encoding from byte strings to
75    /// > points in G. That is, the distribution of its output is not
76    /// > uniformly random in G: the set of possible outputs of
77    /// > encode_to_curve is only a fraction of the points in G, and some
78    /// > points in this set are more likely to be output than others.
79    ///
80    /// # Errors
81    /// See implementors of [`ExpandMsg`] for errors:
82    /// - [`ExpandMsgXmd`]
83    /// - [`ExpandMsgXof`]
84    ///
85    /// `len_in_bytes = <Self::FieldElement as FromOkm>::Length`
86    ///
87    /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd
88    /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof
89    fn encode_from_bytes<'a, X: ExpandMsg<'a>>(
90        msgs: &[&[u8]],
91        dsts: &'a [&'a [u8]],
92    ) -> Result<ProjectivePoint<Self>> {
93        let mut u = [Self::FieldElement::default()];
94        hash_to_field::<X, _>(msgs, dsts, &mut u)?;
95        let q0 = u[0].map_to_curve();
96        Ok(q0.clear_cofactor().into())
97    }
98
99    /// Computes the hash to field routine according to
100    /// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5>
101    /// and returns a scalar.
102    ///
103    /// # Errors
104    /// See implementors of [`ExpandMsg`] for errors:
105    /// - [`ExpandMsgXmd`]
106    /// - [`ExpandMsgXof`]
107    ///
108    /// `len_in_bytes = <Self::Scalar as FromOkm>::Length`
109    ///
110    /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd
111    /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof
112    fn hash_to_scalar<'a, X: ExpandMsg<'a>>(
113        msgs: &[&[u8]],
114        dsts: &'a [&'a [u8]],
115    ) -> Result<Self::Scalar>
116    where
117        Self::Scalar: FromOkm,
118    {
119        let mut u = [Self::Scalar::default()];
120        hash_to_field::<X, _>(msgs, dsts, &mut u)?;
121        Ok(u[0])
122    }
123}