Skip to content

Commit c3a706e

Browse files
committed
crypto/internal/fips140/bigmod: add more //go:norace annotations
//go:norace does not carry over when a function is inlined. Add //go:norace to functions that inline loops over Nat words. Improves race tests, also asan, msan. These are with -race: goos: darwin goarch: arm64 pkg: crypto/internal/fips140/bigmod cpu: Apple M3 Pro │ old │ new │ │ sec/op │ sec/op vs base │ ModAdd-12 172.4n ± 3% 117.9n ± 3% -31.62% (p=0.000 n=20) ModSub-12 147.1n ± 2% 111.4n ± 3% -24.27% (p=0.000 n=20) NewModulus-12 12.966µ ± 1% 9.743µ ± 2% -24.86% (p=0.000 n=20) MontgomeryRepr-12 1305.5n ± 1% 986.3n ± 0% -24.45% (p=0.000 n=20) MontgomeryMul-12 1304.0n ± 1% 976.8n ± 0% -25.10% (p=0.000 n=20) ModMul-12 2.893µ ± 1% 2.055µ ± 3% -28.97% (p=0.000 n=20) ExpBig-12 2.784m ± 0% 2.789m ± 0% +0.17% (p=0.008 n=20) Exp-12 3.468m ± 0% 2.620m ± 0% -24.45% (p=0.000 n=20) geomean 7.930µ 6.073µ -23.41% pkg: crypto/rsa │ old │ new │ │ sec/op │ sec/op vs base │ DecryptPKCS1v15/2048-12 1.795m ± 1% 1.175m ± 1% -34.52% (p=0.000 n=20) DecryptPKCS1v15/3072-12 3.836m ± 2% 2.647m ± 0% -31.01% (p=0.000 n=20) DecryptPKCS1v15/4096-12 7.316m ± 0% 5.437m ± 0% -25.68% (p=0.000 n=20) EncryptPKCS1v15/2048-12 45.85µ ± 1% 34.78µ ± 0% -24.15% (p=0.000 n=20) DecryptOAEP/2048-12 1.793m ± 2% 1.188m ± 1% -33.76% (p=0.000 n=20) EncryptOAEP/2048-12 55.11µ ± 1% 43.91µ ± 1% -20.32% (p=0.000 n=20) SignPKCS1v15/2048-12 1.797m ± 2% 1.193m ± 0% -33.62% (p=0.000 n=20) VerifyPKCS1v15/2048-12 45.16µ ± 1% 34.51µ ± 0% -23.57% (p=0.000 n=20) SignPSS/2048-12 1.826m ± 2% 1.213m ± 0% -33.55% (p=0.000 n=20) VerifyPSS/2048-12 53.25µ ± 1% 42.40µ ± 1% -20.36% (p=0.000 n=20) GenerateKey/2048-12 323.7m ± 33% 209.0m ± 17% -35.43% (p=0.000 n=20) ParsePKCS8PrivateKey/2048-12 105.26µ ± 0% 94.74µ ± 0% -9.99% (p=0.000 n=20) geomean 792.5µ 574.3µ -27.53% Change-Id: I1f1986cf2bac126d7346799b08b17d356b28d956 Reviewed-on: https://go-review.googlesource.com/c/go/+/633995 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]>
1 parent aa464fb commit c3a706e

File tree

1 file changed

+29
-2
lines changed
  • src/crypto/internal/fips140/bigmod

1 file changed

+29
-2
lines changed

src/crypto/internal/fips140/bigmod/nat.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ const (
1818
_S = _W / 8
1919
)
2020

