]> git.proxmox.com Git - rustc.git/blob - vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / elliptic-curve / src / hash2curve / hash2field / expand_msg.rs
1 //! `expand_message` interface `for hash_to_field`.
2
3 pub(super) mod xmd;
4 pub(super) mod xof;
5
6 use crate::{Error, Result};
7 use digest::{Digest, ExtendableOutput, Update, XofReader};
8 use generic_array::typenum::{IsLess, U256};
9 use generic_array::{ArrayLength, GenericArray};
10
11 /// Salt when the DST is too long
12 const OVERSIZE_DST_SALT: &[u8] = b"H2C-OVERSIZE-DST-";
13 /// Maximum domain separation tag length
14 const MAX_DST_LEN: usize = 255;
15
16 /// Trait for types implementing expand_message interface for `hash_to_field`.
17 ///
18 /// # Errors
19 /// See implementors of [`ExpandMsg`] for errors.
20 pub trait ExpandMsg<'a> {
21 /// Type holding data for the [`Expander`].
22 type Expander: Expander + Sized;
23
24 /// Expands `msg` to the required number of bytes.
25 ///
26 /// Returns an expander that can be used to call `read` until enough
27 /// bytes have been consumed
28 fn expand_message(msgs: &[&[u8]], dst: &'a [u8], len_in_bytes: usize)
29 -> Result<Self::Expander>;
30 }
31
32 /// Expander that, call `read` until enough bytes have been consumed.
33 pub trait Expander {
34 /// Fill the array with the expanded bytes
35 fn fill_bytes(&mut self, okm: &mut [u8]);
36 }
37
38 /// The domain separation tag
39 ///
40 /// Implements [section 5.4.3 of `draft-irtf-cfrg-hash-to-curve-13`][dst].
41 ///
42 /// [dst]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-13#section-5.4.3
43 pub(crate) enum Domain<'a, L>
44 where
45 L: ArrayLength<u8> + IsLess<U256>,
46 {
47 /// > 255
48 Hashed(GenericArray<u8, L>),
49 /// <= 255
50 Array(&'a [u8]),
51 }
52
53 impl<'a, L> Domain<'a, L>
54 where
55 L: ArrayLength<u8> + IsLess<U256>,
56 {
57 pub fn xof<X>(dst: &'a [u8]) -> Result<Self>
58 where
59 X: Default + ExtendableOutput + Update,
60 {
61 if dst.is_empty() {
62 Err(Error)
63 } else if dst.len() > MAX_DST_LEN {
64 let mut data = GenericArray::<u8, L>::default();
65 X::default()
66 .chain(OVERSIZE_DST_SALT)
67 .chain(dst)
68 .finalize_xof()
69 .read(&mut data);
70 Ok(Self::Hashed(data))
71 } else {
72 Ok(Self::Array(dst))
73 }
74 }
75
76 pub fn xmd<X>(dst: &'a [u8]) -> Result<Self>
77 where
78 X: Digest<OutputSize = L>,
79 {
80 if dst.is_empty() {
81 Err(Error)
82 } else if dst.len() > MAX_DST_LEN {
83 Ok(Self::Hashed({
84 let mut hash = X::new();
85 hash.update(OVERSIZE_DST_SALT);
86 hash.update(dst);
87 hash.finalize()
88 }))
89 } else {
90 Ok(Self::Array(dst))
91 }
92 }
93
94 pub fn data(&self) -> &[u8] {
95 match self {
96 Self::Hashed(d) => &d[..],
97 Self::Array(d) => *d,
98 }
99 }
100
101 pub fn len(&self) -> u8 {
102 match self {
103 // Can't overflow because it's enforced on a type level.
104 Self::Hashed(_) => L::to_u8(),
105 // Can't overflow because it's checked on creation.
106 Self::Array(d) => u8::try_from(d.len()).expect("length overflow"),
107 }
108 }
109
110 #[cfg(test)]
111 pub fn assert(&self, bytes: &[u8]) {
112 assert_eq!(self.data(), &bytes[..bytes.len() - 1]);
113 assert_eq!(self.len(), bytes[bytes.len() - 1]);
114 }
115 }