-
-
Save schas002/757c0b948b469cd591c24f27eb16edf0 to your computer and use it in GitHub Desktop.
/** | |
*** blum_blum_shub.js *** | |
An implementation of the Blum Blum Shub pseudorandom number generator proposed | |
in 1986 by Lenore Blum, Manuel Blum and Michael Shub that is derived from | |
Michael O. Rabin's oblivious transfer mapping. | |
Blum Blum Shub takes the form | |
2 | |
x = x mod M | |
n+1 n | |
where M = pq is the product of two large primes p and q. At each step of the | |
algorithm, some output is derived from x[n+1]; the output is commonly either | |
the bit parity of x[n+1] or one or more of the least significant bits of | |
x[n+1]. | |
The seed x[0] should be an integer that is co-prime to M (i.e. p and q are not | |
factors of x[0]) and not 1 or 0. | |
The two primes, p and q, should both be congruent to 3 (mod 4) (this guarantees | |
that each quadratic residue has one square root which is also a quadratic | |
residue) and gcd(phi(p - 1), phi(q - 1)) should be small (this makes the cycle | |
length large). | |
In this implementation, p = 5651 and q = 5623. | |
This software is licensed under the zlib/libpng license: | |
Copyright (c) 2016 Andrew Zyabin | |
This software is provided 'as-is', without any express or implied warranty. In | |
no event will the authors be held liable for any damages arising from the use | |
of this software. | |
Permission is granted to anyone to use this software for any purpose, including | |
commercial applications, and to alter it and redistribute it freely, subject to | |
the following restrictions: | |
1. The origin of this software must not be misrepresented; you must not | |
claim that you wrote the original software. If you use this software in a | |
product, an acknowledgment in the product documentation would be | |
appreciated but is not required. | |
2. Altered source versions must be plainly marked as such, and must not be | |
misrepresented as being the original software. | |
3. This notice may not be removed or altered from any source distribution. | |
*/ | |
var p = 5651; | |
var q = 5623; | |
var M = p * q; | |
var x = undefined; | |
/** Get the gcd of two numbers, A and B. */ | |
function gcd(a, b) { | |
while(a != b) { | |
if(a > b) { | |
a = a - b; | |
} else { | |
b = b - a; | |
} | |
} | |
return a; | |
} | |
/** Seed the random number generator. */ | |
function seed(s) { | |
if(s == 0) { | |
throw new Error("The seed x[0] cannot be 0"); | |
} else if(s == 1) { | |
throw new Error("The seed x[0] cannot be 1"); | |
} else if(gcd(s, M) != 1) { | |
throw new Error("The seed x[0] must be co-prime to " + M.toString()); | |
} else { | |
x = s; | |
return s; | |
} | |
} | |
/** Get next item from the random number generator. */ | |
function next() { | |
var cachedx = x; | |
cachedx = cachedx * x; | |
cachedx = cachedx % M; | |
x = cachedx; | |
return x; | |
} |
@francoislaberge
<script>
/** Get next item from the random number generator. */
function next() {
var cachedx = x;
cachedx = cachedx * x;
cachedx = cachedx % M;
x = cachedx;
return x;
}
//fast modPow
function powmod( base, exp, mod ){
if (exp == 0) return 1;
if (exp % 2 == 0){
return Math.pow( powmod( base, (exp / 2), mod), 2) % mod;
}
else {
return (base * powmod( base, (exp - 1), mod)) % mod;
}
}
//least common multiple.
function lcm(A) //A - array with numbers (for example: [57,0,-45,-18,90,447])
{
var n = A.length, a = Math.abs(A[0]);
for (var i = 1; i < n; i++)
{ var b = Math.abs(A[ i ]), c = a;
while (a && b){ a > b ? a %= b : b %= a; }
a = Math.abs(c*A[ i ])/(a+b);
}
return a;
}
function generate(n){ //n-th number from generator, without calculating previous:
return (powmod( x0, powmod( 2, n, lcm([(p-1), (q-1)]) ), M ));
}
//start generator
p = 7;
q = 19;
M = p * q; //update M
var x0 = 53; //p = 7, q = 19, x0 = 53; (53, 16, 123, 100, 25...)
x = x0; //x0 as start nubmer, seed.
var n = 1; //Just to display n in console
//generate numbers. See this in console.log(F12 button)
console.log(
'next(4 numbers): '+ //16 123 100 25 ...
'\n'+(n++)+' = '+next()+
'\n'+(n++)+' = '+next()+
'\n'+(n++)+' = '+next()+
'\n'+(n++)+' = '+next()+
'\n...'
);
var n = 3; //show n-th number
console.log(
//'lcm(p-1, q-1) = ', lcm([(p-1), (q-1)]), //test lcm = 18, true
'\n'+n+'-th number = ', generate(n) //return 25 and this is 4-th number.
);
</script>
Awesome, thank you! I'm super busy lately, but would love to get back to try this as soon as I can. Does this have the property that all integers will generate unique random numbers? I'm trying to make sure that is true for all of my algorithms.
Oww, @Francois-Laberge-Bose... I did not saw your message. Maybe needed to quote my username, to let me receive email from you.
You wrote:
Awesome, thank you! I'm super busy lately, but would love to get back to try this as soon as I can. Does this have the property that all integers will generate unique random numbers? I'm trying to make sure that is true for all of my algorithms.
I do not know, need to test it.
But I know, that, if you want to get [unique integers
] by modulo n
, in range [from 0
up to φ(n)-1
],
and get it from consecutive numbers [from 0
up to φ(n)-1
],
you can use fast modPow
-function, and primitive root by modulo n.
φ(n)
- means Euler function from n
.
Here is described this property (Russian language): http://kaf401.rloc.ru/Criptfiles/primroots.htm
where:
grey values
- primitive root
s a
, by modulo n
,
green values
- consecutive integers, on input in range [from 0
up to φ(n)-1
],
blue values
- unique integers in range [from 0
up to φ(n)-1
].
@username1565 No worries. I'm now too busy to try to understand your answer. Will sometime though. Thanks!
@Francois-Laberge-Bose, really it's easy to understand, and not so hard.
The formula g ^ N mod p = r
, can return a bijective transfromation
some value of index N
, into result r
.
Now, look again, at this simply formula, but in the details:
r = g ^ N mod p
,
and here:
p
- this is a some prime number,
g
- primitive root,
N
- some index of Nth r-number,
r
- result number.
When p
is a prime number, then phi(p) = (p-1)
, and this value is easy to compute.
So, this formula, can return the transformation of this some value of index
- N
in range [1, ..., (p-1)]
,
into some Nth-number r
in range [1, ... (p-1)]
.
This transformation is bijective transformation
(as you requested),
and all r
-values, are unique values, for each unique N
on input.
This formula, seems, like a Blum-Blum-Shub PRNG-algorithm
, too, because any value of r
, can be extracted directly,
without need to compute all previous values, on PRNG
, and then - just skip
it all, to extract that N-th r-value
.
Computing of power by modulus, can be processed fastly, by using fast modPow (powmod)
-algorithm.
This PRNG
, like blum-blum-shub algo
, have a seed
too,
and this is not reversive, because to compute N
by r
, need to resolve a discrete-logarithm
(this is so hard task).
So, this formula
seems, like seeded hash-function,
because while g
can have a small value, and it can be public,
the value of p
, can be a hidden secret value.
Also, g
, can be some any primitive root, and
now, think about the number of primitive roots
, g
by modulo p
...
If some value p
have at least one primitive root g
,
then total number of primitive roots is equal of phi(phi(p))
different primitive roots by modulo p.
While p is a prime number, and phi(p) = (p-1)
for prime number,
the value of phi(phi(p))
can be more lesser than phi(p)
-value,
because phi(p)/2
can be easy factorized.
But if phi(p)/2 = prime
((p-1)/2 = prime
) and this is a prime number too,
then this can not be factorized, and number of primitive roots
is a large number, then.
While phi(p) = (p-1)
, phi(p)
can be factorized as 2
(yeap, because (p-1)
is even value, such as prime is odd)
and some another prime
.
If this some another prime
is a big prime nubmer
, then number of primitive roots by modulo p
is,
maybe, big number
too (but I'm not sure, and need to test it... UPD: And after tests, this seems, like (p-1)/2
primitive roots, in this case).
For your free time, you can also see the details, and comments in this source code:
https://github.com/username1565/BigInteger.js/blob/master/Diffie_Hellman_Key_Exchange_BigInteger.html
Onilie version - here:
https://username1565.github.io/BigInteger.js/Diffie_Hellman_Key_Exchange_BigInteger.html
@Francois-Laberge-Bose!
This all was been so interested for me, and I did implemented BRAPRNG, and Blum-Blum-Shub-algo here: https://github.com/username1565/BigInteger.js/blob/2b2057db04a32996247f2d1182511b6f2fe82395/BigInteger.js#L2161
in this commit: username1565/BigInteger.js@2b2057d
Also, added RSABigInteger. You can see the source code for your free time.
f
@schas002 I'm obsessing with PRNGs this weekend, was looking for a PRNG that is random access, as in:
It seems that this algorithm supposedly is able to be evaluated like that but the math is beyond me. Was wondering if you knew more about how I might translate this to Javascript.
See: https://en.wikipedia.org/wiki/Blum_Blum_Shub: