| // 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. |
| |
| package ecdsa |
| |
| import ( |
| "crypto/internal/boring" |
| "math/big" |
| "sync/atomic" |
| "unsafe" |
| ) |
| |
| // Cached conversions from Go PublicKey/PrivateKey to BoringCrypto. |
| // |
| // A new 'boring atomic.Value' field in both PublicKey and PrivateKey |
| // serves as a cache for the most recent conversion. The cache is an |
| // atomic.Value because code might reasonably set up a key and then |
| // (thinking it immutable) use it from multiple goroutines simultaneously. |
| // The first operation initializes the cache; if there are multiple simultaneous |
| // first operations, they will do redundant work but not step on each other. |
| // |
| // 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. |
| |
| type boringPub struct { |
| key *boring.PublicKeyECDSA |
| orig PublicKey |
| } |
| |
| func boringPublicKey(pub *PublicKey) (*boring.PublicKeyECDSA, error) { |
| b := (*boringPub)(atomic.LoadPointer(&pub.boring)) |
| 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, b.orig.X, b.orig.Y) |
| if err != nil { |
| return nil, err |
| } |
| b.key = key |
| atomic.StorePointer(&pub.boring, unsafe.Pointer(b)) |
| return key, nil |
| } |
| |
| type boringPriv struct { |
| key *boring.PrivateKeyECDSA |
| orig PrivateKey |
| } |
| |
| func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyECDSA, error) { |
| b := (*boringPriv)(atomic.LoadPointer(&priv.boring)) |
| 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, b.orig.X, b.orig.Y, b.orig.D) |
| if err != nil { |
| return nil, err |
| } |
| b.key = key |
| atomic.StorePointer(&priv.boring, unsafe.Pointer(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), |
| } |
| } |