fnv.nx source
↩ module page · 99 lines · 3879 B
1// RETIRED 2026-07-30 -- moved here from runtime/fnv.nx. PRESERVED VERBATIM BELOW, NOT DELETED (rule 13).
2//
3// WHY IT WAS RETIRED: it defined `fnv1a`, `fnv1a_init`, `fnv1a_update` and `fnv1a_cstr` -- THE EXACT FOUR
4// SYMBOLS the canonical runtime/nx_fnv.nx defines -- with a byte-identical algorithm and identical
5// constants. The ONLY difference was `import "syscalls.nx"` vs `import "nx_syscalls.nx"`.
6//
7// TWO FILES CLAIMING TO BE THE CANONICAL HASH IS WORSE THAN NONE: nx_fnv.nx's own header carries the
8// cardinal law "All other primitives needing FNV-1a MUST import nx_fnv.nx ... never re-implement a hash
9// inline" -- but that law names a target that was AMBIGUOUS, and any organ importing both would collide
10// symbol-for-symbol.
11//
12// MEASURED BEFORE RETIRING (complete scan of buildroot, not a partial one):
13// runtime/fnv.nx 2577 B -- 0 importers
14// runtime/nx_fnv.nx 3067 B -- 7 importers <- canonical, keeps the name the law points at
15// A sovereign nx_shelltool scan returned 0 matches too, but reported PARTIAL (budget-exceeded at 15315 of
16// ~19940 files) -- and ZERO ON A PARTIAL SCAN IS NOT PROOF OF ABSENCE, so the count above is from a
17// complete scan. The tool was right to say so; the reading would have been wrong to trust.
18//
19// TO RESURRECT: copy this file back to runtime/fnv.nx and change the import to nx_syscalls.nx -- but do
20// not, because nx_fnv.nx already is this, and re-adding it re-creates the ambiguity.
21// license_tier: ORIGINAL No hw writes (Rule 26).
22//
23// ---------------- ORIGINAL CONTENT, VERBATIM ----------------
24// fnv.nx -- FNV-1a non-cryptographic hash (Fowler-Noll-Vo).
25//
26// 64-bit FNV-1a. Used for: hash table keying, file
27// fingerprinting, Bloom filter mixing, deduplication. NOT for
28// security -- an attacker who controls input can construct
29// collisions. For cryptographic hashing use sha256 / sha512 /
30// sha3.
31//
32// Algorithm (Fowler-Noll-Vo 1991; rfc draft-eastlake-fnv):
33// hash = FNV_OFFSET_BASIS
34// for each byte b in input:
35// hash = hash XOR b
36// hash = hash * FNV_PRIME
37//
38// FNV-1a (xor-then-multiply) has better avalanche than plain
39// FNV-1 (multiply-then-xor) so we implement 1a.
40//
41// 64-bit constants (Eastlake RFC draft):
42// offset_basis = 0xCBF29CE484222325
43// prime = 0x100000001B3
44//
45// Invariants:
46// F1 Empty input hashes to offset_basis (14695981039346656037).
47// F2 Identical byte sequences always hash to the same value
48// across runs / machines / endianness (state is plain i64
49// arithmetic, no byte-order dependence).
50// F3 Multiplication overflows are wrapped mod 2^64 by the
51// underlying i64 arithmetic -- matches reference spec.
52//
53// import "syscalls.nx"
54//
55// const FNV_OFFSET_BASIS: i64 = 0xCBF29CE484222325
56// const FNV_PRIME: i64 = 0x100000001B3
57//
58// func fnv1a(data: *u8, n: i64) -> i64 {
59// var h: i64 = FNV_OFFSET_BASIS
60// var i: i64 = 0
61// while i < n {
62// h = h ^ data[i]
63// h = h * FNV_PRIME
64// i = i + 1
65// }
66// return h
67// }
68//
69// func fnv1a_init() -> i64 { return FNV_OFFSET_BASIS }
70//
71// func fnv1a_update(state: i64, data: *u8, n: i64) -> i64 {
72// var h: i64 = state
73// var i: i64 = 0
74// while i < n {
75// h = h ^ data[i]
76// h = h * FNV_PRIME
77// i = i + 1
78// }
79// return h
80// }
81//
82// func fnv1a_cstr(s: *u8) -> i64 {
83// var i: i64 = 0
84// while s[i] != 0 { i = i + 1 }
85// return fnv1a(s, i)
86// }
87//
88// func main() -> i64 {
89// let empty: i64 = fnv1a(0 as *u8, 0)
90// if empty != FNV_OFFSET_BASIS { return 1 }
91// let ha: i64 = fnv1a("hello", 5)
92// let hb: i64 = fnv1a("world", 5)
93// if ha == hb { return 2 }
94// var st: i64 = fnv1a_init()
95// st = fnv1a_update(st, "hel", 3)
96// st = fnv1a_update(st, "lo", 2)
97// if st != ha { return 3 }
98// return 0
99// }