pairing_plus/
hash_to_field.rs

1/*!
2 This module implements hash_to_field and related hashing primitives
3 for use with BLS signatures.
4*/
5
6use digest::generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
7use digest::{BlockInput, Digest, ExtendableOutput, Input};
8use std::marker::PhantomData;
9
10/// hash_to_field for type T using ExpandMsg variant X
11pub fn hash_to_field<T, X>(msg: &[u8], dst: &[u8], count: usize) -> Vec<T>
12where
13    T: FromRO,
14    X: ExpandMsg,
15{
16    let len_per_elm = <T as FromRO>::Length::to_usize();
17    let len_in_bytes = count * len_per_elm;
18    let pseudo_random_bytes = X::expand_message(msg, dst, len_in_bytes);
19
20    let mut ret = Vec::<T>::with_capacity(count);
21    for idx in 0..count {
22        let bytes_to_convert = &pseudo_random_bytes[idx * len_per_elm..(idx + 1) * len_per_elm];
23        let bytes_arr = GenericArray::<u8, <T as FromRO>::Length>::from_slice(bytes_to_convert);
24        ret.push(T::from_ro(bytes_arr));
25    }
26
27    ret
28}
29
30/// Generate a field element from a random string of bytes
31pub trait FromRO {
32    type Length: ArrayLength<u8>;
33
34    fn from_ro(okm: &GenericArray<u8, <Self as FromRO>::Length>) -> Self;
35}
36
37/// BaseFromRO is a FromRO impl for a field with extension degree 1.
38impl<T: BaseFromRO> FromRO for T {
39    type Length = <T as BaseFromRO>::BaseLength;
40
41    fn from_ro(okm: &GenericArray<u8, <Self as FromRO>::Length>) -> T {
42        T::from_okm(okm)
43    }
44}
45
46/// Generate an element of a base field for a random string of bytes
47/// (used by FromRO for extension fields).
48pub trait BaseFromRO {
49    type BaseLength: ArrayLength<u8>;
50
51    fn from_okm(okm: &GenericArray<u8, <Self as BaseFromRO>::BaseLength>) -> Self;
52}
53
54/// Trait for types implementing expand_message interface for hash_to_field
55pub trait ExpandMsg {
56    fn expand_message(msg: &[u8], dst: &[u8], len_in_bytes: usize) -> Vec<u8>;
57}
58
59/// Placeholder type for implementing expand_message_xof based on a hash function
60#[derive(Debug)]
61pub struct ExpandMsgXof<HashT> {
62    phantom: PhantomData<HashT>,
63}
64
65/// ExpandMsgXof implements expand_message_xof for the ExpandMsg trait
66impl<HashT> ExpandMsg for ExpandMsgXof<HashT>
67where
68    HashT: Default + ExtendableOutput + Input,
69{
70    fn expand_message(msg: &[u8], dst: &[u8], len_in_bytes: usize) -> Vec<u8> {
71        HashT::default()
72            .chain(msg)
73            .chain([
74                (len_in_bytes >> 8) as u8,
75                len_in_bytes as u8,
76            ])
77            .chain(dst)
78            .chain([dst.len() as u8])
79            .vec_result(len_in_bytes)
80    }
81}
82
83/// Placeholder type for implementing expand_message_xmd based on a hash function
84#[derive(Debug)]
85pub struct ExpandMsgXmd<HashT> {
86    phantom: PhantomData<HashT>,
87}
88
89/// ExpandMsgXmd implements expand_message_xmd for the ExpandMsg trait
90impl<HashT> ExpandMsg for ExpandMsgXmd<HashT>
91where
92    HashT: Digest + BlockInput,
93{
94    fn expand_message(msg: &[u8], dst: &[u8], len_in_bytes: usize) -> Vec<u8> {
95        let b_in_bytes = <HashT as Digest>::OutputSize::to_usize();
96        let ell = (len_in_bytes + b_in_bytes - 1) / b_in_bytes;
97        if ell > 255 {
98            panic!("ell was too big in expand_message_xmd");
99        }
100        let b_0 = HashT::new()
101            .chain(GenericArray::<u8, <HashT as BlockInput>::BlockSize>::default())
102            .chain(msg)
103            .chain([
104                (len_in_bytes >> 8) as u8,
105                len_in_bytes as u8,
106                0u8,
107            ])
108            .chain(dst)
109            .chain([dst.len() as u8])
110            .result();
111
112        let mut b_vals = Vec::<u8>::with_capacity(ell * b_in_bytes);
113        // b_1
114        b_vals.extend_from_slice(
115            HashT::new()
116                .chain(&b_0[..])
117                .chain([1u8])
118                .chain(dst)
119                .chain([dst.len() as u8])
120                .result()
121                .as_ref(),
122        );
123
124        for idx in 1..ell {
125            // b_0 XOR b_(idx - 1)
126            let mut tmp = GenericArray::<u8, <HashT as Digest>::OutputSize>::default();
127            b_0.iter()
128                .zip(&b_vals[(idx - 1) * b_in_bytes..idx * b_in_bytes])
129                .enumerate()
130                .for_each(|(jdx, (b0val, bi1val))| tmp[jdx] = b0val ^ bi1val);
131            b_vals.extend_from_slice(
132                HashT::new()
133                    .chain(tmp)
134                    .chain([(idx + 1) as u8])
135                    .chain(dst)
136                    .chain([dst.len() as u8])
137                    .result()
138                    .as_ref(),
139            );
140        }
141
142        b_vals.truncate(len_in_bytes);
143        b_vals
144    }
145}