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}