/*-
 * Copyright (c) 2020 UPLEX Nils Goroll Systemoptimierung
 * All rights reserved
 *
 * Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * It isn't cryptography, but the theoretical guarantees of universal
 * hashing depend on the randomness of the keys, so we need a good RNG.
 *
 * This is an implementation of KISS99, from George Marsaglia's post to
 * sci.stat.math and sci.math on January 20, 1999. It passes all of the
 * tests in TestU01.
 *
 * It is *not* thread-safe, due to the static state variables.
 *
 * http://www.ciphersbyritter.com/NEWS4/RANDC.HTM#36A5FC62.17C9CC33@stat.fsu.edu
 * https://www.iro.umontreal.ca/~lecuyer/myftp/papers/testu01.pdf
 */

#include <stdint.h>

static uint32_t mwc1, mwc2, jsr, jcong;

static inline void
rnd_init(const uint32_t seed[4])
{
	mwc1 = seed[0];
	mwc2 = seed[1];
	jsr = seed[2];
	jcong = seed[3];
}

#define MWC(n, x) ((n) * ((x) & 65535) + ((x) >> 16))

static inline uint32_t
rnd_nxt()
{
	uint32_t mwc;

	mwc1 = MWC(36969, mwc1);
	mwc2 = MWC(18000, mwc2);
	mwc = (mwc1 << 16) + mwc2;

	jsr ^= jsr << 17;
	jsr ^= jsr >> 13;
	jsr ^= jsr << 5;

	jcong = 69069 * jcong + 1234567;

	return ((mwc ^ jcong) + jsr);
}
