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>
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.
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
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)
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.
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
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 {
}
}
+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))))
}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+}
--- /dev/null
+# 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
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 {
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)
// 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)
}
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")
}
}