Technical Forum
Ask questions. Discover Answers.
cancel
Showing results for 
Search instead for 
Did you mean: 

How random is rand()?

Robert_Sutcliff
Nimbostratus
Nimbostratus
Hi,

 

How random is the tcl rand function?

 

 

We're currently using it to generate a unique(ish) value for each request we process - using a code bloc like this

 

 

 
 set rnum [format "%08X" [expr { int(1000000000 * rand() ) } ] ] 
 set cthash [format "%08X" [clock clicks -milliseconds] ] 
 set tracker "$cthash$rnum 
 

 

 

The tracker value then get inserted into a database. We would like to be comfortable in making it the primary key of the table (ie. no duplicates).

 

 

Is there a cryptogrpahically safe equivalent of rand() available from with iRules?

 

If I don't seed rand in a RULE_INIT event, will it be reseeded each time it's called?

 

Alternatively, does anyone have a method to generate a unique request identifier?

 

 

Cheers,

 

Rob
4 REPLIES 4

Robert_Sutcliff
Nimbostratus
Nimbostratus
A solution I've come up with is to use a STATS profile.

 

Then for every connection (on every vhost) we can increment a counter. The code snippet then becomes

 

 

 
   set iruleversion [format "%04X" 1] 
   set F5id "[format "%02X" 1]" 
   STATS::incr Booking_stats request_count 
   set rnum [format "%08X" [STATS::get Booking_stats request_count] ] 
   set cthash [format "%08X" [clock seconds] ] 
   set tracker "$F5id$iruleversion$cthash$rnum" 
 

 

 

This allows us to identify the BigIP pair (F5id) the request was processed by, and gives us a version number (iruleversion) for the iRule, which together with the clock should ensure we don't get duplicate values if/when the Booking_stats profile is reset.

 

Unfortunately the F5id and iruleversion need manual control, but as I don't think we'll be updating either frequently this isn't a problem.

 

 

Rob

hooleylist
Cirrostratus
Cirrostratus

Hi Rob,

Here is a method we used for a customer to generate a unique ID per HTTP request:

 

 
 when RULE_INIT { 
  
     Initialize 10 variables to track the distribution of first digits 
    for {set i 0} {$i < 10} {incr i} { 
       set $i 0 
    } 
  
     Loop through and generate X number of random numbers 
    for {set i 0} {$i < 1000} {incr i} { 
  
        Save a new random number 
       set random_number [expr {rand()}] 
       set random_number_float [format %0.10f $random_number] 
  
        Log the random number, the formatted string and the first digit 
       log local0. "$random_number, [format %010s [string range $random_number 2 12]],\ 
          [string range [format %010s [string range $random_number 2 12]] 0 0], $random_number_float" 
  
       incr [string range [format %010.f [string range $random_number_float 2 12]] end end] 
    } 
    log local0. "Summary: " 
    for {set i 0} {$i < 10} {incr i} { 
       log local0. "$i: [set $i]" 
    } 
 } 
 

 

For a run of 100,000 iterations, the distribution is fairly even:

Rule : Summary:

Rule : 0: 10114

Rule : 1: 9981

Rule : 2: 9781

Rule : 3: 9980

Rule : 4: 10104

Rule : 5: 9993

Rule : 6: 10074

Rule : 7: 10067

Rule : 8: 10013

Rule : 9: 9893

I got the basics from this TCL wiki page (http://wiki.tcl.tk/17696). I didn't seed rand as there were a few people stating:

as specifying our own seed for every call to roll is more likely to reduce randomness than improve it, I've left it out altogether.

Aaron

For several purposes (i.e. creating safe passphrases, cookies etc.) I´m using the rand function of TCL quite often.

 

But for peace of mind I had to prove two aspects of the random numbers:

 

* Will the random numbers be evenly distributed or will they follow a bell-shaped curve?

 

* Will rand return numbers less than 1 typically?

 

Indeed I made a (very short) attempt to have a look at the source code and quickly decided to follow an empiric approach. Instead of opening a new post I will add my 2 cents to this old thread.

Here is the iRule code returning i.e. 10,000 random numbers over a range of 0-20 upon request. A table is used to count the hits for each number in range.

 

when HTTP_REQUEST {
     remove existing table
    table delete -subtable randomtest -all
     find x random values in range of 0-y
    set x 10000
    set y 20
    for {set i 0} {${i} < ${x}} {incr i} {
        table incr -subtable randomtest key[format %03d [expr {int(rand()*${y})}]]
    }
     build output and prove number of results
    set j 0
    set page ""
    for {set i 0} {${i} <= ${y}} {incr i} {
        if { [table lookup -subtable randomtest key[format %03d ${i}]] ne "" } {
             incr j [table lookup -subtable randomtest key[format %03d ${i}]]
        }
        append page "key[format %03d $i]: [table lookup -subtable randomtest key[format %03d $i]]\r\n"
    }
    append page "calculations: $j\r\n"
     return results
    HTTP::respond 200 content ${page} Connection Close Content-Type "text/plain; charset=us-ascii"
    return
}

 

The iRule will be bound to a virtual server having an http-profile.

 

Send a request via browser or cURL as shown below.

 

A table is used to count the hits for each number in range.

 

The result shows an even distribution.

 

The number 20 (representing a random value of 1) doesnt show up.

$ curl http://10.1.1.61/
key000: 537
key001: 557
key002: 464
key003: 518
key004: 487
key005: 482
key006: 482
key007: 520
key008: 502
key009: 502
key010: 516
key011: 479
key012: 525
key013: 470
key014: 554
key015: 439
key016: 471
key017: 477
key018: 541
key019: 477
key020:
calculations: 10000

 

Thanks, Stephan

Kai_Wilke
MVP
MVP

Hi Folks,

I'm using a combination of the TMM_ID and a Timestamp to create unique request IDs that will never colide.

 

set uniqueID [TMM::cmp_unit][clock clicks]

 

Cheers, Kai

 


iRule can do… 😉