Skip to main content

bssl_crypto/
mldsa.rs

1// Copyright 2024 The BoringSSL Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! ML-DSA
16//!
17//! ML-DSA is a post-quantum key signature scheme, specified in
18//! [FIPS 204](https://csrc.nist.gov/pubs/fips/204/final).
19//!
20//! ```
21//! use bssl_crypto::mldsa;
22//!
23//! // Generate a key pair.
24//! let (serialized_public_key, private_key, _private_seed) = mldsa::PrivateKey65::generate();
25//!
26//! // Send `serialized_public_key` to the verifier. The verifier parses it:
27//! let public_key = mldsa::PublicKey65::parse(&serialized_public_key).unwrap();
28//!
29//! // The signer signs a message.
30//! let message = &[0u8, 1, 2, 3];
31//! let signature = private_key.sign(message);
32//!
33//! // Send `message` and `signature` to the verifier. The verifier checks the signature.
34//! assert!(public_key.verify(message, &signature).is_ok());
35//! ```
36
37use crate::{
38    as_cbs, cbb_to_vec, initialized_boxed_struct, initialized_boxed_struct_fallible,
39    initialized_struct, with_output_vec, with_output_vec_fallible, FfiMutSlice, FfiSlice,
40    InvalidSignatureError,
41};
42use alloc::{boxed::Box, vec::Vec};
43use core::mem::MaybeUninit;
44
45/// An ML-DSA-65 private key.
46pub struct PrivateKey65(Box<bssl_sys::MLDSA65_private_key>);
47
48/// An ML-DSA-65 public key.
49pub struct PublicKey65(Box<bssl_sys::MLDSA65_public_key>);
50
51/// The number of bytes in an encoded ML-DSA-65 public key.
52pub const PUBLIC_KEY_BYTES_65: usize = bssl_sys::MLDSA65_PUBLIC_KEY_BYTES as usize;
53
54/// The number of bytes in an encoded ML-DSA-65 signature.
55pub const SIGNATURE_BYTES_65: usize = bssl_sys::MLDSA65_SIGNATURE_BYTES as usize;
56
57/// An ML-DSA-87 private key.
58pub struct PrivateKey87(Box<bssl_sys::MLDSA87_private_key>);
59
60/// An ML-DSA-87 public key.
61pub struct PublicKey87(Box<bssl_sys::MLDSA87_public_key>);
62
63/// The number of bytes in an encoded ML-DSA-87 public key.
64pub const PUBLIC_KEY_BYTES_87: usize = bssl_sys::MLDSA87_PUBLIC_KEY_BYTES as usize;
65
66/// The number of bytes in an encoded ML-DSA-87 signature.
67pub const SIGNATURE_BYTES_87: usize = bssl_sys::MLDSA87_SIGNATURE_BYTES as usize;
68
69/// The number of bytes in an ML-DSA seed value.
70pub const SEED_BYTES: usize = bssl_sys::MLDSA_SEED_BYTES as usize;
71
72/// The number of bytes in an ML-DSA external mu.
73pub const MU_BYTES: usize = bssl_sys::MLDSA_MU_BYTES as usize;
74
75impl PrivateKey65 {
76    /// Generates a random public/private key pair returning a serialized public
77    /// key, a private key, and a private seed value that can be used to
78    /// regenerate the same private key in the future.
79    pub fn generate() -> (Vec<u8>, Self, [u8; SEED_BYTES]) {
80        let mut public_key_bytes = Box::new_uninit_slice(PUBLIC_KEY_BYTES_65);
81        let mut seed = MaybeUninit::<[u8; SEED_BYTES]>::uninit();
82
83        let private_key = unsafe {
84            // Safety: the buffers are the sizes that the FFI code requires.
85            initialized_boxed_struct(|priv_key| {
86                let ok = bssl_sys::MLDSA65_generate_key(
87                    public_key_bytes.as_mut_ptr() as *mut u8,
88                    seed.as_mut_ptr() as *mut u8,
89                    priv_key,
90                );
91                // This function can only fail if out of memory, which is not a
92                // case that this crate handles.
93                assert_eq!(ok, 1);
94            })
95        };
96
97        unsafe {
98            (
99                // Safety: the buffers are always fully initialized by
100                // `MLDSA65_generate_key`.
101                public_key_bytes.assume_init().into(),
102                Self(private_key),
103                seed.assume_init(),
104            )
105        }
106    }
107
108    /// Regenerates a private key from a seed value.
109    pub fn from_seed(seed: &[u8; SEED_BYTES]) -> Self {
110        Self(unsafe {
111            // Safety: `priv_key` is the correct size via the type system and
112            // is always fully written.
113            initialized_boxed_struct(|priv_key| {
114                let ok = bssl_sys::MLDSA65_private_key_from_seed(
115                    priv_key,
116                    seed.as_ffi_ptr(),
117                    seed.len(),
118                );
119                // Since the seed value has the correct length, this function can
120                // never fail.
121                assert_eq!(ok, 1);
122            })
123        })
124    }
125
126    /// Derives the public key corresponding to this private key.
127    pub fn to_public_key(&self) -> PublicKey65 {
128        PublicKey65(unsafe {
129            // Safety: `pub_key` is the correct size via the type system and
130            // is always fully written.
131            initialized_boxed_struct(|pub_key| {
132                bssl_sys::MLDSA65_public_from_private(pub_key, &*self.0);
133            })
134        })
135    }
136
137    /// Signs a message using this private key.
138    pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
139        unsafe {
140            // Safety: `signature` is the correct size via the type system and
141            // is always fully written.
142            with_output_vec(SIGNATURE_BYTES_65, |signature| {
143                let ok = bssl_sys::MLDSA65_sign(
144                    signature,
145                    &*self.0,
146                    msg.as_ffi_ptr(),
147                    msg.len(),
148                    core::ptr::null(),
149                    0,
150                );
151                // This function can only fail if out of memory, which is not a
152                // case that this crate handles.
153                assert_eq!(ok, 1);
154                SIGNATURE_BYTES_65
155            })
156        }
157    }
158
159    /// Signs a message using this private key and the given context.
160    ///
161    /// This function returns None if `context` is longer than 255 bytes.
162    pub fn sign_with_context(&self, msg: &[u8], context: &[u8]) -> Option<Vec<u8>> {
163        unsafe {
164            // Safety: `signature` is the correct size via the type system and
165            // is always fully written.
166            with_output_vec_fallible(SIGNATURE_BYTES_65, |signature| {
167                if bssl_sys::MLDSA65_sign(
168                    signature,
169                    &*self.0,
170                    msg.as_ffi_ptr(),
171                    msg.len(),
172                    context.as_ffi_ptr(),
173                    context.len(),
174                ) == 1
175                {
176                    Some(SIGNATURE_BYTES_65)
177                } else {
178                    None
179                }
180            })
181        }
182    }
183
184    /// Sign pre-hashed data.
185    pub fn sign_prehashed(&self, prehash: Prehash65) -> Vec<u8> {
186        let representative = prehash.finalize();
187        unsafe {
188            // Safety: `signature` is the correct size via the type system and
189            // is always fully written; `representative` is an array of the
190            // correct size.
191            with_output_vec(SIGNATURE_BYTES_65, |signature| {
192                let ok = bssl_sys::MLDSA65_sign_message_representative(
193                    signature,
194                    &*self.0,
195                    representative.as_ffi_ptr(),
196                );
197                // This function can only fail if out of memory, which is not a
198                // case that this crate handles.
199                assert_eq!(ok, 1);
200                SIGNATURE_BYTES_65
201            })
202        }
203    }
204}
205
206impl PublicKey65 {
207    /// Parses a public key from a byte slice.
208    pub fn parse(encoded: &[u8]) -> Option<Self> {
209        let mut cbs = as_cbs(encoded);
210        unsafe {
211            // Safety: `pub_key` is the correct size via the type system and
212            // is fully written if this function returns 1.
213            initialized_boxed_struct_fallible(|pub_key| {
214                bssl_sys::MLDSA65_parse_public_key(pub_key, &mut cbs) == 1 && cbs.len == 0
215            })
216        }
217        .map(Self)
218    }
219
220    /// Return the serialization of this public key.
221    pub fn to_bytes(&self) -> Vec<u8> {
222        unsafe {
223            cbb_to_vec(PUBLIC_KEY_BYTES_65, |buf| {
224                let ok = bssl_sys::MLDSA65_marshal_public_key(buf, &*self.0);
225                // `MLDSA65_marshal_public_key` only fails if it cannot
226                // allocate memory, but `cbb_to_vec` allocates a fixed
227                // amount of memory.
228                assert_eq!(ok, 1);
229            })
230        }
231    }
232
233    /// Verifies a signature for a given message using this public key.
234    pub fn verify(&self, msg: &[u8], signature: &[u8]) -> Result<(), InvalidSignatureError> {
235        unsafe {
236            let ok = bssl_sys::MLDSA65_verify(
237                &*self.0,
238                signature.as_ffi_ptr(),
239                signature.len(),
240                msg.as_ffi_ptr(),
241                msg.len(),
242                core::ptr::null(),
243                0,
244            );
245            if ok == 1 {
246                Ok(())
247            } else {
248                Err(InvalidSignatureError)
249            }
250        }
251    }
252
253    /// Verifies a signature for a given message using this public key and the given context.
254    pub fn verify_with_context(
255        &self,
256        msg: &[u8],
257        signature: &[u8],
258        context: &[u8],
259    ) -> Result<(), InvalidSignatureError> {
260        unsafe {
261            let ok = bssl_sys::MLDSA65_verify(
262                &*self.0,
263                signature.as_ffi_ptr(),
264                signature.len(),
265                msg.as_ffi_ptr(),
266                msg.len(),
267                context.as_ffi_ptr(),
268                context.len(),
269            );
270            if ok == 1 {
271                Ok(())
272            } else {
273                Err(InvalidSignatureError)
274            }
275        }
276    }
277
278    /// Verify pre-hashed data.
279    pub fn verify_prehashed(
280        &self,
281        prehash: Prehash65,
282        signature: &[u8],
283    ) -> Result<(), InvalidSignatureError> {
284        let representative = prehash.finalize();
285        unsafe {
286            let ok = bssl_sys::MLDSA65_verify_message_representative(
287                &*self.0,
288                signature.as_ffi_ptr(),
289                signature.len(),
290                representative.as_ffi_ptr(),
291            );
292            if ok == 1 {
293                Ok(())
294            } else {
295                Err(InvalidSignatureError)
296            }
297        }
298    }
299
300    /// Start a pre-hashing operation using this public key.
301    pub fn prehash(&self) -> Prehash65 {
302        unsafe {
303            // Safety: `self.0` is the correct size via the type system and
304            // is fully written if this function returns 1.
305            initialized_struct(|prehash: *mut Prehash65| {
306                let ok = bssl_sys::MLDSA65_prehash_init(
307                    &mut (*prehash).0,
308                    &*self.0,
309                    core::ptr::null(),
310                    0,
311                );
312                // This function can only fail if too much context is provided, but no context is
313                // used here.
314                assert_eq!(ok, 1);
315            })
316        }
317    }
318}
319
320/// An in-progress ML-DSA-65 pre-hashing operation.
321pub struct Prehash65(bssl_sys::MLDSA65_prehash);
322
323impl Prehash65 {
324    /// Add data to the pre-hashing operation.
325    pub fn update(&mut self, data: &[u8]) {
326        unsafe {
327            // Safety: `self.0` is the correct size via the type system and `data`
328            // is a valid Rust slice.
329            bssl_sys::MLDSA65_prehash_update(&mut self.0, data.as_ffi_ptr(), data.len());
330        }
331    }
332
333    /// Complete the pre-hashing operation.
334    fn finalize(mut self) -> [u8; MU_BYTES] {
335        let mut mu = [0u8; MU_BYTES];
336        unsafe {
337            // Safety: `self.0` is the correct size via the type system, as is `mu`.
338            bssl_sys::MLDSA65_prehash_finalize(mu.as_mut_ffi_ptr(), &mut self.0);
339        }
340        mu
341    }
342}
343
344#[cfg(feature = "std")]
345impl std::io::Write for Prehash65 {
346    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
347        self.update(buf);
348        Ok(buf.len())
349    }
350
351    fn flush(&mut self) -> std::io::Result<()> {
352        Ok(())
353    }
354}
355
356impl PrivateKey87 {
357    /// Generates a random public/private key pair returning a serialized public
358    /// key, a private key, and a private seed value that can be used to
359    /// regenerate the same private key in the future.
360    pub fn generate() -> (Vec<u8>, Self, [u8; SEED_BYTES]) {
361        let mut public_key_bytes = Box::new_uninit_slice(PUBLIC_KEY_BYTES_87);
362        let mut seed = MaybeUninit::<[u8; SEED_BYTES]>::uninit();
363
364        let private_key = unsafe {
365            // Safety: the buffers are the sizes that the FFI code requires.
366            initialized_boxed_struct(|priv_key| {
367                let ok = bssl_sys::MLDSA87_generate_key(
368                    public_key_bytes.as_mut_ptr() as *mut u8,
369                    seed.as_mut_ptr() as *mut u8,
370                    priv_key,
371                );
372                // This function can only fail if out of memory, which is not a
373                // case that this crate handles.
374                assert_eq!(ok, 1);
375            })
376        };
377
378        unsafe {
379            (
380                // Safety: the buffers are always fully initialized by
381                // `MLDSA87_generate_key`.
382                public_key_bytes.assume_init().into(),
383                Self(private_key),
384                seed.assume_init(),
385            )
386        }
387    }
388
389    /// Regenerates a private key from a seed value.
390    pub fn from_seed(seed: &[u8; SEED_BYTES]) -> Self {
391        Self(unsafe {
392            // Safety: `priv_key` is the correct size via the type system and
393            // is always fully written.
394            initialized_boxed_struct(|priv_key| {
395                let ok = bssl_sys::MLDSA87_private_key_from_seed(
396                    priv_key,
397                    seed.as_ffi_ptr(),
398                    seed.len(),
399                );
400                // Since the seed value has the correct length, this function can
401                // never fail.
402                assert_eq!(ok, 1);
403            })
404        })
405    }
406
407    /// Derives the public key corresponding to this private key.
408    pub fn to_public_key(&self) -> PublicKey87 {
409        PublicKey87(unsafe {
410            // Safety: `pub_key` is the correct size via the type system and
411            // is always fully written.
412            initialized_boxed_struct(|pub_key| {
413                bssl_sys::MLDSA87_public_from_private(pub_key, &*self.0);
414            })
415        })
416    }
417
418    /// Signs a message using this private key.
419    pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
420        unsafe {
421            // Safety: `signature` is the correct size via the type system and
422            // is always fully written.
423            with_output_vec(SIGNATURE_BYTES_87, |signature| {
424                let ok = bssl_sys::MLDSA87_sign(
425                    signature,
426                    &*self.0,
427                    msg.as_ffi_ptr(),
428                    msg.len(),
429                    core::ptr::null(),
430                    0,
431                );
432                // This function can only fail if out of memory, which is not a
433                // case that this crate handles.
434                assert_eq!(ok, 1);
435                SIGNATURE_BYTES_87
436            })
437        }
438    }
439
440    /// Signs a message using this private key and the given context.
441    ///
442    /// This function returns None if `context` is longer than 255 bytes.
443    pub fn sign_with_context(&self, msg: &[u8], context: &[u8]) -> Option<Vec<u8>> {
444        unsafe {
445            // Safety: `signature` is the correct size via the type system and
446            // is always fully written.
447            with_output_vec_fallible(SIGNATURE_BYTES_87, |signature| {
448                if bssl_sys::MLDSA87_sign(
449                    signature,
450                    &*self.0,
451                    msg.as_ffi_ptr(),
452                    msg.len(),
453                    context.as_ffi_ptr(),
454                    context.len(),
455                ) == 1
456                {
457                    Some(SIGNATURE_BYTES_87)
458                } else {
459                    None
460                }
461            })
462        }
463    }
464
465    /// Sign pre-hashed data.
466    pub fn sign_prehashed(&self, prehash: Prehash87) -> Vec<u8> {
467        let representative = prehash.finalize();
468        unsafe {
469            // Safety: `signature` is the correct size via the type system and
470            // is always fully written; `representative` is an array of the
471            // correct size.
472            with_output_vec(SIGNATURE_BYTES_87, |signature| {
473                let ok = bssl_sys::MLDSA87_sign_message_representative(
474                    signature,
475                    &*self.0,
476                    representative.as_ffi_ptr(),
477                );
478                // This function can only fail if out of memory, which is not a
479                // case that this crate handles.
480                assert_eq!(ok, 1);
481                SIGNATURE_BYTES_87
482            })
483        }
484    }
485}
486
487impl PublicKey87 {
488    /// Parses a public key from a byte slice.
489    pub fn parse(encoded: &[u8]) -> Option<Self> {
490        let mut cbs = as_cbs(encoded);
491        unsafe {
492            // Safety: `pub_key` is the correct size via the type system and
493            // is fully written if this function returns 1.
494            initialized_boxed_struct_fallible(|pub_key| {
495                bssl_sys::MLDSA87_parse_public_key(pub_key, &mut cbs) == 1 && cbs.len == 0
496            })
497        }
498        .map(Self)
499    }
500
501    /// Return the serialization of this public key.
502    pub fn to_bytes(&self) -> Vec<u8> {
503        unsafe {
504            cbb_to_vec(PUBLIC_KEY_BYTES_87, |buf| {
505                let ok = bssl_sys::MLDSA87_marshal_public_key(buf, &*self.0);
506                // `MLDSA87_marshal_public_key` only fails if it cannot
507                // allocate memory, but `cbb_to_vec` allocates a fixed
508                // amount of memory.
509                assert_eq!(ok, 1);
510            })
511        }
512    }
513
514    /// Verifies a signature for a given message using this public key.
515    pub fn verify(&self, msg: &[u8], signature: &[u8]) -> Result<(), InvalidSignatureError> {
516        unsafe {
517            let ok = bssl_sys::MLDSA87_verify(
518                &*self.0,
519                signature.as_ffi_ptr(),
520                signature.len(),
521                msg.as_ffi_ptr(),
522                msg.len(),
523                core::ptr::null(),
524                0,
525            );
526            if ok == 1 {
527                Ok(())
528            } else {
529                Err(InvalidSignatureError)
530            }
531        }
532    }
533
534    /// Verifies a signature for a given message using this public key and the given context.
535    pub fn verify_with_context(
536        &self,
537        msg: &[u8],
538        signature: &[u8],
539        context: &[u8],
540    ) -> Result<(), InvalidSignatureError> {
541        unsafe {
542            let ok = bssl_sys::MLDSA87_verify(
543                &*self.0,
544                signature.as_ffi_ptr(),
545                signature.len(),
546                msg.as_ffi_ptr(),
547                msg.len(),
548                context.as_ffi_ptr(),
549                context.len(),
550            );
551            if ok == 1 {
552                Ok(())
553            } else {
554                Err(InvalidSignatureError)
555            }
556        }
557    }
558
559    /// Verify pre-hashed data.
560    pub fn verify_prehashed(
561        &self,
562        prehash: Prehash87,
563        signature: &[u8],
564    ) -> Result<(), InvalidSignatureError> {
565        let representative = prehash.finalize();
566        unsafe {
567            let ok = bssl_sys::MLDSA87_verify_message_representative(
568                &*self.0,
569                signature.as_ffi_ptr(),
570                signature.len(),
571                representative.as_ffi_ptr(),
572            );
573            if ok == 1 {
574                Ok(())
575            } else {
576                Err(InvalidSignatureError)
577            }
578        }
579    }
580
581    /// Start a pre-hashing operation using this public key.
582    pub fn prehash(&self) -> Prehash87 {
583        unsafe {
584            // Safety: `self.0` is the correct size via the type system and
585            // is fully written if this function returns 1.
586            initialized_struct(|prehash: *mut Prehash87| {
587                let ok = bssl_sys::MLDSA87_prehash_init(
588                    &mut (*prehash).0,
589                    &*self.0,
590                    core::ptr::null(),
591                    0,
592                );
593                // This function can only fail if too much context is provided, but no context is
594                // used here.
595                assert_eq!(ok, 1);
596            })
597        }
598    }
599}
600
601/// An in-progress ML-DSA-87 pre-hashing operation.
602pub struct Prehash87(bssl_sys::MLDSA87_prehash);
603
604impl Prehash87 {
605    /// Add data to the pre-hashing operation.
606    pub fn update(&mut self, data: &[u8]) {
607        unsafe {
608            // Safety: `self.0` is the correct size via the type system and `data`
609            // is a valid Rust slice.
610            bssl_sys::MLDSA87_prehash_update(&mut self.0, data.as_ffi_ptr(), data.len());
611        }
612    }
613
614    /// Complete the pre-hashing operation.
615    fn finalize(mut self) -> [u8; MU_BYTES] {
616        let mut mu = [0u8; MU_BYTES];
617        unsafe {
618            // Safety: `self.0` is the correct size via the type system, as is `mu`.
619            bssl_sys::MLDSA87_prehash_finalize(mu.as_mut_ffi_ptr(), &mut self.0);
620        }
621        mu
622    }
623}
624
625#[cfg(feature = "std")]
626impl std::io::Write for Prehash87 {
627    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
628        self.update(buf);
629        Ok(buf.len())
630    }
631
632    fn flush(&mut self) -> std::io::Result<()> {
633        Ok(())
634    }
635}
636
637#[cfg(test)]
638mod test {
639    use super::*;
640
641    #[test]
642    fn basic65() {
643        let (serialized_public_key, private_key, private_seed) = PrivateKey65::generate();
644        let public_key = PublicKey65::parse(&serialized_public_key).unwrap();
645        let message = &[0u8, 1, 2, 3];
646        let signature = private_key.sign(message);
647        let private_key2 = PrivateKey65::from_seed(&private_seed);
648        let mut signature2 = private_key2.sign(message);
649        assert!(public_key.verify(message, &signature).is_ok());
650        assert!(public_key.verify(message, &signature2).is_ok());
651
652        signature2[5] ^= 1;
653        assert!(public_key.verify(message, &signature2).is_err());
654
655        let context = b"context";
656        let signature3 = private_key.sign_with_context(message, context).unwrap();
657        assert!(public_key.verify(message, &signature3).is_err());
658        assert!(public_key
659            .verify_with_context(message, &signature3, context)
660            .is_ok());
661    }
662
663    #[test]
664    fn sign_prehashed65() {
665        let (serialized_public_key, private_key, _private_seed) = PrivateKey65::generate();
666        let public_key = PublicKey65::parse(&serialized_public_key).unwrap();
667        let message = &[0u8, 1, 2, 3, 4, 5, 6];
668
669        let mut prehash = public_key.prehash();
670        prehash.update(&message[0..2]);
671        prehash.update(&message[2..4]);
672        prehash.update(&message[4..]);
673        let mut signature = private_key.sign_prehashed(prehash);
674
675        assert!(public_key.verify(message, &signature).is_ok());
676        signature[5] ^= 1;
677        assert!(public_key.verify(message, &signature).is_err());
678    }
679
680    #[cfg(feature = "std")]
681    #[test]
682    fn sign_prehashed65_write() {
683        use std::io::Write;
684        let (serialized_public_key, private_key, _private_seed) = PrivateKey65::generate();
685        let public_key = PublicKey65::parse(&serialized_public_key).unwrap();
686        let message = &[0u8, 1, 2, 3, 4, 5, 6];
687
688        let mut prehash = public_key.prehash();
689        prehash.write(&message[0..2]).unwrap();
690        prehash.write(&message[2..4]).unwrap();
691        prehash.write(&message[4..]).unwrap();
692        prehash.flush().unwrap();
693        let mut signature = private_key.sign_prehashed(prehash);
694
695        assert!(public_key.verify(message, &signature).is_ok());
696        signature[5] ^= 1;
697        assert!(public_key.verify(message, &signature).is_err());
698    }
699
700    #[test]
701    fn verify_prehashed65() {
702        let (serialized_public_key, private_key, _private_seed) = PrivateKey65::generate();
703        let public_key = PublicKey65::parse(&serialized_public_key).unwrap();
704        let message = &[0u8, 1, 2, 3, 4, 5, 6];
705
706        let signature = private_key.sign(message);
707
708        let mut prehash = public_key.prehash();
709        prehash.update(&message[0..2]);
710        prehash.update(&message[2..4]);
711        assert!(public_key.verify_prehashed(prehash, &signature).is_err());
712
713        let mut prehash = public_key.prehash();
714        prehash.update(&message[0..2]);
715        prehash.update(&message[2..4]);
716        prehash.update(&message[4..]);
717        assert!(public_key.verify_prehashed(prehash, &signature).is_ok());
718    }
719
720    #[cfg(feature = "std")]
721    #[test]
722    fn verify_prehashed65_write() {
723        use std::io::Write;
724        let (serialized_public_key, private_key, _private_seed) = PrivateKey65::generate();
725        let public_key = PublicKey65::parse(&serialized_public_key).unwrap();
726        let message = &[0u8, 1, 2, 3, 4, 5, 6];
727
728        let signature = private_key.sign(message);
729
730        let mut prehash = public_key.prehash();
731        prehash.write(&message[0..2]).unwrap();
732        prehash.write(&message[2..4]).unwrap();
733        prehash.flush().unwrap();
734        assert!(public_key.verify_prehashed(prehash, &signature).is_err());
735
736        let mut prehash = public_key.prehash();
737        prehash.write(&message[0..2]).unwrap();
738        prehash.write(&message[2..4]).unwrap();
739        prehash.write(&message[4..]).unwrap();
740        prehash.flush().unwrap();
741        assert!(public_key.verify_prehashed(prehash, &signature).is_ok());
742    }
743
744    #[test]
745    fn marshal_public_key65() {
746        let (serialized_public_key, private_key, _) = PrivateKey65::generate();
747        let public_key = PublicKey65::parse(&serialized_public_key).unwrap();
748        assert_eq!(serialized_public_key, public_key.to_bytes());
749        assert_eq!(
750            serialized_public_key,
751            private_key.to_public_key().to_bytes()
752        );
753    }
754
755    #[test]
756    fn basic87() {
757        let (serialized_public_key, private_key, private_seed) = PrivateKey87::generate();
758        let public_key = PublicKey87::parse(&serialized_public_key).unwrap();
759        let message = &[0u8, 1, 2, 3];
760        let signature = private_key.sign(message);
761        let private_key2 = PrivateKey87::from_seed(&private_seed);
762        let mut signature2 = private_key2.sign(message);
763        assert!(public_key.verify(message, &signature).is_ok());
764        assert!(public_key.verify(message, &signature2).is_ok());
765
766        signature2[5] ^= 1;
767        assert!(public_key.verify(message, &signature2).is_err());
768
769        let context = b"context";
770        let signature3 = private_key.sign_with_context(message, context).unwrap();
771        assert!(public_key.verify(message, &signature3).is_err());
772        assert!(public_key
773            .verify_with_context(message, &signature3, context)
774            .is_ok());
775    }
776
777    #[test]
778    fn sign_prehashed87() {
779        let (serialized_public_key, private_key, _private_seed) = PrivateKey87::generate();
780        let public_key = PublicKey87::parse(&serialized_public_key).unwrap();
781        let message = &[0u8, 1, 2, 3, 4, 5, 6];
782
783        let mut prehash = public_key.prehash();
784        prehash.update(&message[0..2]);
785        prehash.update(&message[2..4]);
786        prehash.update(&message[4..]);
787        let mut signature = private_key.sign_prehashed(prehash);
788
789        assert!(public_key.verify(message, &signature).is_ok());
790        signature[5] ^= 1;
791        assert!(public_key.verify(message, &signature).is_err());
792    }
793
794    #[cfg(feature = "std")]
795    #[test]
796    fn sign_prehashed87_write() {
797        use std::io::Write;
798        let (serialized_public_key, private_key, _private_seed) = PrivateKey87::generate();
799        let public_key = PublicKey87::parse(&serialized_public_key).unwrap();
800        let message = &[0u8, 1, 2, 3, 4, 5, 6];
801
802        let mut prehash = public_key.prehash();
803        prehash.write(&message[0..2]).unwrap();
804        prehash.write(&message[2..4]).unwrap();
805        prehash.write(&message[4..]).unwrap();
806        prehash.flush().unwrap();
807        let mut signature = private_key.sign_prehashed(prehash);
808
809        assert!(public_key.verify(message, &signature).is_ok());
810        signature[5] ^= 1;
811        assert!(public_key.verify(message, &signature).is_err());
812    }
813
814    #[test]
815    fn verify_prehashed87() {
816        let (serialized_public_key, private_key, _private_seed) = PrivateKey87::generate();
817        let public_key = PublicKey87::parse(&serialized_public_key).unwrap();
818        let message = &[0u8, 1, 2, 3, 4, 5, 6];
819
820        let signature = private_key.sign(message);
821
822        let mut prehash = public_key.prehash();
823        prehash.update(&message[0..2]);
824        prehash.update(&message[2..4]);
825        assert!(public_key.verify_prehashed(prehash, &signature).is_err());
826
827        let mut prehash = public_key.prehash();
828        prehash.update(&message[0..2]);
829        prehash.update(&message[2..4]);
830        prehash.update(&message[4..]);
831        assert!(public_key.verify_prehashed(prehash, &signature).is_ok());
832    }
833
834    #[cfg(feature = "std")]
835    #[test]
836    fn verify_prehashed87_write() {
837        use std::io::Write;
838        let (serialized_public_key, private_key, _private_seed) = PrivateKey87::generate();
839        let public_key = PublicKey87::parse(&serialized_public_key).unwrap();
840        let message = &[0u8, 1, 2, 3, 4, 5, 6];
841
842        let signature = private_key.sign(message);
843
844        let mut prehash = public_key.prehash();
845        prehash.write(&message[0..2]).unwrap();
846        prehash.write(&message[2..4]).unwrap();
847        prehash.flush().unwrap();
848        assert!(public_key.verify_prehashed(prehash, &signature).is_err());
849
850        let mut prehash = public_key.prehash();
851        prehash.write(&message[0..2]).unwrap();
852        prehash.write(&message[2..4]).unwrap();
853        prehash.write(&message[4..]).unwrap();
854        prehash.flush().unwrap();
855        assert!(public_key.verify_prehashed(prehash, &signature).is_ok());
856    }
857
858    #[test]
859    fn marshal_public_key87() {
860        let (serialized_public_key, private_key, _) = PrivateKey87::generate();
861        let public_key = PublicKey87::parse(&serialized_public_key).unwrap();
862        assert_eq!(serialized_public_key, public_key.to_bytes());
863        assert_eq!(
864            serialized_public_key,
865            private_key.to_public_key().to_bytes()
866        );
867    }
868}