Prüfsumme und wiederholbarer Zufall

FNV-1a für Zustandsprüfsummen und SplitMix64 als einzige Zufallsquelle
des Kerns. Beide sind gegen veröffentlichte Referenzwerte geprüft.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Steven Wroblewski
2026-09-30 20:24:15 +02:00
parent 4eed8efed0
commit 4df328243c
5 changed files with 115 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
//! FNV-1a hashing for state checksums.
//!
//! The hash only has to reveal accidental divergence between peers. It is
//! not meant to resist tampering.
const FNV_OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325;
const FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
/// Returns the 64-bit FNV-1a hash of `bytes`.
pub fn fnv1a64(bytes: &[u8]) -> u64 {
let mut hash = FNV_OFFSET_BASIS;
for &byte in bytes {
hash ^= u64::from(byte);
hash = hash.wrapping_mul(FNV_PRIME);
}
hash
}
+2
View File
@@ -7,3 +7,5 @@
//! world and exchange nothing but commands.
pub mod codec;
pub mod hash;
pub mod rng;
+34
View File
@@ -0,0 +1,34 @@
//! Repeatable pseudo random numbers (SplitMix64).
//!
//! The core never uses any other source of randomness. The same seed always
//! gives the same sequence, on every machine.
/// Pseudo random number generator with 64 bits of state.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Rng {
state: u64,
}
impl Rng {
pub fn new(seed: u64) -> Self {
Self { state: seed }
}
/// Returns the next value of the sequence.
pub fn next_u64(&mut self) -> u64 {
self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = self.state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
/// Returns a value in `0..bound`.
///
/// # Panics
/// Panics if `bound` is zero.
pub fn below(&mut self, bound: u32) -> u32 {
assert!(bound > 0, "bound must be greater than zero");
((u128::from(self.next_u64()) * u128::from(bound)) >> 64) as u32
}
}