1use crate::account_address::AccountAddress;
9use anyhow::{bail, ensure, Error, Result};
10use diem_crypto::{
11 bls::{
12 BLSPublicKey, BLSPublicKeyUnchecked, BLSSignature,
13 BLSSignatureUnchecked,
14 },
15 hash::CryptoHash,
16 multi_bls::MultiBLSSignature,
17 traits::Signature,
18 CryptoMaterialError, HashValue, ValidCryptoMaterial,
19 ValidCryptoMaterialStringExt,
20};
21use diem_crypto_derive::{CryptoHasher, DeserializeKey, SerializeKey};
22#[cfg(any(test, feature = "fuzzing"))]
23use proptest_derive::Arbitrary;
24use rand::{rngs::OsRng, Rng};
25use serde::{Deserialize, Serialize};
26use std::{convert::TryFrom, fmt, str::FromStr};
27
28#[derive(Debug)]
47#[repr(u8)]
48#[non_exhaustive]
49pub enum Scheme {
50 ReservedEd25519 = 0,
52 ReservedMultiEd25519 = 1,
54 BLS = 2,
55 MultiBLS = 3,
56 }
58
59impl fmt::Display for Scheme {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 let display = match self {
62 Scheme::ReservedEd25519 => "reserved_ed25519",
63 Scheme::ReservedMultiEd25519 => "reserved_multi_ed25519",
64 Scheme::BLS => "bls",
65 Scheme::MultiBLS => "multi_bls",
66 };
67 write!(f, "Scheme::{}", display)
68 }
69}
70
71#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
72pub enum TransactionAuthenticator {
73 _ReservedEd25519,
76 _ReservedMultiEd25519,
79 BLS {
81 public_key: BLSPublicKey,
82 signature: BLSSignature,
83 },
84 MultiBLS {
85 signature: MultiBLSSignature,
86 }, }
88
89#[derive(Deserialize)]
90pub enum TransactionAuthenticatorUnchecked {
91 _ReservedEd25519,
94 _ReservedMultiEd25519,
97 BLS {
98 public_key: BLSPublicKeyUnchecked,
99 signature: BLSSignatureUnchecked,
100 },
101 MultiBLS {
102 signature: MultiBLSSignature,
103 },
104}
105
106impl From<TransactionAuthenticatorUnchecked> for TransactionAuthenticator {
107 fn from(t: TransactionAuthenticatorUnchecked) -> Self {
108 match t {
109 TransactionAuthenticatorUnchecked::_ReservedEd25519 => {
110 Self::_ReservedEd25519
111 }
112 TransactionAuthenticatorUnchecked::_ReservedMultiEd25519 => {
113 Self::_ReservedMultiEd25519
114 }
115 TransactionAuthenticatorUnchecked::BLS {
116 public_key,
117 signature,
118 } => Self::BLS {
119 public_key: public_key.into(),
120 signature: signature.into(),
121 },
122 TransactionAuthenticatorUnchecked::MultiBLS { signature } => {
123 Self::MultiBLS { signature }
124 }
125 }
126 }
127}
128
129impl TransactionAuthenticator {
130 pub fn scheme(&self) -> Scheme {
132 match self {
133 Self::_ReservedEd25519 => Scheme::ReservedEd25519,
134 Self::_ReservedMultiEd25519 => Scheme::ReservedMultiEd25519,
135 Self::BLS { .. } => Scheme::BLS,
136 Self::MultiBLS { .. } => Scheme::MultiBLS,
137 }
138 }
139
140 pub fn bls(public_key: BLSPublicKey, signature: BLSSignature) -> Self {
141 Self::BLS {
142 public_key,
143 signature,
144 }
145 }
146
147 pub fn multi_bls(signature: MultiBLSSignature) -> Self {
148 Self::MultiBLS { signature }
149 }
150
151 pub fn verify<T: Serialize + CryptoHash>(&self, message: &T) -> Result<()> {
155 match self {
156 Self::_ReservedEd25519 | Self::_ReservedMultiEd25519 => {
157 bail!("reserved authenticator variant has no signature")
158 }
159 Self::BLS {
160 public_key,
161 signature,
162 } => signature.verify(message, public_key),
163 Self::MultiBLS { .. } => {
164 Ok(())
166 }
167 }
168 }
169
170 pub fn public_key_bytes(&self) -> Vec<u8> {
174 match self {
175 Self::_ReservedEd25519 | Self::_ReservedMultiEd25519 => Vec::new(),
176 Self::BLS { public_key, .. } => public_key.to_bytes().to_vec(),
177 Self::MultiBLS { .. } => Vec::new(),
178 }
179 }
180
181 pub fn signature_bytes(&self) -> Vec<u8> {
183 match self {
184 Self::_ReservedEd25519 | Self::_ReservedMultiEd25519 => Vec::new(),
185 Self::BLS { signature, .. } => signature.to_bytes().to_vec(),
186 Self::MultiBLS { signature } => signature.to_bytes(),
187 }
188 }
189
190 pub fn authentication_key_preimage(&self) -> AuthenticationKeyPreimage {
193 AuthenticationKeyPreimage::new(self.public_key_bytes(), self.scheme())
194 }
195
196 pub fn authentication_key(&self) -> AuthenticationKey {
199 AuthenticationKey::from_preimage(&self.authentication_key_preimage())
200 }
201}
202
203#[derive(
206 Clone,
207 Copy,
208 CryptoHasher,
209 Debug,
210 DeserializeKey,
211 Eq,
212 Hash,
213 Ord,
214 PartialEq,
215 PartialOrd,
216 SerializeKey,
217)]
218#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
219pub struct AuthenticationKey([u8; AuthenticationKey::LENGTH]);
220
221impl AuthenticationKey {
222 pub const LENGTH: usize = 32;
224
225 pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { Self(bytes) }
227
228 pub fn from_preimage(
230 preimage: &AuthenticationKeyPreimage,
231 ) -> AuthenticationKey {
232 AuthenticationKey::new(*HashValue::sha3_256_of(&preimage.0).as_ref())
233 }
234
235 pub fn derived_address(&self) -> AccountAddress {
238 let mut array = [0u8; AccountAddress::LENGTH];
240 array.copy_from_slice(&self.0[Self::LENGTH - AccountAddress::LENGTH..]);
241 AccountAddress::new(array)
242 }
243
244 pub fn prefix(&self) -> [u8; AccountAddress::LENGTH] {
246 let mut array = [0u8; AccountAddress::LENGTH];
247 array.copy_from_slice(&self.0[..AccountAddress::LENGTH]);
248 array
249 }
250
251 pub fn to_vec(&self) -> Vec<u8> { self.0.to_vec() }
253
254 pub fn random() -> Self {
256 let mut rng = OsRng;
257 let buf: [u8; Self::LENGTH] = rng.gen();
258 AuthenticationKey::new(buf)
259 }
260}
261
262impl ValidCryptoMaterial for AuthenticationKey {
263 fn to_bytes(&self) -> Vec<u8> { self.to_vec() }
264}
265
266pub struct AuthenticationKeyPreimage(Vec<u8>);
268
269impl AuthenticationKeyPreimage {
270 fn new(mut public_key_bytes: Vec<u8>, scheme: Scheme) -> Self {
272 public_key_bytes.push(scheme as u8);
273 Self(public_key_bytes)
274 }
275
276 pub fn into_vec(self) -> Vec<u8> { self.0 }
278}
279
280impl fmt::Display for TransactionAuthenticator {
281 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282 write!(
283 f,
284 "TransactionAuthenticator[scheme id: {:?}, public key: {}, signature: {}]",
285 self.scheme(),
286 hex::encode(&self.public_key_bytes()),
287 hex::encode(&self.signature_bytes())
288 )
289 }
290}
291
292impl TryFrom<&[u8]> for AuthenticationKey {
293 type Error = CryptoMaterialError;
294
295 fn try_from(
296 bytes: &[u8],
297 ) -> std::result::Result<AuthenticationKey, CryptoMaterialError> {
298 if bytes.len() != Self::LENGTH {
299 return Err(CryptoMaterialError::WrongLengthError);
300 }
301 let mut addr = [0u8; Self::LENGTH];
302 addr.copy_from_slice(bytes);
303 Ok(AuthenticationKey(addr))
304 }
305}
306
307impl TryFrom<Vec<u8>> for AuthenticationKey {
308 type Error = CryptoMaterialError;
309
310 fn try_from(
311 bytes: Vec<u8>,
312 ) -> std::result::Result<AuthenticationKey, CryptoMaterialError> {
313 AuthenticationKey::try_from(&bytes[..])
314 }
315}
316
317impl FromStr for AuthenticationKey {
318 type Err = Error;
319
320 fn from_str(s: &str) -> Result<Self> {
321 ensure!(
322 !s.is_empty(),
323 "authentication key string should not be empty.",
324 );
325 let bytes_out = ::hex::decode(s)?;
326 let key = AuthenticationKey::try_from(bytes_out.as_slice())?;
327 Ok(key)
328 }
329}
330
331impl AsRef<[u8]> for AuthenticationKey {
332 fn as_ref(&self) -> &[u8] { &self.0 }
333}
334
335impl fmt::LowerHex for AuthenticationKey {
336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337 write!(f, "{}", hex::encode(&self.0))
338 }
339}
340
341impl fmt::Display for AuthenticationKey {
342 fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
343 write!(f, "{:#x}", self)
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use super::{Scheme, TransactionAuthenticator};
351 use crate::{
352 account_address::AccountAddress,
353 transaction::{
354 authenticator::AuthenticationKey, RawTransaction, RetirePayload,
355 },
356 };
357 use std::str::FromStr;
358
359 #[test]
360 fn test_from_str_should_not_panic_by_given_empty_string() {
361 assert!(AuthenticationKey::from_str("").is_err());
362 }
363
364 #[test]
368 fn reserved_authenticator_verify_returns_err_not_panic() {
369 let raw_txn = RawTransaction::new_retire(
370 AccountAddress::ZERO,
371 RetirePayload {
372 node_id: AccountAddress::ZERO,
373 votes: 0,
374 },
375 );
376
377 for auth in [
378 TransactionAuthenticator::_ReservedEd25519,
379 TransactionAuthenticator::_ReservedMultiEd25519,
380 ] {
381 let err = auth.verify(&raw_txn).unwrap_err();
382 assert!(
383 err.to_string().contains("reserved"),
384 "expected 'reserved' in error, got: {}",
385 err,
386 );
387 }
388 }
389
390 #[test]
391 fn reserved_authenticator_accessors_are_panic_free() {
392 let auth_a = TransactionAuthenticator::_ReservedEd25519;
393 let auth_b = TransactionAuthenticator::_ReservedMultiEd25519;
394
395 assert!(matches!(auth_a.scheme(), Scheme::ReservedEd25519));
397 assert!(matches!(auth_b.scheme(), Scheme::ReservedMultiEd25519));
398 assert_ne!(auth_a.scheme() as u8, auth_b.scheme() as u8);
399 assert!(auth_a.public_key_bytes().is_empty());
400 assert!(auth_a.signature_bytes().is_empty());
401 assert!(auth_b.public_key_bytes().is_empty());
402 assert!(auth_b.signature_bytes().is_empty());
403 }
404}