0701 nwnss: make rand helpers seed deterministic

This commit is contained in:
Mario Fetka
2026-06-17 10:53:02 +00:00
parent c7f7164931
commit 8cc8b8663d
3 changed files with 110 additions and 39 deletions

View File

@@ -106,7 +106,7 @@ still stay original and remain listed, because later imports may rely on them.
| PARTIAL | `src/nwnss/comn/common/ndp_messagehandler.c` | ORIG wrapper | link smoke | Novell wrapper name/pattern; full audit open. |
| TEMP | `src/nwnss/comn/comnModule.c` | TEMP | link smoke | Transition module identity bridge; should disappear later. |
| AUDITED | `src/nwnss/library/bit.c` | PORT | nwnss.bit, nwnss.bitmap | No original provider found beyond bit.h/libNSS.imp; native-NINT semantics fixed/tested in 0698. |
| AUDITED | `src/nwnss/library/misc/rand.c` | PORT | nwnss.rand, nwnss.namespace | No original provider found beyond rand.h/libNSS.imp/callers; libsodium entropy port checked in 0700. |
| AUDITED | `src/nwnss/library/misc/rand.c` | PORT | nwnss.rand, nwnss.namespace | No original provider found beyond rand.h/libNSS.imp/callers; seed-deterministic PRNG port checked in 0700/0701; libsodium only initializes default state before explicit seeding. |
| TODO | `src/nwnss/library/misc/rbpTree.c` | PORT | nwnss.rbpTree | Algorithmic port; has tests, but original-provider search/checklist still open. |
| TODO | `src/nwnss/library/os/currentTime.c` | PORT | nwnss.utc | Userspace time port; full audit open. |
| AUDITED | `src/nwnss/library/os/delay.c` | ORIG+FIX/PORT | nwnss.schedule, nwnss.snooze | Scheduler functions kept as functions, not macros; checked in 0688-0690. |
@@ -606,7 +606,7 @@ even if it already compiles or has indirect test coverage.
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/misc/histogram.c` | Must be compared against original source and classified. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/misc/lbVolume.c` | Must be compared against original source and classified. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/misc/nssErrorTable.c` | Must be compared against original source and classified. |
| AUDITED | PORT | nwnss.rand, nwnss.namespace | `src/nwnss/library/misc/rand.c` | No original provider found beyond rand.h/libNSS.imp/callers; libsodium entropy port checked in 0700. |
| AUDITED | PORT | nwnss.rand, nwnss.namespace | `src/nwnss/library/misc/rand.c` | No original provider found beyond rand.h/libNSS.imp/callers; seed-deterministic PRNG port checked in 0700/0701; libsodium only initializes default state before explicit seeding. |
| TODO | PORT | nwnss.rbpTree | `src/nwnss/library/misc/rbpTree.c` | Algorithmic port; has tests, but original-provider search/checklist still open. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/misc/register.c` | Must be compared against original source and classified. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/misc/sysimp.c` | Must be compared against original source and classified. |

View File

@@ -4,12 +4,18 @@
|
| The shipped NSS sources contain shared/sdk/library/rand.h and export
| these symbols from the NSS library import lists, but no corresponding
| C implementation was present in the supplied source archives.
| C implementation was present in the supplied source archives or public
| sources checked during the nwnss import audit.
|
| Keep the NSS symbol surface and back every generated value with the
| bundled libsodium randombytes backend. The seed entry points are kept
| as API-compatible state hooks only; they do not replace OS entropy with
| a private deterministic generator.
| Novell LibC documents rand()/rand_r() as seeded pseudo-random sequence
| APIs. Keep the same seed-driven model for the wider NSS QUAD helpers:
| srandQuad()/srndQuad()/srndLong() set deterministic state and subsequent
| randQuad()/rndQuad()/rndLong() calls advance that state. If callers use
| the generator before explicitly seeding it, initialize the state once
| from libsodium randombytes_buf(), which is the userspace equivalent of a
| kernel random-byte source.
|
| This is a MARS userspace port, not Novell original source.
+-------------------------------------------------------------------------*/
#include <rand.h>
@@ -18,12 +24,11 @@
#include <sodium/core.h>
#include <sodium/randombytes.h>
static QUAD seedSalt;
static QUAD seedCounter;
static int haveSeedSalt;
static QUAD randState;
static int haveRandState;
static int sodiumReady;
static void nwnssRandInit(void)
static void nwnssRandInitSodium(void)
{
if (!sodiumReady) {
int rc = sodium_init();
@@ -32,34 +37,37 @@ static void nwnssRandInit(void)
}
}
static QUAD nwnssSeedMix(void)
static QUAD nwnssRandNextFromState(QUAD *state)
{
QUAD z;
if (!haveSeedSalt)
return 0;
z = seedSalt + (++seedCounter * 0x9e3779b97f4a7c15ULL);
*state += 0x9e3779b97f4a7c15ULL;
z = *state;
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
return z ^ (z >> 31);
}
static void nwnssRandEnsureSeeded(void)
{
if (haveRandState)
return;
nwnssRandInitSodium();
randombytes_buf(&randState, sizeof(randState));
haveRandState = 1;
}
void srandQuad(QUAD seed)
{
seedSalt ^= seed + 0x4e53534c49424e57ULL;
seedCounter = 0;
haveSeedSalt = 1;
randState = seed;
haveRandState = 1;
}
SQUAD randQuad(void)
{
QUAD value;
nwnssRandInit();
randombytes_buf(&value, sizeof(value));
value ^= nwnssSeedMix();
return (SQUAD)value;
nwnssRandEnsureSeeded();
return (SQUAD)nwnssRandNextFromState(&randState);
}
void srndQuad(QUAD seed)

View File

@@ -17,27 +17,80 @@ static QUAD deterministic_rand(void)
return deterministic_next++;
}
int main(void)
static int check_repeatable_quad_seed(void)
{
unsigned freq[4];
SQUAD first;
SQUAD second;
QUAD long_value;
double chi;
SQUAD first_a;
SQUAD second_a;
SQUAD first_b;
SQUAD second_b;
SQUAD first_other;
srandQuad(0x123456789abcdef0ULL);
first = randQuad();
second = randQuad();
CHECK(first != second);
first_a = randQuad();
second_a = randQuad();
CHECK(first_a != second_a);
srandQuad(0x123456789abcdef0ULL);
first_b = randQuad();
second_b = randQuad();
CHECK(first_b == first_a);
CHECK(second_b == second_a);
srandQuad(0x123456789abcdef1ULL);
first_other = randQuad();
CHECK(first_other != first_a);
return 0;
}
static int check_repeatable_rnd_quad_seed(void)
{
SQUAD seq_a[3];
SQUAD seq_b[3];
int i;
srndQuad(0x55aaULL);
first = rndQuad();
second = rndQuad();
CHECK(first != second);
for (i = 0; i < 3; ++i)
seq_a[i] = rndQuad();
srndQuad(0x55aaULL);
for (i = 0; i < 3; ++i)
seq_b[i] = rndQuad();
for (i = 0; i < 3; ++i)
CHECK(seq_a[i] == seq_b[i]);
CHECK(seq_a[0] != seq_a[1]);
CHECK(seq_a[1] != seq_a[2]);
return 0;
}
static int check_repeatable_long_seed(void)
{
QUAD first_a;
QUAD second_a;
QUAD first_b;
QUAD second_b;
srndLong(0x77bbULL);
long_value = rndLong();
CHECK((SQUAD)long_value == (SQUAD)long_value);
first_a = rndLong();
second_a = rndLong();
CHECK(first_a != second_a);
srndLong(0x77bbULL);
first_b = rndLong();
second_b = rndLong();
CHECK(first_b == first_a);
CHECK(second_b == second_a);
return 0;
}
static int check_chi_square(void)
{
unsigned freq[4];
double chi;
deterministic_next = 0;
chi = chiSquareQuad(8, 4, freq, deterministic_rand);
@@ -62,3 +115,13 @@ int main(void)
return 0;
}
int main(void)
{
CHECK(check_repeatable_quad_seed() == 0);
CHECK(check_repeatable_rnd_quad_seed() == 0);
CHECK(check_repeatable_long_seed() == 0);
CHECK(check_chi_square() == 0);
return 0;
}