crypto/internal/fips140/rsa: add Miller-Rabin test

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>
This commit is contained in:
Filippo Valsorda 2024-11-27 18:17:28 +01:00 committed by Gopher Robot
parent caee788a48
commit 22b5c145fb
6 changed files with 799 additions and 19 deletions

View 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

View 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))))
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View 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")
}
}