| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you 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 amcl |
| |
| import ( |
| "sync" |
| ) |
| |
| //import "fmt" |
| |
| const rand_NK int = 21 |
| const rand_NJ int = 6 |
| const rand_NV int = 8 |
| |
| type RAND struct { |
| sync.Mutex |
| 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 := NewHASH() |
| for i := 0; i < 128; i++ { |
| sh.Process(byte(R.sbrand() & 0xff)) |
| } |
| R.pool = sh.Hash() |
| 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 := NewHASH() |
| 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.Lock() |
| defer R.Unlock() |
| |
| 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()) |
| } |
| } |
| */ |