1use iota_types::{
6 Ed25519PublicKey, Ed25519Signature, SignatureScheme, SimpleSignature, UserSignature,
7};
8
9use crate::{SignatureError, Signer, Verifier};
10
11#[derive(Clone, Eq, PartialEq)]
12pub struct Ed25519PrivateKey(ed25519_dalek::SigningKey);
13
14impl std::fmt::Debug for Ed25519PrivateKey {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 f.debug_tuple("Ed25519PrivateKey")
17 .field(&"__elided__")
18 .finish()
19 }
20}
21
22#[cfg(test)]
23impl proptest::arbitrary::Arbitrary for Ed25519PrivateKey {
24 type Parameters = ();
25 type Strategy = proptest::strategy::BoxedStrategy<Self>;
26 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
27 use proptest::strategy::Strategy;
28
29 proptest::arbitrary::any::<[u8; Self::LENGTH]>()
30 .prop_map(Self::new)
31 .boxed()
32 }
33}
34
35impl Ed25519PrivateKey {
36 pub const LENGTH: usize = 32;
38
39 pub fn new(bytes: [u8; Self::LENGTH]) -> Self {
40 Self(bytes.into())
41 }
42
43 pub fn scheme(&self) -> SignatureScheme {
44 SignatureScheme::Ed25519
45 }
46
47 pub fn verifying_key(&self) -> Ed25519VerifyingKey {
48 let verifying_key = self.0.verifying_key();
49 Ed25519VerifyingKey(verifying_key)
50 }
51
52 pub fn public_key(&self) -> Ed25519PublicKey {
53 self.verifying_key().public_key()
54 }
55
56 pub fn generate<R>(mut rng: R) -> Self
57 where
58 R: rand_core::RngCore + rand_core::CryptoRng,
59 {
60 let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH];
61 rng.fill_bytes(&mut buf);
62 Self(buf.into())
63 }
64
65 #[cfg(feature = "pem")]
66 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
67 pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
70 ed25519_dalek::pkcs8::DecodePrivateKey::from_pkcs8_der(bytes)
71 .map(Self)
72 .map_err(SignatureError::from_source)
73 }
74
75 #[cfg(feature = "pem")]
76 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
77 pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
79 use ed25519_dalek::pkcs8::EncodePrivateKey;
80
81 self.0
82 .to_pkcs8_der()
83 .map_err(SignatureError::from_source)
84 .map(|der| der.as_bytes().to_owned())
85 }
86
87 #[cfg(feature = "pem")]
88 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
89 pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
91 ed25519_dalek::pkcs8::DecodePrivateKey::from_pkcs8_pem(s)
92 .map(Self)
93 .map_err(SignatureError::from_source)
94 }
95
96 #[cfg(feature = "pem")]
97 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
98 pub fn to_pem(&self) -> Result<String, SignatureError> {
100 use pkcs8::EncodePrivateKey;
101
102 self.0
103 .to_pkcs8_pem(pkcs8::LineEnding::default())
104 .map_err(SignatureError::from_source)
105 .map(|pem| (*pem).to_owned())
106 }
107
108 #[cfg(feature = "pem")]
109 pub(crate) fn from_dalek(private_key: ed25519_dalek::SigningKey) -> Self {
110 Self(private_key)
111 }
112}
113
114impl crate::ToFromBytes for Ed25519PrivateKey {
115 type Error = crate::PrivateKeyError;
116 type ByteArray = [u8; Self::LENGTH];
117
118 fn to_bytes(&self) -> Self::ByteArray {
120 self.0.to_bytes()
121 }
122
123 fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
124 if bytes.len() != Self::LENGTH {
125 return Err(crate::PrivateKeyError::InvalidScheme(
126 "invalid ed25519 key length".to_string(),
127 ));
128 }
129
130 let mut arr = [0u8; Self::LENGTH];
131 arr.copy_from_slice(bytes);
132 Ok(Self::new(arr))
133 }
134}
135
136impl crate::PrivateKeyScheme for Ed25519PrivateKey {
137 const SCHEME: SignatureScheme = SignatureScheme::Ed25519;
138}
139
140#[cfg(feature = "mnemonic")]
141impl crate::FromMnemonic for Ed25519PrivateKey {
142 type Error = crate::PrivateKeyError;
143
144 fn from_mnemonic(
145 phrase: &str,
146 account_index: impl Into<Option<u64>>,
147 password: impl Into<Option<String>>,
148 ) -> Result<Self, Self::Error>
149 where
150 Self: Sized,
151 {
152 let path = format!(
153 "m/{}'/{}'/0'/0'/{}'",
154 crate::DERIVATION_PATH_PURPOSE_ED25519,
155 crate::DERIVATION_PATH_COIN_TYPE,
156 account_index.into().unwrap_or_default()
157 );
158 Self::from_mnemonic_with_path(phrase, path, password)
159 }
160
161 fn from_mnemonic_with_path(
162 phrase: &str,
163 path: String,
164 password: impl Into<Option<String>>,
165 ) -> Result<Self, Self::Error>
166 where
167 Self: Sized,
168 {
169 use std::str::FromStr;
170
171 let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?;
172 let seed = mnemonic.to_seed(password.into().unwrap_or_default());
173 let path = bip32::DerivationPath::from_str(&path)?
174 .into_iter()
175 .map(|c| c.0)
176 .collect::<Vec<_>>();
177 Ok(Self::new(slip10_ed25519::derive_ed25519_private_key(
178 &seed, &path,
179 )))
180 }
181}
182
183impl Signer<Ed25519Signature> for Ed25519PrivateKey {
184 fn try_sign(&self, msg: &[u8]) -> Result<Ed25519Signature, SignatureError> {
185 self.0
186 .try_sign(msg)
187 .map(|signature| Ed25519Signature::new(signature.to_bytes()))
188 }
189}
190
191impl Signer<SimpleSignature> for Ed25519PrivateKey {
192 fn try_sign(&self, msg: &[u8]) -> Result<SimpleSignature, SignatureError> {
193 <Self as Signer<Ed25519Signature>>::try_sign(self, msg).map(|signature| {
194 SimpleSignature::Ed25519 {
195 signature,
196 public_key: self.public_key(),
197 }
198 })
199 }
200}
201
202impl Signer<UserSignature> for Ed25519PrivateKey {
203 fn try_sign(&self, msg: &[u8]) -> Result<UserSignature, SignatureError> {
204 <Self as Signer<SimpleSignature>>::try_sign(self, msg).map(UserSignature::Simple)
205 }
206}
207
208#[derive(Debug, Clone, Eq, PartialEq, Default)]
209pub struct Ed25519VerifyingKey(ed25519_dalek::VerifyingKey);
210
211impl Ed25519VerifyingKey {
212 pub fn new(public_key: &Ed25519PublicKey) -> Result<Self, SignatureError> {
213 ed25519_dalek::VerifyingKey::from_bytes(public_key.inner()).map(Self)
214 }
215
216 pub fn public_key(&self) -> Ed25519PublicKey {
217 Ed25519PublicKey::new(self.0.to_bytes())
218 }
219
220 #[cfg(feature = "pem")]
221 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
222 pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
224 ed25519_dalek::pkcs8::DecodePublicKey::from_public_key_der(bytes)
225 .map(Self)
226 .map_err(SignatureError::from_source)
227 }
228
229 #[cfg(feature = "pem")]
230 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
231 pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
233 use pkcs8::EncodePublicKey;
234
235 self.0
236 .to_public_key_der()
237 .map_err(SignatureError::from_source)
238 .map(|der| der.into_vec())
239 }
240
241 #[cfg(feature = "pem")]
242 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
243 pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
245 ed25519_dalek::pkcs8::DecodePublicKey::from_public_key_pem(s)
246 .map(Self)
247 .map_err(SignatureError::from_source)
248 }
249
250 #[cfg(feature = "pem")]
251 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
252 pub fn to_pem(&self) -> Result<String, SignatureError> {
254 use pkcs8::EncodePublicKey;
255
256 self.0
257 .to_public_key_pem(pkcs8::LineEnding::default())
258 .map_err(SignatureError::from_source)
259 }
260
261 #[cfg(feature = "pem")]
262 pub(crate) fn from_dalek(verifying_key: ed25519_dalek::VerifyingKey) -> Self {
263 Self(verifying_key)
264 }
265}
266
267impl Verifier<Ed25519Signature> for Ed25519VerifyingKey {
268 fn verify(&self, message: &[u8], signature: &Ed25519Signature) -> Result<(), SignatureError> {
269 let signature = ed25519_dalek::Signature::from_bytes(signature.inner());
270 self.0.verify_strict(message, &signature)
271 }
272}
273
274impl Verifier<SimpleSignature> for Ed25519VerifyingKey {
275 fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
276 let SimpleSignature::Ed25519 {
277 signature,
278 public_key,
279 } = signature
280 else {
281 return Err(SignatureError::from_source("not an ed25519 signature"));
282 };
283
284 if public_key.inner() != self.0.as_bytes() {
285 return Err(SignatureError::from_source(
286 "public_key in signature does not match",
287 ));
288 }
289
290 <Self as Verifier<Ed25519Signature>>::verify(self, message, signature)
291 }
292}
293
294impl Verifier<UserSignature> for Ed25519VerifyingKey {
295 fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
296 let UserSignature::Simple(signature) = signature else {
297 return Err(SignatureError::from_source("not an ed25519 signature"));
298 };
299
300 <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
301 }
302}
303
304#[derive(Default, Clone, Debug)]
305pub struct Ed25519Verifier {}
306
307impl Ed25519Verifier {
308 pub fn new() -> Self {
309 Self {}
310 }
311}
312
313impl Verifier<SimpleSignature> for Ed25519Verifier {
314 fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
315 let SimpleSignature::Ed25519 {
316 signature,
317 public_key,
318 } = signature
319 else {
320 return Err(SignatureError::from_source("not an ed25519 signature"));
321 };
322
323 let verifying_key = Ed25519VerifyingKey::new(public_key)?;
324
325 verifying_key.verify(message, signature)
326 }
327}
328
329impl Verifier<UserSignature> for Ed25519Verifier {
330 fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
331 let UserSignature::Simple(signature) = signature else {
332 return Err(SignatureError::from_source("not an ed25519 signature"));
333 };
334
335 <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
336 }
337}
338
339#[cfg(test)]
340mod tests {
341 use iota_types::{PersonalMessage, Transaction};
342 use test_strategy::proptest;
343
344 use super::*;
345 use crate::{IotaSigner, IotaVerifier};
346
347 #[proptest]
348 fn transaction_signing(signer: Ed25519PrivateKey, transaction: Transaction) {
349 let signature = signer.sign_transaction(&transaction).unwrap();
350 let verifier = signer.verifying_key();
351 verifier
352 .verify_transaction(&transaction, &signature)
353 .unwrap();
354 }
355
356 #[proptest]
357 fn personal_message_signing(signer: Ed25519PrivateKey, message: Vec<u8>) {
358 let message = PersonalMessage(message.into());
359 let signature = signer.sign_personal_message(&message).unwrap();
360 let verifying_key = signer.verifying_key();
361 verifying_key
362 .verify_personal_message(&message, &signature)
363 .unwrap();
364
365 let verifier = Ed25519Verifier::default();
366 verifier
367 .verify_personal_message(&message, &signature)
368 .unwrap();
369 }
370}