7
7
package ecdsa
8
8
9
9
import (
10
- "crypto/elliptic"
10
+ "crypto/internal/fips/bigmod"
11
+ "crypto/internal/fipsdeps/cpu"
12
+ "crypto/internal/impl"
11
13
"errors"
12
- "internal/cpu"
13
14
"io"
14
- "math/big"
15
15
)
16
16
17
17
// kdsa invokes the "compute digital signature authentication"
@@ -25,62 +25,47 @@ import (
25
25
//go:noescape
26
26
func kdsa (fc uint64 , params * [4096 ]byte ) (errn uint64 )
27
27
28
- // testingDisableKDSA forces the generic fallback path. It must only be set in tests.
29
- var testingDisableKDSA bool
28
+ var supportsKDSA = cpu .S390XHasECDSA
29
+
30
+ func init () {
31
+ // CP Assist for Cryptographic Functions (CPACF)
32
+ // https://www.ibm.com/docs/en/zos/3.1.0?topic=icsf-cp-assist-cryptographic-functions-cpacf
33
+ impl .Register ("ecdsa" , "CPACF" , & supportsKDSA )
34
+ }
30
35
31
36
// canUseKDSA checks if KDSA instruction is available, and if it is, it checks
32
37
// the name of the curve to see if it matches the curves supported(P-256, P-384, P-521).
33
38
// Then, based on the curve name, a function code and a block size will be assigned.
34
39
// If KDSA instruction is not available or if the curve is not supported, canUseKDSA
35
40
// 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
+ func canUseKDSA (c curveID ) (functionCode uint64 , blockSize int , ok bool ) {
42
+ if ! supportsKDSA {
41
43
return 0 , 0 , false
42
44
}
43
- switch c . Params (). Name {
44
- case "P-256" :
45
+ switch c {
46
+ case p256 :
45
47
return 1 , 32 , true
46
- case "P-384" :
48
+ case p384 :
47
49
return 2 , 48 , true
48
- case "P-521" :
50
+ case p521 :
49
51
return 3 , 80 , true
50
52
}
51
53
return 0 , 0 , false // A mismatch
52
54
}
53
55
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 )
56
+ func hashToBytes [P Point [P ]](c * Curve [P ], dst , hash []byte ) {
57
+ e := bigmod .NewNat ()
58
+ hashToNat (c , e , hash )
59
+ copy (dst , e .Bytes (c .N ))
73
60
}
74
61
75
- func signAsm (priv * PrivateKey , csprng io.Reader , hash []byte ) (sig []byte , err error ) {
76
- c := priv .Curve
77
- functionCode , blockSize , ok := canUseKDSA (c )
62
+ func sign [P Point [P ]](c * Curve [P ], priv * PrivateKey , csprng io.Reader , hash []byte ) (* Signature , error ) {
63
+ functionCode , blockSize , ok := canUseKDSA (c .curve )
78
64
if ! ok {
79
- return nil , errNoAsm
65
+ return signGeneric ( c , priv , csprng , hash )
80
66
}
81
67
for {
82
- var k * big.Int
83
- k , err = randFieldElement (c , csprng )
68
+ k , _ , err := randomPoint (c , csprng )
84
69
if err != nil {
85
70
return nil , err
86
71
}
@@ -109,36 +94,31 @@ func signAsm(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err e
109
94
// Copy content into the parameter block. In the sign case,
110
95
// we copy hashed message, private key and random number into
111
96
// 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 ])
97
+ hashToBytes (c , params [2 * blockSize :3 * blockSize ], hash )
98
+ copy (params [3 * blockSize + blockSize - len ( priv . d ):], priv . d )
99
+ copy (params [4 * blockSize : 5 * blockSize ], k . Bytes ( c . N ) )
115
100
// Convert verify function code into a sign function code by adding 8.
116
101
// We also need to set the 'deterministic' bit in the function code, by
117
102
// adding 128, in order to stop the instruction using its own random number
118
103
// generator in addition to the random number we supply.
119
104
switch kdsa (functionCode + 136 , & params ) {
120
105
case 0 : // success
121
- return encodeSignature ( params [:blockSize ], params [blockSize : 2 * blockSize ])
106
+ return & Signature { R : params [:blockSize ], S : params [blockSize : 2 * blockSize ]}, nil
122
107
case 1 : // error
123
- return nil , errZeroParam
108
+ return nil , errors . New ( "zero parameter" )
124
109
case 2 : // retry
125
110
continue
126
111
}
127
- panic ("unreachable" )
128
112
}
129
113
}
130
114
131
- func verifyAsm (pub * PublicKey , hash []byte , sig []byte ) error {
132
- c := pub .Curve
133
- functionCode , blockSize , ok := canUseKDSA (c )
115
+ func verify [P Point [P ]](c * Curve [P ], pub * PublicKey , hash []byte , sig * Signature ) error {
116
+ functionCode , blockSize , ok := canUseKDSA (c .curve )
134
117
if ! ok {
135
- return errNoAsm
118
+ return verifyGeneric ( c , pub , hash , sig )
136
119
}
137
120
138
- r , s , err := parseSignature (sig )
139
- if err != nil {
140
- return err
141
- }
121
+ r , s := sig .R , sig .S
142
122
if len (r ) > blockSize || len (s ) > blockSize {
143
123
return errors .New ("invalid signature" )
144
124
}
@@ -169,9 +149,8 @@ func verifyAsm(pub *PublicKey, hash []byte, sig []byte) error {
169
149
// and public key y component into the parameter block.
170
150
copy (params [0 * blockSize + blockSize - len (r ):], r )
171
151
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 ])
152
+ hashToBytes (c , params [2 * blockSize :3 * blockSize ], hash )
153
+ copy (params [3 * blockSize :5 * blockSize ], pub .q [1 :]) // strip 0x04 prefix
175
154
if kdsa (functionCode , & params ) != 0 {
176
155
return errors .New ("invalid signature" )
177
156
}
0 commit comments