sandeepmistry / arduino-LoRa

An Arduino library for sending and receiving data using LoRa radios.
MIT License
1.65k stars 630 forks source link

Fix Random function II #496

Open plybrd opened 3 years ago

plybrd commented 3 years ago

Hi,

I am included a function which returns an array of random bytes. This work is based on the work of @Kongduino and resolves the issue #394. To get real random bytes one have to follow the guidelines given in Application Note AN1200.24 from Semtech. See Chapter 4 of Random Number Generation for Cryptography.

There is a setup described in this Application Note to be done before starting collecting random bits. These setup is done in function random(uint8 *, size_t) which then calls random0() to actually collect the random bytes.

The setup can be done in two ways:

Using the API will set some fancy values for sending or receiving but which are not needed for just measuring the RssiWideband for collecting random bits. Writing directly to the registers will reduce much of the overhead due to setup for random number generations. But for review you will find both ways in the pull request:

There is one imported behavior of random(uint8 *, size_t). This function will memory the state before setup for random number generation and will reset to this state back at end. This is hidden for users of the library.

The old function random(byte) is still there and works now as expected.

Kongduino commented 3 years ago

I have done this in my Lorandom library – part of which has been included here. Not sure fillRandom was in the lib when this was done:

void fillRandom(unsigned char *x, size_t len) {
  setupLoRandom();
  size_t i;
  for (i = 0; i < len; i++) {
    x[i] = getLoRandomByte();
  }
  resetLoRa();
}

https://github.com/Kongduino/LoRandom/blob/master/src/LoRandom.h#L69-L77

Anyway sounds like a good idea – I use this in my own code, filling up a 256-byte buffer to speed things up.

plybrd commented 3 years ago

I added just a small example for the use of random().

@Kongduino Many Thanks to figure out how to generate real random numbers with Semtech SX1276. I did not check your header file for a simple reason. For using it I would have to change Sandeepmistry's famous LoRa library anyway. So it is just simpler to add a correct random function to sandeepmistry/arduino-LoRa and ask for commit. By the way your function getLoRandomByte() just returns even numbers: 0 2 4 6 ... No odd numbers! So the function does not return really a random BYTE (Please compare to function LoRaClass::random0() in this commit.). Still much better then the original function which just returns the wide band RSSI measurement and especially these numbers of the original function random() are not even distributed.

Kongduino commented 3 years ago

Let me check on my end – I did some testing when I wrote it and it SEEMED it was working properly. Thanks for the feedback!

Kongduino commented 3 years ago

Thanks @plybrd there was indeed a bug – and thanks to you I was able to fix it. https://github.com/Kongduino/LoRandom/blob/master/src/LoRandom.h#L45-L51

https://github.com/Kongduino/LoRandom/blob/master/Fixed.png

Odd and even numbers now... :-)

plybrd commented 3 years ago

Using just the LSB of a RSSI wideband maeassurement gives random numbers but they are still quite biased. You get more '1' bits then '0'. This explains the uneven curves in the following histogram. The more '1' bits are in a random number value the more often you get the number. The cureves are for 20, 50, 200, 1000, ... samples. The more samples you have the better shows the bias up.

Histogram: as AN1200.24 Chapter 4

In the new code for random() I use a basic von Neumann extractor (see at Wikipedia). This extractor is whitening some LSBs of RSSI wide-band measurements for each random byte. The histogram of the random number values from the improved function shows now the behavior of real random numbers:

Histogram: as AN1200.24 Chapter 4 with basic von Neumann extractor

Further the improved function 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.

I tried to add all the ideas found in PR #150, #190, and #395. It's look like there is much bother about the original random() which just returns a wide-band RSSI measurement. And this is NOT in any way a random number.

To give the expert the possibility to make his own, improved random function I added the function rssi_wideband().

Kongduino commented 3 years ago

Any update on this? You really need to fix the random() function...

plybrd commented 1 year ago

Please rename the corrupt random() to rssi_wideband()

This library with a correct random() can be found here.

rforro commented 9 months ago

Please just merge this PR.

plybrd commented 9 months ago

I would if I could. @rforro You can use my fork at plybrd/arduino-LoRa.