halo2curves_axiom/bls12_381/hash_to_curve/
mod.rs

1//! This module implements hash_to_curve, hash_to_field and related
2//! hashing primitives for use with BLS signatures.
3//!
4//! Source: <https://github.com/privacy-scaling-explorations/bls12_381>
5
6use core::ops::Add;
7
8use subtle::Choice;
9
10pub(crate) mod chain;
11
12mod expand_msg;
13pub use self::expand_msg::{
14    ExpandMessage, ExpandMessageState, ExpandMsgXmd, ExpandMsgXof, InitExpandMessage,
15};
16
17mod map_g1;
18mod map_g2;
19mod map_scalar;
20
21use crate::bls12_381::generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
22
23/// Enables a byte string to be hashed into one or more field elements for a given curve.
24///
25/// Implements [section 5 of `draft-irtf-cfrg-hash-to-curve-12`][hash_to_field].
26///
27/// [hash_to_field]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-5
28pub trait HashToField: Sized {
29    /// The length of the data used to produce an individual field element.
30    ///
31    /// This must be set to `m * L = m * ceil((ceil(log2(p)) + k) / 8)`, where `p` is the
32    /// characteristic of `Self`, `m` is the extension degree of `Self`, and `k` is the
33    /// security parameter.
34    type InputLength: ArrayLength<u8>;
35
36    /// Interprets the given output keying material as a big endian integer, and reduces
37    /// it into a field element.
38    fn from_okm(okm: &GenericArray<u8, Self::InputLength>) -> Self;
39
40    /// Hashes a byte string of arbitrary length into one or more elements of `Self`,
41    /// using [`ExpandMessage`] variant `X`.
42    ///
43    /// Implements [section 5.3 of `draft-irtf-cfrg-hash-to-curve-12`][hash_to_field].
44    ///
45    /// [hash_to_field]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-5.3
46    fn hash_to_field<X: ExpandMessage>(message: &[u8], dst: &[u8], output: &mut [Self]) {
47        let len_per_elm = Self::InputLength::to_usize();
48        let len_in_bytes = output.len() * len_per_elm;
49        let mut expander = X::init_expand(message, dst, len_in_bytes);
50
51        let mut buf = GenericArray::<u8, Self::InputLength>::default();
52        output.iter_mut().for_each(|item| {
53            expander.read_into(&mut buf[..]);
54            *item = Self::from_okm(&buf);
55        });
56    }
57}
58
59/// Allow conversion from the output of hashed or encoded input into points on the curve
60pub trait MapToCurve: Sized {
61    /// The field element type.
62    type Field: Copy + Default + HashToField;
63
64    /// Maps an element of the finite field `Self::Field` to a point on the curve `Self`.
65    fn map_to_curve(elt: &Self::Field) -> Self;
66
67    /// Clears the cofactor, sending a point on curve E to the target group (G1/G2).
68    fn clear_h(&self) -> Self;
69}
70
71/// Implementation of random oracle maps to the curve.
72pub trait HashToCurve<X: ExpandMessage>: MapToCurve + for<'a> Add<&'a Self, Output = Self> {
73    /// Implements a uniform encoding from byte strings to elements of `Self`.
74    ///
75    /// This function is suitable for most applications requiring a random
76    /// oracle returning points in `Self`.
77    fn hash_to_curve(message: impl AsRef<[u8]>, dst: &[u8]) -> Self {
78        let mut u = [Self::Field::default(); 2];
79        Self::Field::hash_to_field::<X>(message.as_ref(), dst, &mut u);
80        let p1 = Self::map_to_curve(&u[0]);
81        let p2 = Self::map_to_curve(&u[1]);
82        (p1 + &p2).clear_h()
83    }
84
85    /// Implements a **non-uniform** encoding from byte strings to elements of `Self`.
86    ///
87    /// The distribution of its output is not uniformly random in `Self`: the set of
88    /// possible outputs of this function is only a fraction of the points in `Self`, and
89    /// some elements of this set are more likely to be output than others. See
90    /// [section 10.1 of `draft-irtf-cfrg-hash-to-curve-12`][encode_to_curve-distribution]
91    /// for a more precise definition of `encode_to_curve`'s output distribution.
92    ///
93    /// [encode_to_curve-distribution]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-10.1
94    fn encode_to_curve(message: impl AsRef<[u8]>, dst: &[u8]) -> Self {
95        let mut u = [Self::Field::default(); 1];
96        Self::Field::hash_to_field::<X>(message.as_ref(), dst, &mut u);
97        let p = Self::map_to_curve(&u[0]);
98        p.clear_h()
99    }
100}
101
102impl<G, X> HashToCurve<X> for G
103where
104    G: MapToCurve + for<'a> Add<&'a Self, Output = Self>,
105    X: ExpandMessage,
106{
107}
108
109pub(crate) trait Sgn0 {
110    /// Returns either 0 or 1 indicating the "sign" of x, where sgn0(x) == 1
111    /// just when x is "negative". (In other words, this function always considers 0 to be positive.)
112    /// <https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-4.1>
113    /// The equivalent for draft 6 would be `lexicographically_largest`.
114    fn sgn0(&self) -> Choice;
115}