working on driver
This commit is contained in:
@@ -376,7 +376,7 @@ key, the more likely it is insecure. Therefore, the initial Infinite Noise Mult
|
||||
does not even have a microcontroller onboard, and only returns raw data, direct from the
|
||||
noise source. Whitening is done in the INM driver.
|
||||
|
||||
The INM driver uses the reference versoin of the SHA3 "sponge" with a 1600 bit state. The
|
||||
The INM driver uses the reference version of the SHA3 "sponge" with a 1600 bit state. The
|
||||
state of the sponge needs to be made unpredictable. It is initialized with 3200 bits of
|
||||
entropy before any data is output. After that, reading bytes from the SHA3 sponge blocks
|
||||
until twice as many bytes of entropy have been fed into the sponge from the INM. Data is
|
||||
|
||||
26
software/KeccakF-1600-interface.h
Normal file
26
software/KeccakF-1600-interface.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
|
||||
Michaël Peeters and Gilles Van Assche. For more information, feedback or
|
||||
questions, please refer to our website: http://keccak.noekeon.org/
|
||||
|
||||
Implementation by the designers,
|
||||
hereby denoted as "the implementer".
|
||||
|
||||
To the extent possible under law, the implementer has waived all copyright
|
||||
and related or neighboring rights to the source code in this file.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#ifndef _KeccakPermutationInterface_h_
|
||||
#define _KeccakPermutationInterface_h_
|
||||
|
||||
|
||||
#define KeccakPermutationSize 1600
|
||||
#define KeccakPermutationSizeInBytes (KeccakPermutationSize/8)
|
||||
|
||||
void KeccakInitializeState(unsigned char *state);
|
||||
void KeccakPermutation(unsigned char *state);
|
||||
void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount);
|
||||
void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount);
|
||||
|
||||
#endif
|
||||
209
software/KeccakF-1600-reference.c
Normal file
209
software/KeccakF-1600-reference.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
|
||||
Michaël Peeters and Gilles Van Assche. For more information, feedback or
|
||||
questions, please refer to our website: http://keccak.noekeon.org/
|
||||
|
||||
Implementation by the designers,
|
||||
hereby denoted as "the implementer".
|
||||
|
||||
To the extent possible under law, the implementer has waived all copyright
|
||||
and related or neighboring rights to the source code in this file.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "brg_endian.h"
|
||||
#include "KeccakF-1600-interface.h"
|
||||
|
||||
typedef unsigned char UINT8;
|
||||
typedef unsigned long long int UINT64;
|
||||
|
||||
#define nrRounds 24
|
||||
UINT64 KeccakRoundConstants[nrRounds];
|
||||
#define nrLanes 25
|
||||
unsigned int KeccakRhoOffsets[nrLanes];
|
||||
|
||||
void KeccakPermutationOnWords(UINT64 *state);
|
||||
void theta(UINT64 *A);
|
||||
void rho(UINT64 *A);
|
||||
void pi(UINT64 *A);
|
||||
void chi(UINT64 *A);
|
||||
void iota(UINT64 *A, unsigned int indexRound);
|
||||
|
||||
void fromBytesToWords(UINT64 *stateAsWords, const unsigned char *state)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for(i=0; i<(KeccakPermutationSize/64); i++) {
|
||||
stateAsWords[i] = 0;
|
||||
for(j=0; j<(64/8); j++)
|
||||
stateAsWords[i] |= (UINT64)(state[i*(64/8)+j]) << (8*j);
|
||||
}
|
||||
}
|
||||
|
||||
void fromWordsToBytes(unsigned char *state, const UINT64 *stateAsWords)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for(i=0; i<(KeccakPermutationSize/64); i++)
|
||||
for(j=0; j<(64/8); j++)
|
||||
state[i*(64/8)+j] = (stateAsWords[i] >> (8*j)) & 0xFF;
|
||||
}
|
||||
|
||||
void KeccakPermutation(unsigned char *state)
|
||||
{
|
||||
#if (PLATFORM_BYTE_ORDER != IS_LITTLE_ENDIAN)
|
||||
UINT64 stateAsWords[KeccakPermutationSize/64];
|
||||
#endif
|
||||
|
||||
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
|
||||
KeccakPermutationOnWords((UINT64*)state);
|
||||
#else
|
||||
fromBytesToWords(stateAsWords, state);
|
||||
KeccakPermutationOnWords(stateAsWords);
|
||||
fromWordsToBytes(state, stateAsWords);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KeccakPermutationAfterXor(unsigned char *state, const unsigned char *data, unsigned int dataLengthInBytes)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for(i=0; i<dataLengthInBytes; i++)
|
||||
state[i] ^= data[i];
|
||||
KeccakPermutation(state);
|
||||
}
|
||||
|
||||
void KeccakPermutationOnWords(UINT64 *state)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for(i=0; i<nrRounds; i++) {
|
||||
theta(state);
|
||||
rho(state);
|
||||
pi(state);
|
||||
chi(state);
|
||||
iota(state, i);
|
||||
}
|
||||
}
|
||||
|
||||
#define index(x, y) (((x)%5)+5*((y)%5))
|
||||
#define ROL64(a, offset) ((offset != 0) ? ((((UINT64)a) << offset) ^ (((UINT64)a) >> (64-offset))) : a)
|
||||
|
||||
void theta(UINT64 *A)
|
||||
{
|
||||
unsigned int x, y;
|
||||
UINT64 C[5], D[5];
|
||||
|
||||
for(x=0; x<5; x++) {
|
||||
C[x] = 0;
|
||||
for(y=0; y<5; y++)
|
||||
C[x] ^= A[index(x, y)];
|
||||
}
|
||||
for(x=0; x<5; x++)
|
||||
D[x] = ROL64(C[(x+1)%5], 1) ^ C[(x+4)%5];
|
||||
for(x=0; x<5; x++)
|
||||
for(y=0; y<5; y++)
|
||||
A[index(x, y)] ^= D[x];
|
||||
}
|
||||
|
||||
void rho(UINT64 *A)
|
||||
{
|
||||
unsigned int x, y;
|
||||
|
||||
for(x=0; x<5; x++) for(y=0; y<5; y++)
|
||||
A[index(x, y)] = ROL64(A[index(x, y)], KeccakRhoOffsets[index(x, y)]);
|
||||
}
|
||||
|
||||
void pi(UINT64 *A)
|
||||
{
|
||||
unsigned int x, y;
|
||||
UINT64 tempA[25];
|
||||
|
||||
for(x=0; x<5; x++) for(y=0; y<5; y++)
|
||||
tempA[index(x, y)] = A[index(x, y)];
|
||||
for(x=0; x<5; x++) for(y=0; y<5; y++)
|
||||
A[index(0*x+1*y, 2*x+3*y)] = tempA[index(x, y)];
|
||||
}
|
||||
|
||||
void chi(UINT64 *A)
|
||||
{
|
||||
unsigned int x, y;
|
||||
UINT64 C[5];
|
||||
|
||||
for(y=0; y<5; y++) {
|
||||
for(x=0; x<5; x++)
|
||||
C[x] = A[index(x, y)] ^ ((~A[index(x+1, y)]) & A[index(x+2, y)]);
|
||||
for(x=0; x<5; x++)
|
||||
A[index(x, y)] = C[x];
|
||||
}
|
||||
}
|
||||
|
||||
void iota(UINT64 *A, unsigned int indexRound)
|
||||
{
|
||||
A[index(0, 0)] ^= KeccakRoundConstants[indexRound];
|
||||
}
|
||||
|
||||
int LFSR86540(UINT8 *LFSR)
|
||||
{
|
||||
int result = ((*LFSR) & 0x01) != 0;
|
||||
if (((*LFSR) & 0x80) != 0)
|
||||
// Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
|
||||
(*LFSR) = ((*LFSR) << 1) ^ 0x71;
|
||||
else
|
||||
(*LFSR) <<= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
void KeccakInitializeRoundConstants()
|
||||
{
|
||||
UINT8 LFSRstate = 0x01;
|
||||
unsigned int i, j, bitPosition;
|
||||
|
||||
for(i=0; i<nrRounds; i++) {
|
||||
KeccakRoundConstants[i] = 0;
|
||||
for(j=0; j<7; j++) {
|
||||
bitPosition = (1<<j)-1; //2^j-1
|
||||
if (LFSR86540(&LFSRstate))
|
||||
KeccakRoundConstants[i] ^= (UINT64)1<<bitPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeccakInitializeRhoOffsets()
|
||||
{
|
||||
unsigned int x, y, t, newX, newY;
|
||||
|
||||
KeccakRhoOffsets[index(0, 0)] = 0;
|
||||
x = 1;
|
||||
y = 0;
|
||||
for(t=0; t<24; t++) {
|
||||
KeccakRhoOffsets[index(x, y)] = ((t+1)*(t+2)/2) % 64;
|
||||
newX = (0*x+1*y) % 5;
|
||||
newY = (2*x+3*y) % 5;
|
||||
x = newX;
|
||||
y = newY;
|
||||
}
|
||||
}
|
||||
|
||||
void KeccakInitialize()
|
||||
{
|
||||
KeccakInitializeRoundConstants();
|
||||
KeccakInitializeRhoOffsets();
|
||||
}
|
||||
|
||||
void KeccakInitializeState(unsigned char *state)
|
||||
{
|
||||
memset(state, 0, KeccakPermutationSizeInBytes);
|
||||
}
|
||||
|
||||
void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount)
|
||||
{
|
||||
KeccakPermutationAfterXor(state, data, laneCount*8);
|
||||
}
|
||||
|
||||
void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount)
|
||||
{
|
||||
memcpy(data, state, laneCount*8);
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
all: hello-ftdi healthcheck
|
||||
all: infnoise healthcheck
|
||||
|
||||
hello-ftdi: hello-ftdi.c
|
||||
gcc -Wall -std=c11 -O3 -m64 -march=native -o hello-ftdi hello-ftdi.c -lftdi
|
||||
infnoise: infnoise.c healthcheck.c KeccakF-1600-reference.c brg_endian.h
|
||||
gcc -Wall -std=c11 -O3 -m64 -march=native -o infnoise infnoise.c healthcheck.c KeccakF-1600-reference.c -lftdi -lm
|
||||
|
||||
healthcheck: healthcheck.c
|
||||
gcc -Wall -std=c11 -g -m64 -march=native -o healthcheck healthcheck.c -lm
|
||||
gcc -Wall -std=c11 -g -m64 -march=native -D TEST_HEALTHCHECK -o healthcheck healthcheck.c -lm
|
||||
|
||||
clean:
|
||||
rm -f healthcheck hello-ftdi
|
||||
rm -f healthcheck infnoise
|
||||
|
||||
142
software/brg_endian.h
Normal file
142
software/brg_endian.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
1. source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
2. binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation;
|
||||
|
||||
3. the name of the copyright holder is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
Changes for ARM 9/9/2010
|
||||
*/
|
||||
|
||||
#ifndef _BRG_ENDIAN_H
|
||||
#define _BRG_ENDIAN_H
|
||||
|
||||
#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */
|
||||
#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */
|
||||
|
||||
#if 0
|
||||
/* Include files where endian defines and byteswap functions may reside */
|
||||
#if defined( __sun )
|
||||
# include <sys/isa_defs.h>
|
||||
#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
# include <sys/endian.h>
|
||||
#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \
|
||||
defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ )
|
||||
# include <machine/endian.h>
|
||||
#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
|
||||
# if !defined( __MINGW32__ ) && !defined( _AIX )
|
||||
# include <endian.h>
|
||||
# if !defined( __BEOS__ )
|
||||
# include <byteswap.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Now attempt to set the define for platform byte order using any */
|
||||
/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */
|
||||
/* seem to encompass most endian symbol definitions */
|
||||
|
||||
#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN )
|
||||
# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN )
|
||||
# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( _BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( _LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN )
|
||||
# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( __BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( __LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ )
|
||||
# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( __BIG_ENDIAN__ )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( __LITTLE_ENDIAN__ )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
/* if the platform byte order could not be determined, then try to */
|
||||
/* set this define using common machine defines */
|
||||
#if !defined(PLATFORM_BYTE_ORDER)
|
||||
|
||||
#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \
|
||||
defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \
|
||||
defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \
|
||||
defined( vax ) || defined( vms ) || defined( VMS ) || \
|
||||
defined( __VMS ) || defined( _M_X64 )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
|
||||
#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \
|
||||
defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \
|
||||
defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \
|
||||
defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \
|
||||
defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \
|
||||
defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \
|
||||
defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
|
||||
#elif defined(__arm__)
|
||||
# ifdef __BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# else
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif 1 /* **** EDIT HERE IF NECESSARY **** */
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif 0 /* **** EDIT HERE IF NECESSARY **** */
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
# error Please edit lines 132 or 134 in brg_endian.h to set the platform byte order
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -26,6 +26,7 @@ confirmed.
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include "healthcheck.h"
|
||||
|
||||
#define INM_MIN_SAMPLE_SIZE 100
|
||||
#define INM_ACCURACY 1.05
|
||||
@@ -44,18 +45,8 @@ static double inmCurrentProbability;
|
||||
static uint64_t inmTotalBits;
|
||||
static bool inmPrevBit;
|
||||
|
||||
// Print the tables of statistics.
|
||||
static void inmDumpStats(void) {
|
||||
uint32_t i;
|
||||
for(i = 0; i < 1 << inmN; i++) {
|
||||
//if(inmOnes[i] > 0 || inmZeros[i] > 0) {
|
||||
printf("%x ones:%u zeros:%u\n", i, inmOnes[i], inmZeros[i]);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory used by the health checker.
|
||||
void inmHealthCheckerStop(void) {
|
||||
// Free memory used by the health check.
|
||||
void inmHealthCheckStop(void) {
|
||||
if(inmOnes != NULL) {
|
||||
free(inmOnes);
|
||||
}
|
||||
@@ -64,10 +55,18 @@ void inmHealthCheckerStop(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the health checker. N is the number of bits used to predict the next bit.
|
||||
// Reset the statistics.
|
||||
static void resetStats(void) {
|
||||
inmNumBitsSampled = 0;
|
||||
inmNumBitsCounted = 0;
|
||||
inmCurrentProbability = 1.0;
|
||||
inmNumBitsOfEntropy = 0;
|
||||
}
|
||||
|
||||
// Initialize the health check. N is the number of bits used to predict the next bit.
|
||||
// At least 8 bits must be used, and no more than 30. In general, we should use bits
|
||||
// large enough so that INM output will be uncorrelated with bits N samples back in time.
|
||||
bool inmHealthCheckerStart(uint8_t N, double K) {
|
||||
bool inmHealthCheckStart(uint8_t N, double K) {
|
||||
if(N < 1 || N > 30) {
|
||||
return false;
|
||||
}
|
||||
@@ -76,31 +75,37 @@ bool inmHealthCheckerStart(uint8_t N, double K) {
|
||||
inmK = K;
|
||||
inmN = N;
|
||||
inmPrevBits = 0;
|
||||
inmNumBitsCounted = 0;
|
||||
inmNumBitsSampled = 0;
|
||||
inmOnes = calloc(1u << N, sizeof(uint32_t));
|
||||
inmZeros = calloc(1u << N, sizeof(uint32_t));
|
||||
inmExpectedEntropyPerBit = log(K)/log(2.0);
|
||||
inmTotalBits = 0;
|
||||
inmPrevBit = false;
|
||||
resetStats();
|
||||
if(inmOnes == NULL || inmZeros == NULL) {
|
||||
inmHealthCheckerStop();
|
||||
inmHealthCheckStop();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reset the statistics.
|
||||
static void resetStats(void) {
|
||||
printf("Resetting with numSampled=%u and numCounted=%u\n", inmNumBitsSampled, inmNumBitsCounted);
|
||||
inmNumBitsSampled = 0;
|
||||
inmNumBitsCounted = 0;
|
||||
inmCurrentProbability = 1.0;
|
||||
inmNumBitsOfEntropy = 0;
|
||||
// If running continuously, it is possible to start overflowing the 32-bit counters for
|
||||
// zeros and ones. Check for this, and scale the stats if needed.
|
||||
static void scaleStats(void) {
|
||||
uint32_t i;
|
||||
printf("Scaling stats...\n");
|
||||
for(i = 0; i < (1 << inmN); i++) {
|
||||
inmZeros[i] >>= 1;
|
||||
inmOnes[i] >>= 1;
|
||||
}
|
||||
if(inmNumBitsSampled > 20000) {
|
||||
inmNumBitsCounted = inmNumBitsCounted*(uint64_t)20000/inmNumBitsSampled;
|
||||
inmNumBitsOfEntropy = inmNumBitsOfEntropy*(uint64_t)20000/inmNumBitsSampled;
|
||||
inmNumBitsSampled = 20000;
|
||||
}
|
||||
}
|
||||
|
||||
// This should be called for each bit generated.
|
||||
bool inmHealthCheckerAddBit(bool bit) {
|
||||
bool inmHealthCheckAddBit(bool bit) {
|
||||
inmTotalBits++;
|
||||
if(inmOnes[inmPrevBits] > INM_MIN_SAMPLE_SIZE ||
|
||||
inmZeros[inmPrevBits] > INM_MIN_SAMPLE_SIZE) {
|
||||
@@ -124,8 +129,14 @@ bool inmHealthCheckerAddBit(bool bit) {
|
||||
inmNumBitsSampled++;
|
||||
if(bit) {
|
||||
inmOnes[inmPrevBits]++;
|
||||
if(inmOnes[inmPrevBits] == INM_MAX_COUNT) {
|
||||
scaleStats();
|
||||
}
|
||||
} else {
|
||||
inmZeros[inmPrevBits]++;
|
||||
if(inmZeros[inmPrevBits] == INM_MAX_COUNT) {
|
||||
scaleStats();
|
||||
}
|
||||
}
|
||||
// Check for max sequence of 0's or 1's.
|
||||
uint32_t lowBits = inmPrevBits & ((1 << (INM_MAX_SEQUENCE+1))-1);
|
||||
@@ -143,7 +154,7 @@ bool inmHealthCheckerAddBit(bool bit) {
|
||||
return true;
|
||||
}
|
||||
if(inmNumBitsSampled == 10000) {
|
||||
printf("Generated a total of %lu bits to initialize health checker\n", inmTotalBits);
|
||||
printf("Generated a total of %lu bits to initialize health check\n", inmTotalBits);
|
||||
}
|
||||
// Check the entropy is in line with expectations
|
||||
uint32_t expectedEntropy = inmExpectedEntropyPerBit*inmNumBitsCounted;
|
||||
@@ -157,7 +168,7 @@ bool inmHealthCheckerAddBit(bool bit) {
|
||||
|
||||
// Once we have enough samples, we know that entropyPerBit = log(K)/log(2), so
|
||||
// K must be 2^entryopPerBit.
|
||||
double inmHealthCheckerEstimateK(void) {
|
||||
double inmHealthCheckEstimateK(void) {
|
||||
if(inmNumBitsOfEntropy <= 10000) {
|
||||
return inmK;
|
||||
}
|
||||
@@ -167,13 +178,26 @@ double inmHealthCheckerEstimateK(void) {
|
||||
|
||||
// Once we have enough samples, we know that entropyPerBit = log(K)/log(2), so
|
||||
// K must be 2^entryopPerBit.
|
||||
double inmHealthCheckerEstimateEntropyPerBit(void) {
|
||||
double inmHealthCheckEstimateEntropyPerBit(void) {
|
||||
if(inmNumBitsOfEntropy <= 10000) {
|
||||
return inmExpectedEntropyPerBit;
|
||||
}
|
||||
return (double)inmNumBitsOfEntropy/inmNumBitsCounted;
|
||||
}
|
||||
|
||||
#ifdef TEST_HEALTHCHECK
|
||||
|
||||
// Print the tables of statistics.
|
||||
static void inmDumpStats(void) {
|
||||
uint32_t i;
|
||||
for(i = 0; i < 1 << inmN; i++) {
|
||||
//if(inmOnes[i] > 0 || inmZeros[i] > 0) {
|
||||
printf("%x ones:%u zeros:%u\n", i, inmOnes[i], inmZeros[i]);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Compare the ability to predict with 1 fewer bits and see how much less accurate we are.
|
||||
static void checkLSBStatsForNBits(uint8_t N) {
|
||||
uint32_t i, j;
|
||||
@@ -207,37 +231,6 @@ static void checkLSBStats(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// If running continuously, it is possible to start overflowing the 32-bit counters for
|
||||
// zeros and ones. Check for this, and scale the stats if needed.
|
||||
static void reduceStatsIfNeeded(void) {
|
||||
uint32_t i;
|
||||
uint32_t maxValue = 0;
|
||||
for(i = 0; i < (1 << inmN); i++) {
|
||||
uint32_t zeros = inmZeros[i];
|
||||
uint32_t ones = inmOnes[i];
|
||||
if(zeros >= maxValue) {
|
||||
maxValue = zeros;
|
||||
}
|
||||
if(ones > maxValue) {
|
||||
maxValue = ones;
|
||||
}
|
||||
}
|
||||
if(maxValue > INM_MAX_COUNT) {
|
||||
printf("Scaling stats...\n");
|
||||
for(i = 0; i < (1 << inmN); i++) {
|
||||
inmZeros[i] = inmZeros[i]*INM_MAX_COUNT/maxValue;
|
||||
inmOnes[i] = inmOnes[i]*INM_MAX_COUNT/maxValue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if(numBitsSampled > 20000) {
|
||||
inmNumBitsCounted = inmNumBitsCounted*20000/inmNumBitsSampled;
|
||||
inmNumBitsOfEntropy = inmNumBitsOfEntropy*20000/inmNumBitsSampled;
|
||||
inmNumBitsSampled = 20000;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* This could be built with one opamp for the multiplier, a comparator with
|
||||
rail-to-rail outputs, and switches and caps and resistors.*/
|
||||
static inline bool updateA(double *A, double K, double noise) {
|
||||
@@ -270,7 +263,7 @@ int main() {
|
||||
//double K = sqrt(2.0);
|
||||
double K = 1.82;
|
||||
uint8_t N = 7;
|
||||
inmHealthCheckerStart(N, K);
|
||||
inmHealthCheckStart(N, K);
|
||||
srand(time(NULL));
|
||||
double A = (double)rand()/RAND_MAX; // Simulating INM
|
||||
double noiseAmplitude = 1.0/(1 << 10);
|
||||
@@ -281,19 +274,18 @@ int main() {
|
||||
}
|
||||
for(i = 0; i < 1 << 24; i++) {
|
||||
bool bit = computeRandBit(&A, K, noiseAmplitude);
|
||||
if(!inmHealthCheckerAddBit(bit)) {
|
||||
if(!inmHealthCheckAddBit(bit)) {
|
||||
printf("Failed health check!\n");
|
||||
resetStats();
|
||||
return 1;
|
||||
} else if(inmNumBitsCounted > 0 && (inmNumBitsCounted & 0xfffff) == 0) {
|
||||
printf("Estimated entropy per bit: %f, estimated K: %f\n", inmHealthCheckerEstimateEntropyPerBit(),
|
||||
inmHealthCheckerEstimateK());
|
||||
}
|
||||
if(inmTotalBits > 0 && (inmTotalBits & 0xfffff) == 0) {
|
||||
printf("Estimated entropy per bit: %f, estimated K: %f\n", inmHealthCheckEstimateEntropyPerBit(),
|
||||
inmHealthCheckEstimateK());
|
||||
checkLSBStats();
|
||||
reduceStatsIfNeeded();
|
||||
//resetStats();
|
||||
}
|
||||
}
|
||||
inmDumpStats();
|
||||
inmHealthCheckerStop();
|
||||
inmHealthCheckStop();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
5
software/healthcheck.h
Normal file
5
software/healthcheck.h
Normal file
@@ -0,0 +1,5 @@
|
||||
bool inmHealthCheckStart(uint8_t N, double K);
|
||||
void inmHealthCheckStop(void);
|
||||
bool inmHealthCheckAddBit(bool bit);
|
||||
double inmHealthCheckEstimateK(void);
|
||||
double inmHealthCheckEstimateEntropyPerBit(void);
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <ftdi.h>
|
||||
#include "healthcheck.h"
|
||||
|
||||
#define BUFLEN 64
|
||||
//#define BUFLEN 1
|
||||
@@ -26,7 +27,7 @@ int main()
|
||||
|
||||
/* Open FTDI device based on FT232R vendor & product IDs */
|
||||
if(ftdi_usb_open(&ftdic, 0x0403, 0x6015) < 0) {
|
||||
puts("Can't open device");
|
||||
puts("Can't find Infinite Noise Multiplier");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -39,7 +40,7 @@ int main()
|
||||
puts("Setting baud rate failed\n");
|
||||
return -1;
|
||||
} else if(rc == -3) {
|
||||
puts("USB device unavailable\n");
|
||||
puts("Infinite Noise Multiplier unavailable\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -50,7 +51,7 @@ int main()
|
||||
puts("Can't enable bit-bang mode\n");
|
||||
return -1;
|
||||
} else if(rc == -2) {
|
||||
puts("USB device unavailable\n");
|
||||
puts("Infinite Noise Multiplier unavailable\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user