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::error::Error;
61
62pub fn crypto_sign_keypair_inplace(public_key: &mut PublicKey, secret_key: &mut SecretKey) {
64 crypto_sign_ed25519_keypair_inplace(public_key, secret_key)
65}
66
67pub fn crypto_sign_seed_keypair_inplace(
69 public_key: &mut PublicKey,
70 secret_key: &mut SecretKey,
71 seed: &[u8; 32],
72) {
73 crypto_sign_ed25519_seed_keypair_inplace(public_key, secret_key, seed)
74}
75
76#[must_use]
79pub fn crypto_sign_keypair() -> (PublicKey, SecretKey) {
80 crypto_sign_ed25519_keypair()
81}
82
83#[must_use]
86pub fn crypto_sign_seed_keypair(seed: &[u8; 32]) -> (PublicKey, SecretKey) {
87 crypto_sign_ed25519_seed_keypair(seed)
88}
89
90pub fn crypto_sign(
102 signed_message: &mut [u8],
103 message: &[u8],
104 secret_key: &SecretKey,
105) -> Result<(), Error> {
106 crypto_sign_ed25519(signed_message, message, secret_key)
107}
108
109pub fn crypto_sign_open(
121 message: &mut [u8],
122 signed_message: &[u8],
123 public_key: &PublicKey,
124) -> Result<(), Error> {
125 crypto_sign_ed25519_open(message, signed_message, public_key)
126}
127
128pub fn crypto_sign_detached(
140 signature: &mut Signature,
141 message: &[u8],
142 secret_key: &SecretKey,
143) -> Result<(), Error> {
144 crypto_sign_ed25519_detached(signature, message, secret_key);
145 Ok(())
146}
147
148pub fn crypto_sign_verify_detached(
159 signature: &Signature,
160 message: &[u8],
161 public_key: &PublicKey,
162) -> Result<(), Error> {
163 crypto_sign_ed25519_verify_detached(signature, message, public_key)
164}
165
166pub struct SignerState {
168 pub(crate) state: Ed25519SignerState,
169}
170
171#[must_use]
173pub fn crypto_sign_init() -> SignerState {
174 SignerState {
175 state: crypto_sign_ed25519ph_init(),
176 }
177}
178
179pub fn crypto_sign_update(state: &mut SignerState, message: &[u8]) {
181 crypto_sign_ed25519ph_update(&mut state.state, message)
182}
183
184pub fn crypto_sign_final_create(
193 state: SignerState,
194 signature: &mut Signature,
195 secret_key: &SecretKey,
196) -> Result<(), Error> {
197 crypto_sign_ed25519ph_final_create(state.state, signature, secret_key);
198 Ok(())
199}
200
201pub fn crypto_sign_final_verify(
209 state: SignerState,
210 signature: &Signature,
211 public_key: &PublicKey,
212) -> Result<(), Error> {
213 crypto_sign_ed25519ph_final_verify(state.state, signature, public_key)
214}
215
216#[cfg(test)]
217mod consistency_tests {
218 use super::*;
219 use crate::constants::CRYPTO_SIGN_BYTES;
220 use crate::test_prelude::*;
221 use crate::utils::test_util::XorShift64;
222
223 #[test]
227 fn combined_signature_prefix_matches_detached() {
228 let mut rng = XorShift64::new(0x1f83_d9ab_fb41_bd6b);
229 let (public_key, secret_key) = crypto_sign_seed_keypair(&[21u8; 32]);
230 let mut random = Vec::with_capacity(1023);
231 while random.len() < 1023 {
232 random.extend_from_slice(&rng.next_bytes32());
233 }
234 random.truncate(1023);
235
236 for message in [&[][..], &[0x72], &random] {
237 let mut signature = [0u8; CRYPTO_SIGN_BYTES];
238 crypto_sign_detached(&mut signature, message, &secret_key).unwrap();
239
240 let mut signed_message = vec![0u8; message.len() + CRYPTO_SIGN_BYTES];
241 crypto_sign(&mut signed_message, message, &secret_key).unwrap();
242 assert_eq!(
243 signed_message[..CRYPTO_SIGN_BYTES],
244 signature,
245 "{}",
246 message.len()
247 );
248 assert_eq!(
249 signed_message[CRYPTO_SIGN_BYTES..],
250 *message,
251 "{}",
252 message.len()
253 );
254
255 crypto_sign_verify_detached(&signature, message, &public_key).unwrap();
256 let mut opened = vec![0xa5; message.len()];
257 crypto_sign_open(&mut opened, &signed_message, &public_key).unwrap();
258 assert_eq!(opened, message);
259 }
260 }
261
262 #[test]
266 fn incremental_signature_is_independent_of_split_points() {
267 let mut rng = XorShift64::new(0x5be0_cd19_137e_2179);
268 let (public_key, secret_key) = crypto_sign_seed_keypair(&[22u8; 32]);
269 let message: Vec<u8> = (0..3).flat_map(|_| rng.next_bytes32()).take(75).collect();
270
271 let mut whole = crypto_sign_init();
272 crypto_sign_update(&mut whole, &message);
273 let mut reference = [0u8; CRYPTO_SIGN_BYTES];
274 crypto_sign_final_create(whole, &mut reference, &secret_key).unwrap();
275
276 let mut byte_at_a_time = crypto_sign_init();
277 for byte in &message {
278 crypto_sign_update(&mut byte_at_a_time, core::slice::from_ref(byte));
279 }
280 crypto_sign_final_verify(byte_at_a_time, &reference, &public_key).unwrap();
281
282 for split in [0, 1, 63, 64, 65, 74, 75] {
283 let mut signer = crypto_sign_init();
284 crypto_sign_update(&mut signer, &message[..split]);
285 crypto_sign_update(&mut signer, &message[split..]);
286 let mut signature = [0u8; CRYPTO_SIGN_BYTES];
287 crypto_sign_final_create(signer, &mut signature, &secret_key).unwrap();
288 assert_eq!(signature, reference, "split {split}");
289 }
290
291 let mut detached = [0u8; CRYPTO_SIGN_BYTES];
292 crypto_sign_detached(&mut detached, &message, &secret_key).unwrap();
293 assert_ne!(reference, detached);
294 let mut verifier = crypto_sign_init();
295 crypto_sign_update(&mut verifier, &message);
296 assert!(matches!(
297 crypto_sign_final_verify(verifier, &detached, &public_key),
298 Err(Error::AuthenticationFailed)
299 ));
300 assert!(matches!(
301 crypto_sign_verify_detached(&reference, &message, &public_key),
302 Err(Error::AuthenticationFailed)
303 ));
304 }
305}
306
307#[cfg(all(test, dryoc_native_tests))]
308mod tests {
309 use super::*;
310 use crate::constants::{CRYPTO_SIGN_BYTES, CRYPTO_SIGN_PUBLICKEYBYTES};
311 use crate::test_prelude::*;
312
313 #[test]
314 fn combined_signing_rejects_invalid_buffer_lengths() {
315 let (public_key, secret_key) = crypto_sign_keypair();
316
317 let mut short_signed_message = [0u8; CRYPTO_SIGN_BYTES];
318 let error = crypto_sign(&mut short_signed_message, b"x", &secret_key)
319 .expect_err("the signed-message buffer should include the message");
320 assert!(matches!(
321 error,
322 Error::InvalidLength {
323 context: crate::ErrorContext::SignedMessage,
324 ..
325 }
326 ));
327
328 let mut message = [];
329 let short_input = [0u8; CRYPTO_SIGN_BYTES - 1];
330 let error = crypto_sign_open(&mut message, &short_input, &public_key)
331 .expect_err("a signed message must contain a full signature");
332 assert!(matches!(
333 error,
334 Error::InvalidLength {
335 context: crate::ErrorContext::SignedMessage,
336 ..
337 }
338 ));
339
340 let mut oversized_message = [0u8; 1];
341 let signature_only = [0u8; CRYPTO_SIGN_BYTES];
342 let error = crypto_sign_open(&mut oversized_message, &signature_only, &public_key)
343 .expect_err("the output length should match the embedded message");
344 assert!(matches!(
345 error,
346 Error::InvalidLength {
347 context: crate::ErrorContext::Message,
348 ..
349 }
350 ));
351 }
352
353 #[test]
354 fn verification_classifies_invalid_signatures_and_public_keys() {
355 let (public_key, secret_key) = crypto_sign_keypair();
356 let message = b"important message";
357 let mut signature = [0u8; CRYPTO_SIGN_BYTES];
358 crypto_sign_detached(&mut signature, message, &secret_key).expect("signing should succeed");
359
360 let mut tampered_signature = signature;
361 tampered_signature[CRYPTO_SIGN_BYTES - 1] ^= 1;
362 assert!(matches!(
363 crypto_sign_verify_detached(&tampered_signature, message, &public_key),
364 Err(Error::AuthenticationFailed)
365 ));
366 let mut tampered_s_low = signature;
370 tampered_s_low[32] ^= 1;
371 assert!(matches!(
372 crypto_sign_verify_detached(&tampered_s_low, message, &public_key),
373 Err(Error::AuthenticationFailed)
374 ));
375 for byte in [0, 15, 31] {
378 let mut tampered_r = signature;
379 tampered_r[byte] ^= 0x10;
380 assert!(matches!(
381 crypto_sign_verify_detached(&tampered_r, message, &public_key),
382 Err(Error::AuthenticationFailed)
383 ));
384 }
385 assert!(matches!(
386 crypto_sign_verify_detached(&signature, b"important massage", &public_key),
387 Err(Error::AuthenticationFailed)
388 ));
389 let (other_public_key, _) = crypto_sign_keypair();
390 assert!(matches!(
391 crypto_sign_verify_detached(&signature, message, &other_public_key),
392 Err(Error::AuthenticationFailed)
393 ));
394
395 assert!(matches!(
396 crypto_sign_verify_detached(&[0u8; CRYPTO_SIGN_BYTES], message, &public_key),
397 Err(Error::AuthenticationFailed)
398 ));
399
400 assert!(matches!(
401 crypto_sign_verify_detached(&signature, message, &[0u8; CRYPTO_SIGN_PUBLICKEYBYTES],),
402 Err(Error::InvalidKey {
403 context: crate::ErrorContext::Ed25519PublicKey,
404 })
405 ));
406 }
407
408 #[test]
409 fn test_crypto_sign() {
410 use base64::Engine as _;
411 use base64::engine::general_purpose;
412
413 use crate::native_test_util::{sign_ed25519, sign_ed25519_open};
414
415 for _ in 0..10 {
416 let (public_key, secret_key) = crypto_sign_keypair();
417 let message = b"important message";
418 let mut signed_message = vec![0u8; message.len() + CRYPTO_SIGN_BYTES];
419 crypto_sign(&mut signed_message, message, &secret_key).expect("sign failed");
420
421 let so_signed_message = sign_ed25519(message, &secret_key);
422
423 assert_eq!(
424 general_purpose::STANDARD.encode(&signed_message),
425 general_purpose::STANDARD.encode(&so_signed_message)
426 );
427
428 let so_m = sign_ed25519_open(&signed_message, &public_key).expect("verify failed");
429
430 assert_eq!(so_m, message);
431 }
432 }
433
434 #[test]
435 fn test_crypto_sign_open() {
436 use base64::Engine as _;
437 use base64::engine::general_purpose;
438
439 use crate::native_test_util::{sign_ed25519, sign_ed25519_open};
440
441 for _ in 0..10 {
442 let (public_key, secret_key) = crypto_sign_keypair();
443 let message = b"important message";
444 let mut signed_message = vec![0u8; message.len() + CRYPTO_SIGN_BYTES];
445 crypto_sign(&mut signed_message, message, &secret_key).expect("sign failed");
446
447 let so_signed_message = sign_ed25519(message, &secret_key);
448
449 assert_eq!(
450 general_purpose::STANDARD.encode(&signed_message),
451 general_purpose::STANDARD.encode(&so_signed_message)
452 );
453
454 let so_m = sign_ed25519_open(&signed_message, &public_key).expect("verify failed");
455
456 assert_eq!(so_m, message);
457
458 let mut opened_message = vec![0u8; message.len()];
459
460 crypto_sign_open(&mut opened_message, &signed_message, &public_key)
461 .expect("verify failed");
462
463 assert_eq!(opened_message, message);
464 }
465 }
466
467 #[test]
468 fn test_crypto_sign_detached() {
469 use crate::native_test_util::sign_ed25519_verify_detached;
470
471 for _ in 0..10 {
472 let (public_key, secret_key) = crypto_sign_keypair();
473 let message = b"important message";
474 let mut signature = [0u8; CRYPTO_SIGN_BYTES];
475 crypto_sign_detached(&mut signature, message, &secret_key).expect("sign failed");
476
477 assert!(sign_ed25519_verify_detached(
478 &signature,
479 message,
480 &public_key
481 ));
482
483 crypto_sign_verify_detached(&signature, message, &public_key).expect("verify failed");
484 }
485 }
486
487 #[test]
488 fn test_crypto_sign_incremental() {
489 use crate::native_test_util::{sign_ed25519ph, sign_ed25519ph_verify};
490 use crate::rng::copy_randombytes;
491
492 for _ in 0..10 {
493 let (public_key, secret_key) = crypto_sign_keypair();
494 let mut signer = crypto_sign_init();
495 let mut verifier = crypto_sign_init();
496
497 let mut so_parts = Vec::new();
499
500 for _ in 0..3 {
501 let mut randos = vec![0u8; 100];
502 copy_randombytes(&mut randos);
503
504 crypto_sign_update(&mut signer, &randos);
505 crypto_sign_update(&mut verifier, &randos);
506
507 so_parts.push(randos);
508 }
509 let so_parts: Vec<&[u8]> = so_parts.iter().map(Vec::as_slice).collect();
510
511 let mut signature = [0u8; CRYPTO_SIGN_BYTES];
512 crypto_sign_final_create(signer, &mut signature, &secret_key)
513 .expect("final create failed");
514
515 let so_signature = sign_ed25519ph(&so_parts, &secret_key);
516
517 assert_eq!(signature, so_signature);
518
519 crypto_sign_final_verify(verifier, &so_signature, &public_key).expect("verify failed");
520
521 assert!(sign_ed25519ph_verify(&so_parts, &signature, &public_key));
522 }
523 }
524}