]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/fips140/rsa: add Miller-Rabin test
authorFilippo Valsorda <filippo@golang.org>
Wed, 27 Nov 2024 17:17:28 +0000 (18:17 +0100)
committerGopher Robot <gobot@golang.org>
Sat, 30 Nov 2024 01:46:21 +0000 (01:46 +0000)
A following CL will move key generation to crypto/internal/fips140/rsa.

Updates #69799
For #69536

Change-Id: Icdf9b8424da20453939c6587af7dc922aad9e0ca
Reviewed-on: https://go-review.googlesource.com/c/go/+/632215
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
src/crypto/internal/fips140/bigmod/nat.go
src/crypto/internal/fips140/bigmod/nat_test.go
src/crypto/internal/fips140/rsa/keygen.go [new file with mode: 0644]
src/crypto/internal/fips140/rsa/keygen_test.go [new file with mode: 0644]
src/crypto/internal/fips140/rsa/testdata/miller_rabin_tests.txt [new file with mode: 0644]
src/crypto/rsa/rsa.go

index 13a4ba6e967099bc9eeefcfa1ff5f578f6d5bc6c..e640696729f72c20ca59195d99de74a186ed84f3 100644 (file)
@@ -244,6 +244,56 @@ func (x *Nat) IsZero() choice {
        return zero
 }
 
+// IsOne returns 1 if x == 1, and 0 otherwise.
+func (x *Nat) IsOne() choice {
+       // Eliminate bounds checks in the loop.
+       size := len(x.limbs)
+       xLimbs := x.limbs[:size]
+
+       if len(xLimbs) == 0 {
+               return no
+       }
+
+       one := ctEq(xLimbs[0], 1)
+       for i := 1; i < size; i++ {
+               one &= ctEq(xLimbs[i], 0)
+       }
+       return one
+}
+
+// IsMinusOne returns 1 if x == -1 mod m, and 0 otherwise.
+//
+// The length of x must be the same as the modulus. x must already be reduced
+// modulo m.
+func (x *Nat) IsMinusOne(m *Modulus) choice {
+       minusOne := m.Nat()
+       minusOne.SubOne(m)
+       return x.Equal(minusOne)
+}
+
+// IsOdd returns 1 if x is odd, and 0 otherwise.
+func (x *Nat) IsOdd() choice {
+       if len(x.limbs) == 0 {
+               return no
+       }
+       return choice(x.limbs[0] & 1)
+}
+
+// TrailingZeroBitsVarTime returns the number of trailing zero bits in x.
+func (x *Nat) TrailingZeroBitsVarTime() uint {
+       var t uint
+       limbs := x.limbs
+       for _, l := range limbs {
+               if l == 0 {
+                       t += _W
+                       continue
+               }
+               t += uint(bits.TrailingZeros(l))
+               break
+       }
+       return t
+}
+
 // cmpGeq returns 1 if x >= y, and 0 otherwise.
 //
 // Both operands must have the same announced length.
@@ -308,6 +358,37 @@ func (x *Nat) sub(y *Nat) (c uint) {
        return
 }
 
+// ShiftRightVarTime sets x = x >> n.
+//
+// The announced length of x is unchanged.
+func (x *Nat) ShiftRightVarTime(n uint) *Nat {
+       // Eliminate bounds checks in the loop.
+       size := len(x.limbs)
+       xLimbs := x.limbs[:size]
+
+       shift := int(n % _W)
+       shiftLimbs := int(n / _W)
+
+       var shiftedLimbs []uint
+       if shiftLimbs < size {
+               shiftedLimbs = xLimbs[shiftLimbs:]
+       }
+
+       for i := range xLimbs {
+               if i >= len(shiftedLimbs) {
+                       xLimbs[i] = 0
+                       continue
+               }
+
+               xLimbs[i] = shiftedLimbs[i] >> shift
+               if i+1 < len(shiftedLimbs) {
+                       xLimbs[i] |= shiftedLimbs[i+1] << (_W - shift)
+               }
+       }
+
+       return x
+}
+
 // Modulus is used for modular arithmetic, precomputing relevant constants.
 //
 // A Modulus can leak the exact number of bits needed to store its value
@@ -403,7 +484,7 @@ func NewModulus(b []byte) (*Modulus, error) {
                return nil, errors.New("modulus must be > 0")
        }
        m.leading = _W - bitLen(m.nat.limbs[len(m.nat.limbs)-1])
