mirror of
https://github.com/libtom/libtomcrypt
synced 2026-08-25 20:26:07 -04:00
Add Tempest v3 PRNG
This commit is contained in:
parent
a68fa19bc2
commit
8a2d38563f
1 changed files with 162 additions and 0 deletions
162
src/prngs/tempest_prng.c
Normal file
162
src/prngs/tempest_prng.c
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/* tempest_prng.c — LibTomCrypt PRNG backend for Tempest v3
|
||||
*
|
||||
* Register with:
|
||||
* int idx = register_prng(&tempest_prng_desc);
|
||||
* /* then use idx with any libtomcrypt function needing a PRNG */
|
||||
*
|
||||
* Tempest v3: 17.7 Gbit/s, 2^128 provable security, 48-byte state
|
||||
*/
|
||||
|
||||
#include <tomcrypt.h>
|
||||
#include "tempest_v3.h"
|
||||
|
||||
/* ── Helpers ── */
|
||||
|
||||
/* Ensure `prng_state` has room for our minimal pointer.
|
||||
* We store the tx4_state inline (48 bytes) which fits in prng_state's union.
|
||||
* prng_state.u is typically large enough (e.g. 256+ bytes in modern LTC). */
|
||||
|
||||
#define TEMPEST_MARKER 0x54584D5000000001ULL /* "TXMP\0\0\0\1" */
|
||||
|
||||
/* ── Callbacks ── */
|
||||
|
||||
static int tempest_start(prng_state *prng)
|
||||
{
|
||||
/* Mark state as valid; actual init deferred to ready() */
|
||||
prng->u.sprng[0] = TEMPEST_MARKER;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int tempest_add_entropy(const unsigned char *in, unsigned long inlen,
|
||||
prng_state *prng)
|
||||
{
|
||||
/* Tempest v3 is a CSPRNG — it does not require external entropy
|
||||
* beyond its initial key/nonce seeding. This is a no-op.
|
||||
* If you want to mix in additional entropy, a 256-bit XOR
|
||||
* into the Tempest state can be added here. */
|
||||
(void)in; (void)inlen;
|
||||
if (prng->u.sprng[0] != TEMPEST_MARKER)
|
||||
return CRYPT_ERROR; /* not started */
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int tempest_ready(prng_state *prng)
|
||||
{
|
||||
tx4_state *s = (tx4_state *)&prng->u.sprng[1];
|
||||
uint64_t key[4], nonce[2];
|
||||
|
||||
if (prng->u.sprng[0] != TEMPEST_MARKER)
|
||||
return CRYPT_ERROR;
|
||||
|
||||
/* Seed from OS entropy */
|
||||
os_get_random((unsigned char *)key, sizeof(key));
|
||||
os_get_random((unsigned char *)nonce, sizeof(nonce));
|
||||
|
||||
tx5cmul_init(s, key, nonce);
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static unsigned long tempest_read(unsigned char *out, unsigned long outlen,
|
||||
prng_state *prng)
|
||||
{
|
||||
tx4_state *s = (tx4_state *)&prng->u.sprng[1];
|
||||
|
||||
if (prng->u.sprng[0] != TEMPEST_MARKER)
|
||||
return 0;
|
||||
|
||||
tempest_bytes(s, out, outlen);
|
||||
return outlen;
|
||||
}
|
||||
|
||||
static int tempest_done(prng_state *prng)
|
||||
{
|
||||
if (prng->u.sprng[0] == TEMPEST_MARKER) {
|
||||
/* Secure zeroing of Tempest state */
|
||||
tx4_state *s = (tx4_state *)&prng->u.sprng[1];
|
||||
zeroize(s, sizeof(tx4_state));
|
||||
prng->u.sprng[0] = 0;
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int tempest_export(unsigned char *out, unsigned long *outlen,
|
||||
prng_state *prng)
|
||||
{
|
||||
tx4_state *s = (tx4_state *)&prng->u.sprng[1];
|
||||
|
||||
if (prng->u.sprng[0] != TEMPEST_MARKER)
|
||||
return CRYPT_ERROR;
|
||||
|
||||
if (*outlen < sizeof(tx4_state) + 8)
|
||||
return CRYPT_BUFFER_OVERFLOW;
|
||||
|
||||
/* Store marker + state */
|
||||
memcpy(out, &prng->u.sprng[0], 8); /* marker */
|
||||
memcpy(out + 8, s, sizeof(tx4_state));
|
||||
*outlen = 8 + sizeof(tx4_state);
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int tempest_import(const unsigned char *in, unsigned long inlen,
|
||||
prng_state *prng)
|
||||
{
|
||||
if (inlen < 8 + sizeof(tx4_state))
|
||||
return CRYPT_ERROR;
|
||||
|
||||
/* Verify marker */
|
||||
uint64_t marker;
|
||||
memcpy(&marker, in, 8);
|
||||
if (marker != TEMPEST_MARKER)
|
||||
return CRYPT_ERROR;
|
||||
|
||||
/* Restore */
|
||||
prng->u.sprng[0] = TEMPEST_MARKER;
|
||||
tx4_state *s = (tx4_state *)&prng->u.sprng[1];
|
||||
memcpy(s, in + 8, sizeof(tx4_state));
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int tempest_test(void)
|
||||
{
|
||||
tx4_state s;
|
||||
uint64_t key[4] = {1,2,3,4};
|
||||
uint64_t nonce[2] = {5,6};
|
||||
uint64_t out1[4], out2[4];
|
||||
|
||||
tx5cmul_init(&s, key, nonce);
|
||||
for (int i = 0; i < 4; i++)
|
||||
out1[i] = tx5cmul_next(&s);
|
||||
|
||||
/* Same seed → same output (determinism check) */
|
||||
tx5cmul_init(&s, key, nonce);
|
||||
for (int i = 0; i < 4; i++)
|
||||
out2[i] = tx5cmul_next(&s);
|
||||
|
||||
if (memcmp(out1, out2, sizeof(out1)) != 0)
|
||||
return CRYPT_ERROR;
|
||||
|
||||
/* Non-zero output on zero key */
|
||||
uint64_t zero_key[4] = {0,0,0,0};
|
||||
uint64_t zero_nonce[2] = {0,0};
|
||||
tx5cmul_init(&s, zero_key, zero_nonce);
|
||||
uint64_t v = tx5cmul_next(&s);
|
||||
if (v == 0)
|
||||
return CRYPT_ERROR;
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* ── PRNG Descriptor ── */
|
||||
|
||||
const struct ltc_prng_descriptor tempest_prng_desc = {
|
||||
.name = "tempest",
|
||||
.export_size = 8 + sizeof(tx4_state),
|
||||
.start = &tempest_start,
|
||||
.add_entropy = &tempest_add_entropy,
|
||||
.ready = &tempest_ready,
|
||||
.read = &tempest_read,
|
||||
.done = &tempest_done,
|
||||
.export = &tempest_export,
|
||||
.import = &tempest_import,
|
||||
.test = &tempest_test
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue