1use crate::SignatureError;
2use crate::Signer;
3use crate::Verifier;
4use sui_sdk_types::Ed25519PublicKey;
5use sui_sdk_types::Ed25519Signature;
6use sui_sdk_types::SignatureScheme;
7use sui_sdk_types::SimpleSignature;
8use sui_sdk_types::UserSignature;
9
10#[derive(Clone, Eq, PartialEq)]
11pub struct Ed25519PrivateKey(ed25519_dalek::SigningKey);
12
13impl std::fmt::Debug for Ed25519PrivateKey {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 f.debug_tuple("Ed25519PrivateKey")
16 .field(&"__elided__")
17 .finish()
18 }
19}
20
21#[cfg(test)]
22impl proptest::arbitrary::Arbitrary for Ed25519PrivateKey {
23 type Parameters = ();
24 type Strategy = proptest::strategy::BoxedStrategy<Self>;
25 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
26 use proptest::strategy::Strategy;
27
28 proptest::arbitrary::any::<[u8; Self::LENGTH]>()
29 .prop_map(Self::new)
30 .boxed()
31 }
32}
33
34impl Ed25519PrivateKey {
35 pub const LENGTH: usize = 32;
37
38 pub fn new(bytes: [u8; Self::LENGTH]) -> Self {
39 Self(bytes.into())
40 }
41
42 pub fn scheme(&self) -> SignatureScheme {
43 SignatureScheme::Ed25519
44 }
45
46 pub fn verifying_key(&self) -> Ed25519VerifyingKey {
47 let verifying_key = self.0.verifying_key();
48 Ed25519VerifyingKey(verifying_key)
49 }
50
51 pub fn public_key(&self) -> Ed25519PublicKey {
52 self.verifying_key().public_key()
53 }
54
55 pub fn generate<R>(mut rng: R) -> Self
56 where
57 R: rand_core::RngCore + rand_core::CryptoRng,
58 {
59 let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH];
60 rng.fill_bytes(&mut buf);
61 Self(buf.into())
62 }
63
64 #[cfg(feature = "pem")]
65 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
66 pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
68 ed25519_dalek::pkcs8::DecodePrivateKey::from_pkcs8_der(bytes)
69 .map(Self)
70 .map_err(SignatureError::from_source)
71 }
72
73 #[cfg(feature = "pem")]
74 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
75 pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
77 use ed25519_dalek::pkcs8::EncodePrivateKey;
78
79 self.0
80 .to_pkcs8_der()
81 .map_err(SignatureError::from_source)
82 .map(|der| der.as_bytes().to_owned())
83 }
84
85 #[cfg(feature = "pem")]
86 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
87 pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
89 ed25519_dalek::pkcs8::DecodePrivateKey::from_pkcs8_pem(s)
90 .map(Self)
91 .map_err(SignatureError::from_source)
92 }
93
94 #[cfg(feature = "pem")]
95 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
96 pub fn to_pem(&self) -> Result<String, SignatureError> {
98 use pkcs8::EncodePrivateKey;
99
100 self.0
101 .to_pkcs8_pem(pkcs8::LineEnding::default())
102 .map_err(SignatureError::from_source)
103 .map(|pem| (*pem).to_owned())
104 }
105
106 #[cfg(feature = "pem")]
107 pub(crate) fn from_dalek(private_key: ed25519_dalek::SigningKey) -> Self {
108 Self(private_key)
109 }
110
111 fn from_flagged_key_bytes(
114 scheme: SignatureScheme,
115 key: Vec<u8>,
116 ) -> Result<Self, SignatureError> {
117 if scheme != SignatureScheme::Ed25519 {
118 return Err(SignatureError::from_source(format!(
119 "private key scheme flag is `{}`, expected `ed25519`",
120 scheme.name(),
121 )));
122 }
123 let bytes: [u8; Self::LENGTH] = key.try_into().map_err(|_: Vec<u8>| {
124 SignatureError::from_source("private key has invalid length for ed25519")
125 })?;
126 Ok(Self::new(bytes))
127 }
128
129 #[cfg(feature = "bech32")]
130 #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
131 pub fn from_suiprivkey(s: &str) -> Result<Self, SignatureError> {
137 let (scheme, key) = crate::suipriv::decode(s)?;
138 Self::from_flagged_key_bytes(scheme, key)
139 }
140
141 #[cfg(feature = "bech32")]
142 #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
143 pub fn to_suiprivkey(&self) -> Result<String, SignatureError> {
145 crate::suipriv::encode(SignatureScheme::Ed25519, self.0.to_bytes().as_slice())
146 }
147
148 pub fn from_base64(s: &str) -> Result<Self, SignatureError> {
154 let (scheme, key) = crate::suipriv::decode_base64(s)?;
155 Self::from_flagged_key_bytes(scheme, key)
156 }
157
158 pub fn to_base64(&self) -> String {
162 crate::suipriv::encode_base64(SignatureScheme::Ed25519, self.0.to_bytes().as_slice())
163 }
164}
165
166impl Signer<Ed25519Signature> for Ed25519PrivateKey {
167 fn try_sign(&self, msg: &[u8]) -> Result<Ed25519Signature, SignatureError> {
168 self.0
169 .try_sign(msg)
170 .map(|signature| Ed25519Signature::new(signature.to_bytes()))
171 }
172}
173
174impl Signer<SimpleSignature> for Ed25519PrivateKey {
175 fn try_sign(&self, msg: &[u8]) -> Result<SimpleSignature, SignatureError> {
176 <Self as Signer<Ed25519Signature>>::try_sign(self, msg).map(|signature| {
177 SimpleSignature::Ed25519 {
178 signature,
179 public_key: self.public_key(),
180 }
181 })
182 }
183}
184
185impl Signer<UserSignature> for Ed25519PrivateKey {
186 fn try_sign(&self, msg: &[u8]) -> Result<UserSignature, SignatureError> {
187 <Self as Signer<SimpleSignature>>::try_sign(self, msg).map(UserSignature::Simple)
188 }
189}
190
191#[derive(Debug, Clone, Eq, PartialEq, Default)]
192pub struct Ed25519VerifyingKey(ed25519_dalek::VerifyingKey);
193
194impl Ed25519VerifyingKey {
195 pub fn new(public_key: &Ed25519PublicKey) -> Result<Self, SignatureError> {
196 ed25519_dalek::VerifyingKey::from_bytes(public_key.inner()).map(Self)
197 }
198
199 pub fn public_key(&self) -> Ed25519PublicKey {
200 Ed25519PublicKey::new(self.0.to_bytes())
201 }
202
203 #[cfg(feature = "pem")]
204 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
205 pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
207 ed25519_dalek::pkcs8::DecodePublicKey::from_public_key_der(bytes)
208 .map(Self)
209 .map_err(SignatureError::from_source)
210 }
211
212 #[cfg(feature = "pem")]
213 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
214 pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
216 use pkcs8::EncodePublicKey;
217
218 self.0
219 .to_public_key_der()
220 .map_err(SignatureError::from_source)
221 .map(|der| der.into_vec())
222 }
223
224 #[cfg(feature = "pem")]
225 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
226 pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
228 ed25519_dalek::pkcs8::DecodePublicKey::from_public_key_pem(s)
229 .map(Self)
230 .map_err(SignatureError::from_source)
231 }
232
233 #[cfg(feature = "pem")]
234 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
235 pub fn to_pem(&self) -> Result<String, SignatureError> {
237 use pkcs8::EncodePublicKey;
238
239 self.0
240 .to_public_key_pem(pkcs8::LineEnding::default())
241 .map_err(SignatureError::from_source)
242 }
243
244 #[cfg(feature = "pem")]
245 pub(crate) fn from_dalek(verifying_key: ed25519_dalek::VerifyingKey) -> Self {
246 Self(verifying_key)
247 }
248}
249
250impl Verifier<Ed25519Signature> for Ed25519VerifyingKey {
251 fn verify(&self, message: &[u8], signature: &Ed25519Signature) -> Result<(), SignatureError> {
252 let signature = ed25519_dalek::Signature::from_bytes(signature.inner());
253 self.0.verify_strict(message, &signature)
254 }
255}
256
257impl Verifier<SimpleSignature> for Ed25519VerifyingKey {
258 fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
259 let SimpleSignature::Ed25519 {
260 signature,
261 public_key,
262 } = signature
263 else {
264 return Err(SignatureError::from_source("not an ed25519 signature"));
265 };
266
267 if public_key.inner() != self.0.as_bytes() {
268 return Err(SignatureError::from_source(
269 "public_key in signature does not match",
270 ));
271 }
272
273 <Self as Verifier<Ed25519Signature>>::verify(self, message, signature)
274 }
275}
276
277impl Verifier<UserSignature> for Ed25519VerifyingKey {
278 fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
279 let UserSignature::Simple(signature) = signature else {
280 return Err(SignatureError::from_source("not an ed25519 signature"));
281 };
282
283 <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
284 }
285}
286
287#[derive(Default, Clone, Debug)]
288pub struct Ed25519Verifier {}
289
290impl Ed25519Verifier {
291 pub fn new() -> Self {
292 Self {}
293 }
294}
295
296impl Verifier<SimpleSignature> for Ed25519Verifier {
297 fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
298 let SimpleSignature::Ed25519 {
299 signature,
300 public_key,
301 } = signature
302 else {
303 return Err(SignatureError::from_source("not an ed25519 signature"));
304 };
305
306 let verifying_key = Ed25519VerifyingKey::new(public_key)?;
307
308 verifying_key.verify(message, signature)
309 }
310}
311
312impl Verifier<UserSignature> for Ed25519Verifier {
313 fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
314 let UserSignature::Simple(signature) = signature else {
315 return Err(SignatureError::from_source("not an ed25519 signature"));
316 };
317
318 <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
319 }
320}
321
322#[cfg(test)]
323mod test {
324 use super::*;
325 use crate::SuiSigner;
326 use crate::SuiVerifier;
327 use sui_sdk_types::PersonalMessage;
328 use test_strategy::proptest;
329
330 #[cfg(target_arch = "wasm32")]
331 use wasm_bindgen_test::wasm_bindgen_test as test;
332
333 #[proptest]
344 fn personal_message_signing(signer: Ed25519PrivateKey, message: Vec<u8>) {
345 let message = PersonalMessage(message.into());
346 let signature = signer.sign_personal_message(&message).unwrap();
347 let verifying_key = signer.verifying_key();
348 verifying_key
349 .verify_personal_message(&message, &signature)
350 .unwrap();
351
352 let verifier = Ed25519Verifier::default();
353 verifier
354 .verify_personal_message(&message, &signature)
355 .unwrap();
356 }
357}