sapling_crypto/
group_hash.rs

1//! Implementation of [group hashing into Jubjub][grouphash].
2//!
3//! [grouphash]: https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub
4
5use ff::PrimeField;
6use group::{cofactor::CofactorGroup, Group, GroupEncoding};
7
8use super::constants;
9use blake2s_simd::Params;
10
11/// Produces a random point in the Jubjub curve.
12/// The point is guaranteed to be prime order
13/// and not the identity.
14#[allow(clippy::assertions_on_constants)]
15pub fn group_hash(tag: &[u8], personalization: &[u8]) -> Option<jubjub::SubgroupPoint> {
16    assert_eq!(personalization.len(), 8);
17
18    // Check to see that scalar field is 255 bits
19    assert!(bls12_381::Scalar::NUM_BITS == 255);
20
21    let h = Params::new()
22        .hash_length(32)
23        .personal(personalization)
24        .to_state()
25        .update(constants::GH_FIRST_BLOCK)
26        .update(tag)
27        .finalize();
28
29    let p = jubjub::ExtendedPoint::from_bytes(h.as_array());
30    if p.is_some().into() {
31        // <ExtendedPoint as CofactorGroup>::clear_cofactor is implemented using
32        // ExtendedPoint::mul_by_cofactor in the jubjub crate.
33        let p = CofactorGroup::clear_cofactor(&p.unwrap());
34
35        if p.is_identity().into() {
36            None
37        } else {
38            Some(p)
39        }
40    } else {
41        None
42    }
43}