Source file src/crypto/ecdsa/ecdsa_s390x.go

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

View as plain text