21+
// Note: These functions make many loops over all the words in a Nat.
22+
// These loops used to be in assembly, invisible to -race, -asan, and -msan,
23+
// but now they are in Go and incur significant overhead in those modes.
24+
// To bring the old performance back, we mark all functions that loop
25+
// over Nat words with //go:norace. Because //go:norace does not
26+
// propagate across inlining, we must also mark functions that inline
27+
// //go:norace functions - specifically, those that inline add, addMulVVW,
28+
// assign, cmpGeq, rshift1, and sub.
29+
2130
// choice represents a constant-time boolean. The value of choice is always
2231
// either 1 or 0. We use an int instead of bool in order to make decisions in
2332
// constant time by turning it into a mask.
@@ -152,6 +161,8 @@ func (x *Nat) Bytes(m *Modulus) []byte {
152161
// SetBytes returns an error if b >= m.
153162
//
154163
// The output will be resized to the size of m and overwritten.
164+
//
165+
//go:norace
155166
func (x *Nat) SetBytes(b []byte, m *Modulus) (*Nat, error) {
156167
x.resetFor(m)
157168
if err := x.setBytes(b); err != nil {
@@ -283,8 +294,6 @@ func (x *Nat) IsMinusOne(m *Modulus) choice {
283294
}
284295

285296
// IsOdd returns 1 if x is odd, and 0 otherwise.
286-
//
287-
//go:norace
288297
func (x *Nat) IsOdd() choice {
289298
if len(x.limbs) == 0 {
290299
return no
@@ -538,6 +547,8 @@ func NewModulus(b []byte) (*Modulus, error) {
538547

539548
// NewModulusProduct creates a new Modulus from the product of two numbers
540549
// represented as big-endian byte slices. The result must be greater than one.
550+
//
551+
//go:norace
541552
func NewModulusProduct(a, b []byte) (*Modulus, error) {
542553
x := NewNat().resetToBytes(a)
543554
y := NewNat().resetToBytes(b)
@@ -624,6 +635,8 @@ func (x *Nat) shiftIn(y uint, m *Modulus) *Nat {
624635
// This works regardless how large the value of x is.
625636
//
626637
// The output will be resized to the size of m and overwritten.
638+
//
639+
//go:norace
627640
func (out *Nat) Mod(x *Nat, m *Modulus) *Nat {
628641
out.resetFor(m)
629642
// Working our way from the most significant to the least significant limb,
@@ -673,6 +686,8 @@ func (out *Nat) resetFor(m *Modulus) *Nat {
673686
// overflowed its size, meaning abstractly x > 2^_W*n > m even if x < m.
674687
//
675688
// x and m operands must have the same announced length.
689+
//
690+
//go:norace
676691
func (x *Nat) maybeSubtractModulus(always choice, m *Modulus) {
677692
t := NewNat().set(x)
678693
underflow := t.sub(m.nat)
@@ -686,6 +701,8 @@ func (x *Nat) maybeSubtractModulus(always choice, m *Modulus) {
686701
//
687702
// The length of both operands must be the same as the modulus. Both operands
688703
// must already be reduced modulo m.
704+
//
705+
//go:norace
689706
func (x *Nat) Sub(y *Nat, m *Modulus) *Nat {
690707
underflow := x.sub(y)
691708
// If the subtraction underflowed, add m.
@@ -710,6 +727,8 @@ func (x *Nat) SubOne(m *Modulus) *Nat {
710727
//
711728
// The length of both operands must be the same as the modulus. Both operands
712729
// must already be reduced modulo m.
730+
//
731+
//go:norace
713732
func (x *Nat) Add(y *Nat, m *Modulus) *Nat {
714733
overflow := x.add(y)
715734
x.maybeSubtractModulus(choice(overflow), m)
@@ -747,6 +766,8 @@ func (x *Nat) montgomeryReduction(m *Modulus) *Nat {
747766
//
748767
// All inputs should be the same length and already reduced modulo m.
749768
// x will be resized to the size of m and overwritten.
769+
//
770+
//go:norace
750771
func (x *Nat) montgomeryMul(a *Nat, b *Nat, m *Modulus) *Nat {
751772
n := len(m.nat.limbs)
752773
mLimbs := m.nat.limbs[:n]
@@ -890,6 +911,8 @@ func addMulVVW(z, x []uint, y uint) (carry uint) {
890911
//
891912
// The length of both operands must be the same as the modulus. Both operands
892913
// must already be reduced modulo m.
914+
//
915+
//go:norace
893916
func (x *Nat) Mul(y *Nat, m *Modulus) *Nat {
894917
if m.odd {
895918
// A Montgomery multiplication by a value out of the Montgomery domain
@@ -951,6 +974,8 @@ func (x *Nat) Mul(y *Nat, m *Modulus) *Nat {
951974
// to the size of m and overwritten. x must already be reduced modulo m.
952975
//
953976
// m must be odd, or Exp will panic.
977+
//
978+
//go:norace
954979
func (out *Nat) Exp(x *Nat, e []byte, m *Modulus) *Nat {
955980
if !m.odd {
956981
panic("bigmod: modulus for Exp must be odd")
@@ -1030,6 +1055,8 @@ func (out *Nat) ExpShortVarTime(x *Nat, e uint, m *Modulus) *Nat {
10301055
//
10311056
// a must be reduced modulo m, but doesn't need to have the same size. The
10321057
// output will be resized to the size of m and overwritten.
1058+
//
1059+
//go:norace
10331060
func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
10341061
// This is the extended binary GCD algorithm described in the Handbook of
10351062
// Applied Cryptography, Algorithm 14.61, adapted by BoringSSL to bound

0 commit comments

Comments
 (0)