Add more state objects.

This commit is contained in:
Michael Mikovsky
2026-05-31 14:47:25 -06:00
parent b2e2523860
commit 966f16008b
10 changed files with 200 additions and 15 deletions
+67
View File
@@ -0,0 +1,67 @@
use crate::crypto::feistel_shuffle;
#[cfg(feature = "counter_shuffle_none")]
pub type Counter = NoShuffle;
#[cfg(feature = "counter_shuffle_feistel")]
pub type Counter = FeistelShuffle;
#[cfg(feature = "counter_shuffle_feistel_lcg")]
pub type Counter = FeistelLCGShuffle;
const NONCE16_1: u16 = const_random::const_random!(u16);
const NONCE16_2: u16 = const_random::const_random!(u16);
const NONCE32: u32 = const_random::const_random!(u32);
pub struct NoShuffle(u16);
/// Linear shuffle, no randomization, just a random starting point and step size
impl NoShuffle {
pub fn new() -> Self {
Self(NONCE16_1)
}
pub fn next(&mut self) -> u16 {
self.0 = self.0.wrapping_add(1);
self.0
}
}
/// Shuffle all 16 bit numbers, an actual shuffle
/// But this still stores local values in a linear format
pub struct FeistelShuffle(u16, u32);
impl FeistelShuffle {
pub fn new() -> Self {
Self(NONCE16_1, NONCE32)
}
pub fn next(&mut self) -> u16 {
self.0 = self.0.wrapping_add(NONCE16_2);
feistel_shuffle(self.0, self.1)
}
}
/// Linear recursive shuffle,
/// feeds back into itself and doesn't store the actual state.
/// Harder to decompile
pub struct FeistelLCGShuffle {
state: u16,
a: u16, // Multiplier (must be 1 mod 4)
c: u16, // Increment (must be odd)
}
impl FeistelLCGShuffle {
pub fn new() -> Self {
let seed = NONCE32;
let a = (((seed & 0x3FFF) as u16) << 2) | 1;
let c = ((seed >> 16) as u16) | 1;
Self { state: 0, a, c }
}
pub fn next(&mut self) -> u16 {
// 1. Advance state using LCG (Guarantees single cycle of 65536)
self.state = self.state.wrapping_mul(self.a).wrapping_add(self.c);
// 2. Apply Feistel shuffle to the state (Adds randomness)
feistel_shuffle(self.state, self.a as u32)
}
}
+21 -4
View File
@@ -1,10 +1,27 @@
use alloc::string::String;
mod hash;
mod ordering;
// TODO: Make this seed dependent on env var;
pub const GLOBAL_SEED: u32 = 0xDEAFBEEF;
// pub const GLOBAL_NONCE: u32 = {
// let time = match u128::from_str_radix(env!("BUILD_TIME"), 10) {
// Ok(i) => i,
// Err(_) => panic!("Failed to parse BUILD_TIME"),
// };
pub use hash::sha256;
pub use ordering::feistel_shuffle;
// GLOBAL_SEED ^ (time as u32)
// };
mod feistel;
#[allow(dead_code)]
mod feistel_state;
mod sha256;
pub use feistel::feistel_shuffle;
pub use feistel_state::{Counter, FeistelLCGShuffle, FeistelShuffle, NoShuffle};
pub use sha256::sha256;
#[cfg(test)]
mod tests;
#[macro_export]
macro_rules! hash_256 {
+40
View File
@@ -0,0 +1,40 @@
use crate::crypto::{FeistelLCGShuffle, FeistelShuffle, NoShuffle};
#[test]
fn test_linear_shuffle() {
let mut seen = [false; 65536];
let mut counter = NoShuffle::new();
for _ in 0..65535 {
let val = counter.next();
assert!(!seen[val as usize], "Collision detected");
seen[val as usize] = true;
}
}
#[test]
fn test_feistel_shuffle() {
let mut seen = [false; 65536];
let mut counter = FeistelShuffle::new();
for _ in 0..65535 {
let val = counter.next();
assert!(!seen[val as usize], "Collision detected");
seen[val as usize] = true;
}
}
#[test]
fn test_fristel_lcg_shuffle() {
let mut seen = [false; 65536];
let mut counter = FeistelLCGShuffle::new();
for _ in 0..65535 {
let val = counter.next();
assert!(!seen[val as usize], "Collision detected");
seen[val as usize] = true;
}
}
+3 -2
View File
@@ -16,10 +16,11 @@ impl Endpoint {
/// reuse an id before the previous route has closed. If every `u16` id is active
/// the function panics; that is a hard local resource exhaustion condition, not a
/// recoverable packet error.
///
/// TODO: Reevaluate this method of allocation checking. It can be quite slow
pub fn allocate_hook_id(&mut self) -> HookID {
for _ in 0..=HookID::MAX {
let candidate = self.last_hook;
self.last_hook = self.last_hook.wrapping_add(1);
let candidate = self.last_hook.next();
if !self.hooks.contains_key(&candidate) {
return candidate;
+6 -4
View File
@@ -5,15 +5,17 @@ pub use hooks::HookID;
use alloc::{boxed::Box, vec::Vec};
use crate::protocol::{ConnectionSet, HookMap, Leaf, Packet, Path, RouteMap};
use crate::{
crypto::Counter,
protocol::{ConnectionSet, HookMap, Leaf, Packet, Path, RouteMap},
};
pub struct Endpoint {
// This endpoint's identifier
pub id: u32,
// A counter that creates unique hook IDs.
// TODO: Randomize the hooks for more obfuscation
pub(crate) last_hook: u16,
pub(crate) last_hook: Counter,
// Absolute path for this node. Must be set by some leaf
pub path: Path,
@@ -36,7 +38,7 @@ impl Endpoint {
Self {
id,
// Init the hook at 0, which will increment
last_hook: 0,
last_hook: Counter::new(),
// Set the current path as an empty vec
path: Vec::new(),