summaryrefslogtreecommitdiffstats
path: root/src/crypto/ecdsa/boring.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/ecdsa/boring.go')
-rw-r--r--src/crypto/ecdsa/boring.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/crypto/ecdsa/boring.go b/src/crypto/ecdsa/boring.go
new file mode 100644
index 0000000..275c60b
--- /dev/null
+++ b/src/crypto/ecdsa/boring.go
@@ -0,0 +1,106 @@
+// Copyright 2017 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.
+
+//go:build boringcrypto
+
+package ecdsa
+
+import (
+ "crypto/internal/boring"
+ "crypto/internal/boring/bbig"
+ "crypto/internal/boring/bcache"
+ "math/big"
+)
+
+// Cached conversions from Go PublicKey/PrivateKey to BoringCrypto.
+//
+// The first operation on a PublicKey or PrivateKey makes a parallel
+// BoringCrypto key and saves it in pubCache or privCache.
+//
+// We could just assume that once used in a Sign or Verify operation,
+// a particular key is never again modified, but that has not been a
+// stated assumption before. Just in case there is any existing code that
+// does modify the key between operations, we save the original values
+// alongside the cached BoringCrypto key and check that the real key
+// still matches before using the cached key. The theory is that the real
+// operations are significantly more expensive than the comparison.
+
+var pubCache bcache.Cache[PublicKey, boringPub]
+var privCache bcache.Cache[PrivateKey, boringPriv]
+
+func init() {
+ pubCache.Register()
+ privCache.Register()
+}
+
+type boringPub struct {
+ key *boring.PublicKeyECDSA
+ orig PublicKey
+}
+
+func boringPublicKey(pub *PublicKey) (*boring.PublicKeyECDSA, error) {
+ b := pubCache.Get(pub)
+ if b != nil && publicKeyEqual(&b.orig, pub) {
+ return b.key, nil
+ }
+
+ b = new(boringPub)
+ b.orig = copyPublicKey(pub)
+ key, err := boring.NewPublicKeyECDSA(b.orig.Curve.Params().Name, bbig.Enc(b.orig.X), bbig.Enc(b.orig.Y))
+ if err != nil {
+ return nil, err
+ }
+ b.key = key
+ pubCache.Put(pub, b)
+ return key, nil
+}
+
+type boringPriv struct {
+ key *boring.PrivateKeyECDSA
+ orig PrivateKey
+}
+
+func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyECDSA, error) {
+ b := privCache.Get(priv)
+ if b != nil && privateKeyEqual(&b.orig, priv) {
+ return b.key, nil
+ }
+
+ b = new(boringPriv)
+ b.orig = copyPrivateKey(priv)
+ key, err := boring.NewPrivateKeyECDSA(b.orig.Curve.Params().Name, bbig.Enc(b.orig.X), bbig.Enc(b.orig.Y), bbig.Enc(b.orig.D))
+ if err != nil {
+ return nil, err
+ }
+ b.key = key
+ privCache.Put(priv, b)
+ return key, nil
+}
+
+func publicKeyEqual(k1, k2 *PublicKey) bool {
+ return k1.X != nil &&
+ k1.Curve.Params() == k2.Curve.Params() &&
+ k1.X.Cmp(k2.X) == 0 &&
+ k1.Y.Cmp(k2.Y) == 0
+}
+
+func privateKeyEqual(k1, k2 *PrivateKey) bool {
+ return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
+ k1.D.Cmp(k2.D) == 0
+}
+
+func copyPublicKey(k *PublicKey) PublicKey {
+ return PublicKey{
+ Curve: k.Curve,
+ X: new(big.Int).Set(k.X),
+ Y: new(big.Int).Set(k.Y),
+ }
+}
+
+func copyPrivateKey(k *PrivateKey) PrivateKey {
+ return PrivateKey{
+ PublicKey: copyPublicKey(&k.PublicKey),
+ D: new(big.Int).Set(k.D),
+ }
+}