1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 //go:build boringcrypto
6 7 package ecdsa
8 9 import (
10 "crypto/internal/boring"
11 "crypto/internal/boring/bbig"
12 "crypto/internal/boring/bcache"
13 "math/big"
14 )
15 16 // Cached conversions from Go PublicKey/PrivateKey to BoringCrypto.
17 //
18 // The first operation on a PublicKey or PrivateKey makes a parallel
19 // BoringCrypto key and saves it in pubCache or privCache.
20 //
21 // We could just assume that once used in a Sign or Verify operation,
22 // a particular key is never again modified, but that has not been a
23 // stated assumption before. Just in case there is any existing code that
24 // does modify the key between operations, we save the original values
25 // alongside the cached BoringCrypto key and check that the real key
26 // still matches before using the cached key. The theory is that the real
27 // operations are significantly more expensive than the comparison.
28 29 var pubCache bcache.Cache[PublicKey, boringPub]
30 var privCache bcache.Cache[PrivateKey, boringPriv]
31 32 func init() {
33 pubCache.Register()
34 privCache.Register()
35 }
36 37 type boringPub struct {
38 key *boring.PublicKeyECDSA
39 orig PublicKey
40 }
41 42 func boringPublicKey(pub *PublicKey) (*boring.PublicKeyECDSA, error) {
43 b := pubCache.Get(pub)
44 if b != nil && publicKeyEqual(&b.orig, pub) {
45 return b.key, nil
46 }
47 48 b = &boringPub{}
49 b.orig = copyPublicKey(pub)
50 key, err := boring.NewPublicKeyECDSA(b.orig.Curve.Params().Name, bbig.Enc(b.orig.X), bbig.Enc(b.orig.Y))
51 if err != nil {
52 return nil, err
53 }
54 b.key = key
55 pubCache.Put(pub, b)
56 return key, nil
57 }
58 59 type boringPriv struct {
60 key *boring.PrivateKeyECDSA
61 orig PrivateKey
62 }
63 64 func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyECDSA, error) {
65 b := privCache.Get(priv)
66 if b != nil && privateKeyEqual(&b.orig, priv) {
67 return b.key, nil
68 }
69 70 b = &boringPriv{}
71 b.orig = copyPrivateKey(priv)
72 key, err := boring.NewPrivateKeyECDSA(b.orig.Curve.Params().Name, bbig.Enc(b.orig.X), bbig.Enc(b.orig.Y), bbig.Enc(b.orig.D))
73 if err != nil {
74 return nil, err
75 }
76 b.key = key
77 privCache.Put(priv, b)
78 return key, nil
79 }
80 81 func publicKeyEqual(k1, k2 *PublicKey) bool {
82 return k1.X != nil &&
83 k1.Curve.Params() == k2.Curve.Params() &&
84 k1.X.Cmp(k2.X) == 0 &&
85 k1.Y.Cmp(k2.Y) == 0
86 }
87 88 func privateKeyEqual(k1, k2 *PrivateKey) bool {
89 return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
90 k1.D.Cmp(k2.D) == 0
91 }
92 93 func copyPublicKey(k *PublicKey) PublicKey {
94 return PublicKey{
95 Curve: k.Curve,
96 X: (&big.Int{}).Set(k.X),
97 Y: (&big.Int{}).Set(k.Y),
98 }
99 }
100 101 func copyPrivateKey(k *PrivateKey) PrivateKey {
102 return PrivateKey{
103 PublicKey: copyPublicKey(&k.PublicKey),
104 D: (&big.Int{}).Set(k.D),
105 }
106 }
107