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