mnem_core/prolly/
constants.rs1use core::fmt;
8
9use serde::de::{self, Visitor};
10use serde::{Deserialize, Deserializer, Serialize, Serializer};
11
12use crate::id::{ChangeId, EdgeId, NodeId};
13
14pub const PROLLY_KEY_BYTES: usize = 16;
19
20#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub struct ProllyKey(pub [u8; PROLLY_KEY_BYTES]);
32
33impl ProllyKey {
34 #[must_use]
36 pub const fn new(bytes: [u8; PROLLY_KEY_BYTES]) -> Self {
37 Self(bytes)
38 }
39
40 #[must_use]
42 pub const fn as_bytes(&self) -> &[u8; PROLLY_KEY_BYTES] {
43 &self.0
44 }
45
46 #[must_use]
48 pub const fn into_bytes(self) -> [u8; PROLLY_KEY_BYTES] {
49 self.0
50 }
51}
52
53impl fmt::Debug for ProllyKey {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "ProllyKey(")?;
56 for b in &self.0 {
57 write!(f, "{b:02x}")?;
58 }
59 f.write_str(")")
60 }
61}
62
63impl From<NodeId> for ProllyKey {
66 fn from(v: NodeId) -> Self {
67 Self(v.into_bytes())
68 }
69}
70
71impl From<EdgeId> for ProllyKey {
72 fn from(v: EdgeId) -> Self {
73 Self(v.into_bytes())
74 }
75}
76
77impl From<ChangeId> for ProllyKey {
78 fn from(v: ChangeId) -> Self {
79 Self(v.into_bytes())
80 }
81}
82
83impl Serialize for ProllyKey {
86 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
87 serializer.serialize_bytes(&self.0)
88 }
89}
90
91struct ProllyKeyVisitor;
92
93impl<'de> Visitor<'de> for ProllyKeyVisitor {
94 type Value = ProllyKey;
95
96 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 f.write_str("a 16-byte prolly key byte string")
98 }
99
100 fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
101 if v.len() != PROLLY_KEY_BYTES {
102 return Err(E::invalid_length(v.len(), &"16"));
103 }
104 let mut arr = [0u8; PROLLY_KEY_BYTES];
105 arr.copy_from_slice(v);
106 Ok(ProllyKey(arr))
107 }
108
109 fn visit_borrowed_bytes<E: de::Error>(self, v: &'de [u8]) -> Result<Self::Value, E> {
110 self.visit_bytes(v)
111 }
112
113 fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
114 self.visit_bytes(&v)
115 }
116}
117
118impl<'de> Deserialize<'de> for ProllyKey {
119 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
120 deserializer.deserialize_bytes(ProllyKeyVisitor)
121 }
122}
123
124pub const ROLLING_WINDOW_BYTES: usize = 64;
128
129pub const ROLLING_KEY: [u8; 32] = [
137 0x6d, 0x6e, 0x65, 0x6d, 0x2d, 0x70, 0x72, 0x6f, 0x6c, 0x6c, 0x79, 0x2d, 0x72, 0x68, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
146
147pub const MIN_ENTRIES_PER_CHUNK: usize = 16;
149
150pub const TARGET_AVG_ENTRIES_PER_CHUNK: usize = 64;
153
154pub const MAX_ENTRIES_PER_CHUNK: usize = 512;
157
158pub const THRESHOLD: u64 = u64::MAX / 48;
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172 use crate::codec::{from_canonical_bytes, to_canonical_bytes};
173
174 #[test]
175 fn rolling_key_is_ascii_prefix_plus_zeros() {
176 assert_eq!(&ROLLING_KEY[..16], b"mnem-prolly-rh-1");
177 assert!(ROLLING_KEY[16..].iter().all(|&b| b == 0));
178 }
179
180 #[test]
181 fn threshold_probability_is_about_one_in_48() {
182 let ratio = THRESHOLD as f64 / u64::MAX as f64;
183 assert!((ratio - 1.0 / 48.0).abs() < 1e-9, "ratio was {ratio}");
184 }
185
186 #[test]
187 fn bounds_are_ordered() {
188 assert!(MIN_ENTRIES_PER_CHUNK < TARGET_AVG_ENTRIES_PER_CHUNK);
189 assert!(TARGET_AVG_ENTRIES_PER_CHUNK < MAX_ENTRIES_PER_CHUNK);
190 }
191
192 #[test]
193 fn prolly_key_cbor_round_trip_as_byte_string() {
194 let original = ProllyKey([0xAB; PROLLY_KEY_BYTES]);
195 let bytes = to_canonical_bytes(&original).expect("encode");
196 assert_eq!(bytes[0], 0x50, "expected CBOR byte-string-16 prefix");
198 assert_eq!(bytes.len(), 17);
199 let decoded: ProllyKey = from_canonical_bytes(&bytes).expect("decode");
200 assert_eq!(original, decoded);
201 }
202
203 #[test]
204 fn node_id_converts_to_prolly_key() {
205 let n = NodeId::from_bytes_raw([7u8; 16]);
206 let k: ProllyKey = n.into();
207 assert_eq!(k.as_bytes(), &[7u8; 16]);
208 }
209}