github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/bcns/random.go (about) 1 // 2 // Random Number Generation 3 // 4 // To the extent possible under law, Yawning Angel waived all copyright 5 // and related or neighboring rights to bcns, using the Creative 6 // Commons "CC0" public domain dedication. See LICENSE or 7 // <http://creativecommons.org/publicdomain/zero/1.0/> for full details. 8 9 package bcns 10 11 import ( 12 "crypto/aes" 13 "crypto/cipher" 14 "encoding/binary" 15 "io" 16 ) 17 18 // 19 // Like the original code this was based on, use AES to derive all the 20 // random numbers needed, since using "cryto/rand" will be rather slow. 21 // 22 // To facilitate making the algorithm deterministic for testing, an 23 // io.Reader can be provided to the constructor, however all actual users 24 // should use a cryptographic entropy source. 25 // 26 27 type randCtx struct { 28 s cipher.Stream 29 } 30 31 func newRandCtx(r io.Reader) (*randCtx, error) { 32 var key [32]byte 33 var iv [aes.BlockSize]byte 34 35 // Use a random key/IV... 36 if _, err := io.ReadFull(r, key[:]); err != nil { 37 return nil, err 38 } 39 if _, err := io.ReadFull(r, iv[:]); err != nil { 40 return nil, err 41 } 42 43 // ...AES-256... 44 block, err := aes.NewCipher(key[:]) 45 if err != nil { 46 return nil, err 47 } 48 49 // ...CTR mode. I would have used ChaCha20 here if I had vectorized my 50 // implementation. Oh well. 51 ctx := &randCtx{s: cipher.NewCTR(block, iv[:])} 52 return ctx, nil 53 } 54 55 func (c *randCtx) random32() uint32 { 56 var b [4]byte 57 c.s.XORKeyStream(b[:], b[:]) 58 return binary.LittleEndian.Uint32(b[:]) 59 } 60 61 func (c *randCtx) random64() uint64 { 62 var b [8]byte 63 c.s.XORKeyStream(b[:], b[:]) 64 return binary.LittleEndian.Uint64(b[:]) 65 } 66 67 func (c *randCtx) random192(r *[3]uint64) { 68 var buf [24]byte 69 c.s.XORKeyStream(buf[:], buf[:]) 70 r[0] = binary.LittleEndian.Uint64(buf[0:]) 71 r[1] = binary.LittleEndian.Uint64(buf[8:]) 72 r[2] = binary.LittleEndian.Uint64(buf[16:]) 73 }