#ifndef KInum
#define KInum

#ifdef __cplusplus
	extern "C" {
#endif

#include <k/type.h>

typedef enum kncond {
	kncond_ok = kncond_id,
	kncond_saturate,
	kncond_wrap,

	/* error states */
	kncond_fail,
	kncond_fail_io,
	kncond_overflow,
	kncond_underflow,
	kncond_bad_domain,
} kncond;

/* this "hard" random number generator
 * returns a block of random data that
 * can be used safely in cryptographic
 * pseudorandom number algorithms such
 * as e.g. knrands() */

enum kncond
knrandh(u8* mem, sz count);

/* we define the largest available native
 * type as `knword` for convenience; this
 * is the type that the pseudorandom func
 * will use for state and return; */
typedef unsigned long long knword;

/* to encapsulate the state of the pseudo
 * random number generator,  we define an
 * array as an opaque seed reference type */
typedef knword knseed [8];

/* this function implements a "soft" RNG
 * that can be safely used as a cryptographic
 * primitive, keeping its state in a value of
 * type of knseed (which needs to be seeded
 * initially by knrandh() or another reliable
 * source of entropy. */
knword knrands(knseed state);

/* addition and subtraction in C can be
 * complex due to the need to check for
 * underflow and overflow,  so we offer
 * a suite of functions which implement
 * reliable arithmetic over integers of
 * arbitrary bit lengths. functions for 
 * fixed point & floating point numbers
 * should also be added eventually.
 * note that these functions use either
 * two's complement or one's complement
 * for signed */

typedef enum knmode {
	knmode_saturate = 0x0001, /* 0b001 */
	knmode_wrap     = 0x0002, /* 0b010 */
	knmode_fail     = 0x0003, /* 0b011 */

	knmode_signed   = 1 << 2, /* 0b100*/
	knmode_unsigned = 0 /* default */
} knmode;

/* it is legal for src and dest to be the
 * same location in memory. this will not
 * produce incorrect output. although the
 * functions formally take pointers to u8,
 * they are converted  appropriately with
 * regard to sign and size within the fn */

kncond kniadd(knmode, sz, u8* dest, u8* src, u8* delta);
kncond knisub(knmode, sz, u8* dest, u8* src, u8* delta);
kncond knimul(knmode, sz, u8* dest, u8* src, u8* delta);
kncond knidiv(knmode, sz,
	/* output */ u8* ratio, u8* remainder,
	/*  input */ u8* src, u8* delta);

/* we should probably also offer a bignum
 * type eventually, tho this will need to
 * be integrated with kmem for allocation. */

#ifdef __cplusplus
	}
#endif

#endif
