// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sysrand

import (
	"internal/byteorder"
	"internal/chacha8rand"
	"io"
	"os"
	"sync"
)

const randomDevice = "/dev/random"

// This is a pseudorandom generator that seeds itself by reading from
// /dev/random. The read function always returns the full amount asked for, or
// else it returns an error.

var (
	mu      sync.Mutex
	seeded  sync.Once
	seedErr error
	state   chacha8rand.State
)

func read(b []byte) error {
	seeded.Do(func() {
		entropy, err := os.Open(randomDevice)
		if err != nil {
			seedErr = err
			return
		}
		defer entropy.Close()
		var seed [32]byte
		_, err = io.ReadFull(entropy, seed[:])
		if err != nil {
			seedErr = err
			return
		}
		state.Init(seed)
	})
	if seedErr != nil {
		return seedErr
	}

	mu.Lock()
	defer mu.Unlock()

	for len(b) >= 8 {
		if x, ok := state.Next(); ok {
			byteorder.BEPutUint64(b, x)
			b = b[8:]
		} else {
			state.Refill()
		}
	}
	for len(b) > 0 {
		if x, ok := state.Next(); ok {
			var buf [8]byte
			byteorder.BEPutUint64(buf[:], x)
			n := copy(b, buf[:])
			b = b[n:]
		} else {
			state.Refill()
		}
	}
	state.Reseed()

	return nil
}
