static void mrg_orig_step(mrg_state* state) { /* Use original A, not fully optimized yet */ uint_fast32_t new_elt = mod_mac_y(mod_mul_x(state->z1), state->z5); state->z5 = state->z4; state->z4 = state->z3; state->z3 = state->z2; state->z2 = state->z1; state->z1 = new_elt; }
static void mrg_update_cache(mrg_transition_matrix* p) { /* Set a, b, c, and d */ p->a = mod_add(mod_mul_x(p->s), p->t); p->b = mod_add(mod_mul_x(p->a), p->u); p->c = mod_add(mod_mul_x(p->b), p->v); p->d = mod_add(mod_mul_x(p->c), p->w); }
/* [b v w s*y a*y] */ /* [a u v w s*y] */ /* [s t u v w ] */ /* for some values of s, t, u, v, and w */ /* Note that A^n is determined by its bottom row (and x and y, which are */ /* fixed), and that it has a large part that is a Toeplitz matrix. You */ /* can multiply two A-like matrices by: */ /* (defining a..d1 and a..d2 for the two matrices) */ /* s3 = s1 d2 + t1 c2 + u1 b2 + v1 a2 + w1 s2, */ /* t3 = s1 s2 y + t1 w2 + u1 v2 + v1 u2 + w1 t2, */ /* u3 = s1 a2 y + t1 s2 y + u1 w2 + v1 v2 + w1 u2, */ /* v3 = s1 b2 y + t1 a2 y + u1 s2 y + v1 w2 + w1 v2, */ /* w3 = s1 c2 y + t1 b2 y + u1 a2 y + v1 s2 y + w1 w2 */ static void mrg_update_cache(mrg_transition_matrix* restrict p) { /* Set a, b, c, and d */ p->a = mod_add(mod_mul_x(p->s), p->t); p->b = mod_add(mod_mul_x(p->a), p->u); p->c = mod_add(mod_mul_x(p->b), p->v); p->d = mod_add(mod_mul_x(p->c), p->w); } static void mrg_make_identity(mrg_transition_matrix* result) { result->s = result->t = result->u = result->v = 0; result->w = 1; mrg_update_cache(result); } static void mrg_make_A(mrg_transition_matrix* result) { /* Initial RNG transition matrix */ result->s = result->t = result->u = result->w = 0; result->v = 1; mrg_update_cache(result);