The Random.Org folks [http://www.random.org] have some nice cgi-bin scripts that return truly random numbers based on atmospheric noise. Below is a TCL interface to that site. Possible uses: * games - use '''::RandomOrg::getIntList 1 6 100''' to get 100 dice rolls * lotto - use '''::RandomOrg::getSequence 1 40''' to get numbers jumbled up * if the range of your random number queries isn't the same each time, use '''::RandomOrg::getNumber min max''' as that uses an internal cache of random bytes to get the number so avoids HTTP calls for each request Enjoy! [BBH] ====== # ----------------------------------------------------------------- # # Tcl interface to random.org random number generator # # ----------------------------------------------------------------- # # author: Bruce Hartweg # # ----------------------------------------------------------------- # # This creates a namespace called RandomOrg which exports 6 procs # # configProxy - allows configuration of HTTP proxy data # configCache - allows setting parameters for internal caching # # These 3 procs provide direct access to cgi scripts at random.org # they will block until data is complete # # getIntList min max howMany - return a list of random numbers in range # getSequence min max - return a random order list of non-duplicating numbers # getBytes format numBytes - get random bytes in specified format # formats: # raw - binary data # hexadecimal, decimal, octal, binary - list of ascii format numbers in each base # # getNumber min max - uses internal buffer of random bytes to calculate number in range # each call doesn't need to re-query random.org site useful if requested ranges # are not the same each time # # ----------------------------------------------------------------- namespace eval RandomOrg { variable baseURL "http://www.random.org/" variable limits array set limits { maxNum 10000 intMin -1000000000 intMax 1000000000 maxBytes 16384 seqRange 10000 seqMin -1000000000 seqMax 1000000000 } variable proxy array set proxy { host "" port 8080 user "" pw "" haveBase64 1 } variable formats array set formats { raw f hexadecimal h decimal d octal o binary b } variable cache array set cache { maxSize 1024 minSize 128 data "" timeout 120000 token "" } namespace export configProxy namespace export configCache namespace export getIntList namespace export getSequence namespace export getBytes namespace export getNumber } package require http if {[catch {package require base64}]} { set ::RandomOrg::proxy(haveBase64) 0 } proc ::RandomOrg::configProxy {{host ""} {port 8080} {user ""} {pw ""}} { variable proxy foreach v {host port user pw} { set proxy($v) [set $v] } if {[string length $user] > 0 && ! $proxy(haveBase64)} { set proxy(user) "" error "Cannot use proxy authentication - base64 package not found!" } } proc ::RandomOrg::configCache {{minVal 128} {maxVal 1024} {timeout 120}} { variable cache # check args if {![string is int -strict $minVal]} { error "minVal must be an integer" } if {![string is int -strict $maxVal]} { error "maxVal must be an integer" } if {$maxVal <= $minVal} { error "maxVal must be greater than minVal" } if {$minVal < 0} { errpr "minVal cannot be negative" } if {![string is int -strict $timeout] || $timeout < 1} { error "timeout must be a positive integer" } set cache(minSize) $minVal set cache(maxSize) $maxVal set cahce(timeout) [expr {$timeout * 1000}] if {[string length $cache(data)] < $minVal} { _extendCache } return "" } proc ::RandomOrg::getIntList {minVal maxVal numItems} { # check args variable limits if {![string is int -strict $minVal] || $minVal < $limits(intMin)} { error "minVal must be an integer no less than $limits(intMin)" } if {![string is int -strict $maxVal] || $maxVal > $limits(intMax)} { error "maxVal must be an integer no greater than $limits(intMax)" } if {![string is int -strict $numItems] || $numItems < 1 || $numItems > $limits(maxNum)} { error "numItems must be an integer from1 to $limits(maxNum)" } if {$maxVal <= $minVal} { error "maxVal must be greater than minVal" } # build URL string set url "integers/?num=$numItems&min=$minVal&max=$maxVal&col=1&format=plain&base=10" if {[catch { _getData $url } ret]} { error "Failed to get random numbers: $ret" } return [string map {"\n" " "} $ret] } proc ::RandomOrg::getSequence {minVal maxVal} { # check args variable limits if {![string is int -strict $minVal] || $minVal < $limits(seqMin)} { error "minVal must be an integer no less than $limits(seqMin)" } if {![string is int -strict $maxVal] || $maxVal > $limits(seqMax)} { error "maxVal must be an integer no greater than $limits(seqMax)" } if {$maxVal <= $minVal} { error "maxVal must be greater than minVal" } if {($maxVal - $minVal) > $limits(seqRange)} { error "sequence range must not exceed $limits(seqRange)" } # build URL string set url "sequences/?min=$minVal&max=$maxVal&format=plain&col=1" if {[catch { _getData $url } ret]} { error "Failed to get random sequence: $ret" } return [string map {"\n" " "} $ret] } proc ::RandomOrg::getBytes {format numBytes} { variable limits variable formats # check args if {![string is int -strict $numBytes] || $numBytes < 1 || $numBytes > $limits(maxBytes)} { error "numBytes must be an integer from1 to $limits(maxBytes)" } set key [array names formats $format*] if {[llength $key] != 1} { error "format must be one of [array names formats]" } set fmt $formats($key) # build URL string set url "randbyte?nbytes=$numBytes&format=$fmt" if {[catch { _getData $url } ret]} { error "Failed to get random sequence: $ret" } if {[string compare $fmt f]} { regsub -all {\s+} [string trim $ret] " " ret } return $ret } proc ::RandomOrg::getNumber {minVal maxVal} { variable cache # check args if {![string is int -strict $minVal]} { error "minVal must be an integer" } if {![string is int -strict $maxVal]} { error "maxVal must be an integer" } if {$maxVal <= $minVal} { error "maxVal must be greater than minVal" } if {[string length $cache(data)] < 4} { _extendCache set id [after $cache(timeout) set cache(data) Timeout] vwait [namespace which -variable cache](data) after cancel $id if {[string equal $cache(data) Timeout]} { set cache(data) "" error "Timeout while trying to get data" } } set chunk [string range $cache(data) 0 3] set cache(data) [string range $cache(data) 4 end] if {[string length $cache(data)] < $cache(minSize)} { _extendCache } # convert to int binary scan $chunk I num # clear sign bit set val [expr {$num & 0x7FFFFFFF}] # return number in specified range return [expr {round((($maxVal-$minVal)*($val / double(0x7FFFFFFF))) + $minVal)}] } # internal helper procs ----------------------------------------------------- proc ::RandomOrg::_getData {url} { variable baseURL variable proxy set cmd [list ::http::geturl $baseURL$url] # if proxy is set - configure it if {[string length $proxy(host)] > 0} { ::http::config -proxyhost $proxy(host) -proxyport $proxy(port) # see if proxy needs authentication if {[string length $proxy(user)] > 0} { set enc [base64::encode $proxy(user):$Proxy(pw)] set auth [list "Proxy-Authorization" [concat "Basic" $enc]] lappend cmd -headers $auth } } if {[catch $cmd tok]} { error "HTTP Request failed: $tok" } if {[::http::ncode $tok] != 200} { set msg "[::http::status $tok] : [::http::error $tok]" ::http::cleanup $tok error $msg } set ret [::http::data $tok] ::http::cleanup $tok return $ret } proc ::RandomOrg::_extendCache {} { variable baseURL variable proxy variable cache if {[string length $cache(token)] > 0} { # current request pending - don't send another return } set cmd [list ::http::geturl ${baseURL}randbyte?nbytes=$cache(maxSize)&format=f] # if proxy is set - configure it if {[string length $proxy(host)] > 0} { ::http::config -proxyhost $proxy(host) -proxyport $proxy(port) # see if proxy needs authentication if {[string length $proxy(user)] > 0} { set enc [base64::encode $proxy(user):$Proxy(pw)] set auth [list "Proxy-Authorization" [concat "Basic" $enc]] lappend cmd -headers $auth } } lappend cmd -handler [namespace which -command _addToCache] lappend cmd -command [namespace which -command _cacheComplete] if {[catch $cmd tok]} { error "Failed HTTP call : $tok" } set cache(token) $tok } proc ::RandomOrg::_addToCache {sock tok} { variable cache set chunk [read $sock] if {[set sz [string length $chunk]] > 0} { append cache(data) $chunk } return $sz } proc ::RandomOrg::_cacheComplete {tok} { variable cache ::http::cleanup $tok set cache(token) "" if {[string length $cache(data)] < $cache(minSize)} { _extendCache } } ====== ---- [FPX]: Here's a shameless plug for [Combat], which allows you to pull random numbers from their server as simply as ====== package require combat proc getRandomNumber {} { set obj [corba::string_to_object http://www.random.org/Random.ior] set rand [$obj lrand48] corba::release $obj return $rand } ====== Sorry, couldn't resist ... [[yeah, I know that the above code does much more than these lines]] ---- [TV] I'm sure I've mentioned it on some other page, but to prevent being dependent on the internet and the security hazard that someone else may read the data you pass through their network, you could hook up a fm radio to your sound card, record some in between station noise, and interpret the wav file you recorded as quite random data, absolutely unpredictable electronic noise. Recording CD full of it takes about an hour, and that is uncrackable, probably even by nasa, cia and kgb together, except for extracting characteristics of the noise.. [DKF]: On the other hand, that just brings you to the key distribution problem. (You'd also better tune the characteristics of your noise generator carefully so that it has the right spectral properties). [Lars H]: [RFC] 4086 [http://www.ietf.org/rfc/rfc4086.txt] has a lot to say about this matter. One important point is that it doesn't really matter if the hardware produces biased random data, because one should do post-processing ("whitening") to improve the distribution etc. This cannot produce more bits of truly random information than what was there to begin with however, it can only concentrate them. [TV] Well, if you let a gigahertz process gather well made electronics/physics noise (like a transistor makes and can be captured by a decent AD converter) then the correlations and the real randomness may be covered by the idea that such a source could be ´´recognizable´´ but that doesn´t change that the resulting noise is ´´´extremely´´´ random, and equally ´´´unpredictable´´´ and not self-correlated (in EE terminology which can be quantized and qualified). And can be generated at such high rates that not even a hundred [Tesla] node machine can real-time keep up with it to do all too much analysis, so it´s cool. ---- [cmaj] The baseURL changed to "www.random.org/cgi-bin/". I also added a little proc to check when the buffer is full on the server. The site advises that automated clients should wait until the buffer is above 20%. Also, requests when the buffer is at 0% will hang. ====== proc ::RandomOrg::checkBuffer {} { # build URL string set url "checkbuf" if {[catch { _getData $url } ret]} { error "Failed to check buffer: $ret" } return [string map {"\n" " " "%" ""} $ret] } ====== ---- [LD] Lots of things seemed to have changed. I fixed the getIntList and getSequence so they work. For getIntList, though, the base value is hardcoded to 10, evn though 2, 8 and 16 are available. Someone with more time may want to spend some to make it better... ---- [JM] 4/3/2014...Another option: console show package require struct package require htmlparse package require http proc parse {} { ::struct::tree t set url "http://www.random.org/sequences/?min=1&max=54&col=1&format=html&rnd=new" set http [::http::geturl $url] set html [::http::data $http] htmlparse::2tree $html t htmlparse::removeVisualFluff t htmlparse::removeFormDefs t set base [walk {1 4 1 0}] set listado [t get $base data] puts "type(tag): [t get $base type]\n" set ctr 0 foreach card $listado { puts "[incr ctr]: $card" } t destroy return } proc walkf {n p} { foreach idx $p { if {$n == ""} {break} set n [lindex [t children $n] $idx] } return $n } proc walk {p} { return [walkf root $p] } parse <> Mathematics | Security