Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_iop_hash/src/api.rs

4.4 KiB, 9 runs

created by r1870400018:413, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use oxedyne_fe2o3_core::{
2 prelude::*,
3 alt::Gnomon,
4};
5use oxedyne_fe2o3_namex::id::InNamex;
6
7use std::fmt;
8
9
10/// Most hash implementations seem to be multi-step. Hashing in one go allows us to include the
11/// identity transformation as a no-operation option. They are also self-consuming, so we have to
12/// respect that.
13pub trait Hasher:
14 Clone
15 + std::fmt::Debug
16 + InNamex
17 + Send
18 + Sync
19{
20 fn hash<const S: usize>(self, input: &[&[u8]], salt: [u8; S]) -> Hash<S>;
21 /// The a priori length. The identity hash length is the input length, but we don't know
22 /// that before seeing the input.
23 fn hash_length(&self) -> Gnomon<usize>;
24 fn is_identity(&self) -> bool;
25}
26
27/// The empty hasher should just return the input.
28impl Hasher for () {
29 fn hash<const S: usize>(self, input: &[&[u8]], _salt: [u8; S]) -> Hash<S> {
30 let len = input.iter().map(|slice| slice.len()).sum();
31 let mut result = Vec::with_capacity(len);
32
33 for slice in input {
34 result.extend_from_slice(slice);
35 }
36
37 Hash::new(HashForm::Identity(result), [0u8; S])
38 }
39 fn hash_length(&self) -> Gnomon<usize> { Gnomon::Unknown }
40 fn is_identity(&self) -> bool { true }
41}
42
43#[derive(Clone)]
44pub struct Hash<
45 const S: usize,
46> {
47 form: HashForm,
48 salt: [u8; S],
49}
50
51impl<
52 const S: usize,
53>
54 fmt::Debug for Hash<S>
55{
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 write!(f, "Hash{{form: {:?}, salt: {:02x?}}}", self.form, self.salt)
58 }
59}
60
61impl<
62 const S: usize,
63>
64 Hash<S>
65{
66 pub fn new(form: HashForm, salt: [u8; S]) -> Self {
67 Self {
68 form,
69 salt,
70 }
71 }
72
73 pub fn as_hashform(self) -> HashForm { self.form }
74
75 pub fn as_vec(self) -> Vec<u8> {
76 let salt_clone = self.salt.clone();
77 let mut result = self.form.as_vec();
78 result.extend_from_slice(&salt_clone);
79 result
80 }
81}
82
83/// A way to represent a hash result using more efficient primitives, when possible.
84#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
85pub enum HashForm {
86 Identity(Vec<u8>), // Output = Input
87 U32(u32),
88 U64(u64),
89 U128(u128),
90 Bytes32([u8; 32]),
91 Bytes(Vec<u8>),
92}
93
94impl fmt::Debug for HashForm {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 match self {
97 Self::Identity(v) |
98 Self::Bytes(v) => write!(f, "{:02x?}", v),
99 Self::Bytes32(a32) => write!(f, "{:02x?}", a32),
100 Self::U128(nu128) => write!(f, "0x{:032x?}", nu128),
101 Self::U64(nu64) => write!(f, "0x{:016x?}", nu64),
102 Self::U32(nu32) => write!(f, "0x{:08x?}", nu32),
103 }
104 }
105}
106
107impl HashForm {
108 /// A priori length of hash when encoded to bytes.
109 pub fn len(&self) -> Gnomon<usize> {
110 match self {
111 Self::Identity(_) => Gnomon::Unknown,
112 Self::Bytes(v) => Gnomon::Known(v.len()),
113 Self::Bytes32(_) => Gnomon::Known(32),
114 Self::U128(_) => Gnomon::Known(16),
115 Self::U64(_) => Gnomon::Known(8),
116 Self::U32(_) => Gnomon::Known(4),
117 }
118 }
119
120 /// Consuming conversion to byte vector.
121 pub fn as_vec(self) -> Vec<u8> {
122 match self {
123 Self::Identity(v) |
124 Self::Bytes(v) => v,
125 Self::Bytes32(a32) => a32.to_vec(),
126 Self::U128(n128) => n128.to_be_bytes().to_vec(),
127 Self::U64(n64) => n64.to_be_bytes().to_vec(),
128 Self::U32(n32) => n32.to_be_bytes().to_vec(),
129 }
130 }
131
132 /// Truncates the byte encoded form of itself to a `u32`, except when there are not enough
133 /// bytes.
134 pub fn to_u32(&self) -> Outcome<u32> {
135 match self {
136 Self::Identity(v) | Self::Bytes(v) => {
137 if v.len() < 4 {
138 return Err(err!(
139 "With only {} bytes, the HashForm has too few to create \
140 a u32 (4).", v.len();
141 TooSmall, Conversion));
142 }
143 Ok(u32::from_be_bytes(res!(<[u8; 4]>::try_from(&v[..4]), Decode, Bytes)))
144 },
145 Self::Bytes32(a32) => Ok(u32::from_be_bytes(res!(<[u8; 4]>::try_from(&a32[..4]), Decode, Bytes))),
146 Self::U128(nu128) => Ok(*nu128 as u32),
147 Self::U64(nu64) => Ok(*nu64 as u32),
148 Self::U32(nu32) => Ok(*nu32),
149 }
150 }
151}