]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/rsa: improve benchmarks
authorFilippo Valsorda <filippo@golang.org>
Mon, 19 Sep 2022 13:33:49 +0000 (15:33 +0200)
committerGopher Robot <gobot@golang.org>
Tue, 15 Nov 2022 00:16:30 +0000 (00:16 +0000)
Change-Id: Idee03a0c3e4bdb7d6b495f567db8bd644af480e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/433476
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
src/crypto/rsa/boring_test.go
src/crypto/rsa/example_test.go
src/crypto/rsa/pkcs1v15_test.go
src/crypto/rsa/pss_test.go
src/crypto/rsa/rsa_export_test.go [new file with mode: 0644]
src/crypto/rsa/rsa_test.go

index 6223244283fad9157f1720dbe3ee0a0c4cd7ddd7..2234d079f0d9e7fa5f0c1c8bbcd6a4013242757e 100644 (file)
@@ -13,6 +13,8 @@ import (
        "crypto"
        "crypto/rand"
        "encoding/asn1"
+       "encoding/hex"
+       "math/big"
        "runtime"
        "runtime/debug"
        "sync"
@@ -128,3 +130,19 @@ func TestBoringFinalizers(t *testing.T) {
                wg.Wait()
        }
 }
+
+func bigFromHex(hex string) *big.Int {
+       n, ok := new(big.Int).SetString(hex, 16)
+       if !ok {
+               panic("bad hex: " + hex)
+       }
+       return n
+}
+
+func fromHex(hexStr string) []byte {
+       s, err := hex.DecodeString(hexStr)
+       if err != nil {
+               panic(err)
+       }
+       return s
+}
index ce5c2d91cd423bb0cee3a3940e6b5ba8b16ed5cf..8c3a9973467b0d637d1be59069511ef1f88e3da5 100644 (file)
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package rsa
+package rsa_test
 
 import (
        "crypto"
        "crypto/aes"
        "crypto/cipher"
        "crypto/rand"
+       "crypto/rsa"
        "crypto/sha256"
        "encoding/hex"
        "fmt"
@@ -50,7 +51,7 @@ func ExampleDecryptPKCS1v15SessionKey() {
 
        rsaCiphertext, _ := hex.DecodeString("aabbccddeeff")
 
-       if err := DecryptPKCS1v15SessionKey(rng, rsaPrivateKey, rsaCiphertext, key); err != nil {
+       if err := rsa.DecryptPKCS1v15SessionKey(rng, rsaPrivateKey, rsaCiphertext, key); err != nil {
                // Any errors that result will be “public” – meaning that they
                // can be determined without any secret information. (For
                // instance, if the length of key is impossible given the RSA
@@ -99,7 +100,7 @@ func ExampleSignPKCS1v15() {
        // of writing (2016).
        hashed := sha256.Sum256(message)
 
-       signature, err := SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, hashed[:])
+       signature, err := rsa.SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, hashed[:])
        if err != nil {
                fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err)
                return
@@ -119,7 +120,7 @@ func ExampleVerifyPKCS1v15() {
        // of writing (2016).
        hashed := sha256.Sum256(message)
 
-       err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature)
+       err := rsa.VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature)
        if err != nil {
                fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err)
                return
@@ -136,7 +137,7 @@ func ExampleEncryptOAEP() {
        // encryption function.
        rng := rand.Reader
 
-       ciphertext, err := EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label)
+       ciphertext, err := rsa.EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label)
        if err != nil {
                fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
                return
@@ -155,7 +156,7 @@ func ExampleDecryptOAEP() {
        // operation.
        rng := rand.Reader
 
-       plaintext, err := DecryptOAEP(sha256.New(), rng, test2048Key, ciphertext, label)
+       plaintext, err := rsa.DecryptOAEP(sha256.New(), rng, test2048Key, ciphertext, label)
        if err != nil {
                fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
                return
index 69c509a7713c90a814c2bc63e863131650d3a017..dfa1eddc886ff3745b2ad1cc6fc908087c0675ae 100644 (file)
@@ -2,18 +2,20 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package rsa
+package rsa_test
 
 import (
        "bytes"
        "crypto"
        "crypto/rand"
+       . "crypto/rsa"
        "crypto/sha1"
        "crypto/sha256"
+       "crypto/x509"
        "encoding/base64"
        "encoding/hex"
+       "encoding/pem"
        "io"
-       "math/big"
        "testing"
        "testing/quick"
 )
@@ -170,7 +172,7 @@ func TestNonZeroRandomBytes(t *testing.T) {
        random := rand.Reader
 
        b := make([]byte, 512)
-       err := nonZeroRandomBytes(b, random)
+       err := NonZeroRandomBytes(b, random)
        if err != nil {
                t.Errorf("returned error: %s", err)
        }
@@ -276,34 +278,30 @@ func TestShortSessionKey(t *testing.T) {
        }
 }
 
-// In order to generate new test vectors you'll need the PEM form of this key (and s/TESTING/PRIVATE/):
-// -----BEGIN RSA TESTING KEY-----
-// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
-// fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
-// /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
-// RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
-// EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
-// IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
-// tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
-// -----END RSA TESTING KEY-----
-
-var rsaPrivateKey = &PrivateKey{
-       PublicKey: PublicKey{
-               N: fromBase10("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
-               E: 65537,
-       },
-       D: fromBase10("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
-       Primes: []*big.Int{
-               fromBase10("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
-               fromBase10("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
-       },
+var rsaPrivateKey = parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA TESTING KEY-----`))
+
+func parsePublicKey(s string) *PublicKey {
+       p, _ := pem.Decode([]byte(s))
+       k, err := x509.ParsePKCS1PublicKey(p.Bytes)
+       if err != nil {
+               panic(err)
+       }
+       return k
 }
 
 func TestShortPKCS1v15Signature(t *testing.T) {
-       pub := &PublicKey{
-               E: 65537,
-               N: fromBase10("8272693557323587081220342447407965471608219912416565371060697606400726784709760494166080686904546560026343451112103559482851304715739629410219358933351333"),
-       }
+       pub := parsePublicKey(`-----BEGIN RSA PUBLIC KEY-----
+MEgCQQCd9BVzo775lkohasxjnefF1nCMcNoibqIWEVDe/K7M2GSoO4zlSQB+gkix
+O3AnTcdHB51iaZpWfxPSnew8yfulAgMBAAE=
+-----END RSA PUBLIC KEY-----`)
        sig, err := hex.DecodeString("193a310d0dcf64094c6e3a00c8219b80ded70535473acff72c08e1222974bb24a93a535b1dc4c59fc0e65775df7ba2007dd20e9193f4c4025a18a7070aee93")
        if err != nil {
                t.Fatalf("failed to decode signature: %s", err)
index ecc02e47d6c837ddc8ac5e8df034c13926b6a476..f1f17043690d193fa50897ab17c1c1f18376896d 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package rsa
+package rsa_test
 
 import (
        "bufio"
@@ -10,6 +10,7 @@ import (
        "compress/bzip2"
        "crypto"
        "crypto/rand"
+       . "crypto/rsa"
        "crypto/sha1"
        "crypto/sha256"
        "encoding/hex"
@@ -60,7 +61,7 @@ func TestEMSAPSS(t *testing.T) {
        hash.Write(msg)
        hashed := hash.Sum(nil)
 
-       encoded, err := emsaPSSEncode(hashed, 1023, salt, sha1.New())
+       encoded, err := EMSAPSSEncode(hashed, 1023, salt, sha1.New())
        if err != nil {
                t.Errorf("Error from emsaPSSEncode: %s\n", err)
        }
@@ -68,7 +69,7 @@ func TestEMSAPSS(t *testing.T) {
                t.Errorf("Bad encoding. got %x, want %x", encoded, expected)
        }
 
-       if err = emsaPSSVerify(hashed, encoded, 1023, len(salt), sha1.New()); err != nil {
+       if err = EMSAPSSVerify(hashed, encoded, 1023, len(salt), sha1.New()); err != nil {
                t.Errorf("Bad verification: %s", err)
        }
 }
@@ -289,8 +290,8 @@ func TestInvalidPSSSaltLength(t *testing.T) {
        if _, err := SignPSS(rand.Reader, key, crypto.SHA256, digest[:], &PSSOptions{
                SaltLength: -2,
                Hash:       crypto.SHA256,
-       }); err.Error() != invalidSaltLenErr.Error() {
-               t.Fatalf("SignPSS unexpected error: got %v, want %v", err, invalidSaltLenErr)
+       }); err.Error() != InvalidSaltLenErr.Error() {
+               t.Fatalf("SignPSS unexpected error: got %v, want %v", err, InvalidSaltLenErr)
        }
 
        // We don't check the specific error here, because crypto/rsa and crypto/internal/boring
diff --git a/src/crypto/rsa/rsa_export_test.go b/src/crypto/rsa/rsa_export_test.go
new file mode 100644 (file)
index 0000000..70406de
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2022 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
+
+var NonZeroRandomBytes = nonZeroRandomBytes
+var EMSAPSSEncode = emsaPSSEncode
+var EMSAPSSVerify = emsaPSSVerify
+var InvalidSaltLenErr = invalidSaltLenErr
index 99b2cf5ae84801bf3c065c89ada74d589653b1fc..400f40a031b1ed2b453dfe17e0f3e352f7475c25 100644 (file)
@@ -2,17 +2,21 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package rsa
+package rsa_test
 
 import (
+       "bufio"
        "bytes"
        "crypto"
-       "crypto/internal/boring"
        "crypto/rand"
+       . "crypto/rsa"
        "crypto/sha1"
        "crypto/sha256"
+       "crypto/x509"
+       "encoding/pem"
        "fmt"
        "math/big"
+       "strings"
        "testing"
 )
 
@@ -91,17 +95,11 @@ func TestGnuTLSKey(t *testing.T) {
        // This is a key generated by `certtool --generate-privkey --bits 128`.
        // It's such that de ≢ 1 mod φ(n), but is congruent mod the order of
        // the group.
-       priv := &PrivateKey{
-               PublicKey: PublicKey{
-                       N: fromBase10("290684273230919398108010081414538931343"),
-                       E: 65537,
-               },
-               D: fromBase10("31877380284581499213530787347443987241"),
-               Primes: []*big.Int{
-                       fromBase10("16775196964030542637"),
-                       fromBase10("17328218193455850539"),
-               },
-       }
+       priv := parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+MGECAQACEQDar8EuoZuSosYtE9SeXSyPAgMBAAECEBf7XDET8e6jjTcfO7y/sykC
+CQDozXjCjkBzLQIJAPB6MqNbZaQrAghbZTdQoko5LQIIUp9ZiKDdYjMCCCCpqzmX
+d8Y7
+-----END RSA TESTING KEY-----`))
        testKeyBasics(t, priv)
 }
 
@@ -113,125 +111,313 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) {
                t.Errorf("private exponent too large")
        }
 
-       if boring.Enabled {
-               // Cannot call encrypt/decrypt directly. Test via PKCS1v15.
-               msg := []byte("hi!")
-               enc, err := EncryptPKCS1v15(rand.Reader, &priv.PublicKey, msg)
-               if err != nil {
-                       t.Errorf("EncryptPKCS1v15: %v", err)
-                       return
-               }
-               dec, err := DecryptPKCS1v15(rand.Reader, priv, enc)
-               if err != nil {
-                       t.Errorf("DecryptPKCS1v15: %v", err)
-                       return
-               }
-               if !bytes.Equal(dec, msg) {
-                       t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
-               }
+       msg := []byte("hi!")
+       enc, err := EncryptPKCS1v15(rand.Reader, &priv.PublicKey, msg)
+       if err != nil {
+               t.Errorf("EncryptPKCS1v15: %v", err)
                return
        }
 
-       pub := &priv.PublicKey
-       m := big.NewInt(42)
-       c := encrypt(new(big.Int), pub, m)
-
-       m2, err := decrypt(nil, priv, c)
+       dec, err := DecryptPKCS1v15(nil, priv, enc)
        if err != nil {
-               t.Errorf("error while decrypting: %s", err)
-               return
+               t.Fatalf("DecryptPKCS1v15: %v", err)
        }
-       if m.Cmp(m2) != 0 {
-               t.Errorf("got:%v, want:%v (%+v)", m2, m, priv)
+       if !bytes.Equal(dec, msg) {
+               t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
        }
 
-       m3, err := decrypt(rand.Reader, priv, c)
+       dec, err = DecryptPKCS1v15(rand.Reader, priv, enc)
        if err != nil {
-               t.Errorf("error while decrypting (blind): %s", err)
+               t.Fatalf("DecryptPKCS1v15: %v", err)
        }
-       if m.Cmp(m3) != 0 {
-               t.Errorf("(blind) got:%v, want:%v (%#v)", m3, m, priv)
+       if !bytes.Equal(dec, msg) {
+               t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
        }
 }
 
-func fromBase10(base10 string) *big.Int {
-       i, ok := new(big.Int).SetString(base10, 10)
-       if !ok {
-               panic("bad number: " + base10)
+func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
+
+func parseKey(s string) *PrivateKey {
+       p, _ := pem.Decode([]byte(s))
+       k, err := x509.ParsePKCS1PrivateKey(p.Bytes)
+       if err != nil {
+               panic(err)
        }
-       return i
+       return k
 }
 
-var test2048Key *PrivateKey
+var test2048Key = parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIEnwIBAAKCAQBxY8hCshkKiXCUKydkrtQtQSRke28w4JotocDiVqou4k55DEDJ
+akvWbXXDcakV4HA8R2tOGgbxvTjFo8EK470w9O9ipapPUSrRRaBsSOlkaaIs6OYh
+4FLwZpqMNBVVEtguVUR/C34Y2pS9kRrHs6q+cGhDZolkWT7nGy5eSEvPDHg0EBq1
+1hu6HmPmI3r0BInONqJg2rcK3U++wk1lnbD3ysCZsKOqRUms3n/IWKeTqXXmz2XK
+J2t0NSXwiDmA9q0Gm+w0bXh3lzhtUP4MlzS+lnx9hK5bjzSbCUB5RXwMDG/uNMQq
+C4MmA4BPceSfMyAIFjdRLGy/K7gbb2viOYRtAgEDAoIBAEuX2tchZgcGSw1yGkMf
+OB4rbZhSSiCVvB5r1ew5xsnsNFCy1ducMo7zo9ehG2Pq9X2E8jQRWfZ+JdkX1gdC
+fiCjSkHDxt+LceDZFZ2F8O2bwXNF7sFAN0rvEbLNY44MkB7jgv9c/rs8YykLZy/N
+HH71mteZsO2Q1JoSHumFh99cwWHFhLxYh64qFeeH6Gqx6AM2YVBWHgs7OuKOvc8y
+zUbf8xftPht1kMwwDR1XySiEYtBtn74JflK3DcT8oxOuCZBuX6sMJHKbVP41zDj+
+FJZBmpAvNfCEYJUr1Hg+DpMLqLUg+D6v5vpliburbk9LxcKFZyyZ9QVe7GoqMLBu
+eGsCgYEAummUj4MMKWJC2mv5rj/dt2pj2/B2HtP2RLypai4et1/Ru9nNk8cjMLzC
+qXz6/RLuJ7/eD7asFS3y7EqxKxEmW0G8tTHjnzR/3wnpVipuWnwCDGU032HJVd13
+LMe51GH97qLzuDZjMCz+VlbCNdSslMgWWK0XmRnN7Yqxvh6ao2kCgYEAm7fTRBhF
+JtKcaJ7d8BQb9l8BNHfjayYOMq5CxoCyxa2pGBv/Mrnxv73Twp9Z/MP0ue5M5nZt
+GMovpP5cGdJLQ2w5p4H3opcuWeYW9Yyru2EyCEAI/hD/Td3QVP0ukc19BDuPl5Wg
+eIFs218uiVOU4pw3w+Et5B1PZ/F+ZLr5LGUCgYB8RmMKV11w7CyRnVEe1T56Ru09
+Svlp4qQt0xucHr8k6ovSkTO32hd10yxw/fyot0lv1T61JHK4yUydhyDHYMQ81n3O
+IUJqIv/qBpuOxvQ8UqwIQ3iU69uOk6TIhSaNlqlJwffQJEIgHf7kOdbOjchjMA7l
+yLpmETPzscvUFGcXmwKBgGfP4i1lg283EvBp6Uq4EqQ/ViL6l5zECXce1y8Ady5z
+xhASqiHRS9UpN9cU5qiCoyae3e75nhCGym3+6BE23Nede8UBT8G6HuaZZKOzHSeW
+IVrVW1QLVN6T4DioybaI/gLSX7pjwFBWSJI/dFuNDexoJS1AyUK+NO/2VEMnUMhD
+AoGAOsdn3Prnh/mjC95vraHCLap0bRBSexMdx77ImHgtFUUcSaT8DJHs+NZw1RdM
+SZA0J+zVQ8q7B11jIgz5hMz+chedwoRjTL7a8VRTKHFmmBH0zlEuV7L79w6HkRCQ
+VRg10GUN6heGLv0aOHbPdobcuVDH4sgOqpT1QnOuce34sQs=
+-----END RSA TESTING KEY-----`))
+
+var test3072Key = parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+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
+-----END RSA TESTING KEY-----`))
+
+var test4096Key = parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+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
+-----END RSA TESTING KEY-----`))
+
+func BenchmarkDecryptPKCS1v15(b *testing.B) {
+       b.Run("2048", func(b *testing.B) { benchmarkDecryptPKCS1v15(b, test2048Key) })
+       b.Run("3072", func(b *testing.B) { benchmarkDecryptPKCS1v15(b, test3072Key) })
+       b.Run("4096", func(b *testing.B) { benchmarkDecryptPKCS1v15(b, test4096Key) })
+}
 
-func init() {
-       test2048Key = &PrivateKey{
-               PublicKey: PublicKey{
-                       N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"),
-                       E: 3,
-               },
-               D: fromBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731"),
-               Primes: []*big.Int{
-                       fromBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433"),
-                       fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"),
-               },
+func benchmarkDecryptPKCS1v15(b *testing.B, k *PrivateKey) {
+       r := bufio.NewReaderSize(rand.Reader, 1<<15)
+
+       m := []byte("Hello Gophers")
+       c, err := EncryptPKCS1v15(r, &k.PublicKey, m)
+       if err != nil {
+               b.Fatal(err)
        }
-       test2048Key.Precompute()
-}
 
-func BenchmarkRSA2048Decrypt(b *testing.B) {
-       if boring.Enabled {
-               b.Skip("no raw decrypt in BoringCrypto")
+       b.ResetTimer()
+       var sink byte
+       for i := 0; i < b.N; i++ {
+               p, err := DecryptPKCS1v15(r, k, c)
+               if err != nil {
+                       b.Fatal(err)
+               }
+               if !bytes.Equal(p, m) {
+                       b.Fatalf("unexpected output: %q", p)
+               }
+               sink ^= p[0]
        }
+}
 
-       b.StopTimer()
+func BenchmarkEncryptPKCS1v15(b *testing.B) {
+       b.Run("2048", func(b *testing.B) {
+               r := bufio.NewReaderSize(rand.Reader, 1<<15)
+               m := []byte("Hello Gophers")
 
-       c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313")
+               var sink byte
+               for i := 0; i < b.N; i++ {
+                       c, err := EncryptPKCS1v15(r, &test2048Key.PublicKey, m)
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+                       sink ^= c[0]
+               }
+       })
+}
 
-       b.StartTimer()
+func BenchmarkDecryptOAEP(b *testing.B) {
+       b.Run("2048", func(b *testing.B) {
+               r := bufio.NewReaderSize(rand.Reader, 1<<15)
 
-       for i := 0; i < b.N; i++ {
-               decrypt(nil, test2048Key, c)
-       }
+               m := []byte("Hello Gophers")
+               c, err := EncryptOAEP(sha256.New(), r, &test2048Key.PublicKey, m, nil)
+               if err != nil {
+                       b.Fatal(err)
+               }
+
+               b.ResetTimer()
+               var sink byte
+               for i := 0; i < b.N; i++ {
+                       p, err := DecryptOAEP(sha256.New(), r, test2048Key, c, nil)
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+                       if !bytes.Equal(p, m) {
+                               b.Fatalf("unexpected output: %q", p)
+                       }
+                       sink ^= p[0]
+               }
+       })
 }
 
-func BenchmarkRSA2048Sign(b *testing.B) {
-       b.StopTimer()
-       hashed := sha256.Sum256([]byte("testing"))
-       b.StartTimer()
+func BenchmarkEncryptOAEP(b *testing.B) {
+       b.Run("2048", func(b *testing.B) {
+               r := bufio.NewReaderSize(rand.Reader, 1<<15)
+               m := []byte("Hello Gophers")
 
-       for i := 0; i < b.N; i++ {
-               SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:])
-       }
+               var sink byte
+               for i := 0; i < b.N; i++ {
+                       c, err := EncryptOAEP(sha256.New(), r, &test2048Key.PublicKey, m, nil)
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+                       sink ^= c[0]
+               }
+       })
 }
 
-func Benchmark3PrimeRSA2048Decrypt(b *testing.B) {
-       if boring.Enabled {
-               b.Skip("no raw decrypt in BoringCrypto")
-       }
+func BenchmarkSignPKCS1v15(b *testing.B) {
+       b.Run("2048", func(b *testing.B) {
+               hashed := sha256.Sum256([]byte("testing"))
 
-       b.StopTimer()
-       priv := &PrivateKey{
-               PublicKey: PublicKey{
-                       N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"),
-                       E: 3,
-               },
-               D: fromBase10("10897585948254795600358846499957366070880176878341177571733155050184921896034527397712889205732614568234385175145686545381899460748279607074689061600935843283397424506622998458510302603922766336783617368686090042765718290914099334449154829375179958369993407724946186243249568928237086215759259909861748642124071874879861299389874230489928271621259294894142840428407196932444474088857746123104978617098858619445675532587787023228852383149557470077802718705420275739737958953794088728369933811184572620857678792001136676902250566845618813972833750098806496641114644760255910789397593428910198080271317419213080834885003"),
-               Primes: []*big.Int{
-                       fromBase10("1025363189502892836833747188838978207017355117492483312747347695538428729137306368764177201532277413433182799108299960196606011786562992097313508180436744488171474690412562218914213688661311117337381958560443"),
-                       fromBase10("3467903426626310123395340254094941045497208049900750380025518552334536945536837294961497712862519984786362199788654739924501424784631315081391467293694361474867825728031147665777546570788493758372218019373"),
-                       fromBase10("4597024781409332673052708605078359346966325141767460991205742124888960305710298765592730135879076084498363772408626791576005136245060321874472727132746643162385746062759369754202494417496879741537284589047"),
-               },
-       }
-       priv.Precompute()
+               var sink byte
+               b.ResetTimer()
+               for i := 0; i < b.N; i++ {
+                       s, err := SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:])
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+                       sink ^= s[0]
+               }
+       })
+}
 
-       c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313")
+func BenchmarkVerifyPKCS1v15(b *testing.B) {
+       b.Run("2048", func(b *testing.B) {
+               hashed := sha256.Sum256([]byte("testing"))
+               s, err := SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:])
+               if err != nil {
+                       b.Fatal(err)
+               }
 
-       b.StartTimer()
+               b.ResetTimer()
+               for i := 0; i < b.N; i++ {
+                       err := VerifyPKCS1v15(&test2048Key.PublicKey, crypto.SHA256, hashed[:], s)
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+               }
+       })
+}
 
-       for i := 0; i < b.N; i++ {
-               decrypt(nil, priv, c)
-       }
+func BenchmarkSignPSS(b *testing.B) {
+       b.Run("2048", func(b *testing.B) {
+               hashed := sha256.Sum256([]byte("testing"))
+
+               var sink byte
+               b.ResetTimer()
+               for i := 0; i < b.N; i++ {
+                       s, err := SignPSS(rand.Reader, test2048Key, crypto.SHA256, hashed[:], nil)
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+                       sink ^= s[0]
+               }
+       })
+}
+
+func BenchmarkVerifyPSS(b *testing.B) {
+       b.Run("2048", func(b *testing.B) {
+               hashed := sha256.Sum256([]byte("testing"))
+               s, err := SignPSS(rand.Reader, test2048Key, crypto.SHA256, hashed[:], nil)
+               if err != nil {
+                       b.Fatal(err)
+               }
+
+               b.ResetTimer()
+               for i := 0; i < b.N; i++ {
+                       err := VerifyPSS(&test2048Key.PublicKey, crypto.SHA256, hashed[:], s, nil)
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+               }
+       })
 }
 
 type testEncryptOAEPMessage struct {