ecdsa_s390x.mx raw

   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  // randomScalar is a copy of [randomPoint] that doesn't call ScalarBaseMult.
  63  func randomScalar[P Point[P]](c *Curve[P], generate func([]byte) error) (k *bigmod.Nat, err error) {
  64  	for {
  65  		b := []byte{:c.N.Size()}
  66  		if err := generate(b); err != nil {
  67  			return nil, err
  68  		}
  69  		if excess := len(b)*8 - c.N.BitLen(); excess > 0 {
  70  			if c.curve != p521 {
  71  				panic("ecdsa: internal error: unexpectedly masking off bits")
  72  			}
  73  			b = rightShift(b, excess)
  74  		}
  75  		if k, err := bigmod.NewNat().SetBytes(b, c.N); err == nil && k.IsZero() == 0 {
  76  			return k, nil
  77  		}
  78  	}
  79  }
  80  
  81  func appendBlock(p []byte, blocksize int, b []byte) []byte {
  82  	if len(b) > blocksize {
  83  		panic("ecdsa: internal error: appendBlock input larger than block")
  84  	}
  85  	padding := blocksize - len(b)
  86  	p = append(p, []byte{:padding}...)
  87  	return append(p, b...)
  88  }
  89  
  90  func trimBlock(p []byte, size int) ([]byte, error) {
  91  	for _, b := range p[:len(p)-size] {
  92  		if b != 0 {
  93  			return nil, errors.New("ecdsa: internal error: KDSA produced invalid signature")
  94  		}
  95  	}
  96  	return p[len(p)-size:], nil
  97  }
  98  
  99  func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) {
 100  	functionCode, blockSize, ok := canUseKDSA(c.curve)
 101  	if !ok {
 102  		return signGeneric(c, priv, drbg, hash)
 103  	}
 104  	for {
 105  		k, err := randomScalar(c, func(b []byte) error {
 106  			drbg.Generate(b)
 107  			return nil
 108  		})
 109  		if err != nil {
 110  			return nil, err
 111  		}
 112  
 113  		// The parameter block looks like the following for sign.
 114  		// 	+---------------------+
 115  		// 	|   Signature(R)      |
 116  		//	+---------------------+
 117  		//	|   Signature(S)      |
 118  		//	+---------------------+
 119  		//	|   Hashed Message    |
 120  		//	+---------------------+
 121  		//	|   Private Key       |
 122  		//	+---------------------+
 123  		//	|   Random Number     |
 124  		//	+---------------------+
 125  		//	|                     |
 126  		//	|        ...          |
 127  		//	|                     |
 128  		//	+---------------------+
 129  		// The common components(signatureR, signatureS, hashedMessage, privateKey and
 130  		// random number) each takes block size of bytes. The block size is different for
 131  		// different curves and is set by canUseKDSA function.
 132  		var params [4096]byte
 133  
 134  		// Copy content into the parameter block. In the sign case,
 135  		// we copy hashed message, private key and random number into
 136  		// the parameter block. We skip the signature slots.
 137  		p := params[:2*blockSize]
 138  		p = appendBlock(p, blockSize, hashToBytes(c, hash))
 139  		p = appendBlock(p, blockSize, priv.d)
 140  		p = appendBlock(p, blockSize, k.Bytes(c.N))
 141  		// Convert verify function code into a sign function code by adding 8.
 142  		// We also need to set the 'deterministic' bit in the function code, by
 143  		// adding 128, in order to stop the instruction using its own random number
 144  		// generator in addition to the random number we supply.
 145  		switch kdsa(functionCode+136, &params) {
 146  		case 0: // success
 147  			elementSize := (c.N.BitLen() + 7) / 8
 148  			r, err := trimBlock(params[:blockSize], elementSize)
 149  			if err != nil {
 150  				return nil, err
 151  			}
 152  			s, err := trimBlock(params[blockSize:2*blockSize], elementSize)
 153  			if err != nil {
 154  				return nil, err
 155  			}
 156  			return &Signature{R: r, S: s}, nil
 157  		case 1: // error
 158  			return nil, errors.New("zero parameter")
 159  		case 2: // retry
 160  			continue
 161  		}
 162  	}
 163  }
 164  
 165  func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature) error {
 166  	functionCode, blockSize, ok := canUseKDSA(c.curve)
 167  	if !ok {
 168  		return verifyGeneric(c, pub, hash, sig)
 169  	}
 170  
 171  	r, s := sig.R, sig.S
 172  	if len(r) > blockSize || len(s) > blockSize {
 173  		return errors.New("invalid signature")
 174  	}
 175  
 176  	// The parameter block looks like the following for verify:
 177  	// 	+---------------------+
 178  	// 	|   Signature(R)      |
 179  	//	+---------------------+
 180  	//	|   Signature(S)      |
 181  	//	+---------------------+
 182  	//	|   Hashed Message    |
 183  	//	+---------------------+
 184  	//	|   Public Key X      |
 185  	//	+---------------------+
 186  	//	|   Public Key Y      |
 187  	//	+---------------------+
 188  	//	|                     |
 189  	//	|        ...          |
 190  	//	|                     |
 191  	//	+---------------------+
 192  	// The common components(signatureR, signatureS, hashed message, public key X,
 193  	// and public key Y) each takes block size of bytes. The block size is different for
 194  	// different curves and is set by canUseKDSA function.
 195  	var params [4096]byte
 196  
 197  	// Copy content into the parameter block. In the verify case,
 198  	// we copy signature (r), signature(s), hashed message, public key x component,
 199  	// and public key y component into the parameter block.
 200  	p := params[:0]
 201  	p = appendBlock(p, blockSize, r)
 202  	p = appendBlock(p, blockSize, s)
 203  	p = appendBlock(p, blockSize, hashToBytes(c, hash))
 204  	p = appendBlock(p, blockSize, pub.q[1:1+len(pub.q)/2])
 205  	p = appendBlock(p, blockSize, pub.q[1+len(pub.q)/2:])
 206  	if kdsa(functionCode, &params) != 0 {
 207  		return errors.New("invalid signature")
 208  	}
 209  	return nil
 210  }
 211