bee_signing/ternary/wots/
mod.rs1mod normalize;
8mod shake;
9mod sponge;
10
11pub use normalize::{normalize, Error as NormalizeError};
12pub use shake::{WotsShakePrivateKeyGenerator, WotsShakePrivateKeyGeneratorBuilder};
13pub use sponge::{WotsSpongePrivateKeyGenerator, WotsSpongePrivateKeyGeneratorBuilder};
14
15use crate::ternary::{PrivateKey, PublicKey, RecoverableSignature, Signature, SIGNATURE_FRAGMENT_LENGTH};
16
17use bee_common_derive::{SecretDebug, SecretDisplay, SecretDrop};
18use bee_crypto::ternary::{sponge::Sponge, HASH_LENGTH};
19use bee_ternary::{T1B1Buf, TritBuf, Trits, Tryte, T1B1};
20
21use thiserror::Error;
22use zeroize::Zeroize;
23
24use std::{
25 fmt::{self, Display, Formatter},
26 marker::PhantomData,
27};
28
29#[derive(Debug, Error, PartialEq)]
31pub enum Error {
32 #[error("Missing security level in generator.")]
34 MissingSecurityLevel,
35 #[error("Failed sponge operation.")]
37 FailedSpongeOperation,
38 #[error("Invalid entropy length, should be 243 trits, was {0}.")]
40 InvalidEntropyLength(usize),
41 #[error("Invalid message length, should be 243 trits, was {0}.")]
43 InvalidMessageLength(usize),
44 #[error("Invalid public key length, should be 243 trits, was {0}.")]
46 InvalidPublicKeyLength(usize),
47 #[error("Invalid signature length, should be a multiple of 6561 trits, was {0}.")]
49 InvalidSignatureLength(usize),
50 #[error("Last trit of the entropy is not null.")]
52 NonNullEntropyLastTrit,
53}
54
55#[derive(Clone, Copy)]
57#[repr(u8)]
58pub enum WotsSecurityLevel {
59 Low = 1,
61 Medium = 2,
63 High = 3,
65}
66
67impl Default for WotsSecurityLevel {
68 fn default() -> Self {
69 WotsSecurityLevel::Medium
70 }
71}
72
73#[derive(SecretDebug, SecretDisplay, SecretDrop)]
75pub struct WotsPrivateKey<S> {
76 pub(crate) state: TritBuf<T1B1Buf>,
77 pub(crate) marker: PhantomData<S>,
78}
79
80impl<S> Zeroize for WotsPrivateKey<S> {
81 fn zeroize(&mut self) {
82 unsafe { self.state.as_i8_slice_mut().zeroize() }
84 }
85}
86
87impl<S: Sponge + Default> PrivateKey for WotsPrivateKey<S> {
88 type PublicKey = WotsPublicKey<S>;
89 type Signature = WotsSignature<S>;
90 type Error = Error;
91
92 fn generate_public_key(&self) -> Result<Self::PublicKey, Self::Error> {
93 let mut sponge = S::default();
94 let mut hashed_private_key = self.state.clone();
95 let security = self.state.len() / SIGNATURE_FRAGMENT_LENGTH;
96 let mut digests = TritBuf::<T1B1Buf>::zeros(security * HASH_LENGTH);
97 let mut public_key_state = TritBuf::<T1B1Buf>::zeros(HASH_LENGTH);
98
99 for chunk in hashed_private_key.chunks_mut(HASH_LENGTH) {
101 for _ in 0..Tryte::MAX_VALUE as i8 - Tryte::MIN_VALUE as i8 {
102 sponge
103 .absorb(chunk)
104 .and_then(|_| sponge.squeeze_into(chunk))
105 .map_err(|_| Self::Error::FailedSpongeOperation)?;
106 sponge.reset();
107 }
108 }
109
110 for (i, chunk) in hashed_private_key.chunks(SIGNATURE_FRAGMENT_LENGTH).enumerate() {
112 sponge
113 .digest_into(chunk, &mut digests[i * HASH_LENGTH..(i + 1) * HASH_LENGTH])
114 .map_err(|_| Self::Error::FailedSpongeOperation)?;
115 }
116
117 sponge
119 .digest_into(&digests, &mut public_key_state)
120 .map_err(|_| Self::Error::FailedSpongeOperation)?;
121
122 Ok(Self::PublicKey {
123 state: public_key_state,
124 marker: PhantomData,
125 })
126 }
127
128 fn sign(&mut self, message: &Trits<T1B1>) -> Result<Self::Signature, Self::Error> {
129 if message.len() != HASH_LENGTH {
130 return Err(Error::InvalidMessageLength(message.len()));
131 }
132
133 let mut sponge = S::default();
134 let mut signature = self.state.clone();
135
136 for (i, chunk) in signature.chunks_mut(HASH_LENGTH).enumerate() {
137 let val = i8::try_from(&message[i * 3..i * 3 + 3]).unwrap();
139
140 for _ in 0..(Tryte::MAX_VALUE as i8 - val) {
142 sponge
143 .absorb(chunk)
144 .and_then(|_| sponge.squeeze_into(chunk))
145 .map_err(|_| Self::Error::FailedSpongeOperation)?;
146 sponge.reset();
147 }
148 }
149
150 Ok(Self::Signature {
151 state: signature,
152 marker: PhantomData,
153 })
154 }
155}
156
157impl<S: Sponge + Default> WotsPrivateKey<S> {
158 pub fn as_trits(&self) -> &Trits<T1B1> {
160 &self.state
161 }
162}
163
164pub struct WotsPublicKey<S> {
166 state: TritBuf<T1B1Buf>,
167 marker: PhantomData<S>,
168}
169
170impl<S: Sponge + Default> PublicKey for WotsPublicKey<S> {
171 type Signature = WotsSignature<S>;
172 type Error = Error;
173
174 fn verify(&self, message: &Trits<T1B1>, signature: &Self::Signature) -> Result<bool, Self::Error> {
175 Ok(signature.recover_public_key(message)?.state == self.state)
176 }
177
178 fn size(&self) -> usize {
179 self.state.len()
180 }
181
182 fn from_trits(state: TritBuf<T1B1Buf>) -> Result<Self, Self::Error> {
183 if state.len() != HASH_LENGTH {
184 return Err(Error::InvalidPublicKeyLength(state.len()));
185 }
186
187 Ok(Self {
188 state,
189 marker: PhantomData,
190 })
191 }
192
193 fn as_trits(&self) -> &Trits<T1B1> {
194 &self.state
195 }
196}
197
198impl<S: Sponge + Default> Display for WotsPublicKey<S> {
199 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
200 write!(
201 f,
202 "{}",
203 self.as_trits().iter_trytes().map(char::from).collect::<String>()
204 )
205 }
206}
207
208pub struct WotsSignature<S> {
210 state: TritBuf<T1B1Buf>,
211 marker: PhantomData<S>,
212}
213
214impl<S: Sponge + Default> Signature for WotsSignature<S> {
215 type Error = Error;
216
217 fn size(&self) -> usize {
218 self.state.len()
219 }
220
221 fn from_trits(state: TritBuf<T1B1Buf>) -> Result<Self, Self::Error> {
222 if state.len() % SIGNATURE_FRAGMENT_LENGTH != 0 {
223 return Err(Error::InvalidSignatureLength(state.len()));
224 }
225
226 Ok(Self {
227 state,
228 marker: PhantomData,
229 })
230 }
231
232 fn as_trits(&self) -> &Trits<T1B1> {
233 &self.state
234 }
235}
236
237impl<S: Sponge + Default> RecoverableSignature for WotsSignature<S> {
238 type PublicKey = WotsPublicKey<S>;
239 type Error = Error;
240
241 fn recover_public_key(
242 &self,
243 message: &Trits<T1B1>,
244 ) -> Result<Self::PublicKey, <Self as RecoverableSignature>::Error> {
245 if message.len() != HASH_LENGTH {
246 return Err(Error::InvalidMessageLength(message.len()));
247 }
248
249 let mut sponge = S::default();
250 let mut public_key_state = TritBuf::<T1B1Buf>::zeros(HASH_LENGTH);
251 let security = self.state.len() / SIGNATURE_FRAGMENT_LENGTH;
252 let mut digests = TritBuf::<T1B1Buf>::zeros(security * HASH_LENGTH);
253 let mut hashed_signature = self.state.clone();
254
255 for (i, chunk) in hashed_signature.chunks_mut(HASH_LENGTH).enumerate() {
256 let val = i8::try_from(&message[i * 3..i * 3 + 3]).unwrap();
258
259 for _ in 0..(val - Tryte::MIN_VALUE as i8) {
261 sponge
262 .absorb(chunk)
263 .and_then(|_| sponge.squeeze_into(chunk))
264 .map_err(|_| <Self as RecoverableSignature>::Error::FailedSpongeOperation)?;
265 sponge.reset();
266 }
267 }
268
269 for (i, chunk) in hashed_signature.chunks(SIGNATURE_FRAGMENT_LENGTH).enumerate() {
271 sponge
272 .digest_into(chunk, &mut digests[i * HASH_LENGTH..(i + 1) * HASH_LENGTH])
273 .map_err(|_| <Self as RecoverableSignature>::Error::FailedSpongeOperation)?;
274 }
275
276 sponge
278 .digest_into(&digests, &mut public_key_state)
279 .map_err(|_| <Self as RecoverableSignature>::Error::FailedSpongeOperation)?;
280
281 Ok(Self::PublicKey {
282 state: public_key_state,
283 marker: PhantomData,
284 })
285 }
286}
287
288impl<S: Sponge + Default> Display for WotsSignature<S> {
289 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
290 write!(
291 f,
292 "{}",
293 self.as_trits().iter_trytes().map(char::from).collect::<String>()
294 )
295 }
296}