1use super::crypto_sign_ed25519::*;
57pub use super::crypto_sign_ed25519::{
58 PublicKey, SecretKey, crypto_sign_ed25519_sk_to_pk, crypto_sign_ed25519_sk_to_seed,
59};
60use crate::constants::CRYPTO_SIGN_BYTES;
61use crate::error::Error;
62
63pub fn crypto_sign_keypair_inplace(public_key: &mut PublicKey, secret_key: &mut SecretKey) {
65 crypto_sign_ed25519_keypair_inplace(public_key, secret_key)
66}
67
68pub fn crypto_sign_seed_keypair_inplace(
70 public_key: &mut PublicKey,
71 secret_key: &mut SecretKey,
72 seed: &[u8; 32],
73) {
74 crypto_sign_ed25519_seed_keypair_inplace(public_key, secret_key, seed)
75}
76
77pub fn crypto_sign_keypair() -> (PublicKey, SecretKey) {
80 crypto_sign_ed25519_keypair()
81}
82
83pub fn crypto_sign_seed_keypair(seed: &[u8; 32]) -> (PublicKey, SecretKey) {
86 crypto_sign_ed25519_seed_keypair(seed)
87}
88
89pub fn crypto_sign(
101 signed_message: &mut [u8],
102 message: &[u8],
103 secret_key: &SecretKey,
104) -> Result<(), Error> {
105 if signed_message.len() != message.len() + CRYPTO_SIGN_BYTES {
106 Err(length_error!(
107 crate::ErrorContext::SignedMessage,
108 signed_message.len(),
109 exact message.len() + CRYPTO_SIGN_BYTES
110 ))
111 } else {
112 crypto_sign_ed25519(signed_message, message, secret_key)
113 }
114}
115
116pub fn crypto_sign_open(
128 message: &mut [u8],
129 signed_message: &[u8],
130 public_key: &PublicKey,
131) -> Result<(), Error> {
132 if signed_message.len() < CRYPTO_SIGN_BYTES {
133 Err(
134 length_error!(crate::ErrorContext::SignedMessage, signed_message.len(), min CRYPTO_SIGN_BYTES),
135 )
136 } else if message.len() != signed_message.len() - CRYPTO_SIGN_BYTES {
137 Err(length_error!(
138 crate::ErrorContext::Message,
139 message.len(),
140 exact signed_message.len() - CRYPTO_SIGN_BYTES
141 ))
142 } else {
143 crypto_sign_ed25519_open(message, signed_message, public_key)
144 }
145}
146
147pub fn crypto_sign_detached(
159 signature: &mut Signature,
160 message: &[u8],
161 secret_key: &SecretKey,
162) -> Result<(), Error> {
163 crypto_sign_ed25519_detached(signature, message, secret_key)
164}
165
166pub fn crypto_sign_verify_detached(
177 signature: &Signature,
178 message: &[u8],
179 public_key: &PublicKey,
180) -> Result<(), Error> {
181 crypto_sign_ed25519_verify_detached(signature, message, public_key)
182}
183
184pub struct SignerState {
186 state: Ed25519SignerState,
187}
188
189pub fn crypto_sign_init() -> SignerState {
191 SignerState {
192 state: crypto_sign_ed25519ph_init(),
193 }
194}
195
196pub fn crypto_sign_update(state: &mut SignerState, message: &[u8]) {
198 crypto_sign_ed25519ph_update(&mut state.state, message)
199}
200
201pub fn crypto_sign_final_create(
210 state: SignerState,
211 signature: &mut Signature,
212 secret_key: &SecretKey,
213) -> Result<(), Error> {
214 crypto_sign_ed25519ph_final_create(state.state, signature, secret_key)
215}
216
217pub fn crypto_sign_final_verify(
225 state: SignerState,
226 signature: &Signature,
227 public_key: &PublicKey,
228) -> Result<(), Error> {
229 crypto_sign_ed25519ph_final_verify(state.state, signature, public_key)
230}
231
232#[cfg(all(test, dryoc_native_tests))]
233mod tests {
234 use super::*;
235 use crate::constants::CRYPTO_SIGN_PUBLICKEYBYTES;
236
237 #[test]
238 fn combined_signing_rejects_invalid_buffer_lengths() {
239 let (public_key, secret_key) = crypto_sign_keypair();
240
241 let mut short_signed_message = [0u8; CRYPTO_SIGN_BYTES];
242 let error = crypto_sign(&mut short_signed_message, b"x", &secret_key)
243 .expect_err("the signed-message buffer should include the message");
244 assert!(matches!(
245 error,
246 Error::InvalidLength {
247 context: crate::ErrorContext::SignedMessage,
248 ..
249 }
250 ));
251
252 let mut message = [];
253 let short_input = [0u8; CRYPTO_SIGN_BYTES - 1];
254 let error = crypto_sign_open(&mut message, &short_input, &public_key)
255 .expect_err("a signed message must contain a full signature");
256 assert!(matches!(
257 error,
258 Error::InvalidLength {
259 context: crate::ErrorContext::SignedMessage,
260 ..
261 }
262 ));
263
264 let mut oversized_message = [0u8; 1];
265 let signature_only = [0u8; CRYPTO_SIGN_BYTES];
266 let error = crypto_sign_open(&mut oversized_message, &signature_only, &public_key)
267 .expect_err("the output length should match the embedded message");
268 assert!(matches!(
269 error,
270 Error::InvalidLength {
271 context: crate::ErrorContext::Message,
272 ..
273 }
274 ));
275 }
276
277 #[test]
278 fn verification_classifies_invalid_signatures_and_public_keys() {
279 let (public_key, secret_key) = crypto_sign_keypair();
280 let message = b"important message";
281 let mut signature = [0u8; CRYPTO_SIGN_BYTES];
282 crypto_sign_detached(&mut signature, message, &secret_key).expect("signing should succeed");
283
284 let mut tampered_signature = signature;
285 tampered_signature[CRYPTO_SIGN_BYTES - 1] ^= 1;
286 assert!(matches!(
287 crypto_sign_verify_detached(&tampered_signature, message, &public_key),
288 Err(Error::AuthenticationFailed)
289 ));
290
291 assert!(matches!(
292 crypto_sign_verify_detached(&[0u8; CRYPTO_SIGN_BYTES], message, &public_key),
293 Err(Error::AuthenticationFailed)
294 ));
295
296 assert!(matches!(
297 crypto_sign_verify_detached(&signature, message, &[0u8; CRYPTO_SIGN_PUBLICKEYBYTES],),
298 Err(Error::InvalidKey {
299 context: crate::ErrorContext::Ed25519PublicKey,
300 })
301 ));
302 }
303
304 #[test]
305 fn test_crypto_sign() {
306 use base64::Engine as _;
307 use base64::engine::general_purpose;
308 use sodiumoxide::crypto::sign;
309
310 for _ in 0..10 {
311 let (public_key, secret_key) = crypto_sign_keypair();
312 let message = b"important message";
313 let mut signed_message = vec![0u8; message.len() + CRYPTO_SIGN_BYTES];
314 crypto_sign(&mut signed_message, message, &secret_key).expect("sign failed");
315
316 let so_signed_message = sign::sign(
317 message,
318 &sign::SecretKey::from_slice(&secret_key).expect("secret key failed"),
319 );
320
321 assert_eq!(
322 general_purpose::STANDARD.encode(&signed_message),
323 general_purpose::STANDARD.encode(&so_signed_message)
324 );
325
326 let so_m = sign::verify(
327 &signed_message,
328 &sign::PublicKey::from_slice(&public_key).expect("public key failed"),
329 )
330 .expect("verify failed");
331
332 assert_eq!(so_m, message);
333 }
334 }
335
336 #[test]
337 fn test_crypto_sign_open() {
338 use base64::Engine as _;
339 use base64::engine::general_purpose;
340 use sodiumoxide::crypto::sign;
341
342 for _ in 0..10 {
343 let (public_key, secret_key) = crypto_sign_keypair();
344 let message = b"important message";
345 let mut signed_message = vec![0u8; message.len() + CRYPTO_SIGN_BYTES];
346 crypto_sign(&mut signed_message, message, &secret_key).expect("sign failed");
347
348 let so_signed_message = sign::sign(
349 message,
350 &sign::SecretKey::from_slice(&secret_key).expect("secret key failed"),
351 );
352
353 assert_eq!(
354 general_purpose::STANDARD.encode(&signed_message),
355 general_purpose::STANDARD.encode(&so_signed_message)
356 );
357
358 let so_m = sign::verify(
359 &signed_message,
360 &sign::PublicKey::from_slice(&public_key).expect("public key failed"),
361 )
362 .expect("verify failed");
363
364 assert_eq!(so_m, message);
365
366 let mut opened_message = vec![0u8; message.len()];
367
368 crypto_sign_open(&mut opened_message, &signed_message, &public_key)
369 .expect("verify failed");
370
371 assert_eq!(opened_message, message);
372 }
373 }
374
375 #[test]
376 fn test_crypto_sign_detached() {
377 use sodiumoxide::crypto::sign;
378
379 for _ in 0..10 {
380 let (public_key, secret_key) = crypto_sign_keypair();
381 let message = b"important message";
382 let mut signature = [0u8; CRYPTO_SIGN_BYTES];
383 crypto_sign_detached(&mut signature, message, &secret_key).expect("sign failed");
384
385 assert!(sign::verify_detached(
386 &sign::ed25519::Signature::from_bytes(&signature).expect("secret key failed"),
387 message,
388 &sign::PublicKey::from_slice(&public_key).expect("public key failed"),
389 ));
390
391 crypto_sign_verify_detached(&signature, message, &public_key).expect("verify failed");
392 }
393 }
394
395 #[test]
396 fn test_crypto_sign_incremental() {
397 use sodiumoxide::crypto::sign;
398
399 use crate::rng::copy_randombytes;
400
401 for _ in 0..10 {
402 let (public_key, secret_key) = crypto_sign_keypair();
403 let mut signer = crypto_sign_init();
404 let mut verifier = crypto_sign_init();
405
406 let mut so_signer = sign::State::init();
407 let mut so_verifier = sign::State::init();
408
409 for _ in 0..3 {
410 let mut randos = vec![0u8; 100];
411 copy_randombytes(&mut randos);
412
413 crypto_sign_update(&mut signer, &randos);
414 crypto_sign_update(&mut verifier, &randos);
415
416 so_signer.update(&randos);
417 so_verifier.update(&randos);
418 }
419
420 let mut signature = [0u8; CRYPTO_SIGN_BYTES];
421 crypto_sign_final_create(signer, &mut signature, &secret_key)
422 .expect("final create failed");
423
424 let so_signature = so_signer
425 .finalize(&sign::SecretKey::from_slice(&secret_key).expect("secret key failed"));
426
427 assert_eq!(signature, so_signature.to_bytes());
428
429 crypto_sign_final_verify(verifier, &so_signature.to_bytes(), &public_key)
430 .expect("verify failed");
431
432 assert!(so_signer.verify(
433 &sign::ed25519::Signature::from_bytes(&signature).expect("secret key failed"),
434 &sign::PublicKey::from_slice(&public_key).expect("public key failed"),
435 ));
436 }
437 }
438}