threshold_bls/hash/
try_and_increment.rs1use super::{hasher::Hasher, HashToCurve};
2use crate::curve::BLSError;
3use ark_ec::models::{
4 short_weierstrass_jacobian::{GroupAffine, GroupProjective},
5 SWModelParameters,
6};
7use ark_ff::{Field, PrimeField, Zero};
8use ethers_core::utils::hex;
9use log::debug;
10use std::marker::PhantomData;
11
12const NUM_TRIES: u8 = 255;
13
14#[derive(Clone)]
16pub struct TryAndIncrement<'a, H, P> {
17 hasher: &'a H,
18 curve_params: PhantomData<P>,
19}
20
21impl<'a, H, P> TryAndIncrement<'a, H, P>
22where
23 H: Hasher<Error = BLSError>,
24 P: SWModelParameters,
25{
26 pub fn new(h: &'a H) -> Self {
29 TryAndIncrement {
30 hasher: h,
31 curve_params: PhantomData,
32 }
33 }
34}
35
36impl<'a, H, P> HashToCurve for TryAndIncrement<'a, H, P>
37where
38 H: Hasher<Error = BLSError>,
39 P: SWModelParameters,
40{
41 type Output = GroupProjective<P>;
42
43 fn hash(&self, domain: &[u8], message: &[u8]) -> Result<Self::Output, BLSError> {
44 self.hash_with_attempt(domain, message).map(|res| res.0)
45 }
46}
47
48impl<'a, H, P> TryAndIncrement<'a, H, P>
49where
50 H: Hasher<Error = BLSError>,
51 P: SWModelParameters,
52{
53 pub fn hash_with_attempt(
54 &self,
55 domain: &[u8],
56 message: &[u8],
57 ) -> Result<(GroupProjective<P>, usize), BLSError> {
58 let mut candidate_hash = self.hasher.hash(domain, message)?;
59
60 for c in 0..NUM_TRIES {
61 let xfield = if P::BaseField::extension_degree() == 1 {
62 let f = <P::BaseField as Field>::BasePrimeField::from_be_bytes_mod_order(
64 &candidate_hash,
65 );
66 P::BaseField::from_base_prime_field_elems(&[f])
67 } else {
68 P::BaseField::from_random_bytes(&candidate_hash)
69 };
70
71 if let Some(x) = xfield {
72 if let Some(p) = GroupAffine::get_point_from_x(x, false) {
73 debug!(
74 "succeeded hashing \"{}\" to curve in {} tries",
75 hex::encode(message),
76 c + 1
77 );
78
79 let scaled = p.scale_by_cofactor();
80 if scaled.is_zero() {
81 continue;
82 }
83 return Ok((scaled, (c + 1) as usize));
84 }
85 }
86
87 candidate_hash = self.hasher.hash(domain, &candidate_hash)?;
88 }
89
90 Err(BLSError::HashToCurveError)
91 }
92}