1#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize, Versionize)]
10#[versionize(SeedVersions)]
11pub struct Seed(pub u128);
12
13#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize, Versionize)]
21#[versionize(XofSeedVersions)]
22pub struct XofSeed {
23 data: Vec<u8>,
26}
27
28impl XofSeed {
29 pub const DOMAIN_SEP_LEN: usize = 8;
30
31 pub fn new_u128(seed: u128, domain_separator: [u8; Self::DOMAIN_SEP_LEN]) -> Self {
33 let mut data = vec![0u8; size_of::<u128>() + domain_separator.len()];
34 data[..Self::DOMAIN_SEP_LEN].copy_from_slice(domain_separator.as_slice());
35 data[Self::DOMAIN_SEP_LEN..].copy_from_slice(seed.to_le_bytes().as_slice());
36
37 Self { data }
38 }
39
40 pub fn new(mut seed: Vec<u8>, domain_separator: [u8; Self::DOMAIN_SEP_LEN]) -> Self {
41 seed.resize(domain_separator.len() + seed.len(), 0);
42 seed.rotate_right(domain_separator.len());
43 seed[..Self::DOMAIN_SEP_LEN].copy_from_slice(domain_separator.as_slice());
44 Self { data: seed }
45 }
46
47 pub fn seed(&self) -> &[u8] {
49 &self.data[Self::DOMAIN_SEP_LEN..]
50 }
51
52 pub fn domain_separator(&self) -> [u8; Self::DOMAIN_SEP_LEN] {
54 let mut sep = [0u8; Self::DOMAIN_SEP_LEN];
55 sep.copy_from_slice(&self.data[..Self::DOMAIN_SEP_LEN]);
56 sep
57 }
58
59 pub fn bit_len(&self) -> u128 {
61 (self.data.len()) as u128 * 8
62 }
63
64 pub(crate) fn iter_u128_blocks(&self) -> impl Iterator<Item = u128> + '_ {
67 self.data.chunks(size_of::<u128>()).map(move |chunk| {
68 let mut buf = [0u8; size_of::<u128>()];
69 buf[..chunk.len()].copy_from_slice(chunk);
70 u128::from_ne_bytes(buf)
71 })
72 }
73
74 pub fn from_bytes(data: Vec<u8>) -> Self {
80 assert!(
81 data.len() >= Self::DOMAIN_SEP_LEN,
82 "XofSeed must be at least {} bytes long (got {})",
83 Self::DOMAIN_SEP_LEN,
84 data.len()
85 );
86 Self { data }
87 }
88
89 pub fn bytes(&self) -> &Vec<u8> {
90 &self.data
91 }
92
93 pub fn into_bytes(self) -> Vec<u8> {
94 self.data
95 }
96}
97
98#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Versionize)]
99#[versionize(SeedKindVersions)]
100pub enum SeedKind {
101 Ctr(Seed),
104 Xof(XofSeed),
110}
111
112impl From<Seed> for SeedKind {
113 fn from(value: Seed) -> Self {
114 Self::Ctr(value)
115 }
116}
117
118impl From<XofSeed> for SeedKind {
119 fn from(value: XofSeed) -> Self {
120 Self::Xof(value)
121 }
122}
123
124pub trait Seeder {
126 fn seed(&mut self) -> Seed;
128
129 fn is_available() -> bool
132 where
133 Self: Sized;
134}
135
136pub mod backward_compatibility;
137mod implem;
138#[allow(unused_imports)]
141pub use implem::*;
142use tfhe_versionable::Versionize;
143
144use crate::seeders::backward_compatibility::{SeedKindVersions, SeedVersions, XofSeedVersions};
145
146#[cfg(test)]
147mod generic_tests {
148 use crate::seeders::{Seeder, XofSeed};
149
150 #[allow(unused)] pub fn check_seeder_fixed_sequences_different<S: Seeder, F: Fn(u128) -> S>(
154 construct_seeder: F,
155 ) {
156 const SEQUENCE_SIZE: usize = 500;
157 const REPEATS: usize = 10_000;
158 for i in 0..REPEATS {
159 let mut seeder = construct_seeder(i as u128);
160 let orig_seed = seeder.seed();
161 for _ in 0..SEQUENCE_SIZE {
162 assert_ne!(seeder.seed(), orig_seed);
163 }
164 }
165 }
166
167 #[test]
168 fn test_xof_seed_getters() {
169 let seed_bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
170 let bits = u128::from_le_bytes(seed_bytes);
171 let dsep = *b"tfheksps";
172 let seed = XofSeed::new_u128(bits, dsep);
173
174 let s = u128::from_le_bytes(seed.seed().try_into().unwrap());
175 assert_eq!(s, bits);
176 assert_eq!(seed.domain_separator(), dsep);
177 assert_eq!(seed.bit_len(), 192);
178
179 let collected_u128s = seed.iter_u128_blocks().collect::<Vec<_>>();
180 assert_eq!(
183 collected_u128s,
184 vec![
185 u128::from_ne_bytes([
186 b't', b'f', b'h', b'e', b'k', b's', b'p', b's', 1, 2, 3, 4, 5, 6, 7, 8
187 ]),
188 u128::from_ne_bytes([9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0]),
189 ]
190 );
191
192 let seed2 = XofSeed::new(seed_bytes.to_vec(), dsep);
194 assert_eq!(seed.data, seed2.data);
195 }
196}