github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/crypto/ecdsa/ecdsa_s390x.go (about)

     1  // Copyright 2020 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  package ecdsa
     6  
     7  import (
     8  	"crypto/cipher"
     9  	"crypto/elliptic"
    10  	"internal/cpu"
    11  	"math/big"
    12  )
    13  
    14  // kdsa invokes the "compute digital signature authentication"
    15  // instruction with the given function code and 4096 byte
    16  // parameter block.
    17  //
    18  // The return value corresponds to the condition code set by the
    19  // instruction. Interrupted invocations are handled by the
    20  // function.
    21  //
    22  //go:noescape
    23  func kdsa(fc uint64, params *[4096]byte) (errn uint64)
    24  
    25  // testingDisableKDSA forces the generic fallback path. It must only be set in tests.
    26  var testingDisableKDSA bool
    27  
    28  // canUseKDSA checks if KDSA instruction is available, and if it is, it checks
    29  // the name of the curve to see if it matches the curves supported(P-256, P-384, P-521).
    30  // Then, based on the curve name, a function code and a block size will be assigned.
    31  // If KDSA instruction is not available or if the curve is not supported, canUseKDSA
    32  // will set ok to false.
    33  func canUseKDSA(c elliptic.Curve) (functionCode uint64, blockSize int, ok bool) {
    34  	if testingDisableKDSA {
    35  		return 0, 0, false
    36  	}
    37  	if !cpu.S390X.HasECDSA {
    38  		return 0, 0, false
    39  	}
    40  	switch c.Params().Name {
    41  	case "P-256":
    42  		return 1, 32, true
    43  	case "P-384":
    44  		return 2, 48, true
    45  	case "P-521":
    46  		return 3, 80, true
    47  	}
    48  	return 0, 0, false // A mismatch
    49  }
    50  
    51  func hashToBytes(dst, hash []byte, c elliptic.Curve) {
    52  	l := len(dst)
    53  	if n := c.Params().N.BitLen(); n == l*8 {
    54  		// allocation free path for curves with a length that is a whole number of bytes
    55  		if len(hash) >= l {
    56  			// truncate hash
    57  			copy(dst, hash[:l])
    58  			return
    59  		}
    60  		// pad hash with leading zeros
    61  		p := l - len(hash)
    62  		for i := 0; i < p; i++ {
    63  			dst[i] = 0
    64  		}
    65  		copy(dst[p:], hash)
    66  		return
    67  	}
    68  	// TODO(mundaym): avoid hashToInt call here
    69  	hashToInt(hash, c).FillBytes(dst)
    70  }
    71  
    72  func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) {
    73  	if functionCode, blockSize, ok := canUseKDSA(c); ok {
    74  		for {
    75  			var k *big.Int
    76  			k, err = randFieldElement(c, *csprng)
    77  			if err != nil {
    78  				return nil, nil, err
    79  			}
    80  
    81  			// The parameter block looks like the following for sign.
    82  			// 	+---------------------+
    83  			// 	|   Signature(R)      |
    84  			//	+---------------------+
    85  			//	|   Signature(S)      |
    86  			//	+---------------------+
    87  			//	|   Hashed Message    |
    88  			//	+---------------------+
    89  			//	|   Private Key       |
    90  			//	+---------------------+
    91  			//	|   Random Number     |
    92  			//	+---------------------+
    93  			//	|                     |
    94  			//	|        ...          |
    95  			//	|                     |
    96  			//	+---------------------+
    97  			// The common components(signatureR, signatureS, hashedMessage, privateKey and
    98  			// random number) each takes block size of bytes. The block size is different for
    99  			// different curves and is set by canUseKDSA function.
   100  			var params [4096]byte
   101  
   102  			// Copy content into the parameter block. In the sign case,
   103  			// we copy hashed message, private key and random number into
   104  			// the parameter block.
   105  			hashToBytes(params[2*blockSize:3*blockSize], hash, c)
   106  			priv.D.FillBytes(params[3*blockSize : 4*blockSize])
   107  			k.FillBytes(params[4*blockSize : 5*blockSize])
   108  			// Convert verify function code into a sign function code by adding 8.
   109  			// We also need to set the 'deterministic' bit in the function code, by
   110  			// adding 128, in order to stop the instruction using its own random number
   111  			// generator in addition to the random number we supply.
   112  			switch kdsa(functionCode+136, &params) {
   113  			case 0: // success
   114  				r = new(big.Int)
   115  				r.SetBytes(params[:blockSize])
   116  				s = new(big.Int)
   117  				s.SetBytes(params[blockSize : 2*blockSize])
   118  				return
   119  			case 1: // error
   120  				return nil, nil, errZeroParam
   121  			case 2: // retry
   122  				continue
   123  			}
   124  			panic("unreachable")
   125  		}
   126  	}
   127  	return signGeneric(priv, csprng, c, hash)
   128  }
   129  
   130  func verify(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool {
   131  	if functionCode, blockSize, ok := canUseKDSA(c); ok {
   132  		// The parameter block looks like the following for verify:
   133  		// 	+---------------------+
   134  		// 	|   Signature(R)      |
   135  		//	+---------------------+
   136  		//	|   Signature(S)      |
   137  		//	+---------------------+
   138  		//	|   Hashed Message    |
   139  		//	+---------------------+
   140  		//	|   Public Key X      |
   141  		//	+---------------------+
   142  		//	|   Public Key Y      |
   143  		//	+---------------------+
   144  		//	|                     |
   145  		//	|        ...          |
   146  		//	|                     |
   147  		//	+---------------------+
   148  		// The common components(signatureR, signatureS, hashed message, public key X,
   149  		// and public key Y) each takes block size of bytes. The block size is different for
   150  		// different curves and is set by canUseKDSA function.
   151  		var params [4096]byte
   152  
   153  		// Copy content into the parameter block. In the verify case,
   154  		// we copy signature (r), signature(s), hashed message, public key x component,
   155  		// and public key y component into the parameter block.
   156  		r.FillBytes(params[0*blockSize : 1*blockSize])
   157  		s.FillBytes(params[1*blockSize : 2*blockSize])
   158  		hashToBytes(params[2*blockSize:3*blockSize], hash, c)
   159  		pub.X.FillBytes(params[3*blockSize : 4*blockSize])
   160  		pub.Y.FillBytes(params[4*blockSize : 5*blockSize])
   161  		return kdsa(functionCode, &params) == 0
   162  	}
   163  	return verifyGeneric(pub, c, hash, r, s)
   164  }