Difference between revisions of "Dev random"

From Free Pascal wiki
Jump to navigationJump to search
 
m (→‎seed: update Run‑Time Library source code link [Subversion → Git Laboratory])
 
(26 intermediate revisions by 11 users not shown)
Line 1: Line 1:
= Summery =
+
{{Dev random}}
/dev/random and /dev/urandom are two Unix and *nix based devices that allow receives memory, disc, network dumps from the kernel. This allow us to use “random�? like seed for preforming “random' tasks. with the “random�? function.
+
<code>/dev/random</code> and <code>/dev/urandom</code> are two pseudo character devices providing user-land access to random data generated by the system.
 +
Following the paradigm “everything is a file” they usually exist on Unix and *nix-based operating systems, like [[Linux]] or [[FreeBSD]].
  
The difference between /dev/random and /dev/urandom is the “blocking�? and “non blocking�? issues.  
+
The <code>u</code> in <code>urandom</code> stands for “unlimited”.
 +
Theoretically there is no limit on how much data one may obtain <code>/dev/urandom</code>.
  
While /dev/random will give us random seeds, it will wait until it will have something to give us, before return with the seed.  
+
== quality ==
 +
On Linux the kernel will occasonially gather “environmental noise” like memory, disc, network throughput, or dumps from the kernel, as well as cryptography hardware if present and enabled.
  
/dev/urandom does not stop us from when we do not have new seed from dump, and will return also clock cycles, that are less random, but that way we will not need to wait until any type of activity will occure.
+
The key difference between <code>/dev/random</code> versus <code>/dev/urandom</code> is whether a threshold of enough entropy has to be reached before random numbers are generated.
 +
* {{Doc|package=RTL|unit=baseunix|identifier=fpread|text=Reading}} from <code>/dev/random</code> will be put on hold if the kernel has not gathered enough entropy to provide the requested amount of data.
 +
* <code>/dev/urandom</code> on the other hand will not block to wait for more entropy. It will fall back to a pseudo-random number generator (PRNG) if and as long as there is a too small entropy pool.
  
= Coding =
+
== application ==
 +
=== seed ===
 +
Prior any call of {{Doc|package=RTL|unit=system|identifier=random|text=<syntaxhighlight lang="pascal" inline>system.random</syntaxhighlight>}} the programmer has to invoke {{Doc|package=RTL|unit=system|identifier=randomize|text=<syntaxhighlight lang="pascal" inline>system.randomize</syntaxhighlight>}} once, so {{Doc|package=RTL|unit=system|identifier=randseed|text=<syntaxhighlight lang="pascal" inline>system.randSeed</syntaxhighlight>}} provides a “random” value for the PRNG.
 +
