| // Copyright 2020 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/cipher" |
| "crypto/elliptic" |
| "internal/cpu" |
| "math/big" |
| ) |
| |
| // kdsa invokes the "compute digital signature authentication" |
| // instruction with the given function code and 4096 byte |
| // parameter block. |
| // |
| // The return value corresponds to the condition code set by the |
| // instruction. Interrupted invocations are handled by the |
| // function. |
| //go:noescape |
| func kdsa(fc uint64, params *[4096]byte) (errn uint64) |
| |
| // canUseKDSA checks if KDSA instruction is available, and if it is, it checks |
| // the name of the curve to see if it matches the curves supported(P-256, P-384, P-521). |
| // Then, based on the curve name, a function code and a block size will be assigned. |
| // If KDSA instruction is not available or if the curve is not supported, canUseKDSA |
| // will set ok to false. |
| func canUseKDSA(c elliptic.Curve) (functionCode uint64, blockSize int, ok bool) { |
| if !cpu.S390X.HasECDSA { |
| return 0, 0, false |
| } |
| switch c.Params().Name { |
| case "P-256": |
| return 1, 32, true |
| case "P-384": |
| return 2, 48, true |
| case "P-521": |
| return 3, 80, true |
| } |
| 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 |
| } |
| copy(dst[nz:size], src[:size-nz]) |
| return |
| } |
| |
| 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) |
| if err != nil { |
| return nil, nil, err |
| } |
| |
| // The parameter block looks like the following for sign. |
| // +---------------------+ |
| // | Signature(R) | |
| // +---------------------+ |
| // | Signature(S) | |
| // +---------------------+ |
| // | Hashed Message | |
| // +---------------------+ |
| // | Private Key | |
| // +---------------------+ |
| // | Random Number | |
| // +---------------------+ |
| // | | |
| // | ... | |
| // | | |
| // +---------------------+ |
| // The common components(signatureR, signatureS, hashedMessage, privateKey and |
| // random number) each takes block size of bytes. The block size is different for |
| // 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) |
| } |
| |
| // 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 |
| // generator in addition to the random number we supply. |
| switch kdsa(functionCode+136, ¶ms) { |
| case 0: // success |
| r = new(big.Int) |
| r.SetBytes(params[:blockSize]) |
| s = new(big.Int) |
| s.SetBytes(params[blockSize : 2*blockSize]) |
| return |
| case 1: // error |
| return nil, nil, errZeroParam |
| case 2: // retry |
| continue |
| } |
| panic("unreachable") |
| } |
| } |
| return signGeneric(priv, csprng, c, 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) | |
| // +---------------------+ |
| // | Signature(S) | |
| // +---------------------+ |
| // | Hashed Message | |
| // +---------------------+ |
| // | Public Key X | |
| // +---------------------+ |
| // | Public Key Y | |
| // +---------------------+ |
| // | | |
| // | ... | |
| // | | |
| // +---------------------+ |
| // The common components(signatureR, signatureS, hashed message, public key X, |
| // and public key Y) each takes block size of bytes. The block size is different for |
| // different curves and is set by canUseKDSA function. |
| var params [4096]byte |
| |
| // 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) |
| } |
| |
| return kdsa(functionCode, ¶ms) == 0 |
| } |
| return verifyGeneric(pub, c, hash, r, s) |
| } |