Skip to main content

ab_core_primitives/
ed25519.rs

1//! Primitives related to Ed25519
2
3use crate::hashes::Blake3Hash;
4use ab_blake3::single_block_hash;
5use ab_io_type::trivial_type::TrivialType;
6use core::fmt;
7use derive_more::{Deref, From, Into};
8#[cfg(feature = "ed25519")]
9use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey};
10#[cfg(feature = "scale-codec")]
11use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Deserializer, Serialize, Serializer};
14#[cfg(feature = "serde")]
15use serde_big_array::BigArray;
16
17/// Ed25519 public key
18#[derive(
19    Default, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Deref, From, Into, TrivialType,
20)]
21#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
22#[repr(C)]
23pub struct Ed25519PublicKey([u8; Ed25519PublicKey::SIZE]);
24
25#[cfg(feature = "ed25519")]
26impl From<VerifyingKey> for Ed25519PublicKey {
27    #[inline(always)]
28    fn from(verification_key: VerifyingKey) -> Self {
29        Ed25519PublicKey(verification_key.to_bytes())
30    }
31}
32
33impl fmt::Debug for Ed25519PublicKey {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        for byte in self.0 {
36            write!(f, "{byte:02x}")?;
37        }
38        Ok(())
39    }
40}
41
42#[cfg(feature = "serde")]
43#[derive(Serialize, Deserialize)]
44#[serde(transparent)]
45struct Ed25519PublicKeyBinary([u8; Ed25519PublicKey::SIZE]);
46
47#[cfg(feature = "serde")]
48#[derive(Serialize, Deserialize)]
49#[serde(transparent)]
50struct Ed25519PublicKeyHex(#[serde(with = "hex")] [u8; Ed25519PublicKey::SIZE]);
51
52#[cfg(feature = "serde")]
53impl Serialize for Ed25519PublicKey {
54    #[inline]
55    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
56    where
57        S: Serializer,
58    {
59        if serializer.is_human_readable() {
60            Ed25519PublicKeyHex(self.0).serialize(serializer)
61        } else {
62            Ed25519PublicKeyBinary(self.0).serialize(serializer)
63        }
64    }
65}
66
67#[cfg(feature = "serde")]
68impl<'de> Deserialize<'de> for Ed25519PublicKey {
69    #[inline]
70    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
71    where
72        D: Deserializer<'de>,
73    {
74        Ok(Self(if deserializer.is_human_readable() {
75            Ed25519PublicKeyHex::deserialize(deserializer)?.0
76        } else {
77            Ed25519PublicKeyBinary::deserialize(deserializer)?.0
78        }))
79    }
80}
81
82impl fmt::Display for Ed25519PublicKey {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        for byte in self.0 {
85            write!(f, "{byte:02x}")?;
86        }
87        Ok(())
88    }
89}
90
91impl AsRef<[u8]> for Ed25519PublicKey {
92    #[inline]
93    fn as_ref(&self) -> &[u8] {
94        &self.0
95    }
96}
97
98impl Ed25519PublicKey {
99    /// Public key size in bytes
100    pub const SIZE: usize = 32;
101
102    /// Public key hash.
103    pub fn hash(&self) -> Blake3Hash {
104        Blake3Hash::new(
105            single_block_hash(&self.0).expect("Less than a single block worth of bytes; qed"),
106        )
107    }
108
109    /// Verify Ed25519 signature
110    #[cfg(feature = "ed25519")]
111    #[inline]
112    pub fn verify(&self, signature: &Ed25519Signature, msg: &[u8]) -> Result<(), SignatureError> {
113        // TODO: Switch to RFC8032 / NIST validation criteria instead once
114        //  https://github.com/dalek-cryptography/curve25519-dalek/issues/626 is resolved
115        VerifyingKey::from_bytes(&self.0)?.verify(msg, &Signature::from_bytes(signature))
116    }
117}
118
119/// Ed25519 signature
120#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Deref, From, Into, TrivialType)]
121#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
122#[repr(C)]
123pub struct Ed25519Signature([u8; Ed25519Signature::SIZE]);
124
125#[cfg(feature = "ed25519")]
126impl From<Signature> for Ed25519Signature {
127    #[inline(always)]
128    fn from(signature: Signature) -> Self {
129        Ed25519Signature::from(signature.to_bytes())
130    }
131}
132
133impl Default for Ed25519Signature {
134    fn default() -> Self {
135        Self([0; _])
136    }
137}
138
139impl fmt::Debug for Ed25519Signature {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        for byte in self.0 {
142            write!(f, "{byte:02x}")?;
143        }
144        Ok(())
145    }
146}
147
148#[cfg(feature = "serde")]
149#[derive(Serialize, Deserialize)]
150#[serde(transparent)]
151struct Ed25519SignatureBinary(#[serde(with = "BigArray")] [u8; Ed25519Signature::SIZE]);
152
153#[cfg(feature = "serde")]
154#[derive(Serialize, Deserialize)]
155#[serde(transparent)]
156struct Ed25519SignatureHex(#[serde(with = "hex")] [u8; Ed25519Signature::SIZE]);
157
158#[cfg(feature = "serde")]
159impl Serialize for Ed25519Signature {
160    #[inline]
161    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
162    where
163        S: Serializer,
164    {
165        if serializer.is_human_readable() {
166            Ed25519SignatureHex(self.0).serialize(serializer)
167        } else {
168            Ed25519SignatureBinary(self.0).serialize(serializer)
169        }
170    }
171}
172
173#[cfg(feature = "serde")]
174impl<'de> Deserialize<'de> for Ed25519Signature {
175    #[inline]
176    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
177    where
178        D: Deserializer<'de>,
179    {
180        Ok(Self(if deserializer.is_human_readable() {
181            Ed25519SignatureHex::deserialize(deserializer)?.0
182        } else {
183            Ed25519SignatureBinary::deserialize(deserializer)?.0
184        }))
185    }
186}
187
188impl fmt::Display for Ed25519Signature {
189    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190        for byte in self.0 {
191            write!(f, "{byte:02x}")?;
192        }
193        Ok(())
194    }
195}
196
197impl AsRef<[u8]> for Ed25519Signature {
198    #[inline]
199    fn as_ref(&self) -> &[u8] {
200        &self.0
201    }
202}
203
204impl Ed25519Signature {
205    /// Signature size in bytes
206    pub const SIZE: usize = 64;
207}