Source File
entropy.go
Belonging Package
crypto/internal/entropy/v1.0.0
// Copyright 2025 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 entropy implements a CPU jitter-based SP 800-90B entropy source.package entropyimport ()// Version returns the version of the entropy source.//// This is independent of the FIPS 140-3 module version, in order to reuse the// ESV certificate across module versions.func () string {return "v1.0.0"}// ScratchBuffer is a large buffer that will be written to using atomics, to// generate noise from memory access timings. Its contents do not matter.type ScratchBuffer [1 << 25]byte// Seed returns a 384-bit seed with full entropy.//// memory is passed in to allow changing the allocation strategy without// modifying the frozen and certified entropy source in this package.//// Seed returns an error if the entropy source startup health tests fail, which// has a non-negligible chance of happening.func ( *ScratchBuffer) ([48]byte, error) {// Collect w = 1024 samples, each certified to provide no less than h = 0.5// bits of entropy, for a total of hᵢₙ = w × h = 512 bits of entropy, over// nᵢₙ = w × n = 8192 bits of input data.var [1024]byteif := Samples([:], ); != nil {return [48]byte{},}// Use a vetted unkeyed conditioning component, SHA-384, with nw = 384 and// nₒᵤₜ = 384. Per the formula in SP 800-90B Section 3.1.5.1.2, the output// entropy hₒᵤₜ is://// sage: n_in = 8192// sage: n_out = 384// sage: nw = 384// sage: h_in = 512// sage: P_high = 2^(-h_in)// sage: P_low = (1 - P_high) / (2^n_in - 1)// sage: n = min(n_out, nw)// sage: ψ = 2^(n_in - n) * P_low + P_high// sage: U = 2^(n_in - n) + sqrt(2 * n * 2^(n_in - n) * ln(2))// sage: ω = U * P_low// sage: h_out = -log(max(ψ, ω), 2)// sage: h_out.n()// 384.000000000000//// According to Implementation Guidance D.K, Resolution 19, since//// - the conditioning component is vetted,// - hᵢₙ = 512 ≥ nₒᵤₜ + 64 = 448, and// - nₒᵤₜ ≤ security strength of SHA-384 = 384 (per SP 800-107 Rev. 1, Table 1),//// we can claim the output has full entropy.return SHA384(&), nil}// Samples starts a new entropy source, collects the requested number of// samples, conducts startup health tests, and returns the samples or an error// if the health tests fail.//// The health tests have a non-negligible chance of failing.func ( []uint8, *ScratchBuffer) error {if len() < 1024 {return errors.New("entropy: at least 1024 samples are required for startup health tests")}:= newSource()for range 4 {// Warm up the source to avoid any initial bias._ = .Sample()}for := range {[] = .Sample()}if := RepetitionCountTest(); != nil {return}if := AdaptiveProportionTest(); != nil {return}return nil}type source struct {memory *ScratchBufferlcgState uint32previous int64}func newSource( *ScratchBuffer) *source {return &source{memory: ,lcgState: uint32(time.HighPrecisionNow()),previous: time.HighPrecisionNow(),}}// touchMemory performs a write to memory at the given index.//// The memory slice is passed in and may be shared across sources e.g. to avoid// the significant (~500µs) cost of zeroing a new allocation on every [Seed] call.func touchMemory( *ScratchBuffer, uint32) {= / 4 * 4 // align to 32 bits:= (*uint32)(unsafe.Pointer(&[])):= atomic.LoadUint32()atomic.SwapUint32(, +13)}func ( *source) () uint8 {// Perform a few memory accesses in an unpredictable pattern to expose the// next measurement to as much system noise as possible., := .memory, .lcgStateif == nil { // remove the nil check from the inlined touchMemory callspanic("entropy: nil memory buffer")}for range 64 {= 1664525* + 1013904223// Discard the lower bits, which tend to fall into short cycles.:= ( >> 6) & (1<<25 - 1)touchMemory(, )}.lcgState =:= time.HighPrecisionNow():= - .previous.previous =// Reduce the symbol space to 256 values, assuming most of the entropy is in// the least-significant bits, which represent the highest-resolution timing// differences.return uint8()}// RepetitionCountTest implements the repetition count test from SP 800-90B// Section 4.4.1. It returns an error if any symbol is repeated C = 41 or more// times in a row.//// This C value is calculated from a target failure probability α = 2⁻²⁰ and a// claimed min-entropy per symbol h = 0.5 bits, using the formula in SP 800-90B// Section 4.4.1.//// sage: α = 2^-20// sage: H = 0.5// sage: 1 + ceil(-log(α, 2) / H)// 41func ( []uint8) error {:= [0]:= 1for , := range [1:] {if == {++if >= 41 {return errors.New("entropy: repetition count health test failed")}} else {== 1}}return nil}// AdaptiveProportionTest implements the adaptive proportion test from SP 800-90B// Section 4.4.2. It returns an error if any symbol appears C = 410 or more// times in the last W = 512 samples.//// This C value is calculated from a target failure probability α = 2⁻²⁰, a// window size W = 512, and a claimed min-entropy per symbol h = 0.5 bits, using// the formula in SP 800-90B Section 4.4.2, equivalent to the Microsoft Excel// formula 1+CRITBINOM(W, power(2,(−H)),1−α).//// sage: from scipy.stats import binom// sage: α = 2^-20// sage: H = 0.5// sage: W = 512// sage: C = 1 + binom.ppf(1 - α, W, 2**(-H))// sage: ceil(C)// 410func ( []uint8) error {var [256]intfor , := range {[]++if >= 512 {[[-512]]--}if [] >= 410 {return errors.New("entropy: adaptive proportion health test failed")}}return nil}
![]() |
The pages are generated with Golds v0.8.3-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |