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, ¶ms) { 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, ¶ms) != 0 { 176 return errors.New("invalid signature") 177 } 178 return nil 179 } 180