1
0
mirror of https://github.com/golang/go synced 2024-11-17 10:14:46 -07:00

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>
This commit is contained in:
Ruixin Bao 2020-09-29 15:55:19 -04:00 committed by Michael Munday
parent 8b0d00b164
commit 54a112d719

View File

@ -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")
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
}
// the compiler should replace this loop with a memclr call
z := dst[:nz]
for i := range z {
z[i] = 0
}
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, &params) == 0
}
return verifyGeneric(pub, c, hash, r, s)