1pub mod authenticator;
5pub mod chain;
6pub mod encoding;
7pub(crate) mod incremental_mlkem768;
8pub(crate) mod kdf;
9pub mod proto;
10pub mod serialize;
11pub(crate) mod test;
12pub(crate) mod util;
13mod v1;
14
15use crate::chain::Chain;
16pub use crate::chain::ChainParams;
17use crate::proto::pq_ratchet as pqrpb;
18pub use crate::proto::pq_ratchet::{Direction, Version};
19use prost::Message;
20use rand::{CryptoRng, Rng};
21use std::cmp::Ordering;
22use v1::chunked::states as v1states;
23
24pub type Epoch = u64;
25pub type Secret = Vec<u8>;
26pub type MessageKey = Option<Vec<u8>>;
27pub type SerializedState = Vec<u8>;
28pub type SerializedMessage = Vec<u8>;
29
30pub fn empty_state() -> SerializedState {
31 SerializedState::new()
32}
33
34pub struct EpochSecret {
35 pub epoch: Epoch,
36 pub secret: Secret,
37}
38
39pub struct Params<'a> {
40 pub direction: Direction,
41 pub version: Version,
42 pub min_version: Version,
43 pub auth_key: &'a [u8],
44 pub chain_params: ChainParams,
45}
46
47impl Direction {
48 pub fn switch(&self) -> Self {
49 match self {
50 Direction::A2B => Direction::B2A,
51 Direction::B2A => Direction::A2B,
52 }
53 }
54}
55
56#[derive(PartialEq, Debug)]
57pub enum SecretOutput {
58 None,
61 Send(Secret),
65 Recv(Secret),
69}
70
71#[derive(Debug)]
72pub enum CurrentVersion {
73 StillNegotiating {
74 version: Version,
75 min_version: Version,
76 },
77 NegotiationComplete(Version),
78}
79
80#[derive(Debug, thiserror::Error)]
81pub enum Error {
82 #[error("state decode failed")]
83 StateDecode,
84 #[error("not yet implemented")]
85 NotImplemented,
86 #[error("message decode failed")]
87 MsgDecode,
88 #[error("MAC verification failed")]
89 MacVerifyFailed,
90 #[error("epoch not in valid range: {0}")]
91 EpochOutOfRange(Epoch),
92 #[error("Encoding error: {0}")]
93 EncodingDecoding(encoding::EncodingError),
94 #[error("Serialization: {0}")]
95 Serialization(serialize::Error),
96 #[error("Version mismatch after negotiation")]
97 VersionMismatch,
98 #[error("Minimum version")]
99 MinimumVersion,
100 #[error("Key jump: {0} - {1}")]
101 KeyJump(u32, u32),
102 #[error("Key trimmed: {0}")]
103 KeyTrimmed(u32),
104 #[error("Key already requested: {0}")]
105 KeyAlreadyRequested(u32),
106 #[error("Erroneous data received from remote party")]
107 ErroneousDataReceived,
108 #[error("Send key epoch decreased ({0} -> {1})")]
109 SendKeyEpochDecreased(u64, u64),
110 #[error("Invalid params: {0}")]
111 InvalidParams(&'static str),
112 #[error("Chain not available")]
113 ChainNotAvailable,
114}
115
116impl From<encoding::EncodingError> for Error {
117 fn from(e: encoding::EncodingError) -> Error {
118 Error::EncodingDecoding(e)
119 }
120}
121
122impl From<serialize::Error> for Error {
123 fn from(v: serialize::Error) -> Self {
124 Error::Serialization(v)
125 }
126}
127
128impl From<authenticator::Error> for Error {
129 fn from(_v: authenticator::Error) -> Self {
130 Error::MacVerifyFailed
131 }
132}
133
134impl SecretOutput {
135 pub fn send_secret(&self) -> Option<&Secret> {
136 match self {
137 SecretOutput::Send(s) => Some(s),
138 SecretOutput::Recv(_) => None,
139 SecretOutput::None => None,
140 }
141 }
142 pub fn recv_secret(&self) -> Option<&Secret> {
143 match self {
144 SecretOutput::Send(_) => None,
145 SecretOutput::Recv(s) => Some(s),
146 SecretOutput::None => None,
147 }
148 }
149
150 pub fn secret(&self) -> Option<&Secret> {
151 match self {
152 SecretOutput::Send(s) | SecretOutput::Recv(s) => Some(s),
153 _ => None,
154 }
155 }
156 pub fn has_secret(&self) -> bool {
157 !matches!(self, Self::None)
158 }
159}
160
161#[hax_lib::opaque]
162impl TryFrom<u8> for Version {
163 type Error = String;
164 fn try_from(value: u8) -> Result<Self, Self::Error> {
165 match value {
166 0 => Ok(Version::V0),
167 1 => Ok(Version::V1),
168 _ => Err("Expected 0 or 1".to_owned()),
169 }
170 }
171}
172
173impl From<Version> for u8 {
174 fn from(v: Version) -> u8 {
175 match v {
176 Version::V0 => 0,
177 Version::V1 => 1,
178 }
179 }
180}
181
182fn init_inner(v: Version, d: Direction, auth_key: &[u8]) -> Option<pqrpb::pq_ratchet_state::Inner> {
183 match v {
184 Version::V0 => None,
185 Version::V1 => match d {
186 Direction::A2B => Some(pqrpb::pq_ratchet_state::Inner::V1(
187 v1states::States::init_a(auth_key).into_pb(),
188 )),
189 Direction::B2A => Some(pqrpb::pq_ratchet_state::Inner::V1(
190 v1states::States::init_b(auth_key).into_pb(),
191 )),
192 },
193 }
194}
195
196pub fn initial_state(params: Params) -> Result<SerializedState, Error> {
197 hax_lib::fstar!("admit()");
198 log::info!(
199 "spqr initiating state with version {:?} and direction {:?}",
200 params.version,
201 params.direction
202 );
203 match params.version {
204 Version::V0 => Ok(empty_state()),
205 _ => {
206 let version_negotiation = Some(pqrpb::pq_ratchet_state::VersionNegotiation {
207 auth_key: params.auth_key.to_vec(),
208 direction: params.direction.into(),
209 min_version: params.min_version.into(),
210 chain_params: Some(params.chain_params.into_pb()),
211 });
212 Ok(pqrpb::PqRatchetState {
213 inner: init_inner(params.version, params.direction, params.auth_key),
214 chain: None,
215 version_negotiation,
216 }
217 .encode_to_vec())
218 }
219 }
220}
221
222impl Version {
223 pub const DISABLED: Version = Self::V0;
224 pub const MAX: Version = Self::V1;
225}
226
227pub struct Send {
228 pub state: SerializedState,
229 pub msg: SerializedMessage,
230 pub key: MessageKey,
231}
232
233pub fn current_version(state: &SerializedState) -> Result<CurrentVersion, Error> {
234 let state_pb = decode_state(state)?;
235 let version = match state_pb.inner {
236 None => Version::V0,
237 Some(pqrpb::pq_ratchet_state::Inner::V1(_)) => Version::V1,
238 };
239 Ok(match state_pb.version_negotiation {
240 None => CurrentVersion::NegotiationComplete(version),
241 Some(vn) => CurrentVersion::StillNegotiating {
242 version,
243 min_version: vn.min_version.try_into().map_err(|_| Error::StateDecode)?,
244 },
245 })
246}
247
248#[hax_lib::fstar::verification_status(lax)]
249pub fn send<R: Rng + CryptoRng>(state: &SerializedState, rng: &mut R) -> Result<Send, Error> {
250 let state_pb = decode_state(state)?;
251 match state_pb.inner {
252 None => Ok(Send {
253 state: vec![],
254 msg: vec![],
255 key: None,
256 }),
257 Some(pqrpb::pq_ratchet_state::Inner::V1(pb)) => {
258 let v1states::Send { msg, key, state } = v1states::States::from_pb(pb)?.send(rng)?;
259 let chain = match state_pb.chain {
260 None => match state_pb.version_negotiation.as_ref() {
261 Some(vn) => {
262 if vn.min_version > Version::V0 as i32 {
263 Some(chain_from_version_negotiation(vn)?)
264 } else {
265 None
266 }
267 }
268 None => {
269 return Err(Error::ChainNotAvailable);
270 }
271 },
272 Some(pb) => Some(Chain::from_pb(pb)?),
273 };
274 let (index, msg_key, chain_pb) = match chain {
275 None => {
276 assert!(key.is_none());
277 (0, vec![], None)
278 }
279 Some(mut chain) => {
280 if let Some(epoch_secret) = key {
281 chain.add_epoch(epoch_secret);
282 }
283 let (index, msg_key) = chain.send_key(msg.epoch - 1)?;
284 (index, msg_key, Some(chain.into_pb()))
285 }
286 };
287
288 let msg = msg.serialize(index);
289 assert!(!msg.is_empty());
290 assert_eq!(msg[0], Version::V1.into());
291 Ok(Send {
292 state: pqrpb::PqRatchetState {
293 inner: Some(pqrpb::pq_ratchet_state::Inner::V1(state.into_pb())),
294 version_negotiation: state_pb.version_negotiation,
296 chain: chain_pb,
297 }
298 .encode_to_vec(),
299 msg,
300 key: if msg_key.is_empty() {
302 None
303 } else {
304 Some(msg_key)
305 },
306 })
307 }
308 }
309}
310
311pub struct Recv {
312 pub state: SerializedState,
313 pub key: MessageKey,
314}
315
316fn chain_from_version_negotiation(
317 vn: &pqrpb::pq_ratchet_state::VersionNegotiation,
318) -> Result<Chain, Error> {
319 Chain::new(
320 &vn.auth_key,
321 vn.direction.try_into().map_err(|_| Error::StateDecode)?,
322 vn.chain_params.ok_or(Error::ChainNotAvailable)?,
323 )
324}
325
326fn chain_from(
327 pb: Option<pqrpb::Chain>,
328 vn: Option<&pqrpb::pq_ratchet_state::VersionNegotiation>,
329) -> Result<Chain, Error> {
330 match pb {
331 Some(pb) => Ok(Chain::from_pb(pb)?),
332 None => match vn {
333 None => Err(Error::ChainNotAvailable),
334 Some(vn) => chain_from_version_negotiation(vn),
335 },
336 }
337}
338
339#[hax_lib::fstar::verification_status(lax)]
340pub fn recv(state: &SerializedState, msg: &SerializedMessage) -> Result<Recv, Error> {
341 let prenegotiated_state_pb = decode_state(state)?;
347 let state_pb = match msg_version(msg) {
348 None => {
349 return Ok(Recv {
352 state: state.to_vec(),
353 key: None,
354 });
355 }
356 Some(v) => match (v as u8).cmp(&(state_version(&prenegotiated_state_pb) as u8)) {
357 Ordering::Equal | Ordering::Greater => {
358 prenegotiated_state_pb
360 }
361 Ordering::Less => {
362 match prenegotiated_state_pb.version_negotiation {
367 None => {
368 return Err(Error::VersionMismatch);
369 }
370 Some(ref vn) => {
371 if (v as i32) < vn.min_version {
372 return Err(Error::MinimumVersion);
373 }
374 log::info!("spqr negotiating version down to {v:?}");
375 pqrpb::PqRatchetState {
376 inner: init_inner(
377 v,
378 vn.direction.try_into().map_err(|_| Error::StateDecode)?,
379 &vn.auth_key,
380 ),
381 version_negotiation: None,
383 chain: Some(
384 chain_from(
385 prenegotiated_state_pb.chain,
386 prenegotiated_state_pb.version_negotiation.as_ref(),
387 )?
388 .into_pb(),
389 ),
390 }
391 }
392 }
393 }
394 },
395 };
396
397 match state_pb.inner {
401 None => Ok(Recv {
402 state: vec![],
403 key: None,
404 }),
405 Some(pqrpb::pq_ratchet_state::Inner::V1(pb)) => {
406 let (scka_msg, index, _) = v1states::Message::deserialize(msg)?;
407
408 let v1states::Recv { key, state } = v1states::States::from_pb(pb)?.recv(&scka_msg)?;
409 let msg_key_epoch = scka_msg.epoch - 1;
410 let mut chain = chain_from(state_pb.chain, state_pb.version_negotiation.as_ref())?;
411 if let Some(epoch_secret) = key {
412 chain.add_epoch(epoch_secret);
413 }
414 let msg_key = if msg_key_epoch == 0 && index == 0 {
415 vec![]
416 } else {
417 chain.recv_key(msg_key_epoch, index)?
418 };
419
420 Ok(Recv {
421 state: pqrpb::PqRatchetState {
422 inner: Some(pqrpb::pq_ratchet_state::Inner::V1(state.into_pb())),
423 version_negotiation: None,
425 chain: Some(chain.into_pb()),
426 }
427 .encode_to_vec(),
428 key: if msg_key.is_empty() {
430 None
431 } else {
432 Some(msg_key)
433 },
434 })
435 }
436 }
437}
438
439fn state_version(state: &pqrpb::PqRatchetState) -> Version {
440 match state.inner {
441 None => Version::V0,
442 Some(proto::pq_ratchet::pq_ratchet_state::Inner::V1(_)) => Version::V1,
443 }
444}
445
446#[hax_lib::fstar::verification_status(lax)]
447fn msg_version(msg: &SerializedMessage) -> Option<Version> {
448 if msg.is_empty() {
449 Some(Version::V0)
450 } else {
451 msg[0].try_into().ok()
452 }
453}
454
455#[hax_lib::fstar::verification_status(lax)]
456fn decode_state(s: &SerializedState) -> Result<pqrpb::PqRatchetState, Error> {
457 if s.is_empty() {
458 Ok(proto::pq_ratchet::PqRatchetState {
459 inner: None,
460 version_negotiation: None,
461 chain: None,
462 })
463 } else {
464 proto::pq_ratchet::PqRatchetState::decode(s.as_slice()).map_err(|_| Error::StateDecode)
465 }
466}
467
468#[cfg(test)]
469mod lib_test {
470 use rand::Rng;
471 use rand::TryRngCore;
472 use rand_core::OsRng;
473
474 use super::*;
475
476 #[test]
477 fn ratchet() -> Result<(), Error> {
478 let mut rng = OsRng.unwrap_err();
479
480 let version = Version::V1;
481
482 let alex_pq_state = initial_state(Params {
483 version,
484 min_version: version,
485 direction: Direction::A2B,
486 auth_key: &[41u8; 32],
487 chain_params: ChainParams::default(),
488 })?;
489 let blake_pq_state = initial_state(Params {
490 version,
491 min_version: version,
492 direction: Direction::B2A,
493 auth_key: &[41u8; 32],
494 chain_params: ChainParams::default(),
495 })?;
496
497 let Send {
499 state: alex_pq_state,
500 msg,
501 key: alex_key,
502 } = send(&alex_pq_state, &mut rng)?;
503
504 let Recv {
505 state: blake_pq_state,
506 key: blake_key,
507 } = recv(&blake_pq_state, &msg)?;
508
509 assert_eq!(alex_key, blake_key);
510
511 let Send {
512 state: mut blake_pq_state,
513 msg,
514 key: blake_key,
515 } = send(&blake_pq_state, &mut rng)?;
516
517 let Recv {
518 state: mut alex_pq_state,
519 key: alex_key,
520 } = recv(&alex_pq_state, &msg)?;
521
522 assert_eq!(alex_key, blake_key);
523
524 for _ in 0..1000 {
526 let a_send = rng.random_bool(0.5);
527 let b_send = rng.random_bool(0.5);
528 let a_recv = rng.random_bool(0.7);
529 let b_recv = rng.random_bool(0.7);
530
531 if a_send {
532 let Send {
533 state,
534 msg,
535 key: alex_key,
536 } = send(&alex_pq_state, &mut rng)?;
537 alex_pq_state = state;
538 if b_recv {
539 let Recv {
540 state,
541 key: blake_key,
542 } = recv(&blake_pq_state, &msg)?;
543 blake_pq_state = state;
544
545 assert_eq!(alex_key, blake_key);
546 }
547 }
548
549 if b_send {
550 let Send {
551 state,
552 msg,
553 key: blake_key,
554 } = send(&blake_pq_state, &mut rng)?;
555 blake_pq_state = state;
556 if a_recv {
557 let Recv {
558 state,
559 key: alex_key,
560 } = recv(&alex_pq_state, &msg)?;
561 alex_pq_state = state;
562
563 assert_eq!(alex_key, blake_key);
564 }
565 }
566 }
567
568 Ok(())
569 }
570
571 #[test]
572 fn ratchet_v0_empty_states() -> Result<(), Error> {
573 let mut rng = OsRng.unwrap_err();
574
575 let alex_pq_state = SerializedState::new();
578 let blake_pq_state = SerializedState::new();
579
580 let Send {
582 state: alex_pq_state,
583 msg,
584 key: alex_key,
585 } = send(&alex_pq_state, &mut rng)?;
586
587 let Recv {
588 state: blake_pq_state,
589 key: blake_key,
590 } = recv(&blake_pq_state, &msg)?;
591
592 assert_eq!(alex_key, blake_key);
593
594 let Send {
595 state: mut blake_pq_state,
596 msg,
597 key: blake_key,
598 } = send(&blake_pq_state, &mut rng)?;
599
600 let Recv {
601 state: mut alex_pq_state,
602 key: alex_key,
603 } = recv(&alex_pq_state, &msg)?;
604
605 assert_eq!(alex_key, blake_key);
606
607 for _ in 0..1000 {
609 let a_send = rng.random_bool(0.5);
610 let b_send = rng.random_bool(0.5);
611 let a_recv = rng.random_bool(0.7);
612 let b_recv = rng.random_bool(0.7);
613
614 if a_send {
615 let Send {
616 state,
617 msg,
618 key: alex_key,
619 } = send(&alex_pq_state, &mut rng)?;
620 alex_pq_state = state;
621 if b_recv {
622 let Recv {
623 state,
624 key: blake_key,
625 } = recv(&blake_pq_state, &msg)?;
626 blake_pq_state = state;
627
628 assert_eq!(alex_key, blake_key);
629 }
630 }
631
632 if b_send {
633 let Send {
634 state,
635 msg,
636 key: blake_key,
637 } = send(&blake_pq_state, &mut rng)?;
638 blake_pq_state = state;
639 if a_recv {
640 let Recv {
641 state,
642 key: alex_key,
643 } = recv(&alex_pq_state, &msg)?;
644 alex_pq_state = state;
645
646 assert_eq!(alex_key, blake_key);
647 }
648 }
649 }
650
651 Ok(())
652 }
653
654 #[test]
655 fn empty_constructor_for_state() {
656 let v = empty_state();
657 assert!(v.is_empty());
658 }
659
660 #[test]
661 fn empty_key_until_version_negotiation() -> Result<(), Error> {
662 let mut rng = OsRng.unwrap_err();
663
664 let version = Version::V1;
665
666 let alex_pq_state = initial_state(Params {
667 version,
668 min_version: Version::V0,
669 direction: Direction::A2B,
670 auth_key: &[41u8; 32],
671 chain_params: ChainParams::default(),
672 })?;
673 let blake_pq_state = initial_state(Params {
674 version,
675 min_version: Version::V0,
676 direction: Direction::B2A,
677 auth_key: &[41u8; 32],
678 chain_params: ChainParams::default(),
679 })?;
680
681 let Send {
683 state: alex_pq_state,
684 msg: msg_a1,
685 key: key_a1,
686 } = send(&alex_pq_state, &mut rng)?;
687 let Send {
688 state: alex_pq_state,
689 msg: msg_a2,
690 key: key_a2,
691 } = send(&alex_pq_state, &mut rng)?;
692 let Send {
693 state: alex_pq_state,
694 msg: msg_a3,
695 key: key_a3,
696 } = send(&alex_pq_state, &mut rng)?;
697
698 let Send {
699 state: blake_pq_state,
700 msg: msg_b1,
701 key: key_b1,
702 } = send(&blake_pq_state, &mut rng)?;
703 let Send {
704 state: blake_pq_state,
705 msg: msg_b2,
706 key: key_b2,
707 } = send(&blake_pq_state, &mut rng)?;
708 let Send {
709 state: blake_pq_state,
710 msg: msg_b3,
711 key: key_b3,
712 } = send(&blake_pq_state, &mut rng)?;
713
714 assert_eq!(key_a1, None);
715 assert_eq!(key_a2, None);
716 assert_eq!(key_a3, None);
717 assert_eq!(key_b1, None);
718 assert_eq!(key_b2, None);
719 assert_eq!(key_b3, None);
720
721 let Recv {
722 state: alex_pq_state,
723 key: key_b2,
724 } = recv(&alex_pq_state, &msg_b2)?;
725 assert_eq!(key_b2, None);
726 let Send {
728 state: alex_pq_state,
729 msg: msg_a4,
730 key: key_a4,
731 } = send(&alex_pq_state, &mut rng)?;
732 assert!(key_a4.is_some());
733 let Send {
734 state: mut alex_pq_state,
735 msg: msg_a5,
736 key: key_a5,
737 } = send(&alex_pq_state, &mut rng)?;
738 assert!(key_a5.is_some());
739
740 let Recv {
741 state: blake_pq_state,
742 key: key_a1,
743 } = recv(&blake_pq_state, &msg_a1)?;
744 assert_eq!(key_a1, None);
745 let Send {
747 state: blake_pq_state,
748 msg: msg_b4,
749 key: key_b4,
750 } = send(&blake_pq_state, &mut rng)?;
751 assert!(key_b4.is_some());
752 let Send {
753 state: mut blake_pq_state,
754 msg: msg_b5,
755 key: key_b5,
756 } = send(&blake_pq_state, &mut rng)?;
757 assert!(key_b5.is_some());
758
759 for (msg, want_key) in [
760 (msg_a3, key_a3),
761 (msg_a4, key_a4),
762 (msg_a2, key_a2),
763 (msg_a5, key_a5),
764 ] {
765 let Recv { state, key } = recv(&blake_pq_state, &msg)?;
766 assert_eq!(want_key, key);
767 blake_pq_state = state;
768 }
769
770 for (msg, want_key) in [
771 (msg_b1, key_b1),
772 (msg_b3, key_b3),
773 (msg_b4, key_b4),
774 (msg_b5, key_b5),
775 ] {
776 let Recv { state, key } = recv(&alex_pq_state, &msg)?;
777 assert_eq!(want_key, key);
778 alex_pq_state = state;
779 }
780
781 Ok(())
782 }
783
784 #[test]
785 fn min_version_v1_always_creates_keys_a2b() -> Result<(), Error> {
786 let mut rng = OsRng.unwrap_err();
787
788 let alex_pq_state = initial_state(Params {
789 version: Version::MAX,
790 min_version: Version::V1,
791 direction: Direction::A2B,
792 auth_key: &[41u8; 32],
793 chain_params: ChainParams::default(),
794 })?;
795 let blake_pq_state = initial_state(Params {
796 version: Version::MAX,
797 min_version: Version::V0,
798 direction: Direction::B2A,
799 auth_key: &[41u8; 32],
800 chain_params: ChainParams::default(),
801 })?;
802 let Send {
803 msg: msg_a1,
804 key: key_a1,
805 ..
806 } = send(&alex_pq_state, &mut rng)?;
807 assert!(key_a1.is_some());
808 let Send {
809 state: blake_pq_state,
810 key: key_b1,
811 ..
812 } = send(&blake_pq_state, &mut rng)?;
813 assert!(key_b1.is_none());
814 let Recv {
815 state: blake_pq_state,
816 ..
817 } = recv(&blake_pq_state, &msg_a1)?;
818 let Send { key: key_b2, .. } = send(&blake_pq_state, &mut rng)?;
820 assert!(key_b2.is_some());
821 Ok(())
822 }
823
824 #[test]
825 fn min_version_v1_always_creates_keys_b2a() -> Result<(), Error> {
826 let mut rng = OsRng.unwrap_err();
827
828 let alex_pq_state = initial_state(Params {
829 version: Version::MAX,
830 min_version: Version::V0,
831 direction: Direction::A2B,
832 auth_key: &[41u8; 32],
833 chain_params: ChainParams::default(),
834 })?;
835 let blake_pq_state = initial_state(Params {
836 version: Version::MAX,
837 min_version: Version::V1,
838 direction: Direction::B2A,
839 auth_key: &[41u8; 32],
840 chain_params: ChainParams::default(),
841 })?;
842 let Send {
843 msg: msg_b1,
844 key: key_b1,
845 ..
846 } = send(&blake_pq_state, &mut rng)?;
847 assert!(key_b1.is_some());
848 let Send {
849 state: alex_pq_state,
850 key: key_a1,
851 ..
852 } = send(&alex_pq_state, &mut rng)?;
853 assert!(key_a1.is_none());
854 let Recv {
855 state: alex_pq_state,
856 ..
857 } = recv(&alex_pq_state, &msg_b1)?;
858 let Send { key: key_a2, .. } = send(&alex_pq_state, &mut rng)?;
860 assert!(key_a2.is_some());
861 Ok(())
862 }
863
864 #[test]
865 fn negotiate_to_v0_a2b() -> Result<(), Error> {
866 let mut rng = OsRng.unwrap_err();
867
868 let alex_pq_state = initial_state(Params {
869 version: Version::MAX,
870 min_version: Version::V0,
871 direction: Direction::A2B,
872 auth_key: &[41u8; 32],
873 chain_params: ChainParams::default(),
874 })?;
875 let blake_pq_state = initial_state(Params {
876 version: Version::V0,
877 min_version: Version::V0,
878 direction: Direction::B2A,
879 auth_key: &[41u8; 32],
880 chain_params: ChainParams::default(),
881 })?;
882 assert!(matches!(
883 current_version(&alex_pq_state)?,
884 CurrentVersion::StillNegotiating {
885 version: Version::MAX,
886 min_version: Version::V0
887 },
888 ));
889 assert!(matches!(
890 current_version(&blake_pq_state)?,
891 CurrentVersion::NegotiationComplete(Version::V0),
892 ));
893 let Send {
894 msg: msg_a1,
895 state: alex_pq_state,
896 ..
897 } = send(&alex_pq_state, &mut rng)?;
898 let Recv {
899 state: blake_pq_state,
900 ..
901 } = recv(&blake_pq_state, &msg_a1)?;
902 let Send { msg: msg_b1, .. } = send(&blake_pq_state, &mut rng)?;
903 let Recv {
904 state: alex_pq_state,
905 ..
906 } = recv(&alex_pq_state, &msg_b1)?;
907 assert!(matches!(
908 current_version(&alex_pq_state)?,
909 CurrentVersion::NegotiationComplete(Version::V0),
910 ));
911 assert!(matches!(
912 current_version(&alex_pq_state)?,
913 CurrentVersion::NegotiationComplete(Version::V0),
914 ));
915 Ok(())
916 }
917
918 #[test]
919 fn negotiate_to_v0_b2a() -> Result<(), Error> {
920 let mut rng = OsRng.unwrap_err();
921
922 let alex_pq_state = initial_state(Params {
923 version: Version::V0,
924 min_version: Version::V0,
925 direction: Direction::A2B,
926 auth_key: &[41u8; 32],
927 chain_params: ChainParams::default(),
928 })?;
929 let blake_pq_state = initial_state(Params {
930 version: Version::MAX,
931 min_version: Version::V0,
932 direction: Direction::B2A,
933 auth_key: &[41u8; 32],
934 chain_params: ChainParams::default(),
935 })?;
936 assert!(matches!(
937 current_version(&alex_pq_state)?,
938 CurrentVersion::NegotiationComplete(Version::V0),
939 ));
940 assert!(matches!(
941 current_version(&blake_pq_state)?,
942 CurrentVersion::StillNegotiating {
943 version: Version::MAX,
944 min_version: Version::V0
945 },
946 ));
947 let Send {
948 msg: msg_a1,
949 state: alex_pq_state,
950 ..
951 } = send(&alex_pq_state, &mut rng)?;
952 let Recv {
953 state: blake_pq_state,
954 ..
955 } = recv(&blake_pq_state, &msg_a1)?;
956 let Send { msg: msg_b1, .. } = send(&blake_pq_state, &mut rng)?;
957 let Recv {
958 state: alex_pq_state,
959 ..
960 } = recv(&alex_pq_state, &msg_b1)?;
961 assert!(matches!(
962 current_version(&alex_pq_state)?,
963 CurrentVersion::NegotiationComplete(Version::V0),
964 ));
965 assert!(matches!(
966 current_version(&alex_pq_state)?,
967 CurrentVersion::NegotiationComplete(Version::V0),
968 ));
969 Ok(())
970 }
971
972 #[test]
973 fn negotiation_refused_a2b() -> Result<(), Error> {
974 let mut rng = OsRng.unwrap_err();
975
976 let alex_pq_state = initial_state(Params {
977 version: Version::MAX,
978 min_version: Version::V1,
979 direction: Direction::A2B,
980 auth_key: &[41u8; 32],
981 chain_params: ChainParams::default(),
982 })?;
983 let blake_pq_state = initial_state(Params {
984 version: Version::V0,
985 min_version: Version::V0,
986 direction: Direction::B2A,
987 auth_key: &[41u8; 32],
988 chain_params: ChainParams::default(),
989 })?;
990 assert!(matches!(
991 current_version(&alex_pq_state)?,
992 CurrentVersion::StillNegotiating {
993 version: Version::MAX,
994 min_version: Version::V1
995 },
996 ));
997 assert!(matches!(
998 current_version(&blake_pq_state)?,
999 CurrentVersion::NegotiationComplete(Version::V0),
1000 ));
1001 let Send {
1002 msg: msg_a1,
1003 state: alex_pq_state,
1004 ..
1005 } = send(&alex_pq_state, &mut rng)?;
1006 let Recv {
1007 state: blake_pq_state,
1008 ..
1009 } = recv(&blake_pq_state, &msg_a1)?;
1010 let Send { msg: msg_b1, .. } = send(&blake_pq_state, &mut rng)?;
1011 assert!(matches!(
1012 recv(&alex_pq_state, &msg_b1),
1013 Err(Error::MinimumVersion),
1014 ));
1015 Ok(())
1016 }
1017
1018 #[test]
1019 fn negotiation_refused_b2a() -> Result<(), Error> {
1020 let mut rng = OsRng.unwrap_err();
1021
1022 let alex_pq_state = initial_state(Params {
1023 version: Version::V0,
1024 min_version: Version::V0,
1025 direction: Direction::A2B,
1026 auth_key: &[41u8; 32],
1027 chain_params: ChainParams::default(),
1028 })?;
1029 let blake_pq_state = initial_state(Params {
1030 version: Version::MAX,
1031 min_version: Version::V1,
1032 direction: Direction::B2A,
1033 auth_key: &[41u8; 32],
1034 chain_params: ChainParams::default(),
1035 })?;
1036 assert!(matches!(
1037 current_version(&alex_pq_state)?,
1038 CurrentVersion::NegotiationComplete(Version::V0),
1039 ));
1040 assert!(matches!(
1041 current_version(&blake_pq_state)?,
1042 CurrentVersion::StillNegotiating {
1043 version: Version::MAX,
1044 min_version: Version::V1
1045 },
1046 ));
1047 let Send { msg: msg_a1, .. } = send(&alex_pq_state, &mut rng)?;
1048 assert!(matches!(
1049 recv(&blake_pq_state, &msg_a1),
1050 Err(Error::MinimumVersion)
1051 ));
1052 Ok(())
1053 }
1054}