diff options
author | Ruixin Bao <ruixin.bao@ibm.com> | 2020-09-29 15:55:19 -0400 |
---|---|---|
committer | Michael Munday <mike.munday@ibm.com> | 2020-09-30 15:32:53 +0000 |
commit | 54a112d7197ec320527614e7502a3243eab93b6e (patch) | |
tree | 4f46ef5b992656eb57975a57712edce3e7d41cdf /src/crypto | |
parent | 8b0d00b1645c47076f5b20dc692b2ca6d9bac19b (diff) | |
download | go-54a112d7197ec320527614e7502a3243eab93b6e.tar.gz go-54a112d7197ec320527614e7502a3243eab93b6e.zip |
crypto/ecdsa: use FillBytes on s390x
Originally, zeroExtendAndCopy is used to pad src with leading zeros and
copy the padded src into the destination. It is no longer needed after
CL 230397 introduced FillBytes. We can simply use that and remove the
zeroExtendAndCopy function. It is cleaner and reduces some allocation.
In addition, this patch tries to avoid calling hashToInt function in
both Sign and Verify function so some allocation is reduced.
Benchmarks:
name old alloc/op new alloc/op delta
SignP256-8 1.60kB ± 0% 1.49kB ± 0% -7.23% (p=0.000 n=20+20)
SignP384-8 1.74kB ± 0% 1.59kB ± 0% -8.50% (p=0.000 n=20+18)
VerifyP256-8 176B ± 0% 0B -100.00% (p=0.000 n=20+20)
KeyGeneration-8 640B ± 0% 640B ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
SignP256-8 22.0 ± 0% 17.0 ± 0% -22.73% (p=0.000 n=20+20)
SignP384-8 22.0 ± 0% 17.0 ± 0% -22.73% (p=0.000 n=20+20)
VerifyP256-8 7.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
KeyGeneration-8 13.0 ± 0% 13.0 ± 0% ~ (all equal)
Change-Id: Ic4c95191eded55deb3420d97db501689f3b173c9
Reviewed-on: https://go-review.googlesource.com/c/go/+/232297
Reviewed-by: Michael Munday <mike.munday@ibm.com>
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
Diffstat (limited to 'src/crypto')
-rw-r--r-- | src/crypto/ecdsa/ecdsa_s390x.go | 59 |
1 files changed, 27 insertions, 32 deletions
diff --git a/src/crypto/ecdsa/ecdsa_s390x.go b/src/crypto/ecdsa/ecdsa_s390x.go index d8d2c716db..0a1d73e7a4 100644 --- a/src/crypto/ecdsa/ecdsa_s390x.go +++ b/src/crypto/ecdsa/ecdsa_s390x.go @@ -41,26 +41,29 @@ func canUseKDSA(c elliptic.Curve) (functionCode uint64, blockSize int, ok bool) return 0, 0, false // A mismatch } -// zeroExtendAndCopy pads src with leading zeros until it has the size given. -// It then copies the padded src into the dst. Bytes beyond size in dst are -// not modified. -func zeroExtendAndCopy(dst, src []byte, size int) { - nz := size - len(src) - if nz < 0 { - panic("src is too long") - } - // the compiler should replace this loop with a memclr call - z := dst[:nz] - for i := range z { - z[i] = 0 +func hashToBytes(dst, hash []byte, c elliptic.Curve) { + l := len(dst) + if n := c.Params().N.BitLen(); n == l*8 { + // allocation free path for curves with a length that is a whole number of bytes + if len(hash) >= l { + // truncate hash + copy(dst, hash[:l]) + return + } + // pad hash with leading zeros + p := l - len(hash) + for i := 0; i < p; i++ { + dst[i] = 0 + } + copy(dst[p:], hash) + return } - copy(dst[nz:size], src[:size-nz]) - return + // TODO(mundaym): avoid hashToInt call here + hashToInt(hash, c).FillBytes(dst) } func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) { if functionCode, blockSize, ok := canUseKDSA(c); ok { - e := hashToInt(hash, c) for { var k *big.Int k, err = randFieldElement(c, *csprng) @@ -89,17 +92,12 @@ func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash // different curves and is set by canUseKDSA function. var params [4096]byte - startingOffset := 2 * blockSize // Set the starting location for copying // Copy content into the parameter block. In the sign case, // we copy hashed message, private key and random number into - // the parameter block. Since those are consecutive components in the parameter - // block, we use a for loop here. - for i, v := range []*big.Int{e, priv.D, k} { - startPosition := startingOffset + i*blockSize - endPosition := startPosition + blockSize - zeroExtendAndCopy(params[startPosition:endPosition], v.Bytes(), blockSize) - } - + // the parameter block. + hashToBytes(params[2*blockSize:3*blockSize], hash, c) + priv.D.FillBytes(params[3*blockSize : 4*blockSize]) + k.FillBytes(params[4*blockSize : 5*blockSize]) // Convert verify function code into a sign function code by adding 8. // We also need to set the 'deterministic' bit in the function code, by // adding 128, in order to stop the instruction using its own random number @@ -124,7 +122,6 @@ func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash func verify(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool { if functionCode, blockSize, ok := canUseKDSA(c); ok { - e := hashToInt(hash, c) // The parameter block looks like the following for verify: // +---------------------+ // | Signature(R) | @@ -149,13 +146,11 @@ func verify(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool { // Copy content into the parameter block. In the verify case, // we copy signature (r), signature(s), hashed message, public key x component, // and public key y component into the parameter block. - // Since those are consecutive components in the parameter block, we use a for loop here. - for i, v := range []*big.Int{r, s, e, pub.X, pub.Y} { - startPosition := i * blockSize - endPosition := startPosition + blockSize - zeroExtendAndCopy(params[startPosition:endPosition], v.Bytes(), blockSize) - } - + r.FillBytes(params[0*blockSize : 1*blockSize]) + s.FillBytes(params[1*blockSize : 2*blockSize]) + hashToBytes(params[2*blockSize:3*blockSize], hash, c) + pub.X.FillBytes(params[3*blockSize : 4*blockSize]) + pub.Y.FillBytes(params[4*blockSize : 5*blockSize]) return kdsa(functionCode, ¶ms) == 0 } return verifyGeneric(pub, c, hash, r, s) |