Announcement

Collapse
No announcement yet.

CryptoRndIII

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • CryptoRndIII

    In a nutshell: CryptoRndIII = CryptoRndII - BCryptGenRandom + Intel RdRand

    This is the slowest generator that I have written coming in at roughly three quarters the speed of Rnd. However, it is a CPRNG getting its source of entropy from thermal noise on the CPU. It should not be used for cryptographic purposes as it uses pre-filled buffers in the same vein as CryptoRndII. It does, however, provide the best quality of randomness for PowerBASIC on my machine. RdRand was introduced by Intel in 2012 followed by AMD in 2015. CryptoRndIII.dll assumes that you have RdRand.

    If we have three generators all passing PractRand to at least 1TB then how can we tell which is the best generator? We can't using PractRand. All generators have what I call 'bad days'. Some generators seem to have more bad days than others. Of those some will have the occasional exceptional day. The secret is to choose a generator which is the most likely to have a good day. Many years ago I did some tests and found that a RdRand based generator was more likely to have a good day than a BcryptGenRandom based generator. In turn a BcryptGenRandom based generator was more likely to have a good day than CMWC256 and that was more likely to have a good day than Rnd. With some tests Rnd was better than the others but that was very rare. Remember "No one will get sacked for using IBM"? Well no one will get sacked for using CryptoRndIII. However, if a blindingly fast generator is needed then CryptoRndIII is not a good choice.

    The following link is a zip of a folder, CryptoRndIII. The folder contains CryptoRndIII.dll (21.5KB), TestbedRdRand.bas and MultipleTimersLite.inc (used by TestbedRdRand.bas). Here is a typical TestbedRdRand.exe output. CryptoS is Single precision with a granularity of 24-bit and CryptoSE is Double precision with a granularity of 32-bit. CryptoSX is [-1, 1) based. CryptoD is Double precision with 53-bit granularity and uses two 32-bit outputs. CryptoDX is [-1,1} based. I would probably use CryptoSE more than any of the others, followed by CryptoR.
    Code:
    Throughput for CryptoDW 60 MHz
    Throughput for CryptoS 61 MHz
    Throughput for CryptoSE 61 MHz
    Throughput for CryptoSX 61 MHz
    Throughput for CryptoD 30 MHz
    Throughput for CryptoDX 30 MHz
    Throughput for CryptoR 61 MHz
    Throughput for Rnd 82 MHz
    
    CryptoDW  1746254531
    CryptoS  .7423732
    CryptoSE  3.50383438635617E-2
    CryptoSX  .929145968984812
    CryptoD  .95320168430721
    CryptoDX -.91128149572362
    CryptoR  213
    
    Average CryptoS  .500010343006147
    Average CryptoSE  .49999250288878
    Average CryptoSX -7.51874318748293E-5
    Average CryptoD  .499983485421413
    Average CryptoDX  8.43186693543828E-5
    Average CryptoR 127.51506464
    
    Done. Press any key
    CryptoRndIII.zip

  • #2
    Originally posted by David Roberts View Post
    All generators have what I call 'bad days'. Some generators seem to have more bad days than others. Of those some will have the occasional exceptional day. The secret is to choose a generator which is the most likely to have a good day.
    That's the nature of randomness

    Comment


    • #3
      It is. All normal distributions have 'tails'. Some look like traffic cones with a small variance and others look like fried eggs with a larger variance. With random number generators we need fried eggs.

      Comment


      • #4
        I should have included this but forgot. If you don't already know, this will tell you whether your CPU supports RdRand or not.
        Code:
        Function PBMain
        Local CPUManID As String * 12
        Local CPUManIDPtr As Byte Ptr
        Local RdRand As Long
        
        ' Get Manufactures Id String
        CPUManIDPtr = VarPtr(CPUManID)
        ! mov eax, 0 ' Get Vendor Id
        ! cpuid
        ! mov eax, CPUManIDPtr
        ! mov [eax], ebx
        ! mov [eax + 4], edx
        ! mov [eax + 8], ecx
        If CPUManID = "GenuineIntel" Or CPUManID = "AuthenticAMD" Then
        ' Is RdRand supported?
        ! mov eax, 1 ' Get features
        ! cpuid
        ! test ecx, &h40000000 ' Bit 30
        ! jz NoRdRand
        RdRand = -1
        NoRdRand:
        End If
        
        If IsTrue RdRand Then
          MsgBox "Your CPU supports RdRand", , "RdRand test"
        Else
          MsgBox "Your CPU does not support RdRand", , "RdRand test"
        End If
        
        End Function

        Comment


        • #5
          I have tested RdRand using PractRand quite a few times and RdRand has not been intimidated. However, I was interested to see how CryptoRndIII's Dwords were from a uniformity point of view and to compare the results with a 100MB download of quantum random numbers from the QRNG Service provided by the Humboldt University in Berlin. From their website they write: "We provide a new quantum random number generator (QRNG) based on the quantum randomness of photon arrival times." We can get similar data from checking out the arrival times of London buses, but it may take a little longer to collect a decent amount of numbers.

          I am not a fan of John Walker's Ent.exe for testing randomness but it comes into its own for checking uniformity. Here are the results.
          Code:
          CryptoRndIII
          
          Chi square distribution for 104857600 samples is 238.00, and randomly
          would exceed this value 77.05 percent of the times.
          
          Arithmetic mean value of data bytes is 127.5054 (127.5 = random).
          Monte Carlo value for Pi is 3.141630827 (error 0.00 percent).              1.000012151
          Serial correlation coefficient is -0.000002 (totally uncorrelated = 0.0).
          
          Quantum random numbers
          
          Chi square distribution for 104857600 samples is 254.57, and randomly
          would exceed this value 49.59 percent of the times.
          
          Arithmetic mean value of data bytes is 127.5161 (127.5 = random).
          Monte Carlo value for Pi is 3.141776395 (error 0.01 percent).              1.000058487
          Serial correlation coefficient is -0.000012 (totally uncorrelated = 0.0).
          For Chi-squared if the figure is greater than 10% and less than 90% then we are OK and both generators did that. CryptoRndIII has a bit of an edge on the arithmetic mean. With the Monte Carlo figures I divided the estimate of Pi with the actual value of Pi to get the figure on the far right. Here too CryptoRndIII has a bit of an edge. The Serial correlation coefficient is the only metric of Ent.exe that has anything to do with randomness and the figure produced by CryptoRndIII is one of the best that I have ever seen and is a factor of six better than the QRNG figure.

          I have absolutely no doubt that repeated tests will see QRNG pipping CryptoRndIII but, at least, it shows that CryptoRndIII is in the same ball park as the one the quantum guys play in. As mentioned above if a very fast generator is needed then we should look elsewhere, CryptoRndII is about five times faster. If speed is not an issue and uncompromising quality is then CryptoRndIII will take some beating.

          Comment


          • #6
            When I first got involved with CryptoRnd my main concern was with stutter and I coined the phrases 'switch stutter' and 'exhaustion stutter', the first occurring when we switch from one buffer to another and the second occurring when one buffer has been exhausted, and we have to wait for the other buffer to fill. The switch stutter is independent of the buffer size but the exhaustion stutter is very much dependent upon the buffer size.

            I spent sometime trying to get the switching time to be as small as possible but, with the best will in the world, if the buffer size was small then much switching may occur and that would impact on the throughput. Too large a buffer size and the exhaustion stutter would impact on the throughput. It follows that a 'sweet spot' should exist with regard the buffer size. I ended up with 128KB when using BCryptGenRandom and 32KB when using RdRdand.

            I decided to revisit the stutters, the original CryptoRnd was written in PowerBASIC whereas this dll was written in FreeBASIC and I am using an optimizing compiler. Analysing the stutters from within the generators suffered from one aspect of Heissenberg's Uncertainty Principle namely: The act of observing an object may affect the object being observed. This time I have kept it really simple, compile with one buffer size and test the throughput, compile with another buffer size and test the throughput. This is what I get from the median of five tests per buffer size, the first column being the buffer size in KB and the second column being throughput in MHz.
            Code:
               8  48
              16  55
              32  59
              64  58
             128  61
             256  63
             512  65
            1024  69
            2048  69
            ...
            8192  69
            We can clearly see the damaging effects of using a small buffer size. However, we do not have a sweet spot, from 1024 and above the throughput levels off. Unless I am mistaken it appears that we do not have an exhaustion stutter now and the buffer being filled completes before we have a chance to exhaust the other buffer, even going 'flat out'. The difference between 69 and 65 is below what I regard as being significant, I've been using 7% for many years now. The difference between 65 and 59, 10%, is significant, so I will now use a buffer size of 512KB even though 10% is not exactly bringing the house down. At the beginning of the century two 512KB buffers would have been a lot when we were using 64MB/128MB of RAM, nowadays two 512KB buffers are neither here nor there.

            The next section is a very different story and surprised me. Well, more like .

            Suppose we have a buffer size greater than required to satisfy an application's need for random numbers then the switching stutter becomes academic. I am not even tempted to use only one buffer. If we underestimate the need then we will be in dead trouble, the other buffer will 'save our bacon' and it may not be possible to determine an accurate need anyway.

            The TestbedRdRand code looked at 10^8 requests. With a 32KB buffer we would see over 12,000 buffer switches, using CyptoSE. With 2KB of requests and a buffer size of 8KB, remembering that CryptoSE needs four bytes, we would not need to switch buffers. OK, so let's look at differing requests and buffer sizes. The first column is requests in KB, the second column is buffer size in KB and the third column is throughput in MHz.
            Code:
              2   8 288
              4  16 290
            ...
             32 128 292
            ...
            128 512 295
            You can see why I was shocked. I mentioned twice above that if a very fast generator was needed then CryptoRndIII would fall short. 290MHz plus is not exactly falling short and is very close on the heels of CryptoRndII and over 3½ times faster than Rnd.

            With CryptoD we need 8 bytes. 64KB of requests and a 512KB buffer gives us a 293MHz throughput. Remember, CryptoD has a 53-bit granularity.

            The declaration for InitializeCryptoBuffers is now
            Code:
            Declare Sub InitializeCryptoBuffers Lib "CryptoRndIII.dll" Alias "InitializeCryptoBuffers" ( Byval BufferLengthKB As Long )
            and the dll has been rewritten.

            So, if we put our thinking caps on and can determine an application's random number needs then it will be very much worth the effort. With a buffer size of 512KB we can request up to 131,072 CryptoSEs or 65,536 CryptoDs without switching buffers. Do you have an application that needs that many, I most certainly do not. I now have a new default random number generator for PowerBASIC, five star randomness and blindingly fast.

            The link in the opening post gives us the updates.
            Last edited by David Roberts; 6 May 2019, 06:24 AM. Reason: Got MB and KB mixed up!

            Comment


            • #7
              Following Stuart McLachian's lead in Random Numbers - Uniform,Gaussian(Normal),Poission Distributions I have added CryptoGauss declared as
              Code:
              Declare Function CryptoGauss Lib "CryptoRndIII.dll" Alias "CryptoGauss" () As Double
              It would be used as
              Code:
              Mean +(2*(Rnd<0.5)+1)* CryptoGauss * Standard_Deviation
              It uses two CryptoSEs and has a throughput of 36MHz on my machine, a little faster than CryptoD.

              The link in the opening post gives us the updates.

              Comment


              • #8
                I have changed
                Code:
                Mean + (2*(Rnd<0.5)+1)* CryptoGauss * Standard_Deviation
                to
                Code:
                Mean + CryptoGauss * Standard_Deviation
                and incorporated (2*(Rnd<0.5)+1) into CryptoGauss which can now be positive or negative, with a theoretical average of zero. The throughput is now 27MHz, which is still OK.

                The link in the opening post gives us the updates.

                Comment


                • #9
                  Originally posted by Muggins here
                  incorporated (2*(Rnd<0.5)+1)
                  I didn't need to do that. Two CryptoSXs will do the job instead of two CryptoSEs. Flaming heck! We are back to 36MHz.

                  The link in the opening post gives us the updates

                  Comment


                  • #10
                    I have been using a coarse method of calculating the throughput. Since I was getting good results I didn't bother to improve on it. Specifically I was not taking into account the For/Next overhead. With PB's Rnd it did not make much difference. What had not occurred to me was that the faster the generator the greater the effect of the For/Next overhead.

                    In post #6 I had '128 512 295'. Removing the For/Next overhead changed that 295 to over 340MHz which is over four times faster than Rnd on my machine. What bit of a salesman I have in me allows me to write greater than a third of a GHz.

                    Comment


                    • #11
                      Originally posted by Yours truly
                      I have tested RdRand using PractRand quite a few times and RdRand has not been intimidated.
                      I should have tested CryptoRndIII using PractRand just to make sure nothing untoward crept in so I piped CryptoDW into PractRand and got the following.

                      The anomaly at 4GB is nothing to be concerned about. The anomaly at 512GB is a little different but PractRand only regarded that as 'mildly suspicious' and got only one anomaly in 295 tests plus we are looking at 128GB of Dwords so I won't be losing any sleep over that; I doubt that Intel would either. George Marsaglia, of Diehard fame, wrote " p happens" and we were using Diehard on MB of data and not GB of data. I would be more concerned with a clean sweep of a 1TB test, we are talking random numbers here so getting that would make me question PractRand. The 1TB run itself did not see any anomalies. I don't go beyond 1TB as PractRand's author reckons that 1TB is good enough. Melissa O'Neill pushed her PCG32 to 16TB but she is very much younger than I am and my PC is not as young as it was either. PractRand is not exactly a stress test, but I was pushing a CPU temperature of 80°C for quite a while and I have a liquid cooler on board although the CPU usage stayed around 50% with a 4/4 core set up.

                      So, nothing untoward crept in and I reckon that CryptoRndIII is deserved of a certificate of merit.

                      This further convinces me to use CryptoRndIII as my default PB generator - I do not have an argument not to - how can I with a potential of 340MHz and using Intel's RdRand. Of course, if ever I wanted to repeat a sequence for some reason then CryptoRndIII will be blown out of the water as would CryptoRndII, for that I would use PCG32 which is twice as fast as Rnd and passes PractRand to 1TB at least with a period of 2^64.

                      Code:
                      E:\PR64>My_rng | rng_test stdin32 -multithreaded
                      RNG_test using PractRand version 0.94
                      RNG = RNG_stdin32, seed = unknown
                      test set = core, folding = standard (32 bit)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 256 megabytes (2^28 bytes), time= 2.3 seconds
                        no anomalies in 165 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 512 megabytes (2^29 bytes), time= 4.4 seconds
                        no anomalies in 178 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 1 gigabyte (2^30 bytes), time= 8.4 seconds
                        no anomalies in 192 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 2 gigabytes (2^31 bytes), time= 15.9 seconds
                        no anomalies in 204 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 4 gigabytes (2^32 bytes), time= 30.4 seconds
                        Test Name                         Raw       Processed     Evaluation
                        DC6-9x1Bytes-1                    R=  +5.9  p =  3.2e-3   unusual
                        ...and 215 test result(s) without anomalies
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 8 gigabytes (2^33 bytes), time= 60.1 seconds
                        no anomalies in 229 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 16 gigabytes (2^34 bytes), time= 119 seconds
                        no anomalies in 240 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 32 gigabytes (2^35 bytes), time= 236 seconds
                        no anomalies in 251 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 64 gigabytes (2^36 bytes), time= 480 seconds
                        no anomalies in 263 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 128 gigabytes (2^37 bytes), time= 959 seconds
                        no anomalies in 273 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 256 gigabytes (2^38 bytes), time= 1888 seconds
                        no anomalies in 284 test result(s)
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 512 gigabytes (2^39 bytes), time= 3827 seconds
                        Test Name                         Raw       Processed     Evaluation
                        [Low8/32]BCFN(2+2,13-0,T)         R=  -9.6  p =1-3.8e-5   mildly suspicious
                        ...and 294 test result(s) without anomalies
                      
                      rng=RNG_stdin32, seed=unknown
                      length= 1 terabyte (2^40 bytes), time= 7652 seconds
                        no anomalies in 304 test result(s)

                      Comment


                      • #12
                        I have been using PractRand for some time but I have misunderstood how it tests data. I thought that a 128GB test, for example, was a fresh 128GB test, it isn't it is a 64GB test plus another 64GB.

                        The anomaly, above, at 4GB tells us that it occurred in the last 2GB of the 4GB tested so far. That anomaly will not get mentioned again. The anomaly at 512GB occurred in the last 256GB of the 512GB tested so far. With no anomalies at 1TB then there were no anomalies in the last 512GB of the 1TB tested so far. A 16TB test would then take about 34 hours, blimey. I have also learned that PractRand will 'go' for 32TB pushing three days on my machine. That is not going to happen.

                        I realized my mistake when reading a blog at Melissa O'Neill's (PCG32) website where she writes "If 1 GB takes 122 seconds, then it'll take 46 days to finish the test!" I don't know what PC did that, my beast is going through 1GB in 8.5 seconds. PractRand's multithreaded switch makes a big difference but not that big. Using stdin32 is also faster than stdin if we know that the data is generated in 32-bit.

                        Anyway the conclusion above is not changed but it is nice to know how PractRand actually works.

                        Mersenne Twister fails PractRand 0.94 big time at 256GB. This tells us the the failure occurred in the last 128GB of the 256GB tested so far. So, we know that Mersenne Twister is a safe bet for 128GB. However, my realization is bad news for PB's Rnd which fails at 4KB. 2KB is a safe bet then but 2KB represents only 512 Rnd requests, oh dear! However, if anyone told me that they had written an application which has an initialization stage requiring 200 random numbers and asked for a recommendation then I would recommend PB's RND. I would press them to see if any more random numbers were needed after the initialization and if there was a chance the total would exceed 512 then I'd be looking at something other than Rnd. Having said that there is a guy at FreeBASIC who wanted a blindingly fast generator but wasn't bothered about the quality of randomness. It takes all kinds, doesn't it?

                        Comment


                        • #13
                          I have been looking at ways to pipe data into PractRand a bit quicker but haven't managed anything decent yet.

                          I got an interesting result with a CryptoRndIII test. I don't cherry pick results and published the above with a 'mildly suspicious' anomaly because that is what I got. I am glad that I did because the following would have made me suspicious.

                          It got to 1TB with a clean sweep. I had to let it contnue. A 2TB clean sweep! Well done, Intel.
                          Code:
                          E:\PR64>my_rng | rng_test stdin32 -multithreaded
                          RNG_test using PractRand version 0.94
                          RNG = RNG_stdin32, seed = unknown
                          test set = core, folding = standard (32 bit)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 256 megabytes (2^28 bytes), time= 2.3 seconds
                            no anomalies in 165 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 512 megabytes (2^29 bytes), time= 4.4 seconds
                            no anomalies in 178 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 1 gigabyte (2^30 bytes), time= 8.5 seconds
                            no anomalies in 192 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 2 gigabytes (2^31 bytes), time= 16.0 seconds
                            no anomalies in 204 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 4 gigabytes (2^32 bytes), time= 30.7 seconds
                            no anomalies in 216 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 8 gigabytes (2^33 bytes), time= 60.4 seconds
                            no anomalies in 229 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 16 gigabytes (2^34 bytes), time= 120 seconds
                            no anomalies in 240 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 32 gigabytes (2^35 bytes), time= 235 seconds
                            no anomalies in 251 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 64 gigabytes (2^36 bytes), time= 475 seconds
                            no anomalies in 263 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 128 gigabytes (2^37 bytes), time= 950 seconds
                            no anomalies in 273 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 256 gigabytes (2^38 bytes), time= 1872 seconds
                            no anomalies in 284 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 512 gigabytes (2^39 bytes), time= 3813 seconds
                            no anomalies in 295 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 1 terabyte (2^40 bytes), time= 9605 seconds
                            no anomalies in 304 test result(s)
                          
                          rng=RNG_stdin32, seed=unknown
                          length= 2 terabytes (2^41 bytes), time= 17134 seconds
                            no anomalies in 313 test result(s)

                          Comment


                          • #14
                            Originally posted by Yours truly
                            Of course, if ever I wanted to repeat a sequence for some reason then CryptoRndIII will be blown out of the water
                            Well it won't now but we need to be carefull. It is impotant that we do not use all of the first buffer and switch into the second buffer because that will see the first buffer being repopulated.

                            The link in the opening post gives the update.

                            Here is an example using the new procedure 'Sub ResetBufferPointer'.
                            Code:
                            #Break On
                            #Compile Exe
                            #Dim All
                            
                            Declare Sub InitializeCryptoBuffers Lib "CryptoRndIII.dll" Alias "InitializeCryptoBuffers" ( ByVal BufferLength As Long )
                            Declare Function CryptoSE           Lib "CryptoRndIII.dll" Alias "CryptoSE" As Double
                            Declare Sub ResetBufferPointer      Lib "CryptoRndIII.dll" Alias "ResetBufferPointer"
                            
                            Function PBMain () As Long
                            Local i As Long
                            
                              InitializeCryptoBuffers( 512 )
                            
                              For i = 1 to 10
                                Print CryptoSE
                              Next
                            
                              ResetBufferPointer
                            
                              Print
                              For i = 1 to 10
                                Print CryptoSE
                              Next
                              Print
                              Print "Done. Press any key"
                              WaitKey$
                            
                            End Function
                            With one run I got:
                            Code:
                             .633539060596377
                             .248873044503853
                             .574536309344694
                             .597187436651438
                             .407834521960467
                             .805035758763552
                             .567368197022006
                             .744858496589586
                             .435006021056324
                             9.50746040325612E-2
                            
                             .633539060596377
                             .248873044503853
                             .574536309344694
                             .597187436651438
                             .407834521960467
                             .805035758763552
                             .567368197022006
                             .744858496589586
                             .435006021056324
                             9.50746040325612E-2
                            
                            Done. Press any key

                            Comment


                            • #15
                              I have extended the last idea. Suppose we have some initialization code which requires random numbers and then we wanted to test a couple of algorithms using a repeat sequecnce. We could use ResetBufferPointer but we would have to 'burn' the initialization random numbers twice to get to where we wanted to be.

                              So, we now have 'Sub SaveBufferPointer' and 'Sub LoadBufferPointer'. Following is an example usage.

                              The link in the opening post gives the update.

                              We could emulate ResetBufferPointer by employing SaveBufferPointer before requesting any random numbers and then employ LoadBufferPointer later. However, I'll keep ResetBufferPointer because that resets with a single statement.

                              I don't want to add any more procedures because the dll is growing rapidly and is now tipping the scales at 23KB.

                              Don't forget to stay in the first buffer.
                              Code:
                              #Break On
                              #Compile Exe
                              #Dim All
                              #Include "Win32API.inc"
                              
                              Declare Sub InitializeCryptoBuffers Lib "CryptoRndIII.dll" Alias "InitializeCryptoBuffers" ( ByVal BufferLength As Long )
                              Declare Function CryptoSE           Lib "CryptoRndIII.dll" Alias "CryptoSE" As Double
                              Declare Sub SaveBufferPointer       Lib "CryptoRndIII.dll" Alias "SaveBufferPointer"
                              Declare Sub LoadBufferPointer       Lib "CryptoRndIII.dll" Alias "LoadBufferPointer"
                              
                              Function PBMain () As Long
                              Local i As Long
                              
                                InitializeCryptoBuffers( 512 )
                              
                                ' Some initialization requiring random numbers
                                For i = 1 To 10
                                  Print CryptoSE
                                Next
                                Print
                              
                                SaveBufferPointer
                              
                                For i = 1 To 10
                                  Print CryptoSE
                                  Next
                                Print
                              
                                LoadBufferPointer
                              
                                For i = 1 To 10
                                  Print CryptoSE
                                  Next
                                Print
                              
                                Print "Done. Press any key"
                                WaitKey$
                              
                              End Function
                              With one run I got:
                              Code:
                               .522466724971309
                               .269777617184445
                               .850423522060737
                               .159930996363982
                               .317334652878344
                               .604398811701685
                               .632216077297926
                               .484515014803037
                               .924333828501403
                               .279172903392464
                              
                               7.27855120785534E-2
                               .406296433648094
                               .818025150103494
                               .146509031066671
                               .484599393326789
                               .262167703127488
                               .316615773364902
                               .846799528226256
                               .39067878620699
                               .746752011356875
                              
                               7.27855120785534E-2
                               .406296433648094
                               .818025150103494
                               .146509031066671
                               .484599393326789
                               .262167703127488
                               .316615773364902
                               .846799528226256
                               .39067878620699
                               .746752011356875
                              
                              Done. Press any key

                              Comment


                              • #16
                                I wanted to use CryptoFR, the floating point range, but had not included it. I had in PCG32.

                                Declare Function CryptoFR Lib "CryptoRndIII.dll" Alias "CryptoFR" (Byval One as Double, Byval Two as Double) As Double

                                Example
                                Code:
                                #Break on
                                #Compile exe
                                #Dim All
                                
                                Declare Sub InitializeCryptoBuffers Lib "CryptoRndIII.dll" Alias "InitializeCryptoBuffers" ( Byval BufferLength As Long )
                                Declare Function CryptoFR           Lib "CryptoRndIII.dll" Alias "CryptoFR" (Byval One As Double, Byval Two As double) As Double
                                
                                Function PBMAIN () As Long
                                Local i As Long, tot As Double
                                
                                InitializeCryptoBuffers( 512 )
                                
                                For i = 1 To 10
                                  Print CryptoFR(1,99)
                                Next
                                Print
                                For i = 1 To 10^8
                                  tot += CryptoFR(1,99)
                                Next
                                Print "10^8 Average";tot/10^8
                                Print
                                Print "Done. Press any key"
                                WAITKEY$
                                
                                End Function
                                and one run gave
                                Code:
                                 32.4383825776167
                                 90.4767565419897
                                 49.0880349008366
                                 94.0584278963506
                                 68.3097142302431
                                 15.7115958635695
                                 45.0137151414528
                                 15.4238693006337
                                 33.8398012574762
                                 38.2880917275324
                                
                                10^8 Average 49.9986088976006
                                
                                Done. Press any key

                                Comment


                                • #17
                                  Just for the record here is a full list of procedures:
                                  Code:
                                  InitializeCryptoBuffers( BufferLength )
                                  CryptoDW - Output Dword
                                  CryptoS  - Output Single [0,1) 24-bit granularity
                                  CryptoSE - Output Double [0,1) 32-bit granularity
                                  CryptoSX - Output Double [-1,1) 32-bit granularity
                                  CryptoD  - Output Double [0,1) 53-bit granularity
                                  CryptoDX - Output Double [-1,1) 53-bit granularity
                                  CryptoR(a,b)  - Output Long discrete range a to b
                                  CryptoFR(a,b) - Output Double floating-point range [a,b)
                                  CryptoGauss - Normal distribution
                                  ResetBufferPointer - Buffer pointer to beginning of 1st buffer
                                  SaveBufferPointer - Saves current buffer pointer of 1st buffer
                                  LoadBufferPointer - Loads saved buffer pointer
                                  dll is now getting out of hand at 23.5KB

                                  Comment

                                  Working...
                                  X