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  // 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 := make([]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, make([]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  

View as plain text