Random generator on ESP32

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
mardi2020
Posts: 15
Joined: Fri Mar 06, 2020 8:48 am

Random generator on ESP32

Post by mardi2020 » Sat Mar 14, 2020 8:24 pm

Hi,

need to create a random string. After some runs, i realized the random result of this function was always the same. when i just used:

Code: Select all

urandom.seed()
Therefore i added the seed with the time in seconds and the time is set via ntp
from ntptime import settime
settime()
(earlier parts of the code)

Code: Select all

    def _random_string(self, length=64):
        #Generate a random string of fixed length
        _randomstring = ''
        x = 0
        #add random seed seconds of localtime
        urandom.seed(time.localtime()[5])
        while x < length:
            _randomstring = _randomstring + urandom.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890')
            x += 1
        return _randomstring
but this does not work, when i call this function several times:

Code: Select all

>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
>>> auth_handler._random_string(64)
'sg01tGwmlfjRQWFskIy56ryZm164815UNsuY06MZxuGahcQ5nKXfxszY8HAx7Xo7'
Could somebody please help?

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Random generator on ESP32

Post by Roberthh » Sun Mar 15, 2020 8:00 am

I cannot replicate your observation by running your code. Some observation:

- If you call _random_string() several times within the span of one second, you get the same result. If that may happen, you could add in tick_us() to get a faster change in the seed. Besides that, it is sufficient to seed only once, using e.g. time.time(). The all calls to _random_string() will deliver different results, but not unexpected ones.
- In addition, you may have a problem with ntptime, returning always the same time.

Besides that, better build your code onto uos.urandom(), since that is using the esp hardware number generator. Like this way:

Code: Select all

import uos

def _random_string(self, length=64):
    #Generate a random string of fixed length
    _randomstring = ''
    _source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890+-'
    x = 0
    while x < length:
        _randomstring = _randomstring + _source[uos.urandom(1)[0] % len(_source)]
        x += 1
    return _randomstring
I added two more characters to the _source string to make it 64 bytes long.That way, I can easily use "uos.urandom(1)[0] % len(_source)" without unbalancing the choices. If the length of the _source string is not a power of two you have to get more bits, convert if to a large integer and then do the modulus.

User avatar
OlivierLenoir
Posts: 126
Joined: Fri Dec 13, 2019 7:10 pm
Location: Picardie, FR

Re: Random generator on ESP32

Post by OlivierLenoir » Sun Mar 15, 2020 8:25 am

I did not test seed() yet, but it's what I get without seed.

Code: Select all

import urandom

keys = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'

def randstr(length=10, aSeq=keys):
    return ''.join((urandom.choice(aSeq) for _ in range(length)))

Code: Select all

>>> randstr(30)
'GedeoDDVSRtwk9tjqJfAL0HeX2IlWF'
>>> randstr(30)
'a5Nme12uu3HjQ5qfCrQE1Aq073O9cQ'
>>> randstr(30)
'MYVdvxsFGEMGTAYAcGkxAwTTBQpRE4'
>>> randstr(30)
'WeKOHYGmuDrCMfu0ImVrNkZGFrkOZX'
Last edited by OlivierLenoir on Sun Mar 15, 2020 10:27 am, edited 1 time in total.

User avatar
OlivierLenoir
Posts: 126
Joined: Fri Dec 13, 2019 7:10 pm
Location: Picardie, FR

Re: Random generator on ESP32

Post by OlivierLenoir » Sun Mar 15, 2020 8:32 am

Using randstr(), seed() Initialize the random number generator. In the here bellow example, I use twice the same seed(12) and you can see that the sequence starts with the same sequence.

Code: Select all

>>> urandom.seed(12)
>>> randstr(30)
'M1OGzB92WBR11tUzaiKogqXLpUAOQe'
>>> randstr(30)
'bE5A1h9a9lBQOY4cxsZE8uk5d0J0sD'
>>> randstr(30)
'Ds1l7rYhAOprrfn3tfkdJEEELmtSBP'
>>> randstr(30)
'i8m1v7QrISF5PdXo3MNBlI8otxdaVR'
>>> randstr(30)
'3FFxQtSogyKVs8tNdiDrVvo06Y1g2W'
>>> randstr(30)
'Cm3Ga3Txujhl5zjO2dVBkJjkQSB1DI'
>>> randstr(30)
'zdKT2NG5d01dC9yJntaEXqx6RLgB8P'
>>>
>>> urandom.seed(12)
>>> randstr(30)
'M1OGzB92WBR11tUzaiKogqXLpUAOQe'
>>> randstr(30)
'bE5A1h9a9lBQOY4cxsZE8uk5d0J0sD'
>>> randstr(30)
'Ds1l7rYhAOprrfn3tfkdJEEELmtSBP'


User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Random generator on ESP32

Post by pythoncoder » Sun Mar 15, 2020 8:35 am

Or using list comprehensions:

Code: Select all

import uos
def randstr(length=20):
    source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
    return ''.join([source[x] for x in [(uos.urandom(1)[0] % len(source)) for _ in range(length)]])
Outcome

Code: Select all

>>> print(randstr(64))
NRq1S0XmgfVct13JJt1L75hLwsZtoRPZmGv3fVB73dDZcFUDWZLasRXW7ET6ZX5t
>>> print(randstr(64))
Emx75ykqLvu3aYtRZ8Lqrpg3u0hvMHr1FPEDDg4yGeyeqZ7KApDv7DIFAR1lPZOn
>>> 
Peter Hinch
Index to my micropython libraries.

mardi2020
Posts: 15
Joined: Fri Mar 06, 2020 8:48 am

Re: Random generator on ESP32

Post by mardi2020 » Mon Mar 16, 2020 4:58 am

Thank you all for your suggestions. It is working now.
I assume import uos did the trick - and the list comprehension is a nice way (i have not been aware of)

Code: Select all

import uos

    def _random_string(self, length=64):
        #Generate a random string of fixed length
        source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
        return ''.join([source[x] for x in [(uos.urandom(1)[0] % len(source)) for _ in range(length)]])


User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Random generator on ESP32

Post by Roberthh » Mon Mar 16, 2020 7:03 am

Please note that I extended the source string in my example to 64 bytes length. Otherwise some characters (A-H) are more probably selected then the other ones. Depending on the application that may not matter.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Random generator on ESP32

Post by pythoncoder » Mon Mar 16, 2020 8:21 am

@Roberthh Are you sure of that? I can't see a mathematical reason for binary modulo values being special. The following, tested with various values of n and run on a Pyboard, shows no obvious bias:

Code: Select all

import uos
n = 7
d = {}
for x in range(n):
    d[x] = 0
for _ in range(30000):
    d[uos.urandom(1)[0] % n] += 1
print(d)
Peter Hinch
Index to my micropython libraries.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Random generator on ESP32

Post by Roberthh » Mon Mar 16, 2020 8:47 am

Yes, I'm sure. The value for n=7 and 30000 may not a good choice for showing the effect. Try n=62 (as in the example) or use a larger number of tests with n=7, like 1000000 trials.
For n=7, the disproportion is 36:37, for n=62 it is 4:5.

mardi2020
Posts: 15
Joined: Fri Mar 06, 2020 8:48 am

Re: Random generator on ESP32

Post by mardi2020 » Mon Mar 16, 2020 2:52 pm

Roberthh wrote:
Mon Mar 16, 2020 7:03 am
Please note that I extended the source string in my example to 64 bytes length. Otherwise some characters (A-H) are more probably selected then the other ones. Depending on the application that may not matter.
Thanks for the advice, but for this application it is not critical.

Post Reply