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 #[cfg(feature = "bech32")]
112 #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
113 pub fn from_suiprivkey(s: &str) -> Result<Self, SignatureError> {
119 let (scheme, key) = crate::suipriv::decode(s)?;
120 if scheme != SignatureScheme::Ed25519 {
121 return Err(SignatureError::from_source(format!(
122 "suipriv scheme flag is `{}`, expected `ed25519`",
123 scheme.name(),
124 )));
125 }
126 let bytes: [u8; Self::LENGTH] = key.try_into().map_err(|_: Vec<u8>| {
127 SignatureError::from_source("suipriv key has invalid length for ed25519")
128 })?;
129 Ok(Self::new(bytes))
130 }
131
132 #[cfg(feature = "bech32")]
133 #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
134 pub fn to_suiprivkey(&self) -> Result<String, SignatureError> {
136 crate::suipriv::encode(SignatureScheme::Ed25519, self.0.to_bytes().as_slice())
137 }
138}
139
140impl Signer<Ed25519Signature> for Ed25519PrivateKey {
141 fn try_sign(&self, msg: &[u8]) -> Result<Ed25519Signature, SignatureError> {
142 self.0
143 .try_sign(msg)
144 .map(|signature| Ed25519Signature::new(signature.to_bytes()))
145 }
146}
147
148impl Signer<SimpleSignature> for Ed25519PrivateKey {
149 fn try_sign(&self, msg: &[u8]) -> Result<SimpleSignature, SignatureError> {
150 <Self as Signer<Ed25519Signature>>::try_sign(self, msg).map(|signature| {
151 SimpleSignature::Ed25519 {
152 signature,
153 public_key: self.public_key(),
154 }
155 })
156 }
157}
158
159impl Signer<UserSignature> for Ed25519PrivateKey {
160 fn try_sign(&self, msg: &[u8]) -> Result<UserSignature, SignatureError> {
161 <Self as Signer<SimpleSignature>>::try_sign(self, msg).map(UserSignature::Simple)
162 }
163}
164
165#[derive(Debug, Clone, Eq, PartialEq, Default)]
166pub struct Ed25519VerifyingKey(ed25519_dalek::VerifyingKey);
167
168impl Ed25519VerifyingKey {
169 pub fn new(public_key: &Ed25519PublicKey) -> Result<Self, SignatureError> {
170 ed25519_dalek::VerifyingKey::from_bytes(public_key.inner()).map(Self)
171 }
172
173 pub fn public_key(&self) -> Ed25519PublicKey {
174 Ed25519PublicKey::new(self.0.to_bytes())
175 }
176
177 #[cfg(feature = "pem")]
178 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
179 pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
181 ed25519_dalek::pkcs8::DecodePublicKey::from_public_key_der(bytes)
182 .map(Self)
183 .map_err(SignatureError::from_source)
184 }
185
186 #[cfg(feature = "pem")]
187 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
188 pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
190 use pkcs8::EncodePublicKey;
191
192 self.0
193 .to_public_key_der()
194 .map_err(SignatureError::from_source)
195 .map(|der| der.into_vec())
196 }
197
198 #[cfg(feature = "pem")]
199 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
200 pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
202 ed25519_dalek::pkcs8::DecodePublicKey::from_public_key_pem(s)
203 .map(Self)
204 .map_err(SignatureError::from_source)
205 }
206
207 #[cfg(feature = "pem")]
208 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
209 pub fn to_pem(&self) -> Result<String, SignatureError> {
211 use pkcs8::EncodePublicKey;
212
213 self.0
214 .to_public_key_pem(pkcs8::LineEnding::default())
215 .map_err(SignatureError::from_source)
216 }
217
218 #[cfg(feature = "pem")]
219 pub(crate) fn from_dalek(verifying_key: ed25519_dalek::VerifyingKey) -> Self {
220 Self(verifying_key)
221 }
222}
223
224impl Verifier<Ed25519Signature> for Ed25519VerifyingKey {
225 fn verify(&self, message: &[u8], signature: &Ed25519Signature) -> Result<(), SignatureError> {
226 let signature = ed25519_dalek::Signature::from_bytes(signature.inner());
227 self.0.verify_strict(message, &signature)
228 }
229}
230
231impl Verifier<SimpleSignature> for Ed25519VerifyingKey {
232 fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
233 let SimpleSignature::Ed25519 {
234 signature,
235 public_key,
236 } = signature
237 else {
238 return Err(SignatureError::from_source("not an ed25519 signature"));
239 };
240
241 if public_key.inner() != self.0.as_bytes() {
242 return Err(SignatureError::from_source(
243 "public_key in signature does not match",
244 ));
245 }
246
247 <Self as Verifier<Ed25519Signature>>::verify(self, message, signature)
248 }
249}
250
251impl Verifier<UserSignature> for Ed25519VerifyingKey {
252 fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
253 let UserSignature::Simple(signature) = signature else {
254 return Err(SignatureError::from_source("not an ed25519 signature"));
255 };
256
257 <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
258 }
259}
260
261#[derive(Default, Clone, Debug)]
262pub struct Ed25519Verifier {}
263
264impl Ed25519Verifier {
265 pub fn new() -> Self {
266 Self {}
267 }
268}
269
270impl Verifier<SimpleSignature> for Ed25519Verifier {
271 fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
272 let SimpleSignature::Ed25519 {
273 signature,
274 public_key,
275 } = signature
276 else {
277 return Err(SignatureError::from_source("not an ed25519 signature"));
278 };
279
280 let verifying_key = Ed25519VerifyingKey::new(public_key)?;
281
282 verifying_key.verify(message, signature)
283 }
284}
285
286impl Verifier<UserSignature> for Ed25519Verifier {
287 fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
288 let UserSignature::Simple(signature) = signature else {
289 return Err(SignatureError::from_source("not an ed25519 signature"));
290 };
291
292 <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
293 }
294}
295
296#[cfg(test)]
297mod test {
298 use super::*;
299 use crate::SuiSigner;
300 use crate::SuiVerifier;
301 use sui_sdk_types::PersonalMessage;
302 use test_strategy::proptest;
303
304 #[cfg(target_arch = "wasm32")]
305 use wasm_bindgen_test::wasm_bindgen_test as test;
306
307 #[proptest]
318 fn personal_message_signing(signer: Ed25519PrivateKey, message: Vec<u8>) {
319 let message = PersonalMessage(message.into());
320 let signature = signer.sign_personal_message(&message).unwrap();
321 let verifying_key = signer.verifying_key();
322 verifying_key
323 .verify_personal_message(&message, &signature)
324 .unwrap();
325
326 let verifier = Ed25519Verifier::default();
327 verifier
328 .verify_personal_message(&message, &signature)
329 .unwrap();
330 }
331}