diff --git a/API.md b/API.md index 572eded..b2d7dc0 100644 --- a/API.md +++ b/API.md @@ -408,10 +408,42 @@ Supported values are between `0` and `6`. If gain is 0, AGC will be enabled and ### Random -Generate a random byte, based on the Wideband RSSI measurement. +Generate random bytes, based on Wideband RSSI measurements. The least significant bit (LSB) of each measurement is fed in a [Basic von Neumann extractor](https://en.wikipedia.org/wiki/Bernoulli_process#Bernoulli_sequence) for additional whitening. ``` byte b = LoRa.random(); ``` Returns random byte. + +``` +LoRa.random(uint8_t *buffer, size_t size); +``` + + + * `buffer` - pointer to an array of bytes + * `size` - size of the buffer in bytes + +Returns nothing but the buffer will be filled with `size` random bytes. + +If you need more than one byte it is recommended to use the second function due to some overhead. + +The LoRa module is put in a receiving mode with configuration as suggested in AN1200.24 from Semtech. Before changing the mode all pending transmits are send. After collecting the random numbers the module is reconfigured to the state it has before calling this function. During the collection of the random numbers no packets can be received. + +The pseudorandom number sequence test program [ENT](http://www.fourmilab.ch/random/) gives quite good results when fed with random bytes generated with a HopeRF RFW95 module and this function: + +Entropy = 7.999980 bits per byte. + +Optimum compression would reduce the size of this 8757184 byte file by 0 percent. + +Chi square distribution for 8757184 samples is 247.56, and randomly +would exceed this value 61.91 percent of the times. + +Arithmetic mean value of data bytes is 127.5110 (127.5 = random). + +Monte Carlo value for Pi is 3.142532185 (error 0.03 percent). + +Serial correlation coefficient is 0.000407 (totally uncorrelated = 0.0). + +You can get around 1000 bytes/s with an ATmega328p and a HopeRF RFW95 module. +For more information see [RANDOM.md](https://github.com/plybrd/arduino-LoRa/blob/master/doc-random/RANDOM.md). diff --git a/README.md b/README.md index 9663b61..48ac492 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,53 @@ +# This Fork + +adds support to **real random numbers** to this library. + +The new methods are + ``` c + byte rssi_wideband(); // RSSI wideband meassurement - the original "random" method + byte random(); + void random(uint8_t *buffer, size_t size); + ``` +There is some overhead in creating random numbers. So if you need more then one you should use `random(uint8 *, size_t)`. + +The improved method takes care if a packet is just to go over the air. It waits until the transmit is finished before setting up for random number generation. + +In general you can not receive a wanted packet after setting up for random number generation. This is because of the fact that bandwidth, spreading factor, and coding rate is changed. For this reason I disable the interrupt IRQ_RX_DONE so no accidental receive will disturb us. In fact all interrupts on the SX127# will be disabled to be on the sure side. After finishing the collection of random numbers all the interrupts are restored to the previous state. Before returning all parameters are set to the original state. + +A long time ago I suggested change request [#496](https://github.com/sandeepmistry/arduino-LoRa/pull/496) but until now nothing happend. + +If you need not only a palmful random numbers you can have a look at library [LoRandom](https://github.com/Kongduino/LoRandom). + +## How is it done? +It first renames the original function `byte random()` to `byte rssi_wideband()` as this is what this function does! It depends on the location of the meassurement and gives only random values from 0 to MAX with MAX<<255. The result (see [here](https://github.com/plybrd/arduino-LoRa/blob/master/doc-random/random-widebandRSSI.png)) looks strongly biased. In my case only numbers between 0 and 31 are returned! The cureves are for 20, 50, 200, 1000, ... samples. The more samples you have the better shows the bias up. + +There is an description how to generate random numbers in Application Note AN1200.24 from Semtech. See Chapter 4 [Random Number Generation for Cryptography](https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/440000001NAw/7YN8ZamV70_xR.vPDAAAshm.0Wt4jmRX0nOKkOzQqiI). + +To generate an N bit random number, perform N read operation of the register RegRssiWideband (address 0x2c) and use the LSB of the fetched value. The value from RegRssiWideband is derived from a wideband (4MHz) signal strength at the receiver input and the LSB of this value constantly and randomly changes. + +Doing so gives this [result](https://github.com/plybrd/arduino-LoRa/blob/master/doc-random/random-asAN1200.24.png). It looks like bit '1' is prefered in comparison to bit '0'. So binary numbers with many '1' occure more often. But we get the whole range of possible numbers. + +Last, we add a basic von Neumann extractor which produce a uniform output even if the distribution of input bits is not uniform so long as each bit has the same probability of being one and there is no correlation between successive bits (see [Bernoulli_sequence@wikipedia](https://en.wikipedia.org/wiki/Bernoulli_process#Bernoulli_sequence) and [Randomness_extractor@wikipedia](https://en.wikipedia.org/wiki/Randomness_extractor)). This extractor is whitening some LSBs of RSSI wide-band measurements for each random byte. The [result](https://github.com/plybrd/arduino-LoRa/blob/master/doc-random/random-asAN1200.24-Neumann.png) shows random numbers without bias. The function reproduces the mean value when we pull enough numbers. + +**Using the program [ENT](http://www.fourmilab.ch/random/) from fourmilab gives** + +### For the new random function of this library + - Entropy = 7.999980 bits per byte. + - Optimum compression would reduce the size of this 8757184 byte file by 0 percent. + - Chi square distribution for 8757184 samples is 247.56, and randomly would exceed this value 61.91 percent of the times. + - Arithmetic mean value of data bytes is 127.5110 (127.5 = random). + - Monte Carlo value for Pi is 3.142532185 (error 0.03 percent). + - Serial correlation coefficient is 0.000407 (totally uncorrelated = 0.0). + +### For rssi_wideband() ( sandeepmistry's "random" function) +- Entropy = 3.910721 bits per byte. + - Optimum compression would reduce the size of this 11800167 byte file by 51 percent. + - Chi square distribution for 11800167 samples is 311806630.27, and randomly would exceed this value less than 0.01 percent of the times. + - Arithmetic mean value of data bytes is 14.9272 (127.5 = random). + - Monte Carlo value for Pi is 4.000000000 (error 27.32 percent). + - Serial correlation coefficient is 0.000269 (totally uncorrelated = 0.0). + + # Arduino LoRa [![Build Status](https://travis-ci.org/sandeepmistry/arduino-LoRa.svg?branch=master)](https://travis-ci.org/sandeepmistry/arduino-LoRa) diff --git a/doc-random/random-asAN1200.24-Neumann.png b/doc-random/random-asAN1200.24-Neumann.png new file mode 100644 index 0000000..bfec995 Binary files /dev/null and b/doc-random/random-asAN1200.24-Neumann.png differ diff --git a/doc-random/random-asAN1200.24.png b/doc-random/random-asAN1200.24.png new file mode 100644 index 0000000..ef01303 Binary files /dev/null and b/doc-random/random-asAN1200.24.png differ diff --git a/doc-random/random-widebandRSSI.png b/doc-random/random-widebandRSSI.png new file mode 100644 index 0000000..9980288 Binary files /dev/null and b/doc-random/random-widebandRSSI.png differ diff --git a/examples/LoRaRandom/LoRaRandom.ino b/examples/LoRaRandom/LoRaRandom.ino new file mode 100644 index 0000000..a316c6e --- /dev/null +++ b/examples/LoRaRandom/LoRaRandom.ino @@ -0,0 +1,37 @@ +#include +#include + +#define LRFRQNCY 866E6 + +void setup() { + Serial.begin(9600); + while (!Serial); + Serial.println("Start LoRaRandom"); + + if (!LoRa.begin(LRFRQNCY)) { + Serial.println("Starting LoRa failed!"); + while(1); + } + Serial.println("LoRa init succeeded."); +} + +#define NRANDOM 1024 + +void loop() { + uint8_t buffer[NRANDOM]; + + LoRa.random(buffer, NRANDOM); + + // Just print them out + for(size_t i=0; i