Skip to content

Commit e966a27

Browse files
committed
crypto/internal/fips140/drbg: avoid global lock on rand state
Having a global lock on the random state (used only in FIPS-140 mode) introduces contention in concurrent programs. Use an approximately per-P random state instead, using sync.Pool to manage per-P state. This code is important to land for the Go 1.24 release because it is part of the FIPS-140 module that will be validated and certified, so it will live for a long time. We otherwise wouldn't be able to correct this contention for at least a year, perhaps more. At the same time, the code is only used in the FIPS-140 mode, so there is no risk to normal programs. Fixes #71155. Change-Id: I6b779f15ddfdf232f608f5cda08f75906e58114f Reviewed-on: https://go-review.googlesource.com/c/go/+/641097 Reviewed-by: Austin Clements <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 9a44df6 commit e966a27

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

src/crypto/internal/fips140/drbg/rand.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,15 @@ import (
1313
"sync"
1414
)
1515

16-
var mu sync.Mutex
17-
var drbg *Counter
16+
var drbgs = sync.Pool{
17+
New: func() any {
18+
var c *Counter
19+
entropy.Depleted(func(seed *[48]byte) {
20+
c = NewCounter(seed)
21+
})
22+
return c
23+
},
24+
}
1825

1926
// Read fills b with cryptographically secure random bytes. In FIPS mode, it
2027
// uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG).
@@ -33,14 +40,8 @@ func Read(b []byte) {
3340
additionalInput := new([SeedSize]byte)
3441
sysrand.Read(additionalInput[:16])
3542

36-
mu.Lock()
37-
defer mu.Unlock()
38-
39-
if drbg == nil {
40-
entropy.Depleted(func(seed *[48]byte) {
41-
drbg = NewCounter(seed)
42-
})
43-
}
43+
drbg := drbgs.Get().(*Counter)
44+
defer drbgs.Put(drbg)
4445

4546
for len(b) > 0 {
4647
size := min(len(b), maxRequestSize)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2025 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 drbg
6+
7+
import (
8+
"crypto/internal/fips140"
9+
"testing"
10+
)
11+
12+
func BenchmarkDBRG(b *testing.B) {
13+
old := fips140.Enabled
14+
defer func() {
15+
fips140.Enabled = old
16+
}()
17+
fips140.Enabled = true
18+
19+
const N = 64
20+
b.SetBytes(N)
21+
b.RunParallel(func(pb *testing.PB) {
22+
buf := make([]byte, N)
23+
for pb.Next() {
24+
Read(buf)
25+
}
26+
})
27+
}

0 commit comments

Comments
 (0)