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}