randomvibe
Well-known member
Is there a Teensy 3.6 library or function that accesses the hardware random number generator in the K66 chip?
Is there a Teensy 3.6 library or function that accesses the hardware random number generator in the K66 chip?
here is example from early T3.6 (K66) beta tests
https://forum.pjrc.com/threads/34808-K66-Beta-Test?p=107134&viewfull=1#post107134
// random RNG
#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#define REPS 50
#define RNG_CR_GO_MASK 0x1u
#define RNG_CR_HA_MASK 0x2u
#define RNG_CR_INTM_MASK 0x4u
#define RNG_CR_CLRI_MASK 0x8u
#define RNG_CR_SLP_MASK 0x10u
#define RNG_SR_OREG_LVL_MASK 0xFF00u
#define RNG_SR_OREG_LVL_SHIFT 8
#define RNG_SR_OREG_LVL(x) (((uint32_t)(((uint32_t)(x))<<RNG_SR_OREG_LVL_SHIFT))&RNG_SR_OREG_LVL_MASK)
#define SIM_SCGC6_RNGA ((uint32_t)0x00000200)
//#define Serial Serial1
uint32_t trng(){
RNG_CR |= RNG_CR_GO_MASK;
while((RNG_SR & RNG_SR_OREG_LVL(0xF)) == 0); // wait
return RNG_OR;
}
void setup() {
Serial.begin(9600);
Serial.println("hello"); delay(2000);
SIM_SCGC6 |= SIM_SCGC6_RNGA; // enable RNG
PRREG(SIM_SCGC6);
RNG_CR &= ~RNG_CR_SLP_MASK;
RNG_CR |= RNG_CR_HA_MASK; // high assurance, not needed
PRREG(RNG_CR);
PRREG(RNG_SR);
}
void loop() {
uint32_t t, r;
int i;
t=micros();
for(i=0;i<REPS;i++) r=trng();
t=micros()-t;
float bps = REPS*32.e6/t;
Serial.println(" ");
Serial.println(t);
Serial.println(bps,2);
Serial.println(r,HEX);
Serial.println(r);
delay(2000);
}
// random RNG
#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#define REPS 50 //not needed in this variant
#define MYDLY 500 //loop delay in milliseconds
#define RNG_CR_GO_MASK 0x1u
#define RNG_CR_HA_MASK 0x2u
#define RNG_CR_INTM_MASK 0x4u
#define RNG_CR_CLRI_MASK 0x8u
#define RNG_CR_SLP_MASK 0x10u
#define RNG_SR_OREG_LVL_MASK 0xFF00u
#define RNG_SR_OREG_LVL_SHIFT 8
#define RNG_SR_OREG_LVL(x) (((uint32_t)(((uint32_t)(x))<<RNG_SR_OREG_LVL_SHIFT))&RNG_SR_OREG_LVL_MASK)
#define SIM_SCGC6_RNGA ((uint32_t)0x00000200)
//#define Serial Serial1
uint32_t trng(){
RNG_CR |= RNG_CR_GO_MASK;
while((RNG_SR & RNG_SR_OREG_LVL(0xF)) == 0); // wait
return RNG_OR;
}
void setup() {
Serial.begin(9600);
Serial.println("hello"); delay(2000);
SIM_SCGC6 |= SIM_SCGC6_RNGA; // enable RNG
PRREG(SIM_SCGC6);
RNG_CR &= ~RNG_CR_SLP_MASK;
RNG_CR |= RNG_CR_HA_MASK; // high assurance, not needed
PRREG(RNG_CR);
PRREG(RNG_SR);
}
void loop() {
uint32_t r;
r=trng();
Serial.println(" ");
Serial.println(r,HEX);
Serial.println(r);
delay(MYDLY);
}
then retrieve an unsigned 32-bit random number with trng()
To visually observe 32-bit random numbers and "determine their randomness" is a fool's errand. You need to run statistical tests over millions of bytes of the random bits (see post #6). Maybe just observe the the low order bit (odd vs even). Here is a sketch that does a weak real-time statistical test of the random bytes.trng() seems to return values greater than 1e9 only
// random RNG
#define RNG_CR_GO_MASK 0x1u
#define RNG_CR_HA_MASK 0x2u
#define RNG_CR_INTM_MASK 0x4u
#define RNG_CR_CLRI_MASK 0x8u
#define RNG_CR_SLP_MASK 0x10u
#define RNG_SR_OREG_LVL_MASK 0xFF00u
#define RNG_SR_OREG_LVL_SHIFT 8
#define RNG_SR_OREG_LVL(x) (((uint32_t)(((uint32_t)(x))<<RNG_SR_OREG_LVL_SHIFT))&RNG_SR_OREG_LVL_MASK)
#define SIM_SCGC6_RNGA ((uint32_t)0x00000200)
uint32_t trng() {
while ((RNG_SR & RNG_SR_OREG_LVL(0xF)) == 0); // wait
return RNG_OR;
}
void setup() {
Serial.begin(9600);
SIM_SCGC6 |= SIM_SCGC6_RNGA; // enable RNG 0x40029000
RNG_CR &= ~RNG_CR_SLP_MASK;
RNG_CR |= RNG_CR_HA_MASK; // high assurance, not needed
RNG_CR |= RNG_CR_GO_MASK; // ? only need to do this once?
}
// quick entropy check expect 8 bits entropy 0.5 1s 127.5
uint32_t bits[8], cnts[256], bytes;
void dobyte(uint8_t byte) {
bytes++;
cnts[byte]++;
for (int j = 0; j < 8; j++) if ( byte & 1 << j) bits[j]++;
}
void loop() {
static uint32_t ms = millis();
uint32_t r = trng();
uint8_t *b = (uint8_t *) &r;
for (int i = 0; i < 4; i++) dobyte(b[i]);
if (millis() - ms > 5000) {
float avrg = 0, p, e = 0;
ms = millis();
for (int i = 0; i < 256; i++) {
avrg += 1.0 * i * cnts[i];
if (cnts[i]) {
p = (float) cnts[i] / bytes;
e -= p * log(p) / log(2.0);
}
}
Serial.printf("%d bytes avrg %f entropy %f\n", bytes, avrg / bytes, e);
for (int j = 0; j < 8; j++) {
Serial.print((float) bits[j] / bytes, 6);
Serial.print(" ");
}
Serial.println();
}
}
#if (F_CPU == 240000000)
#define F_PLL 240000000
#ifndef F_BUS
// #define F_BUS 60000000
//#define F_BUS 80000000 // uncomment these to try peripheral overclocking
#define F_BUS 120000000 // all the usual overclocking caveats apply...
For crypto strength, NXP suggests that the entropy from the 32-bits is really only worth about 1 -bit, so if you needed an 8-bit random number, you would call the hardware RNG 8 times and take only 1 bit from each call.
F_CPU == 240000000 F_BUS == 60000000 1000000 trng() calls millis == 4266
4687812 bytes avrg 127.484650 entropy 7.999966
0.499969 0.499705 0.499510 0.499709 0.500060 0.500247 0.499891 0.499904
9372492 bytes avrg 127.496246 entropy 7.999980
0.499627 0.499808 0.499694 0.499999 0.499889 0.499783 0.500111 0.499999
14057184 bytes avrg 127.503380 entropy 7.999986
0.499836 0.499766 0.499733 0.500013 0.500028 0.499845 0.500095 0.500026
18741880 bytes avrg 127.505615 entropy 7.999991
0.499778 0.499804 0.499788 0.500079 0.499975 0.499886 0.500127 0.500019
23426580 bytes avrg 127.506622 entropy 7.999991
0.499829 0.499845 0.499809 0.500012 0.499976 0.499955 0.500212 0.499969
28111280 bytes avrg 127.507240 entropy 7.999993
0.499851 0.499872 0.499903 0.499988 0.499964 0.499885 0.500207 0.499993
32795980 bytes avrg 127.510254 entropy 7.999993
0.499796 0.499900 0.499938 0.500000 0.499978 0.499870 0.500199 0.500021
37480680 bytes avrg 127.507889 entropy 7.999997
0.499848 0.499843 0.499983 0.499969 0.500019 0.499866 0.500176 0.500011
F_CPU == 240000000 F_BUS == 120000000 1000000 trng() calls millis == 2133
7718948 bytes avrg 127.520798 entropy 7.999976
0.500197 0.500092 0.500216 0.500200 0.500287 0.500074 0.500177 0.499997
15432424 bytes avrg 127.503799 entropy 7.999989
0.500111 0.500096 0.500214 0.500055 0.500128 0.499946 0.500098 0.499966
23145864 bytes avrg 127.510590 entropy 7.999995
0.500093 0.500048 0.500210 0.499964 0.500083 0.500008 0.500114 0.500007
30859064 bytes avrg 127.504814 entropy 7.999996
0.500088 0.500044 0.500124 0.499950 0.500018 0.500070 0.500111 0.499961
38572636 bytes avrg 127.501213 entropy 7.999997
0.500035 0.500060 0.500071 0.499984 0.499987 0.500033 0.500058 0.499971
46285988 bytes avrg 127.502007 entropy 7.999996
0.500046 0.500106 0.500084 0.500021 0.500002 0.500044 0.500066 0.499966
53999544 bytes avrg 127.499855 entropy 7.999997
0.500019 0.500095 0.500083 0.499987 0.500006 0.500037 0.500068 0.499951
61712860 bytes avrg 127.505417 entropy 7.999997
0.500027 0.500111 0.500095 0.499998 0.500039 0.500036 0.500089 0.499979
typedef struct ranctx { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } ranctx;
#define rot(x,k) (((x)<<(k))|((x)>>(32-(k))))
uint32_t ranval( ranctx *x ) {
uint32_t e = x->a - rot(x->b, 27);
x->a = x->b ^ rot(x->c, 17);
x->b = x->c + x->d;
x->c = x->d + e;
x->d = e + x->a;
return x->d;
}
void raninit( ranctx *x, uint32_t seed ) {
uint32_t i;
x->a = 0xf1ea5eed, x->b = x->c = x->d = seed;
for (i=0; i<20; ++i) {
(void)ranval(x);
}
}