Source file src/crypto/internal/fips140/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/internal/fips140/bigmod"
    11  	"crypto/internal/fips140deps/cpu"
    12  	"crypto/internal/impl"
    13  	"errors"
    14  )
    15  
    16  // kdsa invokes the "compute digital signature authentication"
    17  // instruction with the given function code and 4096 byte
    18  // parameter block.
    19  //
    20  // The return value corresponds to the condition code set by the
    21  // instruction. Interrupted invocations are handled by the
    22  // function.
    23  //
    24  //go:noescape
    25  func kdsa(fc uint64, params *[4096]byte) (errn uint64)
    26  
    27  var supportsKDSA = cpu.S390XHasECDSA
    28  
    29  func init() {
    30  	// CP Assist for Cryptographic Functions (CPACF)
    31  	// https://www.ibm.com/docs/en/zos/3.1.0?topic=icsf-cp-assist-cryptographic-functions-cpacf
    32  	impl.Register("ecdsa", "CPACF", &supportsKDSA)
    33  }
    34  
    35  // canUseKDSA checks if KDSA instruction is available, and if it is, it checks
    36  // the name of the curve to see if it matches the curves supported(P-256, P-384, P-521).
    37  // Then, based on the curve name, a function code and a block size will be assigned.
    38  // If KDSA instruction is not available or if the curve is not supported, canUseKDSA
    39  // will set ok to false.
    40  func canUseKDSA(c curveID) (functionCode uint64, blockSize int, ok bool) {
    41  	if !supportsKDSA {
    42  		return 0, 0, false
    43  	}
    44  	switch c {
    45  	case p256:
    46  		return 1, 32, true
    47  	case p384:
    48  		return 2, 48, true
    49  	case p521:
    50  		// Note that the block size doesn't match the field size for P-521.
    51  		return 3, 80, true
    52  	}
    53  	return 0, 0, false // A mismatch
    54  }
    55  
    56  func hashToBytes[P Point[P]](c *Curve[P], hash []byte) []byte {
    57  	e := bigmod.NewNat()
    58  	hashToNat(c, e, hash)
    59  	return e.Bytes(c.N)
    60  }
    61  
    62  func appendBlock(p []byte, blocksize int, b []byte) []byte {
    63  	if len(b) > blocksize {
    64  		panic("ecdsa: internal error: appendBlock input larger than block")
    65  	}
    66  	padding := blocksize - len(b)
    67  	p = append(p, make([]byte, padding)...)
    68  	return append(p, b...)
    69  }
    70  
    71  func trimBlock(p []byte, size int) ([]byte, error) {
    72  	for _, b := range p[:len(p)-size] {
    73  		if b != 0 {
    74  			return nil, errors.New("ecdsa: internal error: KDSA produced invalid signature")
    75  		}
    76  	}
    77  	return p[len(p)-size:], nil
    78  }
    79  
    80  func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) {
    81  	functionCode, blockSize, ok := canUseKDSA(c.curve)
    82  	if !ok {
    83  		return signGeneric(c, priv, drbg, hash)
    84  	}
    85  	for {
    86  		k, _, err := randomPoint(c, func(b []byte) error {
    87  			drbg.Generate(b)
    88  			return nil
    89  		})
    90  		if err != nil {
    91  			return nil, err
    92  		}
    93  
    94  		// The parameter block looks like the following for sign.
    95  		// 	+---------------------+
    96  		// 	|   Signature(R)      |
    97  		//	+---------------------+
    98  		//	|   Signature(S)      |
    99  		//	+---------------------+
   100  		//	|   Hashed Message    |
   101  		//	+---------------------+
   102  		//	|   Private Key       |
   103  		//	+---------------------+
   104  		//	|   Random Number     |
   105  		//	+---------------------+
   106  		//	|                     |
   107  		//	|        ...          |
   108  		//	|                     |
   109  		//	+---------------------+
   110  		// The common components(signatureR, signatureS, hashedMessage, privateKey and
   111  		// random number) each takes block size of bytes. The block size is different for
   112  		// different curves and is set by canUseKDSA function.
   113  		var params [4096]byte
   114  
   115  		// Copy content into the parameter block. In the sign case,
   116  		// we copy hashed message, private key and random number into
   117  		// the parameter block. We skip the signature slots.
   118  		p := params[:2*blockSize]
   119  		p = appendBlock(p, blockSize, hashToBytes(c, hash))
   120  		p = appendBlock(p, blockSize, priv.d)
   121  		p = appendBlock(p, blockSize, k.Bytes(c.N))
   122  		// Convert verify function code into a sign function code by adding 8.
   123  		// We also need to set the 'deterministic' bit in the function code, by
   124  		// adding 128, in order to stop the instruction using its own random number
   125  		// generator in addition to the random number we supply.
   126  		switch kdsa(functionCode+136, &params) {
   127  		case 0: // success
   128  			elementSize := (c.N.BitLen() + 7) / 8
   129  			r, err := trimBlock(params[:blockSize], elementSize)
   130  			if err != nil {
   131  				return nil, err
   132  			}
   133  			s, err := trimBlock(params[blockSize:2*blockSize], elementSize)
   134  			if err != nil {
   135  				return nil, err
   136  			}
   137  			return &Signature{R: r, S: s}, nil
   138  		case 1: // error
   139  			return nil, errors.New("zero parameter")
   140  		case 2: // retry
   141  			continue
   142  		}
   143  	}
   144  }
   145  
   146  func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature) error {
   147  	functionCode, blockSize, ok := canUseKDSA(c.curve)
   148  	if !ok {
   149  		return verifyGeneric(c, pub, hash, sig)
   150  	}
   151  
   152  	r, s := sig.R, sig.S
   153  	if len(r) > blockSize || len(s) > blockSize {
   154  		return errors.New("invalid signature")
   155  	}
   156  
   157  	// The parameter block looks like the following for verify:
   158  	// 	+---------------------+
   159  	// 	|   Signature(R)      |
   160  	//	+---------------------+
   161  	//	|   Signature(S)      |
   162  	//	+---------------------+
   163  	//	|   Hashed Message    |
   164  	//	+---------------------+
   165  	//	|   Public Key X      |
   166  	//	+---------------------+
   167  	//	|   Public Key Y      |
   168  	//	+---------------------+
   169  	//	|                     |
   170  	//	|        ...          |
   171  	//	|                     |
   172  	//	+---------------------+
   173  	// The common components(signatureR, signatureS, hashed message, public key X,
   174  	// and public key Y) each takes block size of bytes. The block size is different for
   175  	// different curves and is set by canUseKDSA function.
   176  	var params [4096]byte
   177  
   178  	// Copy content into the parameter block. In the verify case,
   179  	// we copy signature (r), signature(s), hashed message, public key x component,
   180  	// and public key y component into the parameter block.
   181  	p := params[:0]
   182  	p = appendBlock(p, blockSize, r)
   183  	p = appendBlock(p, blockSize, s)
   184  	p = appendBlock(p, blockSize, hashToBytes(c, hash))
   185  	p = appendBlock(p, blockSize, pub.q[1:1+len(pub.q)/2])
   186  	p = appendBlock(p, blockSize, pub.q[1+len(pub.q)/2:])
   187  	if kdsa(functionCode, &params) != 0 {
   188  		return errors.New("invalid signature")
   189  	}
   190  	return nil
   191  }
   192  

View as plain text