mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 00:55:17 +00:00
179 lines
3.6 KiB
Go
179 lines
3.6 KiB
Go
/*
|
|
* Copyright (c) 2012-2020 MIRACL UK Ltd.
|
|
*
|
|
* This file is part of MIRACL Core
|
|
* (see https://github.com/miracl/core).
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* Cryptographic strong random number generator
|
|
*
|
|
* Unguessable seed -> SHA -> PRNG internal state -> SHA -> random numbers
|
|
* Slow - but secure
|
|
*
|
|
* See ftp://ftp.rsasecurity.com/pub/pdfs/bull-1.pdf for a justification
|
|
*/
|
|
|
|
/* Marsaglia & Zaman Random number generator constants */
|
|
|
|
package core
|
|
|
|
//import "fmt"
|
|
|
|
const rand_NK int = 21
|
|
const rand_NJ int = 6
|
|
const rand_NV int = 8
|
|
|
|
type RAND struct {
|
|
ira [rand_NK]uint32 /* random number... */
|
|
rndptr int
|
|
borrow uint32
|
|
pool_ptr int
|
|
pool [32]byte
|
|
}
|
|
|
|
/* Terminate and clean up */
|
|
func (R *RAND) Clean() { /* kill internal state */
|
|
R.pool_ptr = 0
|
|
R.rndptr = 0
|
|
for i := 0; i < 32; i++ {
|
|
R.pool[i] = 0
|
|
}
|
|
for i := 0; i < rand_NK; i++ {
|
|
R.ira[i] = 0
|
|
}
|
|
R.borrow = 0
|
|
}
|
|
|
|
func NewRAND() *RAND {
|
|
R := new(RAND)
|
|
R.Clean()
|
|
return R
|
|
}
|
|
|
|
func (R *RAND) sbrand() uint32 { /* Marsaglia & Zaman random number generator */
|
|
R.rndptr++
|
|
if R.rndptr < rand_NK {
|
|
return R.ira[R.rndptr]
|
|
}
|
|
R.rndptr = 0
|
|
k := rand_NK - rand_NJ
|
|
for i := 0; i < rand_NK; i++ { /* calculate next NK values */
|
|
if k == rand_NK {
|
|
k = 0
|
|
}
|
|
t := R.ira[k]
|
|
pdiff := t - R.ira[i] - R.borrow
|
|
if pdiff < t {
|
|
R.borrow = 0
|
|
}
|
|
if pdiff > t {
|
|
R.borrow = 1
|
|
}
|
|
R.ira[i] = pdiff
|
|
k++
|
|
}
|
|
|
|
return R.ira[0]
|
|
}
|
|
|
|
func (R *RAND) sirand(seed uint32) {
|
|
var m uint32 = 1
|
|
R.borrow = 0
|
|
R.rndptr = 0
|
|
R.ira[0] ^= seed
|
|
for i := 1; i < rand_NK; i++ { /* fill initialisation vector */
|
|
in := (rand_NV * i) % rand_NK
|
|
R.ira[in] ^= m /* note XOR */
|
|
t := m
|
|
m = seed - m
|
|
seed = t
|
|
}
|
|
for i := 0; i < 10000; i++ {
|
|
R.sbrand()
|
|
} /* "warm-up" & stir the generator */
|
|
}
|
|
|
|
func (R *RAND) fill_pool() {
|
|
sh := NewHASH256()
|
|
for i := 0; i < 128; i++ {
|
|
sh.Process(byte(R.sbrand() & 0xff))
|
|
}
|
|
W := sh.Hash()
|
|
for i := 0; i < 32; i++ {
|
|
R.pool[i] = W[i]
|
|
}
|
|
R.pool_ptr = 0
|
|
}
|
|
|
|
func pack(b [4]byte) uint32 { /* pack 4 bytes into a 32-bit Word */
|
|
return (((uint32(b[3])) & 0xff) << 24) | ((uint32(b[2]) & 0xff) << 16) | ((uint32(b[1]) & 0xff) << 8) | (uint32(b[0]) & 0xff)
|
|
}
|
|
|
|
/* Initialize RNG with some real entropy from some external source */
|
|
func (R *RAND) Seed(rawlen int, raw []byte) { /* initialise from at least 128 byte string of raw random entropy */
|
|
var b [4]byte
|
|
sh := NewHASH256()
|
|
R.pool_ptr = 0
|
|
|
|
for i := 0; i < rand_NK; i++ {
|
|
R.ira[i] = 0
|
|
}
|
|
if rawlen > 0 {
|
|
for i := 0; i < rawlen; i++ {
|
|
sh.Process(raw[i])
|
|
}
|
|
digest := sh.Hash()
|
|
|
|
/* initialise PRNG from distilled randomness */
|
|
|
|
for i := 0; i < 8; i++ {
|
|
b[0] = digest[4*i]
|
|
b[1] = digest[4*i+1]
|
|
b[2] = digest[4*i+2]
|
|
b[3] = digest[4*i+3]
|
|
R.sirand(pack(b))
|
|
}
|
|
}
|
|
R.fill_pool()
|
|
}
|
|
|
|
/* get random byte */
|
|
func (R *RAND) GetByte() byte {
|
|
r := R.pool[R.pool_ptr]
|
|
R.pool_ptr++
|
|
if R.pool_ptr >= 32 {
|
|
R.fill_pool()
|
|
}
|
|
return byte(r & 0xff)
|
|
}
|
|
|
|
/* test main program */
|
|
/*
|
|
func main() {
|
|
var raw [100]byte
|
|
rng:=NewRAND()
|
|
|
|
rng.Clean()
|
|
for i:=0;i<100;i++ {raw[i]=byte(i)}
|
|
|
|
rng.Seed(100,raw[:])
|
|
|
|
for i:=0;i<1000;i++ {
|
|
fmt.Printf("%03d ",rng.GetByte())
|
|
}
|
|
}
|
|
*/
|