Skip to main content

hash2curve/
group_digest.rs

1//! Traits for handling hash to curve.
2
3use super::{ExpandMsg, MapToCurve, hash_to_field};
4use elliptic_curve::ProjectivePoint;
5use elliptic_curve::array::typenum::NonZero;
6use elliptic_curve::array::{Array, ArraySize};
7use elliptic_curve::group::cofactor::CofactorGroup;
8use elliptic_curve::ops::Reduce;
9
10/// Hash arbitrary byte sequences to a valid group element.
11pub trait GroupDigest: MapToCurve {
12    /// Suite ID for the [hash to curve routine](Self::hash_from_bytes).
13    const HASH_TO_CURVE_ID: &[u8];
14    /// Suite ID for the  [encode to curve routine](Self::encode_from_bytes).
15    const ENCODE_TO_CURVE_ID: &[u8];
16
17    /// The `expand_message` function to use.
18    type ExpandMsg: ExpandMsg<Self::SecurityLevel>;
19
20    /// Computes the hash to curve routine, with message equal to the concatenation of the elements
21    /// in `msg`, and domain separator equal to the concatenation of the elements in `dst`.
22    ///
23    /// From <https://www.rfc-editor.org/rfc/rfc9380.html>:
24    ///
25    /// > Uniform encoding from byte strings to points in G.
26    /// > That is, the distribution of its output is statistically close
27    /// > to uniform in G.
28    /// > This function is suitable for most applications requiring a random
29    /// > oracle returning points in G assuming a cryptographically secure
30    /// > hash function is used.
31    ///
32    /// # Errors
33    ///
34    /// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
35    /// and [`ExpandMsgXofError`] for examples.
36    ///
37    /// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
38    /// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
39    fn hash_from_bytes(
40        msg: &[&[u8]],
41        dst: &[&[u8]],
42    ) -> Result<ProjectivePoint<Self>, <Self::ExpandMsg as ExpandMsg<Self::SecurityLevel>>::Error>
43    {
44        hash_from_bytes::<Self, Self::ExpandMsg>(msg, dst)
45    }
46
47    /// Computes the encode to curve routine, with message equal to the concatenation of the elements
48    /// in `msg`, and domain separator equal to the concatenation of the elements in `dst`.
49    ///
50    /// From <https://www.rfc-editor.org/rfc/rfc9380.html>:
51    ///
52    /// > Nonuniform encoding from byte strings to
53    /// > points in G. That is, the distribution of its output is not
54    /// > uniformly random in G: the set of possible outputs of
55    /// > encode_to_curve is only a fraction of the points in G, and some
56    /// > points in this set are more likely to be output than others.
57    ///
58    /// # Errors
59    ///
60    /// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
61    /// and [`ExpandMsgXofError`] for examples.
62    ///
63    /// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
64    /// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
65    fn encode_from_bytes(
66        msg: &[&[u8]],
67        dst: &[&[u8]],
68    ) -> Result<ProjectivePoint<Self>, <Self::ExpandMsg as ExpandMsg<Self::SecurityLevel>>::Error>
69    {
70        encode_from_bytes::<Self, Self::ExpandMsg>(msg, dst)
71    }
72}
73
74/// Computes the hash to curve routine.
75/// See [`GroupDigest::hash_from_bytes()`] for more details.
76///
77/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length * 2`.
78/// This value must be less than `u16::MAX` or otherwise a compiler error will occur.
79///
80/// # Errors
81///
82/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
83/// and [`ExpandMsgXofError`] for examples.
84///
85/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
86/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
87pub fn hash_from_bytes<C, X>(msg: &[&[u8]], dst: &[&[u8]]) -> Result<ProjectivePoint<C>, X::Error>
88where
89    C: MapToCurve,
90    X: ExpandMsg<C::SecurityLevel>,
91{
92    let [u0, u1] = hash_to_field::<2, X, _, C::FieldElement, C::Length>(msg, dst)?;
93    let q0 = C::map_to_curve(u0);
94    let q1 = C::map_to_curve(u1);
95    Ok((q0 + q1).clear_cofactor())
96}
97
98/// Computes the encode to curve routine.
99/// See [`GroupDigest::encode_from_bytes()`] for more details.
100///
101/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length`.
102///
103/// # Errors
104///
105/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
106/// and [`ExpandMsgXofError`] for examples.
107///
108/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
109/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
110pub fn encode_from_bytes<C, X>(msg: &[&[u8]], dst: &[&[u8]]) -> Result<ProjectivePoint<C>, X::Error>
111where
112    C: MapToCurve,
113    X: ExpandMsg<C::SecurityLevel>,
114{
115    let [u] = hash_to_field::<1, X, _, C::FieldElement, C::Length>(msg, dst)?;
116    let q0 = C::map_to_curve(u);
117    Ok(q0.clear_cofactor())
118}
119
120/// Computes the hash to field routine according to
121/// <https://www.rfc-editor.org/rfc/rfc9380.html#section-5-4>
122/// and returns a scalar.
123///   
124/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length`.
125/// This value must be less than `u16::MAX` or otherwise a compiler error will occur.
126///
127/// # Errors
128///
129/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
130/// and [`ExpandMsgXofError`] for examples.
131///
132/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
133/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
134pub fn hash_to_scalar<C, X, L>(msg: &[&[u8]], dst: &[&[u8]]) -> Result<C::Scalar, X::Error>
135where
136    C: MapToCurve,
137    X: ExpandMsg<C::SecurityLevel>,
138    L: ArraySize + NonZero,
139    C::Scalar: Reduce<Array<u8, L>>,
140{
141    let [u] = hash_to_field::<1, X, _, C::Scalar, L>(msg, dst)?;
142    Ok(u)
143}