1use std::collections::VecDeque;
2#[cfg(feature = "std")]
3use std::marker::PhantomData;
4
5#[cfg(not(feature = "std"))]
6use alloc::collections::BTreeMap;
7use cryptimitives::key::x25519_ristretto;
8
9#[cfg(not(feature = "std"))]
10use core::marker::PhantomData;
11
12#[cfg(feature = "serde_derive")]
13use serde::{Deserialize, Serialize};
14
15use cryptraits::{
16 aead::Aead,
17 convert::{Len, ToVec},
18 hmac::Hmac,
19 kdf::Kdf,
20 key::{Generate, KeyPair, PublicKey, SecretKey},
21 key_exchange::DiffieHellman,
22};
23use rand_core::{CryptoRng, RngCore};
24
25use crate::errors::{DoubleRatchetError, DoubleRatchetResult};
26
27pub type Secret = [u8; 32];
28
29pub const DEFAULT_MAX_SKIP: usize = 2000;
30
31pub struct DoubleRatchetOptions {
32 pub max_skip: usize,
33}
34
35impl Default for DoubleRatchetOptions {
36 fn default() -> Self {
37 Self {
38 max_skip: DEFAULT_MAX_SKIP,
39 }
40 }
41}
42
43#[cfg(not(feature = "serde_derive"))]
44trait DrPkToVec: ToVec {}
45
46#[cfg(feature = "serde_derive")]
47pub trait DrPkToVec: ToVec + Serialize + for<'a> Deserialize<'a> {}
48
49#[cfg(feature = "serde_derive")]
50impl DrPkToVec for x25519_ristretto::PublicKey {}
51
52#[cfg(not(feature = "serde_derive"))]
53pub struct DoubleRatchet<K, KDF, AEAD, HMAC>
54where
55 K: KeyPair + DiffieHellman,
56 KDF: Kdf,
57 AEAD: Aead,
58 HMAC: Hmac,
59 <K as DiffieHellman>::SSK: ToVec,
60 <K as DiffieHellman>::PK: DrPkToVec,
61{
62 dhs: K,
64
65 dhr: Option<K::PK>,
67
68 rk: Secret,
70
71 cks: Option<Secret>,
73
74 ckr: Option<Secret>,
76
77 ns: u32,
79
80 nr: u32,
82
83 pn: u32,
85
86 mkskipped: VecDeque<(Vec<u8>, u32, Secret)>,
88
89 max_skipped: usize,
91
92 _kdf: PhantomData<KDF>,
93 _aead: PhantomData<AEAD>,
94 _hmac: PhantomData<HMAC>,
95}
96
97#[cfg(feature = "serde_derive")]
98#[derive(Serialize, Deserialize)]
99pub struct DoubleRatchet<K, KDF, AEAD, HMAC>
100where
101 K: KeyPair + DiffieHellman,
102 KDF: Kdf,
103 AEAD: Aead,
104 HMAC: Hmac,
105 <K as DiffieHellman>::SSK: ToVec,
106 <K as DiffieHellman>::PK: DrPkToVec,
107{
108 dhs: K,
110
111 dhr: Option<K::PK>,
113
114 rk: Secret,
116
117 cks: Option<Secret>,
119
120 ckr: Option<Secret>,
122
123 ns: u32,
125
126 nr: u32,
128
129 pn: u32,
131
132 mkskipped: VecDeque<(Vec<u8>, u32, Secret)>,
134
135 max_skipped: usize,
137
138 #[serde(skip_serializing, skip_deserializing)]
139 _kdf: PhantomData<KDF>,
140
141 #[serde(skip_serializing, skip_deserializing)]
142 _aead: PhantomData<AEAD>,
143
144 #[serde(skip_serializing, skip_deserializing)]
145 _hmac: PhantomData<HMAC>,
146}
147
148#[derive(Debug, Clone, PartialEq)]
150#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
151pub struct Header<PK: PublicKey> {
152 dhs: PK,
154
155 pn: u32,
157
158 n: u32,
160}
161
162impl<PK: PublicKey> Header<PK> {
163 pub fn dhs(&self) -> &PK {
164 &self.dhs
165 }
166
167 pub fn pn(&self) -> u32 {
168 self.pn
169 }
170
171 pub fn n(&self) -> u32 {
172 self.n
173 }
174}
175
176impl<PK: PublicKey + ToVec> ToVec for Header<PK> {
177 fn to_vec(&self) -> Vec<u8>
178 where
179 Self: Sized,
180 {
181 let mut v = Vec::new();
182 v.extend_from_slice(&self.dhs.to_vec());
183 v.extend_from_slice(&self.pn.to_be_bytes());
184 v.extend_from_slice(&self.n.to_be_bytes());
185 v
186 }
187}
188
189impl<PK: PublicKey + Len> Len for Header<PK> {
190 const LEN: usize = PK::LEN + 8;
191}
192
193impl<'a, K, KDF, AEAD, HMAC> DoubleRatchet<K, KDF, AEAD, HMAC>
194where
195 K: KeyPair + DiffieHellman + Generate,
196 KDF: Kdf,
197 AEAD: Aead,
198 HMAC: Hmac,
199 <K as DiffieHellman>::SSK: ToVec,
200 <K as DiffieHellman>::PK: DrPkToVec,
201{
202 pub fn init_alice<R>(
204 ssk: &impl ToVec,
205 bob_dh_pk: K::PK,
206 ckr: Option<Secret>,
207 csprng: &mut R,
208 ) -> DoubleRatchet<K, KDF, AEAD, HMAC>
209 where
210 R: CryptoRng + RngCore,
211 K::SSK: ToVec,
212 {
213 Self::do_init_alice(
214 ssk,
215 bob_dh_pk,
216 ckr,
217 &DoubleRatchetOptions::default(),
218 csprng,
219 )
220 }
221
222 pub fn init_alice_with_options<R>(
224 ssk: &impl ToVec,
225 bob_dh_pk: K::PK,
226 ckr: Option<Secret>,
227 opts: &DoubleRatchetOptions,
228 csprng: &mut R,
229 ) -> DoubleRatchet<K, KDF, AEAD, HMAC>
230 where
231 R: CryptoRng + RngCore,
232 K::SSK: ToVec,
233 {
234 Self::do_init_alice(ssk, bob_dh_pk, ckr, opts, csprng)
235 }
236
237 pub fn do_init_alice<R>(
238 ssk: &impl ToVec,
239 bob_dh_pk: K::PK,
240 ckr: Option<Secret>,
241 opts: &DoubleRatchetOptions,
242 csprng: &mut R,
243 ) -> DoubleRatchet<K, KDF, AEAD, HMAC>
244 where
245 R: CryptoRng + RngCore,
246 K::SSK: ToVec,
247 {
248 let dhs = K::generate_with(csprng);
249 let (rk, cks) = Self::kdf_rk(
250 Some(&ssk.to_vec()),
251 b"WhisperText",
252 &dhs.diffie_hellman(&bob_dh_pk).to_vec(),
253 )
254 .unwrap();
255
256 Self {
257 dhs,
258 dhr: Some(bob_dh_pk),
259 rk,
260 cks: Some(cks),
261 ckr,
262 ns: 0,
263 nr: 0,
264 pn: 0,
265 mkskipped: Default::default(),
266 max_skipped: opts.max_skip,
267 _kdf: PhantomData::default(),
268 _aead: PhantomData::default(),
269 _hmac: PhantomData::default(),
270 }
271 }
272
273 pub fn init_bob(rk: &impl ToVec, dhs: K, cks: Option<Secret>) -> Self {
275 Self::do_init_bob(rk, dhs, cks, &DoubleRatchetOptions::default())
276 }
277
278 pub fn init_bob_with_options(
280 rk: &impl ToVec,
281 dhs: K,
282 cks: Option<Secret>,
283 opts: &DoubleRatchetOptions,
284 ) -> Self {
285 Self::do_init_bob(rk, dhs, cks, opts)
286 }
287
288 pub fn do_init_bob(
289 rk: &impl ToVec,
290 dhs: K,
291 cks: Option<Secret>,
292 opts: &DoubleRatchetOptions,
293 ) -> Self {
294 Self {
295 dhs,
296 dhr: None,
297 rk: rk.to_vec().try_into().unwrap(),
298 cks,
299 ckr: None,
300 ns: 0,
301 nr: 0,
302 pn: 0,
303 mkskipped: Default::default(),
304 max_skipped: opts.max_skip,
305 _kdf: PhantomData::default(),
306 _aead: PhantomData::default(),
307 _hmac: PhantomData::default(),
308 }
309 }
310
311 pub fn encrypt<R>(
312 &mut self,
313 data: &[u8],
314 aad: &[u8],
315 csprng: &mut R,
316 ) -> (Header<<<K as KeyPair>::SK as SecretKey>::PK>, Vec<u8>)
317 where
318 R: CryptoRng + RngCore,
319 {
320 self.try_encrypt(data, aad, csprng).unwrap()
321 }
322
323 pub fn try_encrypt<R>(
324 &mut self,
325 data: &[u8],
326 aad: &[u8],
327 csprng: &mut R,
328 ) -> DoubleRatchetResult<(Header<<<K as KeyPair>::SK as SecretKey>::PK>, Vec<u8>)>
329 where
330 R: CryptoRng + RngCore,
331 {
332 if let Some(dhr) = self.dhr {
333 if self.cks.is_none() {
334 self.dhs = K::generate_with(csprng);
335 let (rk, cks) = Self::kdf_rk(
336 Some(&self.dhs.diffie_hellman(&dhr).to_vec()),
337 b"WhisperText",
338 &self.rk,
339 )
340 .unwrap();
341
342 self.rk = rk;
343 self.cks = Some(cks);
344 self.pn = self.ns;
345 self.ns = 0;
346 }
347 } else {
348 return Err(DoubleRatchetError::NotInitialized);
349 }
350
351 let (new_cks, mk) = Self::kdf_ck(&self.cks.unwrap()).unwrap();
352 self.cks = Some(new_cks);
353
354 let header = self.header();
355
356 let mut nonce = vec![0u8; 8];
357 nonce.extend_from_slice(&self.ns.to_be_bytes());
358
359 self.ns += 1;
360
361 Ok((
362 header,
363 AEAD::new(&mk).encrypt(&nonce, data, Some(aad)).unwrap(),
364 ))
365 }
366
367 fn kdf_rk(salt: Option<&[u8]>, info: &[u8], input: &[u8]) -> Result<(Secret, Secret), KDF::E> {
368 let mut output = [0u8; 64];
369
370 KDF::new(salt, input).expand(info, &mut output)?;
371
372 let (root_key, chain_key) = output.split_at(32);
373
374 Ok((root_key.try_into().unwrap(), chain_key.try_into().unwrap()))
375 }
376
377 fn kdf_ck(key: &[u8]) -> Result<(Secret, Secret), HMAC::E> {
378 let mut mac = HMAC::new_from_slice(key)?;
379 mac.update(&[0x01]);
380 let ck = mac.finalize();
381
382 let mut mac = HMAC::new_from_slice(key)?;
383 mac.update(&[0x02]);
384 let mk = mac.finalize();
385
386 Ok((ck.try_into().unwrap(), mk.try_into().unwrap()))
387 }
388
389 fn header(&self) -> Header<<<K as KeyPair>::SK as SecretKey>::PK> {
390 Header {
391 dhs: self.dhs.to_public(),
392 pn: self.pn,
393 n: self.ns,
394 }
395 }
396
397 pub fn decrypt<R>(
398 &mut self,
399 header: &Header<K::PK>,
400 ciphertext: &[u8],
401 aad: &[u8],
402 csprng: &mut R,
403 ) -> Vec<u8>
404 where
405 R: CryptoRng + RngCore,
406 {
407 self.try_decrypt(header, ciphertext, aad, csprng).unwrap()
408 }
409
410 pub fn try_decrypt<R>(
411 &mut self,
412 header: &Header<K::PK>,
413 ciphertext: &[u8],
414 aad: &[u8],
415 csprng: &mut R,
416 ) -> DoubleRatchetResult<Vec<u8>>
417 where
418 R: CryptoRng + RngCore,
419 {
420 let mut nonce = vec![0u8; 8];
421 nonce.extend_from_slice(&header.n.to_be_bytes());
422
423 if let Some(mk) = self.get_skipped_message_key(header.dhs, header.n) {
424 return AEAD::new(&mk)
425 .decrypt(&nonce, ciphertext, Some(aad))
426 .or(Err(DoubleRatchetError::AeadError));
427 }
428
429 if Some(&header.dhs) != self.dhr.as_ref() {
430 self.skip_message_keys(header.pn)?;
431 self.dh_ratchet(header, csprng)
432 }
433
434 self.skip_message_keys(header.n)?;
435
436 let (ckr, mk) = Self::kdf_ck(&self.ckr.unwrap()).unwrap();
437 self.ckr = Some(ckr);
438 self.nr += 1;
439
440 AEAD::new(&mk)
441 .decrypt(&nonce, ciphertext, Some(aad))
442 .or(Err(DoubleRatchetError::AeadError))
443 }
444
445 fn dh_ratchet<R>(&mut self, header: &Header<K::PK>, csprng: &mut R)
446 where
447 R: CryptoRng + RngCore,
448 {
449 self.pn = self.ns;
450 self.ns = 0;
451 self.nr = 0;
452 self.dhr = Some(header.dhs);
453
454 let (rk, ckr) = Self::kdf_rk(
455 Some(&self.rk),
456 b"WhisperText",
457 &self.dhs.diffie_hellman(&self.dhr.unwrap()).to_vec(),
458 )
459 .unwrap();
460
461 self.rk = rk;
462 self.ckr = Some(ckr);
463 self.dhs = K::generate_with(csprng);
464
465 let (rk, cks) = Self::kdf_rk(
466 Some(&self.rk),
467 b"WhisperText",
468 &self.dhs.diffie_hellman(&self.dhr.unwrap()).to_vec(),
469 )
470 .unwrap();
471
472 self.rk = rk;
473 self.cks = Some(cks);
474 }
475
476 fn skip_message_keys(&mut self, until: u32) -> DoubleRatchetResult<()> {
477 while self.nr < until {
478 if self.mkskipped.len() >= self.max_skipped {
479 self.mkskipped.pop_front();
480 }
481
482 if let Some(ckr) = self.ckr {
483 let (ckr, mk) = Self::kdf_ck(&ckr).unwrap();
484 self.ckr = Some(ckr);
485 self.mkskipped
486 .push_back((self.dhr.unwrap().to_vec(), self.nr, mk));
487 self.nr += 1;
488 }
489 }
490 Ok(())
491 }
492
493 fn get_skipped_message_key(&mut self, ratchet_key: impl ToVec, n: u32) -> Option<[u8; 32]> {
494 let pk = ratchet_key.to_vec();
495
496 self.mkskipped
497 .iter()
498 .position(|(skipped_pk, skipped_n, _)| skipped_pk == &pk && *skipped_n == n)
499 .and_then(|index| self.mkskipped.remove(index))
500 .map(|(_, _, mk)| mk)
501 }
502}
503
504#[cfg(all(test, feature = "cryptimitives"))]
505mod tests {
506 use cryptimitives::{aead, hmac, kdf, key::x25519_ristretto};
507 use rand_core::OsRng;
508
509 use super::*;
510
511 type DR = DoubleRatchet<
512 x25519_ristretto::KeyPair,
513 kdf::sha256::Kdf,
514 aead::aes_gcm::Aes256Gcm,
515 hmac::sha256::Hmac,
516 >;
517
518 fn asymmetric_setup<R>(opts: Option<DoubleRatchetOptions>, csprng: &mut R) -> (DR, DR)
519 where
520 R: CryptoRng + RngCore,
521 {
522 let alice_pair = x25519_ristretto::KeyPair::default();
523 let bob_pair = x25519_ristretto::KeyPair::default();
524
525 let ssk = alice_pair.diffie_hellman(bob_pair.public());
526
527 let opts = opts.unwrap_or_default();
528
529 let alice = DR::init_alice_with_options(&ssk, bob_pair.to_public(), None, &opts, csprng);
530 let bob = DR::init_bob_with_options(&ssk, bob_pair, None, &opts);
531
532 (alice, bob)
533 }
534
535 #[test]
536 fn test_asymmetric() {
537 let (mut alice, mut bob) = asymmetric_setup(None, &mut OsRng);
538
539 let (pt_a, ad_a) = (b"Hey, Bob", b"A2B");
540 let (pt_b, ad_b) = (b"Hey, Alice", b"B2A");
541
542 let (header_a, ciphertext_a) = alice.encrypt(pt_a, ad_a, &mut OsRng);
543
544 assert_eq!(
545 bob.try_encrypt(pt_b, ad_b, &mut OsRng),
546 Err(DoubleRatchetError::NotInitialized)
547 );
548
549 assert_eq!(
550 bob.decrypt(&header_a, &ciphertext_a, ad_a, &mut OsRng),
551 Vec::from(&pt_a[..])
552 );
553 }
554
555 #[test]
556 fn test_out_of_order() {
557 let (mut alice, mut bob) = asymmetric_setup(None, &mut OsRng);
558
559 let (ad_a, ad_b) = (b"A2B", b"B2A");
560 let pt_a_0 = b"Good day Robert";
561
562 let (h_a_0, ct_a_0) = alice.encrypt(pt_a_0, ad_a, &mut OsRng);
563
564 assert_eq!(
565 bob.decrypt(&h_a_0, &ct_a_0, ad_a, &mut OsRng),
566 Vec::from(&pt_a_0[..])
567 );
568
569 let pt_a_1 = b"Do you like Rust?";
570 let (h_a_1, ct_a_1) = alice.encrypt(pt_a_1, ad_a, &mut OsRng);
571
572 let pt_b_0 = b"Salutations Allison";
575 let (h_b_0, ct_b_0) = bob.encrypt(pt_b_0, ad_b, &mut OsRng);
576
577 let pt_b_1 = b"How is your day going?";
579 let (h_b_1, ct_b_1) = bob.encrypt(pt_b_1, ad_b, &mut OsRng);
580
581 assert_eq!(
582 alice.decrypt(&h_b_1, &ct_b_1, ad_b, &mut OsRng),
583 Vec::from(&pt_b_1[..])
584 );
585
586 let pt_a_2 = b"My day is fine.";
587 let (h_a_2, ct_a_2) = alice.encrypt(pt_a_2, ad_a, &mut OsRng);
588
589 let pt_a_3 = b"My day is not that fine...";
590 let (h_a_3, ct_a_3) = alice.encrypt(pt_a_3, ad_a, &mut OsRng);
591
592 let pt_a_4 = b"Its rainy";
593 let (h_a_4, ct_a_4) = alice.encrypt(pt_a_4, ad_a, &mut OsRng);
594
595 let pt_a_5 = b"And windy";
596 let (h_a_5, ct_a_5) = alice.encrypt(pt_a_5, ad_a, &mut OsRng);
597
598 let pt_a_6 = b"And muddy";
599 let (h_a_6, ct_a_6) = alice.encrypt(pt_a_6, ad_a, &mut OsRng);
600
601 assert_eq!(
602 bob.decrypt(&h_a_6, &ct_a_6, ad_a, &mut OsRng),
603 Vec::from(&pt_a_6[..])
604 );
605
606 assert_eq!(
607 bob.decrypt(&h_a_5, &ct_a_5, ad_a, &mut OsRng),
608 Vec::from(&pt_a_5[..])
609 );
610
611 assert_eq!(
612 bob.decrypt(&h_a_4, &ct_a_4, ad_a, &mut OsRng),
613 Vec::from(&pt_a_4[..])
614 );
615
616 assert_eq!(
617 bob.decrypt(&h_a_2, &ct_a_2, ad_a, &mut OsRng),
618 Vec::from(&pt_a_2[..])
619 );
620
621 assert_eq!(
622 bob.decrypt(&h_a_3, &ct_a_3, ad_a, &mut OsRng),
623 Vec::from(&pt_a_3[..])
624 );
625
626 assert_eq!(
628 bob.decrypt(&h_a_1, &ct_a_1, ad_a, &mut OsRng),
629 Vec::from(&pt_a_1[..])
630 );
631
632 let pt_b_2 = b"Yes, I like Rust";
633 let (h_b_2, ct_b_2) = bob.encrypt(pt_b_2, ad_b, &mut OsRng);
634
635 assert_eq!(
636 alice.decrypt(&h_b_2, &ct_b_2, ad_b, &mut OsRng),
637 Vec::from(&pt_b_2[..])
638 );
639
640 assert_eq!(
642 alice.decrypt(&h_b_0, &ct_b_0, ad_b, &mut OsRng),
643 Vec::from(&pt_b_0[..])
644 );
645 }
646
647 #[cfg(feature = "serde_derive")]
648 #[test]
649 fn test_asymmetric_serde() {
650 let (bob_serialized, header_a, ciphertext_a, ad_a, pt_a) = {
651 let (mut alice, mut bob) = asymmetric_setup(None, &mut OsRng);
652
653 let (pt_a, ad_a) = (b"Hey, Bob", b"A2B");
654 let (pt_b, ad_b) = (b"Hey, Alice", b"B2A");
655
656 let (header_a, ciphertext_a) = alice.encrypt(pt_a, ad_a, &mut OsRng);
657
658 assert_eq!(
659 bob.try_encrypt(pt_b, ad_b, &mut OsRng),
660 Err(DoubleRatchetError::NotInitialized)
661 );
662
663 (
664 serde_json::to_string(&bob).unwrap(),
665 header_a,
666 ciphertext_a,
667 ad_a,
668 pt_a,
669 )
670 };
671
672 let mut bob: DR = serde_json::from_str(&bob_serialized).unwrap();
673
674 assert_eq!(
675 bob.decrypt(&header_a, &ciphertext_a, ad_a, &mut OsRng),
676 Vec::from(&pt_a[..])
677 );
678 }
679
680 #[cfg(feature = "serde_derive")]
681 #[test]
682 fn test_out_of_order_serde() {
683 let (mut alice, mut bob) = asymmetric_setup(None, &mut OsRng);
684
685 let (ad_a, ad_b) = (b"A2B", b"B2A");
686 let pt_a_0 = b"Good day Robert";
687
688 let (h_a_0, ct_a_0) = alice.encrypt(pt_a_0, ad_a, &mut OsRng);
689
690 assert_eq!(
691 bob.decrypt(&h_a_0, &ct_a_0, ad_a, &mut OsRng),
692 Vec::from(&pt_a_0[..])
693 );
694
695 let pt_a_1 = b"Do you like Rust?";
696 let (h_a_1, ct_a_1) = alice.encrypt(pt_a_1, ad_a, &mut OsRng);
697
698 let pt_b_0 = b"Salutations Allison";
701 let (h_b_0, ct_b_0) = bob.encrypt(pt_b_0, ad_b, &mut OsRng);
702
703 let pt_b_1 = b"How is your day going?";
705 let (h_b_1, ct_b_1) = bob.encrypt(pt_b_1, ad_b, &mut OsRng);
706
707 assert_eq!(
708 alice.decrypt(&h_b_1, &ct_b_1, ad_b, &mut OsRng),
709 Vec::from(&pt_b_1[..])
710 );
711
712 let pt_a_2 = b"My day is fine.";
713 let (h_a_2, ct_a_2) = alice.encrypt(pt_a_2, ad_a, &mut OsRng);
714
715 assert_eq!(
716 bob.decrypt(&h_a_2, &ct_a_2, ad_a, &mut OsRng),
717 Vec::from(&pt_a_2[..])
718 );
719
720 let bob_serialized = serde_json::to_string(&bob).unwrap();
721
722 let mut bob: DR = serde_json::from_str(&bob_serialized).unwrap();
723
724 assert_eq!(
726 bob.decrypt(&h_a_1, &ct_a_1, ad_a, &mut OsRng),
727 Vec::from(&pt_a_1[..])
728 );
729
730 let pt_b_2 = b"Yes, I like Rust";
731 let (h_b_2, ct_b_2) = bob.encrypt(pt_b_2, ad_b, &mut OsRng);
732
733 assert_eq!(
734 alice.decrypt(&h_b_2, &ct_b_2, ad_b, &mut OsRng),
735 Vec::from(&pt_b_2[..])
736 );
737
738 assert_eq!(
740 alice.decrypt(&h_b_0, &ct_b_0, ad_b, &mut OsRng),
741 Vec::from(&pt_b_0[..])
742 );
743 }
744
745 #[test]
746 fn test_max_keys() {
747 let (mut alice, mut bob) =
748 asymmetric_setup(Some(DoubleRatchetOptions { max_skip: 5 }), &mut OsRng);
749
750 let (pt_a, ad_a) = (b"Hey, Bob", b"A2B");
751
752 let (mut header_a, mut ciphertext_a) = alice.encrypt(pt_a, ad_a, &mut OsRng);
753
754 for _ in 0..=DEFAULT_MAX_SKIP {
755 (header_a, ciphertext_a) = alice.encrypt(pt_a, ad_a, &mut OsRng);
756 }
757
758 assert_eq!(
759 bob.decrypt(&header_a, &ciphertext_a, ad_a, &mut OsRng),
760 Vec::from(&pt_a[..])
761 );
762 }
763}