1use base64ct::{Base64Unpadded, Encoding as _};
13use curve25519_dalek::Scalar;
14use derive_deftly::Deftly;
15use std::fmt::{self, Debug, Display, Formatter};
16use subtle::{Choice, ConstantTimeEq};
17
18#[cfg(feature = "memquota-memcost")]
19use tor_memquota_cost::derive_deftly_template_HasMemoryCost;
20
21use ed25519_dalek::hazmat::ExpandedSecretKey;
22use ed25519_dalek::{Signer as _, Verifier as _};
23
24use crate::util::{
25 ct::{
26 CtByteArray, derive_deftly_template_ConstantTimeEq,
27 derive_deftly_template_PartialEqFromCtEq,
28 },
29 rng::RngCompat,
30};
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub struct Signature(pub(crate) ed25519_dalek::Signature);
37
38#[derive(Debug, Deftly)]
44#[derive_deftly(ConstantTimeEq)]
45pub struct Keypair(pub(crate) ed25519_dalek::SigningKey);
46
47#[derive(Clone, Copy, Debug, Eq, Deftly)]
51#[derive_deftly(PartialEqFromCtEq)]
52pub struct PublicKey(pub(crate) ed25519_dalek::VerifyingKey);
53
54impl<'a> From<&'a Keypair> for PublicKey {
55 fn from(value: &'a Keypair) -> Self {
56 PublicKey((&value.0).into())
57 }
58}
59
60impl ConstantTimeEq for PublicKey {
61 fn ct_eq(&self, other: &Self) -> Choice {
62 self.as_bytes().ct_eq(other.as_bytes())
63 }
64}
65
66impl PublicKey {
67 pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, signature::Error> {
69 Ok(PublicKey(ed25519_dalek::VerifyingKey::from_bytes(bytes)?))
70 }
71
72 pub fn as_bytes(&self) -> &[u8; 32] {
74 self.0.as_bytes()
75 }
76 pub fn to_bytes(&self) -> [u8; 32] {
78 self.0.to_bytes()
79 }
80 pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), signature::Error> {
84 self.0.verify(message, &signature.0)
85 }
86}
87impl Keypair {
88 pub fn generate<R: rand_core::RngCore + rand_core::CryptoRng>(csprng: &mut R) -> Self {
90 Self(ed25519_dalek::SigningKey::generate(&mut RngCompat::new(
91 csprng,
92 )))
93 }
94 pub fn from_bytes(bytes: &[u8; 32]) -> Self {
96 Self(ed25519_dalek::SigningKey::from_bytes(bytes))
97 }
98 pub fn as_bytes(&self) -> &[u8; 32] {
100 self.0.as_bytes()
101 }
102 pub fn to_bytes(&self) -> [u8; 32] {
104 self.0.to_bytes()
105 }
106 pub fn verifying_key(&self) -> PublicKey {
108 PublicKey(*self.0.as_ref())
109 }
110 pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), signature::Error> {
112 self.0.verify(message, &signature.0)
113 }
114 pub fn sign(&self, message: &[u8]) -> Signature {
116 Signature(self.0.sign(message))
117 }
118}
119impl Signature {
120 pub fn from_bytes(bytes: &[u8; 64]) -> Self {
122 Self(ed25519_dalek::Signature::from_bytes(bytes))
123 }
124 pub fn to_bytes(&self) -> [u8; 64] {
126 self.0.to_bytes()
127 }
128}
129impl<'a> TryFrom<&'a [u8]> for PublicKey {
130 type Error = signature::Error;
131
132 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
133 Ok(Self(ed25519_dalek::VerifyingKey::try_from(value)?))
134 }
135}
136impl<'a> From<&'a [u8; 32]> for Keypair {
137 fn from(value: &'a [u8; 32]) -> Self {
138 Self(ed25519_dalek::SigningKey::from(value))
139 }
140}
141impl From<[u8; 64]> for Signature {
142 fn from(value: [u8; 64]) -> Self {
143 Signature(value.into())
144 }
145}
146impl<'a> From<&'a [u8; 64]> for Signature {
147 fn from(value: &'a [u8; 64]) -> Self {
148 Signature(value.into())
149 }
150}
151
152pub const ED25519_ID_LEN: usize = 32;
154
155pub const ED25519_SIGNATURE_LEN: usize = 64;
157
158#[allow(clippy::exhaustive_structs)]
166#[derive(Deftly)]
167#[derive_deftly(ConstantTimeEq)]
168pub struct ExpandedKeypair {
169 pub(crate) secret: ExpandedSecretKey,
171 pub(crate) public: PublicKey,
178}
179
180impl ExpandedKeypair {
181 pub fn public(&self) -> &PublicKey {
183 &self.public
184 }
185
186 pub fn sign(&self, message: &[u8]) -> Signature {
192 use sha2::Sha512;
193 Signature(ed25519_dalek::hazmat::raw_sign::<Sha512>(
195 &self.secret,
196 message,
197 &self.public.0,
198 ))
199 }
200
201 pub fn to_secret_key_bytes(&self) -> [u8; 64] {
206 let mut output = [0_u8; 64];
207 output[0..32].copy_from_slice(&self.secret.scalar.to_bytes());
208 output[32..64].copy_from_slice(&self.secret.hash_prefix);
209 output
210 }
211
212 pub fn from_secret_key_bytes(bytes: [u8; 64]) -> Option<Self> {
219 let scalar = Option::from(Scalar::from_bytes_mod_order(
220 bytes[0..32].try_into().expect("wrong length on slice"),
221 ))?;
222 let hash_prefix = bytes[32..64].try_into().expect("wrong length on slice");
223 let secret = ExpandedSecretKey {
224 scalar,
225 hash_prefix,
226 };
227 let public = PublicKey((&secret).into());
228 Some(Self { secret, public })
229 }
230
231 }
235
236impl<'a> From<&'a Keypair> for ExpandedKeypair {
237 fn from(kp: &'a Keypair) -> ExpandedKeypair {
238 ExpandedKeypair {
239 secret: kp.as_bytes().into(),
240 public: kp.into(),
241 }
242 }
243}
244
245impl From<ExpandedKeypair> for PublicKey {
246 fn from(ekp: ExpandedKeypair) -> PublicKey {
247 ekp.public
248 }
249}
250
251#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq)]
264#[cfg_attr(
265 feature = "memquota-memcost",
266 derive(Deftly),
267 derive_deftly(HasMemoryCost)
268)]
269pub struct Ed25519Identity {
270 id: CtByteArray<ED25519_ID_LEN>,
272}
273
274impl Ed25519Identity {
275 pub fn new(id: [u8; 32]) -> Self {
293 Ed25519Identity { id: id.into() }
294 }
295 pub fn from_bytes(id: &[u8]) -> Option<Self> {
297 Some(Ed25519Identity::new(id.try_into().ok()?))
298 }
299 pub fn as_bytes(&self) -> &[u8] {
301 &self.id.as_ref()[..]
302 }
303 pub fn from_base64(s: &str) -> Option<Self> {
308 let bytes = Base64Unpadded::decode_vec(s).ok()?;
309 Ed25519Identity::from_bytes(&bytes)
310 }
311}
312
313impl From<[u8; ED25519_ID_LEN]> for Ed25519Identity {
314 fn from(id: [u8; ED25519_ID_LEN]) -> Self {
315 Ed25519Identity::new(id)
316 }
317}
318
319impl From<Ed25519Identity> for [u8; ED25519_ID_LEN] {
320 fn from(value: Ed25519Identity) -> Self {
321 value.id.into()
322 }
323}
324
325impl From<PublicKey> for Ed25519Identity {
326 fn from(pk: PublicKey) -> Self {
327 (&pk).into()
328 }
329}
330
331impl From<&PublicKey> for Ed25519Identity {
332 fn from(pk: &PublicKey) -> Self {
333 Ed25519Identity::from_bytes(pk.as_bytes()).expect("Ed25519 public key had wrong length?")
336 }
337}
338
339impl TryFrom<&Ed25519Identity> for PublicKey {
340 type Error = ed25519_dalek::SignatureError;
341 fn try_from(id: &Ed25519Identity) -> Result<PublicKey, Self::Error> {
342 PublicKey::from_bytes(id.id.as_ref())
343 }
344}
345
346impl TryFrom<Ed25519Identity> for PublicKey {
347 type Error = ed25519_dalek::SignatureError;
348 fn try_from(id: Ed25519Identity) -> Result<PublicKey, Self::Error> {
349 (&id).try_into()
350 }
351}
352
353impl ConstantTimeEq for Ed25519Identity {
354 fn ct_eq(&self, other: &Self) -> Choice {
355 self.id.ct_eq(&other.id)
356 }
357}
358
359impl Display for Ed25519Identity {
360 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
361 write!(f, "{}", Base64Unpadded::encode_string(self.id.as_ref()))
362 }
363}
364
365impl Debug for Ed25519Identity {
366 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
367 write!(f, "Ed25519Identity {{ {} }}", self)
368 }
369}
370
371impl safelog::Redactable for Ed25519Identity {
372 fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
375 write!(
376 f,
377 "{}…",
378 &Base64Unpadded::encode_string(self.id.as_ref())[..2]
379 )
380 }
381
382 fn debug_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
383 write!(f, "Ed25519Identity {{ {} }}", self.redacted())
384 }
385}
386
387impl serde::Serialize for Ed25519Identity {
388 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
389 where
390 S: serde::Serializer,
391 {
392 if serializer.is_human_readable() {
393 serializer.serialize_str(&Base64Unpadded::encode_string(self.id.as_ref()))
394 } else {
395 serializer.serialize_bytes(&self.id.as_ref()[..])
396 }
397 }
398}
399
400impl<'de> serde::Deserialize<'de> for Ed25519Identity {
401 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
402 where
403 D: serde::Deserializer<'de>,
404 {
405 if deserializer.is_human_readable() {
406 struct EdIdentityVisitor;
408 impl<'de> serde::de::Visitor<'de> for EdIdentityVisitor {
409 type Value = Ed25519Identity;
410 fn expecting(&self, fmt: &mut std::fmt::Formatter<'_>) -> fmt::Result {
411 fmt.write_str("base64-encoded Ed25519 public key")
412 }
413 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
414 where
415 E: serde::de::Error,
416 {
417 let bytes = Base64Unpadded::decode_vec(s).map_err(E::custom)?;
418 Ed25519Identity::from_bytes(&bytes)
419 .ok_or_else(|| E::custom("wrong length for Ed25519 public key"))
420 }
421 }
422
423 deserializer.deserialize_str(EdIdentityVisitor)
424 } else {
425 struct EdIdentityVisitor;
427 impl<'de> serde::de::Visitor<'de> for EdIdentityVisitor {
428 type Value = Ed25519Identity;
429 fn expecting(&self, fmt: &mut std::fmt::Formatter<'_>) -> fmt::Result {
430 fmt.write_str("ed25519 public key")
431 }
432 fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
433 where
434 E: serde::de::Error,
435 {
436 Ed25519Identity::from_bytes(bytes)
437 .ok_or_else(|| E::custom("wrong length for ed25519 public key"))
438 }
439 }
440 deserializer.deserialize_bytes(EdIdentityVisitor)
441 }
442 }
443}
444
445#[derive(Clone, Debug)]
448#[cfg_attr(
449 feature = "memquota-memcost",
450 derive(Deftly),
451 derive_deftly(HasMemoryCost)
452)]
453pub struct ValidatableEd25519Signature {
454 #[cfg_attr(feature = "memquota-memcost", deftly(has_memory_cost(copy)))]
456 key: PublicKey,
457 #[cfg_attr(feature = "memquota-memcost", deftly(has_memory_cost(copy)))]
459 sig: Signature,
460 entire_text_of_signed_thing: Vec<u8>,
468}
469
470impl ValidatableEd25519Signature {
471 pub fn new(key: PublicKey, sig: Signature, text: &[u8]) -> Self {
473 ValidatableEd25519Signature {
474 key,
475 sig,
476 entire_text_of_signed_thing: text.into(),
477 }
478 }
479
480 pub(crate) fn as_parts(&self) -> (&PublicKey, &Signature, &[u8]) {
482 (&self.key, &self.sig, &self.entire_text_of_signed_thing[..])
483 }
484
485 pub fn signature(&self) -> &Signature {
487 &self.sig
488 }
489}
490
491impl super::ValidatableSignature for ValidatableEd25519Signature {
492 fn is_valid(&self) -> bool {
493 self.key
494 .verify(&self.entire_text_of_signed_thing[..], &self.sig)
495 .is_ok()
496 }
497
498 fn as_ed25519(&self) -> Option<&ValidatableEd25519Signature> {
499 Some(self)
500 }
501}
502
503pub fn validate_batch(sigs: &[&ValidatableEd25519Signature]) -> bool {
515 use crate::pk::ValidatableSignature;
516 if sigs.is_empty() {
517 true
520 } else if sigs.len() == 1 {
521 sigs[0].is_valid()
523 } else {
524 let mut ed_msgs = Vec::new();
525 let mut ed_sigs = Vec::new();
526 let mut ed_pks = Vec::new();
527 for ed_sig in sigs {
528 let (pk, sig, msg) = ed_sig.as_parts();
529 ed_sigs.push(sig.0);
530 ed_pks.push(pk.0);
531 ed_msgs.push(msg);
532 }
533 ed25519_dalek::verify_batch(&ed_msgs[..], &ed_sigs[..], &ed_pks[..]).is_ok()
534 }
535}
536
537pub trait Ed25519PublicKey {
539 fn public_key(&self) -> PublicKey;
541}
542
543impl Ed25519PublicKey for Keypair {
544 fn public_key(&self) -> PublicKey {
545 Keypair::verifying_key(self)
546 }
547}
548
549pub trait Ed25519SigningKey {
551 fn sign(&self, message: &[u8]) -> Signature;
553}
554
555impl Ed25519SigningKey for Keypair {
556 fn sign(&self, message: &[u8]) -> Signature {
557 Keypair::sign(self, message)
558 }
559}
560impl Ed25519SigningKey for ExpandedKeypair {
561 fn sign(&self, message: &[u8]) -> Signature {
562 ExpandedKeypair::sign(self, message)
563 }
564}
565
566#[cfg(test)]
567mod test {
568 #![allow(clippy::bool_assert_comparison)]
570 #![allow(clippy::clone_on_copy)]
571 #![allow(clippy::dbg_macro)]
572 #![allow(clippy::mixed_attributes_style)]
573 #![allow(clippy::print_stderr)]
574 #![allow(clippy::print_stdout)]
575 #![allow(clippy::single_char_pattern)]
576 #![allow(clippy::unwrap_used)]
577 #![allow(clippy::unchecked_time_subtraction)]
578 #![allow(clippy::useless_vec)]
579 #![allow(clippy::needless_pass_by_value)]
580 use super::*;
583
584 #[test]
585 fn ed_from_base64() {
586 let id =
587 Ed25519Identity::from_base64("qpL/LxLYVEXghU76iG3LsSI/UW7MBpIROZK0AB18560").unwrap();
588
589 assert_eq!(
590 id,
591 Ed25519Identity::from([
592 0xaa, 0x92, 0xff, 0x2f, 0x12, 0xd8, 0x54, 0x45, 0xe0, 0x85, 0x4e, 0xfa, 0x88, 0x6d,
593 0xcb, 0xb1, 0x22, 0x3f, 0x51, 0x6e, 0xcc, 0x06, 0x92, 0x11, 0x39, 0x92, 0xb4, 0x00,
594 0x1d, 0x7c, 0xe7, 0xad
595 ]),
596 );
597 }
598}