-       if m.nat.limbs[0]&1 == 1 {
+       if m.nat.IsOdd() == 1 {
                m.odd = true
                m.m0inv = minusInverseModW(m.nat.limbs[0])
                m.rr = rr(m)
@@ -435,9 +516,13 @@ func (m *Modulus) BitLen() int {
        return len(m.nat.limbs)*_W - int(m.leading)
 }
 
-// Nat returns m as a Nat. The return value must not be written to.
+// Nat returns m as a Nat.
 func (m *Modulus) Nat() *Nat {
-       return m.nat
+       // Make a copy so that the caller can't modify m.nat or alias it with
+       // another Nat in a modulus operation.
+       n := NewNat()
+       n.set(m.nat)
+       return n
 }
 
 // shiftIn calculates x = x << _W + y mod m.
@@ -553,6 +638,16 @@ func (x *Nat) Sub(y *Nat, m *Modulus) *Nat {
        return x
 }
 
+// SubOne computes x = x - 1 mod m.
+//
+// The length of x must be the same as the modulus. x must already be reduced
+// modulo m.
+func (x *Nat) SubOne(m *Modulus) *Nat {
+       one := NewNat().ExpandFor(m)
+       one.limbs[0] = 1
+       return x.Sub(one, m)
+}
+
 // Add computes x = x + y mod m.
 //
 // The length of both operands must be the same as the modulus. Both operands
index 6ee0dd48da20ddc0c338de7a6e07a561ba70e3fa..06fd20868d9df04bb204c4fd31463b623e113348 100644 (file)
@@ -31,6 +31,14 @@ func (x *Nat) setBig(n *big.Int) *Nat {
        return x
 }
 
+func (n *Nat) asBig() *big.Int {
+       bits := make([]big.Word, len(n.limbs))
+       for i := range n.limbs {
+               bits[i] = big.Word(n.limbs[i])
+       }
+       return new(big.Int).SetBits(bits)
+}
+
 func (n *Nat) String() string {
        var limbs []string
        for i := range n.limbs {
@@ -404,6 +412,98 @@ func testMul(t *testing.T, n int) {
        }
 }
 
+func TestIs(t *testing.T) {
+       checkYes := func(c choice, err string) {
+               t.Helper()
+               if c != yes {
+                       t.Error(err)
+               }
+       }
+       checkNot := func(c choice, err string) {
+               t.Helper()
+               if c != no {
+                       t.Error(err)
+               }
+       }
+
+       mFour := modulusFromBytes([]byte{4})
+       n, err := NewNat().SetBytes([]byte{3}, mFour)
+       if err != nil {
+               t.Fatal(err)
+       }
+       checkYes(n.IsMinusOne(mFour), "3 is not -1 mod 4")
+       checkNot(n.IsZero(), "3 is zero")
+       checkNot(n.IsOne(), "3 is one")
+       checkYes(n.IsOdd(), "3 is not odd")
+       n.SubOne(mFour)
+       checkNot(n.IsMinusOne(mFour), "2 is -1 mod 4")
+       checkNot(n.IsZero(), "2 is zero")
+       checkNot(n.IsOne(), "2 is one")
+       checkNot(n.IsOdd(), "2 is odd")
+       n.SubOne(mFour)
+       checkNot(n.IsMinusOne(mFour), "1 is -1 mod 4")
+       checkNot(n.IsZero(), "1 is zero")
+       checkYes(n.IsOne(), "1 is not one")
+       checkYes(n.IsOdd(), "1 is not odd")
+       n.SubOne(mFour)
+       checkNot(n.IsMinusOne(mFour), "0 is -1 mod 4")
+       checkYes(n.IsZero(), "0 is not zero")
+       checkNot(n.IsOne(), "0 is one")
+       checkNot(n.IsOdd(), "0 is odd")
+       n.SubOne(mFour)
+       checkYes(n.IsMinusOne(mFour), "-1 is not -1 mod 4")
+       checkNot(n.IsZero(), "-1 is zero")
+       checkNot(n.IsOne(), "-1 is one")
+       checkYes(n.IsOdd(), "-1 mod 4 is not odd")
+
+       mTwoLimbs := maxModulus(2)
+       n, err = NewNat().SetBytes([]byte{0x01}, mTwoLimbs)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if n.IsOne() != 1 {
+               t.Errorf("1 is not one")
+       }
+}
+
+func TestTrailingZeroBits(t *testing.T) {
+       nb := new(big.Int).SetBytes([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e})
+       nb.Lsh(nb, 128)
+       expected := 129
+       for expected >= 0 {
+               n := NewNat().setBig(nb)
+               if n.TrailingZeroBitsVarTime() != uint(expected) {
+                       t.Errorf("%d != %d", n.TrailingZeroBitsVarTime(), expected)
+               }
+               nb.Rsh(nb, 1)
+               expected--
+       }
+}
+
+func TestRightShift(t *testing.T) {
+       nb, err := cryptorand.Int(cryptorand.Reader, new(big.Int).Lsh(big.NewInt(1), 1024))
+       if err != nil {
+               t.Fatal(err)
+       }
+       for _, shift := range []uint{1, 32, 64, 128, 1024 - 128, 1024 - 64, 1024 - 32, 1024 - 1} {
+               testShift := func(t *testing.T, shift uint) {
+                       n := NewNat().setBig(nb)
+                       oldLen := len(n.limbs)
+                       n.ShiftRightVarTime(shift)
+                       if len(n.limbs) != oldLen {
+                               t.Errorf("len(n.limbs) = %d, want %d", len(n.limbs), oldLen)
+                       }
+                       exp := new(big.Int).Rsh(nb, shift)
+                       if n.asBig().Cmp(exp) != 0 {
+                               t.Errorf("%v != %v", n.asBig(), exp)
+                       }
+               }
+               t.Run(fmt.Sprint(shift-1), func(t *testing.T) { testShift(t, shift-1) })
+               t.Run(fmt.Sprint(shift), func(t *testing.T) { testShift(t, shift) })
+               t.Run(fmt.Sprint(shift+1), func(t *testing.T) { testShift(t, shift+1) })
+       }
+}
+
 func natBytes(n *Nat) []byte {
        return n.Bytes(maxModulus(uint(len(n.limbs))))
 }
diff --git a/src/crypto/internal/fips140/rsa/keygen.go b/src/crypto/internal/fips140/rsa/keygen.go
new file mode 100644 (file)
index 0000000..e06e4cf
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright 2024 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 rsa
+
+import (
+       "crypto/internal/fips140/bigmod"
+       "crypto/internal/fips140/drbg"
+       "errors"
+)
+
+// isPrime runs the Miller-Rabin Probabilistic Primality Test from
+// FIPS 186-5, Appendix B.3.1.
+//
+// w must be a random odd integer greater than three in big-endian order.
+// isPrime might return false positives for adversarially chosen values.
+//
+// isPrime is not constant-time.
+func isPrime(w []byte) bool {
+       mr, err := millerRabinSetup(w)
+       if err != nil {
+               // w is zero, one, or even.
+               return false
+       }
+
+       // iterations is the number of Miller-Rabin rounds, each with a
+       // randomly-selected base.
+       //
+       // The worst case false positive rate for a single iteration is 1/4 per
+       // https://eprint.iacr.org/2018/749, so if w were selected adversarially, we
+       // would need up to 64 iterations to get to a negligible (2⁻¹²⁸) chance of
+       // false positive.
+       //
+       // However, since this function is only used for randomly-selected w in the
+       // context of RSA key generation, we can use a smaller number of iterations.
+       // The exact number depends on the size of the prime (and the implied
+       // security level). See BoringSSL for the full formula.
+       // https://cs.opensource.google/boringssl/boringssl/+/master:crypto/fipsmodule/bn/prime.c.inc;l=208-283;drc=3a138e43
+       bits := mr.w.BitLen()
+       var iterations int
+       switch {
+       case bits >= 3747:
+               iterations = 3
+       case bits >= 1345:
+               iterations = 4
+       case bits >= 476:
+               iterations = 5
+       case bits >= 400:
+               iterations = 6
+       case bits >= 347:
+               iterations = 7
+       case bits >= 308:
+               iterations = 8
+       case bits >= 55:
+               iterations = 27
+       default:
+               iterations = 34
+       }
+
+       b := make([]byte, (bits+7)/8)
+       for {
+               drbg.Read(b)
+               if excess := len(b)*8 - bits; excess != 0 {
+                       b[0] >>= excess
+               }
+               result, err := millerRabinIteration(mr, b)
+               if err != nil {
+                       // b was rejected.
+                       continue
+               }
+               if result == millerRabinCOMPOSITE {
+                       return false
+               }
+               iterations--
+               if iterations == 0 {
+                       return true
+               }
+       }
+}
+
+type millerRabin struct {
+       w *bigmod.Modulus
+       a uint
+       m []byte
+}
+
+// millerRabinSetup prepares state that's reused across multiple iterations of
+// the Miller-Rabin test.
+func millerRabinSetup(w []byte) (*millerRabin, error) {
+       mr := &millerRabin{}
+
+       // Check that w is odd, and precompute Montgomery parameters.
+       wm, err := bigmod.NewModulus(w)
+       if err != nil {
+               return nil, err
+       }
+       if wm.Nat().IsOdd() == 0 {
+               return nil, errors.New("candidate is even")
+       }
+       mr.w = wm
+
+       // Compute m = (w-1)/2^a, where m is odd.
+       wMinus1 := mr.w.Nat().SubOne(mr.w)
+       if wMinus1.IsZero() == 1 {
+               return nil, errors.New("candidate is one")
+       }
+       mr.a = wMinus1.TrailingZeroBitsVarTime()
+
+       // Store mr.m as a big-endian byte slice with leading zero bytes removed,
+       // for use with [bigmod.Nat.Exp].
+       m := wMinus1.ShiftRightVarTime(mr.a)
+       mr.m = m.Bytes(mr.w)
+       for mr.m[0] == 0 {
+               mr.m = mr.m[1:]
+       }
+
+       return mr, nil
+}
+
+const millerRabinCOMPOSITE = false
+const millerRabinPOSSIBLYPRIME = true
+
+func millerRabinIteration(mr *millerRabin, bb []byte) (bool, error) {
+       // Reject b ≤ 1 or b ≥ w − 1.
+       if len(bb) != (mr.w.BitLen()+7)/8 {
+               return false, errors.New("incorrect length")
+       }
+       b := bigmod.NewNat()
+       if _, err := b.SetBytes(bb, mr.w); err != nil {
+               return false, err
+       }
+       if b.IsZero() == 1 || b.IsOne() == 1 || b.IsMinusOne(mr.w) == 1 {
+               return false, errors.New("out-of-range candidate")
+       }
+
+       // Compute b^(m*2^i) mod w for successive i.
+       // If b^m mod w = 1, b is a possible prime.
+       // If b^(m*2^i) mod w = -1 for some 0 <= i < a, b is a possible prime.
+       // Otherwise b is composite.
+
+       // Start by computing and checking b^m mod w (also the i = 0 case).
+       z := bigmod.NewNat().Exp(b, mr.m, mr.w)
+       if z.IsOne() == 1 || z.IsMinusOne(mr.w) == 1 {
+               return millerRabinPOSSIBLYPRIME, nil
+       }
+
+       // Check b^(m*2^i) mod w = -1 for 0 < i < a.
+       for range mr.a - 1 {
+               z.Mul(z, mr.w)
+               if z.IsMinusOne(mr.w) == 1 {
+                       return millerRabinPOSSIBLYPRIME, nil
+               }
+               if z.IsOne() == 1 {
+                       // Future squaring will not turn z == 1 into -1.
+                       break
+               }
+       }
+
+       return millerRabinCOMPOSITE, nil
+}
diff --git a/src/crypto/internal/fips140/rsa/keygen_test.go b/src/crypto/internal/fips140/rsa/keygen_test.go
new file mode 100644 (file)
index 0000000..7d613e6
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2024 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 rsa
+
+import (
+       "bufio"
+       "encoding/hex"
+       "fmt"
+       "os"
+       "strings"
+       "testing"
+)
+
+func TestMillerRabin(t *testing.T) {
+       f, err := os.Open("testdata/miller_rabin_tests.txt")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var expected bool
+       var W, B string
+       var lineNum int
+       scanner := bufio.NewScanner(f)
+       for scanner.Scan() {
+               lineNum++
+               line := scanner.Text()
+               if len(line) == 0 || line[0] == '#' {
+                       continue
+               }
+
+               k, v, _ := strings.Cut(line, " = ")
+               switch k {
+               case "Result":
+                       switch v {
+                       case "Composite":
+                               expected = millerRabinCOMPOSITE
+                       case "PossiblyPrime":
+                               expected = millerRabinPOSSIBLYPRIME
+                       default:
+                               t.Fatalf("unknown result %q on line %d", v, lineNum)
+                       }
+               case "W":
+                       W = v
+               case "B":
+                       B = v
+
+                       t.Run(fmt.Sprintf("line %d", lineNum), func(t *testing.T) {
+                               if len(W)%2 != 0 {
+                                       W = "0" + W
+                               }
+                               for len(B) < len(W) {
+                                       B = "0" + B
+                               }
+
+                               mr, err := millerRabinSetup(decodeHex(t, W))
+                               if err != nil {
+                                       t.Logf("W = %s", W)
+                                       t.Logf("B = %s", B)
+                                       t.Fatalf("failed to set up Miller-Rabin test: %v", err)
+                               }
+
+                               result, err := millerRabinIteration(mr, decodeHex(t, B))
+                               if err != nil {
+                                       t.Logf("W = %s", W)
+                                       t.Logf("B = %s", B)
+                                       t.Fatalf("failed to run Miller-Rabin test: %v", err)
+                               }
+
+                               if result != expected {
+                                       t.Logf("W = %s", W)
+                                       t.Logf("B = %s", B)
+                                       t.Fatalf("unexpected result: got %v, want %v", result, expected)
+                               }
+                       })
+               default:
+                       t.Fatalf("unknown key %q on line %d", k, lineNum)
+               }
+       }
+       if err := scanner.Err(); err != nil {
+               t.Fatal(err)
+       }
+}
+
+func decodeHex(t *testing.T, s string) []byte {
+       t.Helper()
+       b, err := hex.DecodeString(s)
+       if err != nil {
+               t.Fatalf("failed to decode hex %q: %v", s, err)
+       }
+       return b
+}
diff --git a/src/crypto/internal/fips140/rsa/testdata/miller_rabin_tests.txt b/src/crypto/internal/fips140/rsa/testdata/miller_rabin_tests.txt
new file mode 100644 (file)
index 0000000..10e9685
--- /dev/null
@@ -0,0 +1,344 @@
+# This file contains test vectors for whether B is a Miller-Rabin composite
+# witness for W. W must be odd and B must satisfy 1 <= B <= W-1.
+#
+# It was copied from BoringSSL's crypto/fipsmodule/bn/test/miller_rabin_tests.txt,
+# removing out-of-range candidates that we reject within the iteration function.
+
+# Exhaustively test a small prime.
+
+Result = PossiblyPrime
+W = 7
+B = 2
+
+Result = PossiblyPrime
+W = 7
+B = 3
+
+Result = PossiblyPrime
+W = 7
+B = 4
+
+Result = PossiblyPrime
+W = 7
+B = 5
+
+
+# Random large inputs which try to cover a few cases. The nontrivial square root
+# case appears to be difficult to hit randomly.
+
+# b^m = w-1
+Result = PossiblyPrime
+W = d6b4ffc7cf70b2a2fc5d6023015875504d40e3dcce7c2e6b762c3de7bb806a5074144e7054198dabf53d23108679ccc541d5a99efeb1d1abaf89e0dbcead2a8b
+B = fabbafdbec6494ddb5ea4bf458536e87082369b0e53a200ed413f3e64b2fddc7c57c565710fbe73fae5b188fce97d8dcca74c2b5d90906c96d3c2c358a735cd
+
+# b^m = w-1
+Result = PossiblyPrime
+W = 52cc61c42b341ad56dc11495e7cb2fe31e506b9e99522efbf44cd7c28468d3833c5e360f3c77b0aa43c0495c4e14665ab0d7cee9294c722f0de47d4401828401
+B = 3bdc9639c0fc2e77ab48d46e0b4ac6529c11c900e8fe4d82d75767c0556feb23d3f42d4924d16876a743feb386b7b84c7fd16a6c252f662faf0024d19972e62f
+
+# b^m = w-1
+Result = PossiblyPrime
+W = cff9897aa7dce0f2afad262b2de57d301305de717f3539c537c4ce062f8cb70df13fbc1eb4a3b9f0958a8810d1ca9042b4f23334b285a15fee3fc66498761d4b
+B = 9ceb43132fddf9ee4104ea1cb3eb2253c1d7f803f05f0305de9e31a17dd75832f47b8bf189a9b7ca0905f2a7470d9c6349080f481ff1708696fa12d972e7d7ba
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 67d1825dad5344170e65247a87aef1634a1b32bdc22f2f04d9d2959767bb5a27610fba55cd607e0f9fdd9fbb0f7f98e40d5e1eb2f52318fb5be4dbfd30d38861
+B = 260fb14724ff80984736859d8755ee98b25bcb56db9fde1db001a1e1273374034c5b75fd60b3710c7a08ce7d390776f010f384d4e32943cf0c477497d53e9e05
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = ad0bc85b58aaa204177aa9431a40929beb1cbea2dd6f66a25cc54600013213b225ba881805661df43f4208965ada7aacc8095d07d3cbef1a7bbfaae8b745f731
+B = 3d9310f20e9c80269fa6830c7e1a6f02fc5c58646001a9ef6b8b3e496602ff22c3dcb2ddb6a221723fc1722ce237fb46f7a7bb2945e415c8839b15a972f076c9
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = b25c917f55f6c7b596921daba919f35039e5d805119c1587e99849dd7104460c86214f162a6f17aea847bc7f3859e59f2991d457059511972ef373d4bc75e309
+B = a1f10b261dee84619b0423201d46af19eef9ec0612cf947c4d5c36c0c4b28207f75967e69452eabad0a5dcd28f27f7a8a7ed9c8b3e5026c6e0ba5634d94c2d44
+
+# b^m = 1
+Result = PossiblyPrime
+W = d3eeb0eff05b6992e9fa61b02755e155f4aae28c6e45ddb874edd86acdd2d83d18a20e0e00d8b8bc94b92d14fc3f41ced6ababe8ac98c7730c075dbe0f699369
+B = 6b7717269c6225203681a1cacec87cacd83003ec6e9e3f04effcc4f86634770c0860e1f2770b8f303719a44949664a1094205a99d95a0856758fed66d690105e
+
+# b^m = 1
+Result = PossiblyPrime
+W = 64561b8d9aa50340c3a01ccb3e6e17f5023513661c012be288f3900a3ca76890e67290b9560fa1d480f9d2aacccca581b5690636665f243fa13aff5d0bff12d3
+B = 1f5ff70d3d60671ebc5fbfca731898a04438053dbc3c841e6335f487e457d92d9efb5d506d5bef6872d58d12b9a41c950bfc38d12ed977c90eacdd6535b811a0
+
+# b^m = 1
+Result = PossiblyPrime
+W = 69c63fbf44df21b0ed0ee929a740c12d1f3f064da0dcd9d509f31fa45fa27d1a759ab5a9f6f1040d7ee90a0b1e68f779273c41ea1c1198fd547ff6bd70c7e787
+B = 5f7996a9bbfd8fd88e472220b70077bfdacdd63d88885134431f024c2acb7126827b174eb093eb5313f07bb5461de9b0feb7d77ca2c39c2a323a150f33ea525f
+
+# End of iteration
+Result = Composite
+W = 28cc3e08c44571c6dcb98a9ab8b4f3e2b16e1f884997d94a3188bcbb7f1b7cdaecdae8329c013ec8f75dc00004da0039943e4262cd080b16a42910102e00dddb
+B = 512061ab1c69931c2fa0bb89d8d09f3c9209230bf927ddd6fb6a72075f967ed3c4dbb5f437bf4d31ca7344782b22011ad56609dc19aed65319bababfc13dd7
+
+# End of iteration
+Result = Composite
+W = 4eeb7b4d371c45fe8586fee3b1efd792176b70f6cc2698dfa1dd028366626febe0199c3c5f77a5c3cad0057a04767383051d41965255d03681b2a37edad34a9b
+B = 4afc2e85f84017b3fd6967a227eb74c8297b40ea02733d9513bff9b3f01081963f25872f4254afc4e9321eea35b2a1e42eadb186fcc84f2f30f4a994350b93b8
+
+# End of iteration
+Result = Composite
+W = 8e35a959555dd2eb66c65cee3c264071d20671f159e1f9896f1d0ceb041905fcf053eacc189de317c3ee6f93901223cbf30d5b7ddbbdab981790e2f6397e6803
+B = 44c0153759309ec4e5b1e59d57c1b126545ef7ea302b6e43561df4d16068b922389d6924f01c945d9080d1f93a0732599bdedae72d6d590839dc0884dd860441
+
+
+# 0x6c1 = 1729 = 7 * 13 * 19 is a Fermat pseudoprime.
+
+# Found non-trivial square root
+Result = Composite
+W = 6c1
+B = b8
+
+# End of iteration
+Result = Composite
+W = 6c1
+B = 111
+
+# End of iteration
+Result = Composite
+W = 6c1
+B = 11d
+
+# Found non-trivial square root
+Result = Composite
+W = 6c1
+B = 19c
+
+# Found non-trivial square root
+Result = Composite
+W = 6c1
+B = 223
+
+# End of iteration
+Result = Composite
+W = 6c1
+B = 3aa
+
+# Found non-trivial square root
+Result = Composite
+W = 6c1
+B = 653
+
+
+# 1729 has a number of false witnesses.
+
+# b^m = 1
+Result = PossiblyPrime
+W = 6c1
+B = 78
+
+# b^m = 1
+Result = PossiblyPrime
+W = 6c1
+B = eb
+
+# b^m = w-1
+Result = PossiblyPrime
+W = 6c1
+B = 178
+
+# b^m = w-1
+Result = PossiblyPrime
+W = 6c1
+B = 178
+
+# b^m = w-1
+Result = PossiblyPrime
+W = 6c1
+B = 1aa
+
+# b^m = 1
+Result = PossiblyPrime
+W = 6c1
+B = 271
+
+# b^m = 1
+Result = PossiblyPrime
+W = 6c1
+B = 2b2
+
+
+# https://kconrad.math.uconn.edu/blurbs/ugradnumthy/millerrabin.pdf, examples
+# 3.1 and 3.2 has a complete list of false witnesses for 65 = 0x41 and
+# 85 = 0x55.
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 41
+B = 8
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 41
+B = 12
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 41
+B = 2f
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 41
+B = 39
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 55
+B = d
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 55
+B = 26
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 55
+B = 2f
+
+# Some b^(m*2^j) = w-1
+Result = PossiblyPrime
+W = 55
+B = 48
+
+# Other witnesses for 65 and 85 will report composite:
+
+# Found non-trivial square root
+Result = Composite
+W = 41
+B = 2c
+
+# End of iteration
+Result = Composite
+W = 41
+B = 16
+
+# End of iteration
+Result = Composite
+W = 41
+B = 14
+
+# End of iteration
+Result = Composite
+W = 41
+B = 2
+
+# End of iteration
+Result = Composite
+W = 41
+B = 3a
+
+# End of iteration
+Result = Composite
+W = 55
+B = 40
+
+# End of iteration
+Result = Composite
+W = 55
+B = 7
+
+# End of iteration
+Result = Composite
+W = 55
+B = 23
+
+# End of iteration
+Result = Composite
+W = 55
+B = 2e
+
+# End of iteration
+Result = Composite
+W = 55
+B = 2a
+
+# W below is composite, but it is one of the worst case scenarios for
+# Miller-Rabin, from Wycheproof tests. 1/4 of witnesses report the value is
+# prime. Test that we correctly classify false and true witnesses.
+
+# b^m = w-1
+Result = PossiblyPrime
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 379c6027f818b5164bc13dff5e996ec7210976f33570d5c60275918b8988d97a63bb6582af85682c45667a8b94b7acab4d919ede00f5bd2ba7abc8634d66f8875fd930f35ec8013d37b958e65f07de015c0574e64198d73aab5466f3a971b74830b7f1671cb9277fbc95c1ba8c29dc903d8cea1b74c22ab9164f9c438ab9ba7d9919f832e40c3e36faca7343e2314669b0104d9c4f2e1b011cdbd9c686baef0
+
+# b^m = w-1
+Result = PossiblyPrime
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 3cc4b644965b2133caffc2bb6258b1ecd5b586b900a09b010382fcef709e4cd37ee3e3182bf8d393c1ab6f9a933d46338b3d960923d8c9607c2b2763d5680230a2bc0c91138e9d0ecb35e7154a06aaa902d34b9b14964b81f4d8232641492d83b22cd805a115e75ddd8e63b864c00e4c90ba36a41e7966e97e063a60a6a6cfd53e1f62a57852c7443e88dcf6245557a4b65494c3e88e466ad75316aaa9727def
+
+# b^m = 1
+Result = PossiblyPrime
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 40c03b6ba22bd62c0379b1c36dfccd34d61e3d15f7af1d5f6a60ab972a9d0e956e2bb9e275294e0f1c879eb7a4555443429c99a8d74f7bd359a1046ac30072c04b0e2cbd005be15ff4ce0c93276de2c513fbc5771b5059904a87f180530f6773498114b5aaf70da01967d8294742e451df6377dd5e64b2a8968f4ba61b51a154317d63958ff3788defbeeebee21af5027c2291e8c5df8c0b66770d91b683cffe
+
+# b^m = w-1
+Result = PossiblyPrime
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 3c7c71b84f0c6c3817f57511946315cec7d0120a9c30ceabda801fbaec329a8f10c7b9f0ae90a3dada9885bf73a3cabed86784af9682f3dea50a7817f65cfc9190cf997f12784223c4965ed6e52a1be26d4dde31741cd3d1a2e2f3a74040d0f3868eef849727aa855f66c94791194ad5d360298364e2de9ca9288e6423f644b01d52e1bd66a9f7f00bd7995a9ca2ed16f40e902852c6250a3b52bbbf5bfd33e8
+
+# b^m = w-1
+Result = PossiblyPrime
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 36e6aa9acb399a50f52be0324dcef05f3cff3117f94538f6d0952b7d7be88ba4dc75d843ff7ff775e11f55c86ba6b2a6ddebd8850c33424b4d35c66321af426662e7074f0a2409a9ccf1c66ef7d823efc8240b8f3c7e9e8dd65a64e8a3ca5b26695ef17171ffe136c0593b179414c5b5ad0d66f2a25146c38b2f97e60b0472ed72de34bff1b6ac186f23645a1bbe909cdfc2b2d861eb44931568f1bb117d8a0c
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 278f2215d3ab836043fbfa472216bbdcedb775a6a0ed711754d05aa75089a9e5d8201e113d68656f37381e44483cd365f5d383bdca5ae8d1f2e6575d7873851cfff0e12b1cfe100a04cb300cbd924353fcbd3307d01242cf6a5e86e752c6f4586bcabf48b018bb97e65c3ed409fd6f67f98987517356d88344b3c8945ccd753148a37b648dd2db44d19522a69a9ad8eb23edc55340e85a198abf179ad731db41
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = afa1478bebbfe1157568f4ae53549b4c3a6a8771b816970bfac6ce5c8b962231db7a41da4d5f1d8bf504dcfe440325b54e1888bdae344eb969436a35e5c6ce5300d46313cb2fcb57fc83305f65f53d392de400e9231cbbc2ac8243defcaf7063c632b9601a81d83138274702ff336d727d3e82ccacce069843ac9c1c590c772c8c586b65c7085a1df5a47fc960d4098a22418b41f0062c77b5d55d17149d167
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 10f7030590b629e0313a61bdf46936a1f25db91b2b421f7ebb671f7844c22561b44b2f7699db61e5228ebb5817afad416325f9439eff7a82d8a630c504de12eaa44d97c79ee56e726ae74ee0b472f0d5fa8f20aee426e689cd33dd084f96bf4d928a21e815f7e8aaca4a5752f39c4a76bdfaa8227dc05d0dfa885d8b26d46fbcbf0d2e0d999d2c31ad84c306c9126539dbdf447f8dc707d29c7fa8021a767668
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 97dbb6a55c039ec926aaa5ff15a2917a2b4cafc3ca07c4c6b05f931d86c9bf60ee05cbbace194e5ca97682ec67c36394018d68c3536fbf13b50f8a7e31eaed87307759a0a48c6c58d21bc7c38b878c53db5d7a8e1fdd81abefc50470a3800852e74d76fdd1933e45f39ee97b8efb68837721890d867b32a894dd0ceb4c5844a05d384145865c10973ce748ccdd8fee73f1bf8611ce0535430b6b98fb36cad7a
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 225f58add44ed2b0a64a1d8452866d0f3c0cd45c8375e1bb33c188915c77fa11b81250b920245dda7f6126e5e0c79e6f98f89dc15db86394cf81b44f0d801e613fa4d5c6fef66fa31f26cfe6153f2e8159aad6b0351dcc0e93f9a68f649b2a77cff747b605b542d22419166befebec6cde3201e3c0cacaa2bc9d87073b8d1f1aa2b114d61de45ac8b0ad2141b43434a629ef284cd999fd82b310db7c57cf5c81
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 2780926c9cf7c1eb2aaa935d90b6d4dea44eeefdfcf9ccd4a33feb215e3a1cb2d358136a490fed18403947f3d98807819737c66e12d42c3cc8c0e246b96b3c3b0795ab875fbaf668b81b5b05bf23e258ea00a0a140a790f76e04ab619800b7597f614ffc1a1c94be2f3f1a71d64eb47d98e4653d76eabedacff3a97ecf590e6a1fd55096b7bc9314629f698d0fbe9b01a1f2bc0bf3a2c097f99f1fd222b52ed2
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 129cc5b0d9f8001b3895f1fcb4833779763636aeeeb3f980e63ea506202e6bde868444b6a58ff1dca08625f025a7e95a5eaaf1a8899eee640e3f05fbdb2867e2483bdc27c87b58684416e521c107f3667ed8dd23f0381edab767c5205a4378118bc011947cb6bdfe3fa4af50b8de876b555c9a0b2b0dae01261847f63e1e0cac2d032530bf19d5da60a04dfe22ce6343f60defbb94ccf0bdf010f89a4029720
+
+# b^m = 1
+Result = PossiblyPrime
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 4e2a47cf67c3331b1e9976f583f6339cf76a8d48682d01355c25b2aed90c5544e737ecfa849c17d27a64fad7e659ef48df9a3ac0410e5c7ca8d087fc3a3ba23e5a3f000be009fcc8227ead28158c5b5d66f2efb47111638ef61cea4984de42fbd476bc2236ad02154d3ce85805c45e49d16b496e313a4052a37d4b88a3b13e598d2074a3e36a37e90278601f2b2305e034f9bf3aea8e939c3ba274e8ff4d8a14
+
+# b^m = 1
+Result = PossiblyPrime
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 2455c4ab826e2ae72708a8ff51348ce4821cb86fa89e298c751c1754211c63b2e9a712d40f0235f310606fcf296726a86973f19f890d571f5b90f026e8d24d07bc0478a3c1333171587387f1f7fe4a770b593216f2743318aabacb3320c40a4e52b9f409e1176fe8db099e93a7991eb8568168e2e486fa5aa228bb1dce9df3290ef13fd21c331479bb0f8b7a7e7f03c5211ae8cc46fa4d0f46e86b2dadeddd5b
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 9951c2c02dd7deedce29bd0c78dd80066b1d69c0e6fe4a17f7d03c6a640d866d01fc8214bafb6737efd93d80a35b8993f5367ce287459b07954e9771ffbc72ccdd812d26a9bf4be0292a24eb5c3b56f09619b1c1b481f7566f7e50e65f69f5feb591bd107fec72a783429dbde6e2607f3db2c58d4b070a45b4d6b43537e19942ce890b04ae1e91069c04a96ed03ddb2f4fc456f136b98102c70a15700dbd911
+
+# End of iteration
+Result = Composite
+W = 550fda19f97cdfbd13930911ef6e9e1cb2b7b5215a35c215d51ebffeb435642174cbe998f4451bde2d4bd2ce92ab5b9493b657f1d77d9ad4d348550247b903906109c608ecba7f88c239c76f0afc231e7f1ac1cee87b4c34448a16f7979ff4c18e65e05d5a86909615fe56587576962a2cb3ba467d9806445a0f039907601af77ba7d07578eff612364fbcac11d35e243734aa6d9a6cdcf912a2dd0a12ba7e87
+B = 4cb8217d229d5f95f6d94807a99363823655d6bba6bdafa4f0dbfe7a5c538aa79c918710aad4f55caaee5ab405ebdcef29dfb76cae99fca8d5a955b6315f71a3cb2d69a217ff45aed66ba87cdc5c0de5d512c6dd12e641e9fe6a2557dd2f03bf3a18650ff139efa179f0fbe69cbb4b54e50d13177bfe7bb90de36b548d5ccfef74b05d3c08a7e2a3bb4dc8d7eb338a7a1b068c433ea204d171eda5e7c6b6722c
index eb6ce73e0f1a97ec8419ca98a925d6890109ab14..3c9b98eae98079011cfd7677163d254a92a66b7c 100644 (file)
@@ -243,10 +243,6 @@ func (priv *PrivateKey) Validate() error {
        if err != nil {
                return fmt.Errorf("crypto/rsa: invalid private exponent: %v", err)
        }
-       one, err := bigmod.NewNat().SetUint(1, N)
-       if err != nil {
-               return fmt.Errorf("crypto/rsa: internal error: %v", err)
-       }
 
        Π := bigmod.NewNat().ExpandFor(N)
        for _, prime := range priv.Primes {
@@ -254,7 +250,7 @@ func (priv *PrivateKey) Validate() error {
                if err != nil {
                        return fmt.Errorf("crypto/rsa: invalid prime: %v", err)
                }
-               if p.IsZero() == 1 {
+               if p.IsZero() == 1 || p.IsOne() == 1 {
                        return errors.New("crypto/rsa: invalid prime")
                }
                Π.Mul(p, N)
@@ -265,11 +261,7 @@ func (priv *PrivateKey) Validate() error {
                // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1
                // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required.
 
-               p.Sub(one, N)
-               if p.IsZero() == 1 {
-                       return errors.New("crypto/rsa: invalid prime")
-               }
-               pMinus1, err := bigmod.NewModulus(p.Bytes(N))
+               pMinus1, err := bigmod.NewModulus(p.SubOne(N).Bytes(N))
                if err != nil {
                        return fmt.Errorf("crypto/rsa: internal error: %v", err)
                }
@@ -278,16 +270,11 @@ func (priv *PrivateKey) Validate() error {
                if err != nil {
                        return fmt.Errorf("crypto/rsa: invalid public exponent: %v", err)
                }
-               one, err := bigmod.NewNat().SetUint(1, pMinus1)
-               if err != nil {
-                       return fmt.Errorf("crypto/rsa: internal error: %v", err)
-               }
 
                de := bigmod.NewNat()
                de.Mod(d, pMinus1)
                de.Mul(e, pMinus1)
-               de.Sub(one, pMinus1)
-               if de.IsZero() != 1 {
+               if de.IsOne() != 1 {
                        return errors.New("crypto/rsa: invalid exponents")
                }
        }