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