The {{gitlab|repository|FPC|release_3_2_0/rtl/linux/system.pp#L231-234|default implementation}} uses the system clock for this, since this a value sort of available on all supported platforms.
 +
However, its predictability is kind of unpleasant, although the argument <syntaxhighlight lang="pascal" inline>system.randomize</syntaxhighlight>’s behavior should not differ significantly regarding quality and speed among platforms is reasonable.
 +
If we want to, we can shadow <syntaxhighlight lang="pascal" inline>system.randomize</syntaxhighlight> by our own “better” implementation, while still relying on the fast Mersenne-Twister PRNG the standard [[RTL|run-time library]] comes with.
 +
<syntaxhighlight lang="pascal" line start="3">
 +
{$ifdef UNIX}
 +
(**
 +
initializes PRNG with data read from /dev/random
 +
 +
Randomize initializes the pseudo-random number generator
 +
by storing a value read from /dev/random to system.randSeed.
 +
If reading fails, system.randomize will be used instead.
 +
*)
 +
procedure randomize;
 +
const
 +
/// file name for random(4) device
 +
randomDeviceName = '/dev/random';
 +
var
 +
/// reading buffer
 +
// same type as system.randSeed
 +
randomNumber: cardinal;
 +
/// file handle
 +
randomReader: file of cardinal;
 +
begin
 +
assign(randomReader, randomDeviceName);
 +
{$push}
 +
// turn off run-time error generation
 +
{$IOChecks off}
 +
reset(randomReader);
 +
 +
if IOResult() = 0 then
 +
begin
 +
// will possibly cause the error
 +
//  EInOutError: Read past end of file
 +
// if /dev/random is depleted
 +
read(randomReader, randomNumber);
 +
 +
if IOResult() = 0 then
 +
begin
 +
system.randSeed := randomNumber;
 +
end
 +
else
 +
begin
 +
// do not call oneself => fully qualified identifier
 +
system.randomize;
 +
end;
 +
 +
close(randomReader);
 +
end
 +
{$pop}
 +
else
 +
begin
 +
// do not call oneself => fully qualified identifier
 +
system.randomize;
 +
end;
 +
end;
 +
{$else}
 +
{$hint program does not use randomize based on /dev/random}
 +
{$endif}
 +
</syntaxhighlight>
 +
 
 +
When using [[gmp]], the same applies.
 +
<syntaxhighlight lang="delphi" line highlight="15-17,19-25,29-45,54-56">
 +
program gmpRandomDemo(input, output, stderr);
 +
 
 +
// objFPC mode for try..finally-construct
 +
{$mode objFPC}
 +
{$typedAddress on}
 +
 
 +
uses
 +
// familiarize with C types
 +
cTypes,
 +
// familiarize with exception classes
 +
sysUtils,
 +
// use GNU multiple precision arithmetic library
 +
gmp;
 +
 
 +
const
 +
/// file name for random(4) device
 +
randomFileName = '/dev/random';
 +
 
 +
var
 +
/// reading buffer
 +
randomNumber: CULong;
 +
/// file handle for random number source
 +
randomReader: file of CULong;
 +
/// keeps GMP random number generator state
 +
prngState: randState_T;
 +
/// some arbitrary number
 +
i: MPZ_T;
 +
begin
 +
MP_randInit_MT(prngState);
 +
assign(randomReader, randomFileName);
 +
try
 +
reset(randomReader);
 +
try
 +
try
 +
read(randomReader, randomNumber);
 +
except on eInOutError do
 +
begin
 +
randomize;
 +
randomNumber := random(high(int64));
 +
end;
 +
end;
 +
finally
 +
close(randomReader);
 +
end;
 +
MP_randSeed_UI(prngState, randomNumber);
 +
 +
MPZ_init(i);
 +
try
 +
MPZ_uRandomB(i, prngState, 256);
 +
MP_printF('%Zd' + lineEnding, @i);
 +
finally
 +
MPZ_clear(i);
 +
end;
 +
finally
 +
MP_randClear(prngState);
 +
end;
 +
end.
 +
</syntaxhighlight>
 +
 
 +
=== multiple values ===
 +
Multiple random values can be read by utilizing {{Doc|package=RTL|unit=system|identifier=blockread|text=<syntaxhighlight lang="pascal" inline>system.blockRead</syntaxhighlight>}}:
 +
<syntaxhighlight lang="delphi" line highlight="31">
 +
program multipleRandomValuesDemo(input, output, stdErr);
 +
 
 +
// include objpas unit
 +
{$mode objFPC}
 +
 
 +
uses
 +
// familiarize with exception classes
 +
sysUtils;
 +
 
 +
const
 +
/// file name for urandom(4) device
 +
randomDeviceName = '/dev/urandom';
 +
 
 +
type
 +
/// base type for numbers in this program
 +
number = dWord;
 +
 
 +
var
 +
/// file handle for random number source
 +
randomFile: file of number;
 +
/// an array of numbers
 +
population: packed array[0..5] of number;
 +
/// temporary iterator variable
 +
i: number;
 +
 
 +
begin
 +
assignFile(randomFile, randomDeviceName);
 +
try
 +
reset(randomFile);
 +
try
 +
blockRead(randomFile, population, length(population));
 +
except on eInOutError do
 +
exitCode := 1;
 +
end;
 +
finally
 +
closeFile(randomFile);
 +
end;
 +
 +
for i in population do
 +
begin
 +
writeLn(i:10);
 +
end;
 +
end.
 +
</syntaxhighlight>
 +
 
 +
== see also ==
 +
* [https://en.wikipedia.org/wiki//dev/random <code>/dev/random</code> on Wikipedia, the free online encyclopedia]
 +
* [[Generating Random Numbers|generating random numbers]], alternative algorithms
 +
* [https://gmplib.org/manual/Random-State-Seeding.html#Random-State-Seeding “random state seeding” in GMP’s documentation]
 +
 
 +
[[Category:Code]]

Latest revision as of 13:49, 28 September 2022

Deutsch (de) English (en) français (fr)
/dev/random and /dev/urandom are two pseudo character devices providing user-land access to random data generated by the system. Following the paradigm “everything is a file” they usually exist on Unix and *nix-based operating systems, like Linux or FreeBSD.

The u in urandom stands for “unlimited”. Theoretically there is no limit on how much data one may obtain /dev/urandom.

quality

On Linux the kernel will occasonially gather “environmental noise” like memory, disc, network throughput, or dumps from the kernel, as well as cryptography hardware if present and enabled.

The key difference between /dev/random versus /dev/urandom is whether a threshold of enough entropy has to be reached before random numbers are generated.

  • Reading from /dev/random will be put on hold if the kernel has not gathered enough entropy to provide the requested amount of data.
  • /dev/urandom on the other hand will not block to wait for more entropy. It will fall back to a pseudo-random number generator (PRNG) if and as long as there is a too small entropy pool.

application

seed

Prior any call of system.random the programmer has to invoke system.randomize once, so system.randSeed provides a “random” value for the PRNG. The default implementation uses the system clock for this, since this a value sort of available on all supported platforms. However, its predictability is kind of unpleasant, although the argument system.randomize’s behavior should not differ significantly regarding quality and speed among platforms is reasonable. If we want to, we can shadow system.randomize by our own “better” implementation, while still relying on the fast Mersenne-Twister PRNG the standard run-time library comes with.

 3{$ifdef UNIX}
 4(**
 5	initializes PRNG with data read from /dev/random
 6	
 7	Randomize initializes the pseudo-random number generator
 8	by storing a value read from /dev/random to system.randSeed.
 9	If reading fails, system.randomize will be used instead.
10*)
11procedure randomize;
12const
13	/// file name for random(4) device
14	randomDeviceName = '/dev/random';
15var
16	/// reading buffer
17	// same type as system.randSeed
18	randomNumber: cardinal;
19	/// file handle
20	randomReader: file of cardinal;
21begin
22	assign(randomReader, randomDeviceName);
23	{$push}
24	// turn off run-time error generation
25	{$IOChecks off}
26	reset(randomReader);
27	
28	if IOResult() = 0 then
29	begin
30		// will possibly cause the error
31		//   EInOutError: Read past end of file
32		// if /dev/random is depleted
33		read(randomReader, randomNumber);
34		
35		if IOResult() = 0 then
36		begin
37			system.randSeed := randomNumber;
38		end
39		else
40		begin
41			// do not call oneself => fully qualified identifier
42			system.randomize;
43		end;
44		
45		close(randomReader);
46	end
47	{$pop}
48	else
49	begin
50		// do not call oneself => fully qualified identifier
51		system.randomize;
52	end;
53end;
54{$else}
55{$hint program does not use randomize based on /dev/random}
56{$endif}

When using gmp, the same applies.

 1program gmpRandomDemo(input, output, stderr);
 2
 3// objFPC mode for try..finally-construct
 4{$mode objFPC}
 5{$typedAddress on}
 6
 7uses
 8	// familiarize with C types
 9	cTypes,
10	// familiarize with exception classes
11	sysUtils,
12	// use GNU multiple precision arithmetic library
13	gmp;
14
15const
16	/// file name for random(4) device
17	randomFileName = '/dev/random';
18
19var
20	/// reading buffer
21	randomNumber: CULong;
22	/// file handle for random number source
23	randomReader: file of CULong;
24	/// keeps GMP random number generator state
25	prngState: randState_T;
26	/// some arbitrary number
27	i: MPZ_T;
28begin
29	MP_randInit_MT(prngState);
30	assign(randomReader, randomFileName);
31	try
32		reset(randomReader);
33		try
34			try
35				read(randomReader, randomNumber);
36			except on eInOutError do
37			begin
38				randomize;
39				randomNumber := random(high(int64));
40			end;
41			end;
42		finally
43			close(randomReader);
44		end;
45		MP_randSeed_UI(prngState, randomNumber);
46		
47		MPZ_init(i);
48		try
49			MPZ_uRandomB(i, prngState, 256);
50			MP_printF('%Zd' + lineEnding, @i);
51		finally
52			MPZ_clear(i);
53		end;
54	finally	
55		MP_randClear(prngState);
56	end;
57end.

multiple values

Multiple random values can be read by utilizing system.blockRead:

 1program multipleRandomValuesDemo(input, output, stdErr);
 2
 3// include objpas unit
 4{$mode objFPC}
 5
 6uses
 7	// familiarize with exception classes
 8	sysUtils;
 9
10const
11	/// file name for urandom(4) device
12	randomDeviceName = '/dev/urandom';
13
14type
15	/// base type for numbers in this program
16	number = dWord;
17
18var
19	/// file handle for random number source
20	randomFile: file of number;
21	/// an array of numbers
22	population: packed array[0..5] of number;
23	/// temporary iterator variable
24	i: number;
25
26begin
27	assignFile(randomFile, randomDeviceName);
28	try
29		reset(randomFile);
30		try
31			blockRead(randomFile, population, length(population));
32		except on eInOutError do
33			exitCode := 1;
34		end;
35	finally
36		closeFile(randomFile);
37	end;
38	
39	for i in population do
40	begin
41		writeLn(i:10);
42	end;
43end.

see also