mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-16 10:28:49 -07:00
198028d627
rand.secureSource.Uint64 no longer allocates. rand.String uses a strings.Builder. Benchmark results on linux/amd64: name old time/op new time/op delta SecureSource-8 69.1ns ± 3% 51.7ns ± 3% -25.21% (p=0.000 n=20+10) String-8 2.66µs ± 2% 1.95µs ± 1% -26.61% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SecureSource-8 8.00B ± 0% 0.00B -100.00% (p=0.000 n=20+10) String-8 288B ± 0% 32B ± 0% -88.89% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SecureSource-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=20+10) String-8 33.0 ± 0% 1.0 ± 0% -96.97% (p=0.000 n=10+10)
63 lines
1.5 KiB
Go
63 lines
1.5 KiB
Go
// Copyright (C) 2016 The Syncthing Authors.
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
package rand
|
|
|
|
import (
|
|
"bufio"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"io"
|
|
"sync"
|
|
)
|
|
|
|
// The secureSource is a math/rand.Source + io.Reader that reads bytes from
|
|
// crypto/rand.Reader. It means we can use the convenience functions
|
|
// provided by math/rand.Rand on top of a secure source of numbers. It is
|
|
// concurrency safe for ease of use.
|
|
type secureSource struct {
|
|
rd io.Reader
|
|
mut sync.Mutex
|
|
buf [8]byte
|
|
}
|
|
|
|
func newSecureSource() *secureSource {
|
|
return &secureSource{
|
|
// Using buffering on top of the rand.Reader increases our
|
|
// performance by about 20%, even though it means we must use
|
|
// locking.
|
|
rd: bufio.NewReader(rand.Reader),
|
|
}
|
|
}
|
|
|
|
func (s *secureSource) Seed(int64) {
|
|
panic("SecureSource is not seedable")
|
|
}
|
|
|
|
func (s *secureSource) Int63() int64 {
|
|
return int64(s.Uint64() & (1<<63 - 1))
|
|
}
|
|
|
|
func (s *secureSource) Read(p []byte) (int, error) {
|
|
s.mut.Lock()
|
|
defer s.mut.Unlock()
|
|
return s.rd.Read(p)
|
|
}
|
|
|
|
func (s *secureSource) Uint64() uint64 {
|
|
// Read eight bytes of entropy from the buffered, secure random number
|
|
// generator. The buffered reader isn't concurrency safe, so we lock
|
|
// around that.
|
|
s.mut.Lock()
|
|
defer s.mut.Unlock()
|
|
|
|
_, err := io.ReadFull(s.rd, s.buf[:])
|
|
if err != nil {
|
|
panic("randomness failure: " + err.Error())
|
|
}
|
|
return binary.LittleEndian.Uint64(s.buf[:])
|
|
}
|