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  }