Files
lazarus-ccr/components/everettrandom/latest_stable/ueverettrandom.pas

412 lines
14 KiB
ObjectPascal
Raw Normal View History

unit ueverettrandom;
{ Random integer generation via beam-splitter quantum event generator
Code copyright (C)2019 minesadorada@charcodelvalle.com
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version with the following modification:
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,and
to copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms
and conditions of the license of that module. An independent module is a
module which is not derived from or based on this library. If you modify
this library, you may extend this exception to your version of the library,
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.
================================================================================
Description and purpose
=======================
The Everett interpretation of quantum mechanics ("Many Worlds") is that when
an interaction is made with an elementary wave function (such as an electron or
photon etc) the universe bifurcates.
ref: https://en.wikipedia.org/wiki/Many-worlds_interpretation
This happens naturally of course (just via radioactive decays in atoms of your
body there are about 5000 bifucations per second) but this component brings into
the mix "Free Will". By requesting a random number from the online source, which
is a beam-splitter based in Austrailia you are bifurcating the Universe deliberately
- that is, based on your Free Will.
You may or may not find that interesting, but nevertheless this component gives
you this ability (to "play God" with the Universe)
The random numbers returned are truly random (i.e. not pseudorandom via algorithm)
Details of the online resource below:
================================================================================
webpage: https://qrng.anu.edu.au/
To get a set of numbers generated online by a quantum number generator:
Post to: https://qrng.anu.edu.au/API/jsonI.php?length=[array length]&type=[data type]&size=[block size]
If the request is successful, the random numbers are returned in a JSON encoded array named 'data'
(Note: block size parameter is only needed for data type=hex16)
The random numbers are generated in real-time in our lab by measuring the quantum fluctuations of the vacuum
Example to get 10 numbers of range 0-255 is
https://qrng.anu.edu.au/API/jsonI.php?length=10&type=uint8
JSON returned:
{"type":"uint8","length":10,"data":[241,83,235,48,81,154,222,4,77,120],"success":true}
Example to get 10 numbers of range 065535 is
https://qrng.anu.edu.au/API/jsonI.php?length=10&type=uint16
JSON returned:
{"type":"uint16","length":10,"data":[50546,25450,24289,44825,10457,49509,48848,30970,33829,47807],"success":true}
Example to get 10 hexadecimal numbers of range 00–FF is
https://qrng.anu.edu.au/API/jsonI.php?length=10&type=hex16
JSON returned:
{"type":"string","length":10,"size":1,"data":["5d","f9","aa","bf","5e","02","3c","55","6e","9e"],"success":true}
Example to get 10 hexadecimal numbers of range 0000–FFFF (blocksize=2) is
https://qrng.anu.edu.au/API/jsonI.php?length=10&type=hex16&size=2
JSON returned:
{"type":"string","length":10,"size":2,"data":["2138","592e","0643","8cdf","b955","e42f","eda6","c62a","2c66","f009"],"success":true}
Example to get 10 hexadecimal numbers of range 000000–FFFFFF (blocksize=3) is
https://qrng.anu.edu.au/API/jsonI.php?length=10&type=hex16&size=3
JSON returned:
{"type":"string","length":10,"size":3,"data":["add825","ac3530","79b708","ee8d42","683647","b6bb25","a92571","a8ae6a","963131","f62ec2"],"success":true}
Javascript:
var json = eval('('+ ajaxobject.responseText +')'); /* JSON is here*/
document.getElementById('json_success').innerHTML = json.success;
document.getElementById('dataHere').innerHTML = ajaxobject.responseText;
================================================================================
Version History:
V0.1.2.0 - initial commit
V0.1.3.0 - cleanup
}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Dialogs, Controls, Forms, StdCtrls, Variants,
everett_httpclient, open_ssl, fpjson, fpjsonrtti;
const
C_QUANTUMSERVERLIMIT = 1024;
C_URL = 'https://qrng.anu.edu.au/API/jsonI.php?length=%d&type=%s&size=%d';
resourcestring
rsSSLLibraries = 'SSL libraries unavailable and/or unable to be downloaded '
+ 'on this system. Please fix.';
rsFailedTooMan = 'Failed - Too many requests to the Quantum server%s%s';
rsFailedQuantu = 'Failed - Quantum server refused with code %d';
rsQuantumServe = 'Quantum server did not deliver a valid array';
rsFailedQuantu2 = 'Failed - Quantum server refused with code %s';
rsPleaseWaitCo = 'Please wait. Contacting Quantum Server';
type
TQuantumNumberType = (uint8, uint16, hex16);
TQuantumNumberDataObject = class; // Forward declaration
// This is a persistent class with an owner
{ TEverett }
TEverett = class(TComponent)
private
fHttpClient: TFPHTTPClient;
fQuantumNumberType: TQuantumNumberType;
fQuantumNumberDataObject: TQuantumNumberDataObject;
fShowWaitDialog: boolean;
fWaitDialogCaption: string;
fArraySize,fHexSize:Integer;
procedure SetArraySize(AValue:Integer);
protected
// Main worker function
function FetchQuantumRandomNumbers(AQuantumNumberType: TQuantumNumberType;
Alength: integer; ABlocksize: integer = 1): boolean; virtual;
// Object that contains array results
property QuantumNumberDataObject: TQuantumNumberDataObject
read fQuantumNumberDataObject;
public
// (Dynamic) Array results
IntegerArray: array of integer;
HexArray: array of string;
// TEverett should have an owner so that cleanup is easy
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
// Fetch a single random number
function GetSingle8Bit: integer;
function GetSingle16Bit: integer;
function GetSingleHex: String;
// Array functions will put results into:
// (uint8, uint16) IntegerArray[0..Pred(ArraySize)]
// (hex16) HexArray[0..Pred(ArraySize)]
function GetInteger8BitArray:Boolean;
function GetInteger16BitArray:Boolean;
function GetHexArray:Boolean;
published
property NumberType: TQuantumNumberType read fQuantumNumberType
write fQuantumNumberType default uint8;
property ShowWaitDialog: boolean
read fShowWaitDialog write fShowWaitDialog default True;
property WaitDialogCaption: string read fWaitDialogCaption write fWaitDialogCaption;
property ArraySize:Integer read fArraySize write SetArraySize default 1;
property HexSize:Integer read fHexSize write fHexSize default 1;
end;
// DeStreamer.JSONToObject populates all the properties
// Do not change any of the properties
TQuantumNumberDataObject = class(TObject)
private
fNumberType: string;
fNumberLength: integer;
fNumbersize: integer;
fNumberData: variant;
fNumberSuccess: string;
public
published
// Prefix property name with & to avoid using a reserved pascal word
// Note: This bugs out the JEDI code formatter
property &type: string read fNumberType write fNumberType;
property length: integer read fNumberLength write fNumberLength;
property size: integer read fNumbersize write fNumbersize;
// Note: property "data" must be lowercase. JEDI changes it to "Data"
property data: variant read fNumberData write fNumberData;
property success: string read fNumberSuccess write fNumberSuccess;
end;
implementation
procedure TEverett.SetArraySize(AValue: Integer);
// Property setter
begin
if Avalue <=C_QUANTUMSERVERLIMIT then
fArraySize:=AValue
else
fArraySize:=1;
end;
// This is the core function.
// If successful, it populates either IntegerArray or HexArray
// Parameters:
// AQuantumNumberType can be uint8, uint16 or hex16
// ALength is the size of the returned array
// ABlocksize is only relavent if AQuantumNumberType=hex16
// it is the size of the hex number in HexArray (1=FF, 2=FFFF, 3=FFFFFF etc)
function TEverett.FetchQuantumRandomNumbers(AQuantumNumberType: TQuantumNumberType;
Alength: integer; ABlocksize: integer): boolean;
var
szURL: string;
JSON: TJSONStringType;
DeStreamer: TJSONDeStreamer;
ct: integer;
frmWaitDlg: TForm;
lbl_WaitDialog: TLabel;
begin
Result := False; // assume failure
// Reset arrays
SetLength(IntegerArray, 0);
SetLength(HexArray, 0);
// Parameter checks
if Alength > C_QUANTUMSERVERLIMIT then
Exit;
if ABlocksize > C_QUANTUMSERVERLIMIT then
Exit;
// Is SSL installed? If not, download it.
// If this fails then just early return FALSE;
if not CheckForOpenSSL then
begin
ShowMessage(rsSSLLibraries);
exit;
end;
// Make up the Quantum Server URL query
case AQuantumNumberType of
uint8:
szURL := Format(C_URL, [Alength, 'uint8', ABlocksize]);
uint16:
szURL := Format(C_URL, [Alength, 'uint16', ABlocksize]);
hex16:
szURL := Format(C_URL, [Alength, 'hex16', ABlocksize]);
else
exit;
end;
try
// Create the Wait Dialog
frmWaitDlg := TForm.CreateNew(nil);
with frmWaitDlg do
begin
// Set Dialog properties
Height := 100;
Width := 200;
position := poOwnerFormCenter;
borderstyle := bsNone;
Caption := '';
formstyle := fsSystemStayOnTop;
lbl_WaitDialog := TLabel.Create(frmWaitDlg);
with lbl_WaitDialog do
begin
align := alClient;
alignment := tacenter;
Caption := fWaitDialogCaption;
ParentFont := True;
Cursor := crHourGlass;
parent := frmWaitDlg;
end;
Autosize := True;
// Show it or not
if fShowWaitDialog then
Show;
Application.ProcessMessages;
end;
with fhttpclient do
begin
// Set up the JSON destramer
DeStreamer := TJSONDeStreamer.Create(nil);
DeStreamer.Options := [jdoIgnorePropertyErrors];
// Set up the http client
ResponseHeaders.NameValueSeparator := ':';
AddHeader('Accept', 'application/json;charset=UTF-8');
//DEBUG:ShowMessage(szURL);
// Go get the data!
JSON := Get(szURL);
// DEBUG: ShowMessageFmt('Response code = %d',[ResponseStatusCode]);
// Any response other than 200 is bad news
if (ResponseStatusCode <> 200) then
case ResponseStatusCode of
429:
begin
ShowMessageFmt(rsFailedTooMan,
[LineEnding, JSON]);
Exit(False);
end;
else
begin
ShowMessageFmt(rsFailedQuantu,
[ResponseStatusCode]);
Exit(False);
end;
end;
try
// Stream it to the object list
DeStreamer.JSONToObject(JSON, fQuantumNumberDataObject);
// Populate IntegerArray/Hexarray
if VarIsArray(QuantumNumberDataObject.Data) then
begin
case AQuantumNumberType of
uint8, uint16:
begin
SetLength(IntegerArray,
fQuantumNumberDataObject.fNumberLength);
for ct := 0 to Pred(fQuantumNumberDataObject.fNumberLength) do
IntegerArray[ct] :=
StrToInt(fQuantumNumberDataObject.Data[ct]);
end;
hex16:
begin
SetLength(HexArray,
fQuantumNumberDataObject.fNumberLength);
for ct := 0 to Pred(fQuantumNumberDataObject.fNumberLength) do
HexArray[ct] :=
fQuantumNumberDataObject.Data[ct];
end;
end;
end
else
begin
ShowMessage(rsQuantumServe);
Exit;
end;
except
On E: Exception do
showmessagefmt(rsFailedQuantu2, [E.Message]);
On E: Exception do
Result := False;
end;
end;
finally
// No matter what - free memory
DeStreamer.Free;
frmWaitDlg.Free;
end;
Result := True; //SUCCESS!
// DEBUG ShowMessage(fQuantumNumberDataObject.fNumberSuccess);
end;
constructor TEverett.Create(AOwner: TComponent);
begin
inherited;
fQuantumNumberType := uint8; // default is 8-bit (byte)
fShowWaitDialog := True; // Show dialog whilst fetching data online
fWaitDialogCaption := rsPleaseWaitCo;
fHttpClient := TFPHTTPClient.Create(Self);
fQuantumNumberDataObject := TQuantumNumberDataObject.Create;
fArraySize:=1; // default
fHexSize:=1; // default
SetLength(IntegerArray, 0);
SetLength(HexArray, 0);
end;
destructor TEverett.Destroy;
begin
FreeAndNil(fQuantumNumberDataObject);
FreeAndNil(fHttpClient);
inherited;
end;
function TEverett.GetSingle8Bit: integer;
begin
Result := 0;
if FetchQuantumRandomNumbers(uint8, 1, 1) then
Result := IntegerArray[0];
end;
function TEverett.GetSingle16Bit: integer;
begin
Result := 0;
if FetchQuantumRandomNumbers(uint16, 1, 1) then
Result := IntegerArray[0];
end;
function TEverett.GetSingleHex: String;
begin
Result:='00';
if FetchQuantumRandomNumbers(hex16, 1, 1) then
Result := HexArray[0];
end;
function TEverett.GetInteger8BitArray: Boolean;
// Populates IntegerArray
begin
Result:=FetchQuantumRandomNumbers(uint8, fArraySize, 1);
end;
function TEverett.GetInteger16BitArray: Boolean;
// Populates IntegerArray
begin
Result:=FetchQuantumRandomNumbers(uint16, fArraySize, 1);
end;
function TEverett.GetHexArray: Boolean;
// Populates HexArray
begin
Result:=FetchQuantumRandomNumbers(hex16, fArraySize, fHexSize);
end;
end.