rand_plan9.mx raw

   1  // Copyright 2010 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package sysrand
   6  
   7  import (
   8  	"internal/byteorder"
   9  	"internal/chacha8rand"
  10  	"io"
  11  	"os"
  12  	"sync"
  13  )
  14  
  15  const randomDevice = "/dev/random"
  16  
  17  // This is a pseudorandom generator that seeds itself by reading from
  18  // /dev/random. The read function always returns the full amount asked for, or
  19  // else it returns an error.
  20  
  21  var (
  22  	mu      sync.Mutex
  23  	seeded  sync.Once
  24  	seedErr error
  25  	state   chacha8rand.State
  26  )
  27  
  28  func read(b []byte) error {
  29  	seeded.Do(func() {
  30  		entropy, err := os.Open(randomDevice)
  31  		if err != nil {
  32  			seedErr = err
  33  			return
  34  		}
  35  		defer entropy.Close()
  36  		var seed [32]byte
  37  		_, err = io.ReadFull(entropy, seed[:])
  38  		if err != nil {
  39  			seedErr = err
  40  			return
  41  		}
  42  		state.Init(seed)
  43  	})
  44  	if seedErr != nil {
  45  		return seedErr
  46  	}
  47  
  48  	mu.Lock()
  49  	defer mu.Unlock()
  50  
  51  	for len(b) >= 8 {
  52  		if x, ok := state.Next(); ok {
  53  			byteorder.BEPutUint64(b, x)
  54  			b = b[8:]
  55  		} else {
  56  			state.Refill()
  57  		}
  58  	}
  59  	for len(b) > 0 {
  60  		if x, ok := state.Next(); ok {
  61  			var buf [8]byte
  62  			byteorder.BEPutUint64(buf[:], x)
  63  			n := copy(b, buf[:])
  64  			b = b[n:]
  65  		} else {
  66  			state.Refill()
  67  		}
  68  	}
  69  	state.Reseed()
  70  
  71  	return nil
  72  }
  73