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, &params) {
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, &params) == 0
164	}
165	return verifyGeneric(pub, c, hash, r, s)
166}
167