sui_crypto/
ed25519.rs

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
10pub struct Ed25519PrivateKey(ed25519_dalek::SigningKey);
11
12impl std::fmt::Debug for Ed25519PrivateKey {
13    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14        f.debug_tuple("Ed25519PrivateKey")
15            .field(&"__elided__")
16            .finish()
17    }
18}
19
20#[cfg(test)]
21impl proptest::arbitrary::Arbitrary for Ed25519PrivateKey {
22    type Parameters = ();
23    type Strategy = proptest::strategy::BoxedStrategy<Self>;
24    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
25        use proptest::strategy::Strategy;
26
27        proptest::arbitrary::any::<[u8; Self::LENGTH]>()
28            .prop_map(Self::new)
29            .boxed()
30    }
31}
32
33impl Ed25519PrivateKey {
34    /// The length of an ed25519 private key in bytes.
35    pub const LENGTH: usize = 32;
36
37    pub fn new(bytes: [u8; Self::LENGTH]) -> Self {
38        Self(bytes.into())
39    }
40
41    pub fn scheme(&self) -> SignatureScheme {
42        SignatureScheme::Ed25519
43    }
44
45    pub fn verifying_key(&self) -> Ed25519VerifyingKey {
46        let verifying_key = self.0.verifying_key();
47        Ed25519VerifyingKey(verifying_key)
48    }
49
50    pub fn public_key(&self) -> Ed25519PublicKey {
51        self.verifying_key().public_key()
52    }
53
54    pub fn generate<R>(mut rng: R) -> Self
55    where
56        R: rand_core::RngCore + rand_core::CryptoRng,
57    {
58        let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH];
59        rng.fill_bytes(&mut buf);
60        Self(buf.into())
61    }
62
63    #[cfg(feature = "pem")]
64    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
65    /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data (binary format).
66    pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
67        ed25519_dalek::pkcs8::DecodePrivateKey::from_pkcs8_der(bytes)
68            .map(Self)
69            .map_err(SignatureError::from_source)
70    }
71
72    #[cfg(feature = "pem")]
73    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
74    /// Serialize this private key as DER-encoded PKCS#8
75    pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
76        use ed25519_dalek::pkcs8::EncodePrivateKey;
77
78        self.0
79            .to_pkcs8_der()
80            .map_err(SignatureError::from_source)
81            .map(|der| der.as_bytes().to_owned())
82    }
83
84    #[cfg(feature = "pem")]
85    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
86    /// Deserialize PKCS#8-encoded private key from PEM.
87    pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
88        ed25519_dalek::pkcs8::DecodePrivateKey::from_pkcs8_pem(s)
89            .map(Self)
90            .map_err(SignatureError::from_source)
91    }
92
93    #[cfg(feature = "pem")]
94    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
95    /// Serialize this private key as PEM-encoded PKCS#8
96    pub fn to_pem(&self) -> Result<String, SignatureError> {
97        use pkcs8::EncodePrivateKey;
98
99        self.0
100            .to_pkcs8_pem(pkcs8::LineEnding::default())
101            .map_err(SignatureError::from_source)
102            .map(|pem| (*pem).to_owned())
103    }
104
105    #[cfg(feature = "pem")]
106    pub(crate) fn from_dalek(private_key: ed25519_dalek::SigningKey) -> Self {
107        Self(private_key)
108    }
109}
110
111impl Signer<Ed25519Signature> for Ed25519PrivateKey {
112    fn try_sign(&self, msg: &[u8]) -> Result<Ed25519Signature, SignatureError> {
113        self.0
114            .try_sign(msg)
115            .map(|signature| Ed25519Signature::new(signature.to_bytes()))
116    }
117}
118
119impl Signer<SimpleSignature> for Ed25519PrivateKey {
120    fn try_sign(&self, msg: &[u8]) -> Result<SimpleSignature, SignatureError> {
121        <Self as Signer<Ed25519Signature>>::try_sign(self, msg).map(|signature| {
122            SimpleSignature::Ed25519 {
123                signature,
124                public_key: self.public_key(),
125            }
126        })
127    }
128}
129
130impl Signer<UserSignature> for Ed25519PrivateKey {
131    fn try_sign(&self, msg: &[u8]) -> Result<UserSignature, SignatureError> {
132        <Self as Signer<SimpleSignature>>::try_sign(self, msg).map(UserSignature::Simple)
133    }
134}
135
136#[derive(Debug)]
137pub struct Ed25519VerifyingKey(ed25519_dalek::VerifyingKey);
138
139impl Ed25519VerifyingKey {
140    pub fn new(public_key: &Ed25519PublicKey) -> Result<Self, SignatureError> {
141        ed25519_dalek::VerifyingKey::from_bytes(public_key.inner()).map(Self)
142    }
143
144    pub fn public_key(&self) -> Ed25519PublicKey {
145        Ed25519PublicKey::new(self.0.to_bytes())
146    }
147
148    #[cfg(feature = "pem")]
149    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
150    /// Deserialize public key from ASN.1 DER-encoded data (binary format).
151    pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
152        ed25519_dalek::pkcs8::DecodePublicKey::from_public_key_der(bytes)
153            .map(Self)
154            .map_err(SignatureError::from_source)
155    }
156
157    #[cfg(feature = "pem")]
158    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
159    /// Serialize this public key as DER-encoded data
160    pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
161        use pkcs8::EncodePublicKey;
162
163        self.0
164            .to_public_key_der()
165            .map_err(SignatureError::from_source)
166            .map(|der| der.into_vec())
167    }
168
169    #[cfg(feature = "pem")]
170    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
171    /// Deserialize public key from PEM.
172    pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
173        ed25519_dalek::pkcs8::DecodePublicKey::from_public_key_pem(s)
174            .map(Self)
175            .map_err(SignatureError::from_source)
176    }
177
178    #[cfg(feature = "pem")]
179    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
180    /// Serialize this public key into PEM format
181    pub fn to_pem(&self) -> Result<String, SignatureError> {
182        use pkcs8::EncodePublicKey;
183
184        self.0
185            .to_public_key_pem(pkcs8::LineEnding::default())
186            .map_err(SignatureError::from_source)
187    }
188
189    #[cfg(feature = "pem")]
190    pub(crate) fn from_dalek(verifying_key: ed25519_dalek::VerifyingKey) -> Self {
191        Self(verifying_key)
192    }
193}
194
195impl Verifier<Ed25519Signature> for Ed25519VerifyingKey {
196    fn verify(&self, message: &[u8], signature: &Ed25519Signature) -> Result<(), SignatureError> {
197        let signature = ed25519_dalek::Signature::from_bytes(signature.inner());
198        self.0.verify_strict(message, &signature)
199    }
200}
201
202impl Verifier<SimpleSignature> for Ed25519VerifyingKey {
203    fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
204        let SimpleSignature::Ed25519 {
205            signature,
206            public_key,
207        } = signature
208        else {
209            return Err(SignatureError::from_source("not an ed25519 signature"));
210        };
211
212        if public_key.inner() != self.0.as_bytes() {
213            return Err(SignatureError::from_source(
214                "public_key in signature does not match",
215            ));
216        }
217
218        <Self as Verifier<Ed25519Signature>>::verify(self, message, signature)
219    }
220}
221
222impl Verifier<UserSignature> for Ed25519VerifyingKey {
223    fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
224        let UserSignature::Simple(signature) = signature else {
225            return Err(SignatureError::from_source("not an ed25519 signature"));
226        };
227
228        <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
229    }
230}
231
232#[derive(Default, Clone, Debug)]
233pub struct Ed25519Verifier {}
234
235impl Ed25519Verifier {
236    pub fn new() -> Self {
237        Self {}
238    }
239}
240
241impl Verifier<SimpleSignature> for Ed25519Verifier {
242    fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
243        let SimpleSignature::Ed25519 {
244            signature,
245            public_key,
246        } = signature
247        else {
248            return Err(SignatureError::from_source("not an ed25519 signature"));
249        };
250
251        let verifying_key = Ed25519VerifyingKey::new(public_key)?;
252
253        verifying_key.verify(message, signature)
254    }
255}
256
257impl Verifier<UserSignature> for Ed25519Verifier {
258    fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
259        let UserSignature::Simple(signature) = signature else {
260            return Err(SignatureError::from_source("not an ed25519 signature"));
261        };
262
263        <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
264    }
265}
266
267#[cfg(test)]
268mod test {
269    use super::*;
270    use crate::SuiSigner;
271    use crate::SuiVerifier;
272    use sui_sdk_types::PersonalMessage;
273    use test_strategy::proptest;
274
275    #[cfg(target_arch = "wasm32")]
276    use wasm_bindgen_test::wasm_bindgen_test as test;
277
278    // TODO need to export proptest impl from core crate
279    // #[proptest]
280    // fn transaction_signing(signer: Ed25519PrivateKey, transaction: Transaction) {
281    //     let signature = signer.sign_transaction(&transaction).unwrap();
282    //     let verifier = signer.public_key();
283    //     verifier
284    //         .verify_transaction(&transaction, &signature)
285    //         .unwrap();
286    // }
287
288    #[proptest]
289    fn personal_message_signing(signer: Ed25519PrivateKey, message: Vec<u8>) {
290        let message = PersonalMessage(message.into());
291        let signature = signer.sign_personal_message(&message).unwrap();
292        let verifying_key = signer.verifying_key();
293        verifying_key
294            .verify_personal_message(&message, &signature)
295            .unwrap();
296
297        let verifier = Ed25519Verifier::default();
298        verifier
299            .verify_personal_message(&message, &signature)
300            .unwrap();
301    }
302}