1use std::{borrow::Cow, fmt, io, num::ParseIntError, str::FromStr};
8
9use ed25519_dalek::{self as dalek, Signer, Verifier};
10use generic_array::typenum::Unsigned;
11use linera_witty::{
12 GuestPointer, HList, InstanceWithMemory, Layout, Memory, Runtime, RuntimeError, RuntimeMemory,
13 WitLoad, WitStore, WitType,
14};
15use serde::{Deserialize, Serialize};
16use thiserror::Error;
17#[cfg(with_testing)]
18use {
19 proptest::{
20 collection::{vec, VecStrategy},
21 prelude::Arbitrary,
22 strategy::{self, Strategy},
23 },
24 std::ops::RangeInclusive,
25};
26
27use crate::doc_scalar;
28
29pub struct KeyPair(dalek::SigningKey);
31
32#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash)]
34pub struct PublicKey(pub [u8; dalek::PUBLIC_KEY_LENGTH]);
35
36type HasherOutputSize = <sha3::Sha3_256 as sha3::digest::OutputSizeUser>::OutputSize;
37type HasherOutput = generic_array::GenericArray<u8, HasherOutputSize>;
38
39#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash)]
41#[cfg_attr(with_testing, derive(Default))]
42pub struct CryptoHash(HasherOutput);
43
44#[derive(Eq, PartialEq, Copy, Clone)]
46pub struct Signature(pub dalek::Signature);
47
48#[derive(Error, Debug)]
50#[allow(missing_docs)]
51pub enum CryptoError {
52 #[error("Signature for object {type_name} is not valid: {error}")]
53 InvalidSignature { error: String, type_name: String },
54 #[error("Signature for object {type_name} is missing")]
55 MissingSignature { type_name: String },
56 #[error("String contains non-hexadecimal digits")]
57 NonHexDigits(#[from] hex::FromHexError),
58 #[error(
59 "Byte slice has length {0} but a `CryptoHash` requires exactly {expected} bytes",
60 expected = HasherOutputSize::to_usize(),
61 )]
62 IncorrectHashSize(usize),
63 #[error(
64 "Byte slice has length {0} but a `PublicKey` requires exactly {expected} bytes",
65 expected = dalek::PUBLIC_KEY_LENGTH,
66 )]
67 IncorrectPublicKeySize(usize),
68 #[error("Could not parse integer")]
69 ParseIntError(#[from] ParseIntError),
70}
71
72impl PublicKey {
73 #[cfg(with_testing)]
75 pub fn test_key(name: u8) -> PublicKey {
76 let addr = [name; dalek::PUBLIC_KEY_LENGTH];
77 PublicKey(addr)
78 }
79}
80
81#[cfg(with_getrandom)]
82pub trait CryptoRng: rand::CryptoRng + rand::RngCore + Send + Sync {}
84
85#[cfg(with_getrandom)]
86impl<T: rand::CryptoRng + rand::RngCore + Send + Sync> CryptoRng for T {}
87
88#[cfg(with_getrandom)]
89impl From<Option<u64>> for Box<dyn CryptoRng> {
90 fn from(seed: Option<u64>) -> Self {
91 use rand::SeedableRng;
92
93 match seed {
94 Some(seed) => Box::new(rand::rngs::StdRng::seed_from_u64(seed)),
95 None => Box::new(rand::rngs::OsRng),
96 }
97 }
98}
99
100impl KeyPair {
101 #[cfg(all(with_getrandom, with_testing))]
102 pub fn generate() -> Self {
104 let mut rng = rand::rngs::OsRng;
105 Self::generate_from(&mut rng)
106 }
107
108 #[cfg(with_getrandom)]
109 pub fn generate_from<R: CryptoRng>(rng: &mut R) -> Self {
111 let keypair = dalek::SigningKey::generate(rng);
112 KeyPair(keypair)
113 }
114
115 pub fn public(&self) -> PublicKey {
117 PublicKey(self.0.verifying_key().to_bytes())
118 }
119
120 pub fn copy(&self) -> KeyPair {
125 KeyPair(self.0.clone())
126 }
127}
128
129impl Serialize for PublicKey {
130 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
131 where
132 S: serde::ser::Serializer,
133 {
134 if serializer.is_human_readable() {
135 serializer.serialize_str(&self.to_string())
136 } else {
137 serializer.serialize_newtype_struct("PublicKey", &self.0)
138 }
139 }
140}
141
142impl<'de> Deserialize<'de> for PublicKey {
143 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144 where
145 D: serde::de::Deserializer<'de>,
146 {
147 if deserializer.is_human_readable() {
148 let s = String::deserialize(deserializer)?;
149 let value = Self::from_str(&s).map_err(serde::de::Error::custom)?;
150 Ok(value)
151 } else {
152 #[derive(Deserialize)]
153 #[serde(rename = "PublicKey")]
154 struct Foo([u8; dalek::PUBLIC_KEY_LENGTH]);
155
156 let value = Foo::deserialize(deserializer)?;
157 Ok(Self(value.0))
158 }
159 }
160}
161
162impl Serialize for CryptoHash {
163 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
164 where
165 S: serde::ser::Serializer,
166 {
167 if serializer.is_human_readable() {
168 serializer.serialize_str(&self.to_string())
169 } else {
170 serializer.serialize_newtype_struct("CryptoHash", &self.0)
171 }
172 }
173}
174
175impl<'de> Deserialize<'de> for CryptoHash {
176 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
177 where
178 D: serde::de::Deserializer<'de>,
179 {
180 if deserializer.is_human_readable() {
181 let s = String::deserialize(deserializer)?;
182 let value = Self::from_str(&s).map_err(serde::de::Error::custom)?;
183 Ok(value)
184 } else {
185 #[derive(Deserialize)]
186 #[serde(rename = "CryptoHash")]
187 struct Foo(HasherOutput);
188
189 let value = Foo::deserialize(deserializer)?;
190 Ok(Self(value.0))
191 }
192 }
193}
194
195impl Serialize for KeyPair {
196 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
197 where
198 S: serde::ser::Serializer,
199 {
200 assert!(serializer.is_human_readable());
202 serializer.serialize_str(&hex::encode(self.0.to_bytes()))
203 }
204}
205
206impl<'de> Deserialize<'de> for KeyPair {
207 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
208 where
209 D: serde::de::Deserializer<'de>,
210 {
211 assert!(deserializer.is_human_readable());
213 let s = String::deserialize(deserializer)?;
214 let value = hex::decode(s).map_err(serde::de::Error::custom)?;
215 let key =
216 dalek::SigningKey::from_bytes(value[..].try_into().map_err(serde::de::Error::custom)?);
217 Ok(KeyPair(key))
218 }
219}
220
221impl Serialize for Signature {
222 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
223 where
224 S: serde::ser::Serializer,
225 {
226 if serializer.is_human_readable() {
227 serializer.serialize_str(&hex::encode(self.0.to_bytes()))
228 } else {
229 serializer.serialize_newtype_struct("Signature", &self.0)
230 }
231 }
232}
233
234impl<'de> Deserialize<'de> for Signature {
235 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
236 where
237 D: serde::de::Deserializer<'de>,
238 {
239 if deserializer.is_human_readable() {
240 let s = String::deserialize(deserializer)?;
241 let value = hex::decode(s).map_err(serde::de::Error::custom)?;
242 let sig =
243 dalek::Signature::try_from(value.as_slice()).map_err(serde::de::Error::custom)?;
244 Ok(Signature(sig))
245 } else {
246 #[derive(Deserialize)]
247 #[serde(rename = "Signature")]
248 struct Foo(dalek::Signature);
249
250 let value = Foo::deserialize(deserializer)?;
251 Ok(Self(value.0))
252 }
253 }
254}
255
256impl FromStr for PublicKey {
257 type Err = CryptoError;
258
259 fn from_str(s: &str) -> Result<Self, Self::Err> {
260 let value = hex::decode(s)?;
261 (value.as_slice()).try_into()
262 }
263}
264
265impl TryFrom<&[u8]> for PublicKey {
266 type Error = CryptoError;
267
268 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
269 if value.len() != dalek::PUBLIC_KEY_LENGTH {
270 return Err(CryptoError::IncorrectPublicKeySize(value.len()));
271 }
272 let mut pubkey = [0u8; dalek::PUBLIC_KEY_LENGTH];
273 pubkey.copy_from_slice(value);
274 Ok(PublicKey(pubkey))
275 }
276}
277
278impl From<[u64; 4]> for PublicKey {
279 fn from(integers: [u64; 4]) -> Self {
280 PublicKey(u64_array_to_le_bytes(integers))
281 }
282}
283
284impl From<PublicKey> for [u64; 4] {
285 fn from(pub_key: PublicKey) -> Self {
286 le_bytes_to_u64_array(&pub_key.0)
287 }
288}
289
290impl FromStr for CryptoHash {
291 type Err = CryptoError;
292
293 fn from_str(s: &str) -> Result<Self, Self::Err> {
294 let value = hex::decode(s)?;
295 (value.as_slice()).try_into()
296 }
297}
298
299impl TryFrom<&[u8]> for CryptoHash {
300 type Error = CryptoError;
301
302 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
303 if value.len() != HasherOutputSize::to_usize() {
304 return Err(CryptoError::IncorrectHashSize(value.len()));
305 }
306 let mut bytes = HasherOutput::default();
307 bytes.copy_from_slice(value);
308 Ok(Self(bytes))
309 }
310}
311
312impl From<[u64; 4]> for CryptoHash {
313 fn from(integers: [u64; 4]) -> Self {
314 CryptoHash(u64_array_to_le_bytes(integers).into())
315 }
316}
317
318impl From<CryptoHash> for [u64; 4] {
319 fn from(crypto_hash: CryptoHash) -> Self {
320 le_bytes_to_u64_array(&crypto_hash.0)
321 }
322}
323
324impl fmt::Display for Signature {
325 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 let s = hex::encode(self.0.to_bytes());
327 write!(f, "{}", s)
328 }
329}
330
331impl fmt::Display for PublicKey {
332 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333 write!(f, "{}", hex::encode(&self.0[..]))
334 }
335}
336
337impl fmt::Display for CryptoHash {
338 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
339 let prec = f.precision().unwrap_or(self.0.len() * 2);
340 hex::encode(&self.0[..((prec + 1) / 2)]).fmt(f)
341 }
342}
343
344impl fmt::Debug for Signature {
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 write!(f, "{}", hex::encode(&self.0.to_bytes()[0..8]))
347 }
348}
349
350impl fmt::Debug for PublicKey {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 write!(f, "{}", hex::encode(&self.0[..8]))
353 }
354}
355
356impl fmt::Debug for CryptoHash {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 write!(f, "{}", hex::encode(&self.0[..8]))
359 }
360}
361
362pub trait Hashable<Hasher> {
364 fn write(&self, hasher: &mut Hasher);
366}
367
368pub trait HasTypeName {
370 fn type_name() -> &'static str;
372}
373
374pub trait BcsHashable: Serialize + serde::de::DeserializeOwned {}
378
379pub trait BcsSignable: Serialize + serde::de::DeserializeOwned {}
383
384impl<T: BcsSignable> BcsHashable for T {}
385
386impl<T, Hasher> Hashable<Hasher> for T
387where
388 T: BcsHashable,
389 Hasher: io::Write,
390{
391 fn write(&self, hasher: &mut Hasher) {
392 let name = <Self as HasTypeName>::type_name();
393 write!(hasher, "{}::", name).expect("Hasher should not fail");
395 bcs::serialize_into(hasher, &self).expect("Message serialization should not fail");
396 }
397}
398
399impl<Hasher> Hashable<Hasher> for [u8]
400where
401 Hasher: io::Write,
402{
403 fn write(&self, hasher: &mut Hasher) {
404 hasher.write_all(self).expect("Hasher should not fail");
405 }
406}
407
408impl<T> HasTypeName for T
409where
410 T: BcsHashable,
411{
412 fn type_name() -> &'static str {
413 serde_name::trace_name::<Self>().expect("Self must be a struct or an enum")
414 }
415}
416
417impl CryptoHash {
418 pub fn new<T: BcsHashable>(value: &T) -> Self {
420 use sha3::digest::Digest;
421
422 let mut hasher = sha3::Sha3_256::default();
423 value.write(&mut hasher);
424 CryptoHash(hasher.finalize())
425 }
426
427 pub fn as_bytes(&self) -> &HasherOutput {
429 &self.0
430 }
431
432 #[cfg(with_testing)]
434 pub fn test_hash(s: impl Into<String>) -> Self {
435 CryptoHash::new(&TestString::new(s))
436 }
437}
438
439impl Signature {
440 pub fn new<T>(value: &T, secret: &KeyPair) -> Self
442 where
443 T: BcsSignable,
444 {
445 let mut message = Vec::new();
446 value.write(&mut message);
447 let signature = secret.0.sign(&message);
448 Signature(signature)
449 }
450
451 fn check_internal<T>(&self, value: &T, author: PublicKey) -> Result<(), dalek::SignatureError>
452 where
453 T: BcsSignable,
454 {
455 let mut message = Vec::new();
456 value.write(&mut message);
457 let public_key = dalek::VerifyingKey::from_bytes(&author.0)?;
458 public_key.verify(&message, &self.0)
459 }
460
461 pub fn check<T>(&self, value: &T, author: PublicKey) -> Result<(), CryptoError>
463 where
464 T: BcsSignable + fmt::Debug,
465 {
466 self.check_internal(value, author)
467 .map_err(|error| CryptoError::InvalidSignature {
468 error: error.to_string(),
469 type_name: T::type_name().to_string(),
470 })
471 }
472
473 pub fn check_optional_signature<T>(
475 signature: Option<&Self>,
476 value: &T,
477 author: &PublicKey,
478 ) -> Result<(), CryptoError>
479 where
480 T: BcsSignable + fmt::Debug,
481 {
482 match signature {
483 Some(sig) => sig.check(value, *author),
484 None => Err(CryptoError::MissingSignature {
485 type_name: T::type_name().to_string(),
486 }),
487 }
488 }
489
490 fn verify_batch_internal<'a, T, I>(value: &'a T, votes: I) -> Result<(), dalek::SignatureError>
491 where
492 T: BcsSignable,
493 I: IntoIterator<Item = (&'a PublicKey, &'a Signature)>,
494 {
495 let mut msg = Vec::new();
496 value.write(&mut msg);
497 let mut messages = Vec::new();
498 let mut signatures = Vec::new();
499 let mut public_keys = Vec::new();
500 for (addr, sig) in votes.into_iter() {
501 messages.push(msg.as_slice());
502 signatures.push(sig.0);
503 public_keys.push(dalek::VerifyingKey::from_bytes(&addr.0)?);
504 }
505 dalek::verify_batch(&messages[..], &signatures[..], &public_keys[..])
506 }
507
508 pub fn verify_batch<'a, T, I>(value: &'a T, votes: I) -> Result<(), CryptoError>
510 where
511 T: BcsSignable,
512 I: IntoIterator<Item = (&'a PublicKey, &'a Signature)>,
513 {
514 Signature::verify_batch_internal(value, votes).map_err(|error| {
515 CryptoError::InvalidSignature {
516 error: format!("batched {}", error),
517 type_name: T::type_name().to_string(),
518 }
519 })
520 }
521}
522
523impl WitType for CryptoHash {
524 const SIZE: u32 = <(u64, u64, u64, u64) as WitType>::SIZE;
525 type Layout = <(u64, u64, u64, u64) as WitType>::Layout;
526 type Dependencies = HList![];
527
528 fn wit_type_name() -> Cow<'static, str> {
529 "crypto-hash".into()
530 }
531
532 fn wit_type_declaration() -> Cow<'static, str> {
533 concat!(
534 " record crypto-hash {\n",
535 " part1: u64,\n",
536 " part2: u64,\n",
537 " part3: u64,\n",
538 " part4: u64,\n",
539 " }\n",
540 )
541 .into()
542 }
543}
544
545impl WitLoad for CryptoHash {
546 fn load<Instance>(
547 memory: &Memory<'_, Instance>,
548 location: GuestPointer,
549 ) -> Result<Self, RuntimeError>
550 where
551 Instance: InstanceWithMemory,
552 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
553 {
554 let (part1, part2, part3, part4) = WitLoad::load(memory, location)?;
555 Ok(CryptoHash::from([part1, part2, part3, part4]))
556 }
557
558 fn lift_from<Instance>(
559 flat_layout: <Self::Layout as Layout>::Flat,
560 memory: &Memory<'_, Instance>,
561 ) -> Result<Self, RuntimeError>
562 where
563 Instance: InstanceWithMemory,
564 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
565 {
566 let (part1, part2, part3, part4) = WitLoad::lift_from(flat_layout, memory)?;
567 Ok(CryptoHash::from([part1, part2, part3, part4]))
568 }
569}
570
571impl WitStore for CryptoHash {
572 fn store<Instance>(
573 &self,
574 memory: &mut Memory<'_, Instance>,
575 location: GuestPointer,
576 ) -> Result<(), RuntimeError>
577 where
578 Instance: InstanceWithMemory,
579 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
580 {
581 let [part1, part2, part3, part4] = (*self).into();
582 (part1, part2, part3, part4).store(memory, location)
583 }
584
585 fn lower<Instance>(
586 &self,
587 memory: &mut Memory<'_, Instance>,
588 ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
589 where
590 Instance: InstanceWithMemory,
591 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
592 {
593 let [part1, part2, part3, part4] = (*self).into();
594 (part1, part2, part3, part4).lower(memory)
595 }
596}
597
598impl WitType for PublicKey {
599 const SIZE: u32 = <(u64, u64, u64, u64) as WitType>::SIZE;
600 type Layout = <(u64, u64, u64, u64) as WitType>::Layout;
601 type Dependencies = HList![];
602
603 fn wit_type_name() -> Cow<'static, str> {
604 "public-key".into()
605 }
606
607 fn wit_type_declaration() -> Cow<'static, str> {
608 concat!(
609 " record public-key {\n",
610 " part1: u64,\n",
611 " part2: u64,\n",
612 " part3: u64,\n",
613 " part4: u64,\n",
614 " }\n",
615 )
616 .into()
617 }
618}
619
620impl WitLoad for PublicKey {
621 fn load<Instance>(
622 memory: &Memory<'_, Instance>,
623 location: GuestPointer,
624 ) -> Result<Self, RuntimeError>
625 where
626 Instance: InstanceWithMemory,
627 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
628 {
629 let (part1, part2, part3, part4) = WitLoad::load(memory, location)?;
630 Ok(PublicKey::from([part1, part2, part3, part4]))
631 }
632
633 fn lift_from<Instance>(
634 flat_layout: <Self::Layout as Layout>::Flat,
635 memory: &Memory<'_, Instance>,
636 ) -> Result<Self, RuntimeError>
637 where
638 Instance: InstanceWithMemory,
639 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
640 {
641 let (part1, part2, part3, part4) = WitLoad::lift_from(flat_layout, memory)?;
642 Ok(PublicKey::from([part1, part2, part3, part4]))
643 }
644}
645
646impl WitStore for PublicKey {
647 fn store<Instance>(
648 &self,
649 memory: &mut Memory<'_, Instance>,
650 location: GuestPointer,
651 ) -> Result<(), RuntimeError>
652 where
653 Instance: InstanceWithMemory,
654 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
655 {
656 let [part1, part2, part3, part4] = (*self).into();
657 (part1, part2, part3, part4).store(memory, location)
658 }
659
660 fn lower<Instance>(
661 &self,
662 memory: &mut Memory<'_, Instance>,
663 ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
664 where
665 Instance: InstanceWithMemory,
666 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
667 {
668 let [part1, part2, part3, part4] = (*self).into();
669 (part1, part2, part3, part4).lower(memory)
670 }
671}
672
673#[cfg(with_testing)]
674impl Arbitrary for CryptoHash {
675 type Parameters = ();
676 type Strategy = strategy::Map<VecStrategy<RangeInclusive<u8>>, fn(Vec<u8>) -> CryptoHash>;
677
678 fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
679 vec(u8::MIN..=u8::MAX, HasherOutputSize::to_usize()).prop_map(|vector| {
680 CryptoHash(generic_array::GenericArray::clone_from_slice(&vector[..]))
681 })
682 }
683}
684
685impl BcsHashable for PublicKey {}
686
687doc_scalar!(CryptoHash, "A Sha3-256 value");
688doc_scalar!(PublicKey, "A signature public key");
689doc_scalar!(Signature, "A signature value");
690
691#[cfg(with_testing)]
693#[derive(Debug, Serialize, Deserialize)]
694pub struct TestString(pub String);
695
696#[cfg(with_testing)]
697impl TestString {
698 pub fn new(s: impl Into<String>) -> Self {
700 Self(s.into())
701 }
702}
703
704#[cfg(with_testing)]
705impl BcsSignable for TestString {}
706
707#[cfg(with_getrandom)]
708#[test]
709fn test_signatures() {
710 #[derive(Debug, Serialize, Deserialize)]
711 struct Foo(String);
712
713 impl BcsSignable for Foo {}
714
715 let key1 = KeyPair::generate();
716 let addr1 = key1.public();
717 let key2 = KeyPair::generate();
718 let addr2 = key2.public();
719
720 let ts = TestString("hello".into());
721 let tsx = TestString("hellox".into());
722 let foo = Foo("hello".into());
723
724 let s = Signature::new(&ts, &key1);
725 assert!(s.check(&ts, addr1).is_ok());
726 assert!(s.check(&ts, addr2).is_err());
727 assert!(s.check(&tsx, addr1).is_err());
728 assert!(s.check(&foo, addr1).is_err());
729}
730
731fn le_bytes_to_u64_array(bytes: &[u8]) -> [u64; 4] {
733 let mut integers = [0u64; 4];
734
735 integers[0] = u64::from_le_bytes(bytes[0..8].try_into().expect("incorrect indices"));
736 integers[1] = u64::from_le_bytes(bytes[8..16].try_into().expect("incorrect indices"));
737 integers[2] = u64::from_le_bytes(bytes[16..24].try_into().expect("incorrect indices"));
738 integers[3] = u64::from_le_bytes(bytes[24..32].try_into().expect("incorrect indices"));
739
740 integers
741}
742
743fn u64_array_to_le_bytes(integers: [u64; 4]) -> [u8; 32] {
745 let mut bytes = [0u8; 32];
746
747 bytes[0..8].copy_from_slice(&integers[0].to_le_bytes());
748 bytes[8..16].copy_from_slice(&integers[1].to_le_bytes());
749 bytes[16..24].copy_from_slice(&integers[2].to_le_bytes());
750 bytes[24..32].copy_from_slice(&integers[3].to_le_bytes());
751
752 bytes
753}