From 9e25b6c0ffe6bfacc03cfce5b1033901c6dff3cc Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Fri, 19 Jul 2024 11:03:54 -0500 Subject: [PATCH] nak: Add an implementation of the ACORN random number generator Part-of: --- src/nouveau/compiler/acorn/lib.rs | 81 +++++++++++++++++++++++++++++++ src/nouveau/compiler/meson.build | 12 +++++ 2 files changed, 93 insertions(+) create mode 100644 src/nouveau/compiler/acorn/lib.rs diff --git a/src/nouveau/compiler/acorn/lib.rs b/src/nouveau/compiler/acorn/lib.rs new file mode 100644 index 00000000000..5daf46fa674 --- /dev/null +++ b/src/nouveau/compiler/acorn/lib.rs @@ -0,0 +1,81 @@ +// Copyright © 2022 Collabora, Ltd. +// SPDX-License-Identifier: MIT + +// Generated by random.org +const INIT_DATA: [u16; 64] = [ + 8235, 45378, 61861, 23858, 42241, 27301, 23697, 15333, 52828, 39161, 46572, + 7478, 11198, 4926, 21736, 23781, 37217, 20323, 32754, 61367, 12882, 35352, + 29343, 26458, 62858, 44415, 35786, 58466, 45062, 30330, 30350, 35134, + 28228, 36077, 26793, 27223, 52219, 52544, 3565, 56253, 40962, 40833, 35607, + 46482, 64735, 31252, 44165, 40273, 46825, 15929, 27160, 1106, 59035, 48146, + 47365, 19901, 37178, 35614, 29628, 23344, 11328, 60105, 28727, 344, +]; + +/// An implementation of the ACORN random number generator +/// +/// See also http://acorn.wikramaratna.org/concept.html +/// +/// This isn't cryptographically secure but it's easy and fast and good enough +/// for generating test data. More importantly, we own the implementation so it +/// won't change with random library or compiler upgrades. +pub struct Acorn { + y_n: [u64; Self::K], +} + +impl Acorn { + const ORD: usize = 60; + const K: usize = 16; + + pub fn new() -> Self { + let mut y_0 = [0_u64; Self::K]; + for m in 0..Self::K { + y_0[m] |= u64::from(INIT_DATA[m * 4 + 0]) << 0; + y_0[m] |= u64::from(INIT_DATA[m * 4 + 1]) << 16; + y_0[m] |= u64::from(INIT_DATA[m * 4 + 2]) << 32; + y_0[m] |= u64::from(INIT_DATA[m * 4 + 3]) << 48; + y_0[m] &= (1u64 << Self::ORD) - 1; + } + // For good randomness, the seed should be odd + assert!(y_0[0] % 2 == 1); + Acorn { y_n: y_0 } + } + + fn next_u60(&mut self) -> u64 { + // y_n[0] remains uncanged + for m in 1..Self::K { + // We go in increasing M so y_n[m] is y_(n-1)[m] when we read it but + // self.y_n[m - 1] is what it says it is + self.y_n[m] = (self.y_n[m] + self.y_n[m - 1]) % (1 << Self::ORD); + } + self.y_n[Self::K - 1] + } + + pub fn get_uint(&mut self, bits: usize) -> u64 { + if bits <= Self::ORD { + self.next_u60() >> (Self::ORD - bits) + } else { + let hi = self.next_u60() << (bits - Self::ORD); + hi | self.get_uint(bits - Self::ORD) + } + } + + pub fn get_bool(&mut self) -> bool { + self.get_uint(1) != 0 + } + + pub fn get_u8(&mut self) -> u8 { + self.get_uint(8) as u8 + } + + pub fn get_u16(&mut self) -> u16 { + self.get_uint(16) as u16 + } + + pub fn get_u32(&mut self) -> u32 { + self.get_uint(32) as u32 + } + + pub fn get_u64(&mut self) -> u64 { + self.get_uint(64) + } +} diff --git a/src/nouveau/compiler/meson.build b/src/nouveau/compiler/meson.build index 0d8e67d7255..b30f910be0f 100644 --- a/src/nouveau/compiler/meson.build +++ b/src/nouveau/compiler/meson.build @@ -66,6 +66,18 @@ libnak_c_files = files( 'nak_memstream.c', ) +_libacorn_rs = static_library( + 'acorn', + files('acorn/lib.rs'), + gnu_symbol_visibility : 'hidden', + rust_abi : 'rust', + rust_args : nak_rust_args, +) + +idep_acorn_rs = declare_dependency( + link_with : _libacorn_rs, +) + _libbitview_rs = static_library( 'bitview', files('bitview/lib.rs'),