1#![no_std]
2#![doc = "Core identifiers and validation primitives for BCX."]
3
4#[cfg(test)]
5extern crate std;
6
7mod error;
8mod ids;
9
10pub use error::ValidationError;
11pub use ids::{CapabilityRef, Digest, EventId, Nonce, OperationSequence, PolicyEpoch};
12
13#[cfg(test)]
14mod tests {
15 use super::*;
16 use std::{format, string::String};
17
18 #[test]
19 fn zero_digest_is_detected() {
20 let digest = Digest::new([0; Digest::LEN]);
21 assert!(digest.is_zero());
22 }
23
24 #[test]
25 fn digest_constant_shape_equality_matches_structural_equality() {
26 let left = Digest::new([7; Digest::LEN]);
27 let same = Digest::new([7; Digest::LEN]);
28 let different = Digest::new([8; Digest::LEN]);
29
30 assert!(left.ct_eq(&same));
31 assert!(!left.ct_eq(&different));
32 }
33
34 #[test]
35 fn nonce_debug_is_redacted() {
36 let nonce = Nonce::new([3; Nonce::LEN]);
37
38 assert_eq!(
39 nonce.map(|value| format!("{value:?}")),
40 Ok(String::from("Nonce(..)"))
41 );
42 }
43
44 #[test]
45 fn nonce_rejects_zero_and_compares_constant_shape() {
46 let left = Nonce::new([9; Nonce::LEN]);
47 let same = Nonce::new([9; Nonce::LEN]);
48 let different = Nonce::new([8; Nonce::LEN]);
49
50 assert_eq!(Nonce::new([0; Nonce::LEN]), Err(ValidationError::ZeroValue));
51 assert!(matches!((&left, &same), (Ok(a), Ok(b)) if a.ct_eq(b)));
52 assert!(matches!((&left, &different), (Ok(a), Ok(b)) if !a.ct_eq(b)));
53 }
54
55 #[test]
56 fn operation_sequence_rejects_zero() {
57 assert_eq!(OperationSequence::new(0), Err(ValidationError::ZeroValue));
58 assert_eq!(OperationSequence::new(7).map(OperationSequence::get), Ok(7));
59 }
60
61 #[test]
62 fn operation_sequence_checks_monotonic_successor() {
63 let previous = OperationSequence::new(7);
64 let next = previous.and_then(OperationSequence::next);
65
66 assert_eq!(next.map(OperationSequence::get), Ok(8));
67 assert!(matches!(
68 (OperationSequence::new(8), OperationSequence::new(7)),
69 (Ok(current), Ok(previous)) if current.immediately_follows(previous)
70 ));
71 assert_eq!(
72 OperationSequence::new(u64::MAX).and_then(OperationSequence::next),
73 Err(ValidationError::TooLarge)
74 );
75 }
76}