Skip to content

Commit 297f7c1

Browse files
siemen11nasahlpa
authored andcommitted
[crypto/tests] Use randomness in ecdsa functests
Use the hardened_memshred and hardened_sub_mod functions in order to provide the p256 and p384 ecdsa functions with fresh randomness in order to help the user give an example and test with randomness. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent 6adb31f commit 297f7c1

4 files changed

Lines changed: 105 additions & 8 deletions

File tree

sw/device/lib/base/hardened_memory.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ status_t hardened_sub(const uint32_t *OT_RESTRICT x,
227227
* guaranteed. The function is hardened against fault injections and is
228228
* constant time in the value being reduced.
229229
*
230+
* In order to have this function constant time, it conditionally adds n only
231+
* once.
232+
* This function mimics OTBN's subm.
233+
*
230234
* @param x Pointer to the first operand.
231235
* @param y Pointer to the second operand.
232236
* @param n Pointer to the multi-word modulus.
@@ -249,6 +253,10 @@ status_t hardened_sub_mod(const uint32_t *OT_RESTRICT x,
249253
* guaranteed. The function is hardened against fault injections and is
250254
* constant time in the value being reduced.
251255
*
256+
* In order to have this function constant time, it conditionally subtracts n
257+
* only once.
258+
* This function mimics OTBN's addm.
259+
*
252260
* @param x Pointer to the first operand.
253261
* @param y Pointer to the second operand.
254262
* @param n Pointer to the multi-word modulus.

sw/device/tests/crypto/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ opentitan_test(
594594
timeout = "long",
595595
),
596596
deps = [
597+
"//sw/device/lib/base:hardened_memory",
597598
"//sw/device/lib/crypto/drivers:otbn",
598599
"//sw/device/lib/crypto/impl:config",
599600
"//sw/device/lib/crypto/impl:ecc_p256",
@@ -617,6 +618,7 @@ opentitan_test(
617618
tags = ["manual"],
618619
),
619620
deps = [
621+
"//sw/device/lib/base:hardened_memory",
620622
"//sw/device/lib/crypto/drivers:otbn",
621623
"//sw/device/lib/crypto/impl:config",
622624
"//sw/device/lib/crypto/impl:ecc_p384",

sw/device/tests/crypto/ecdsa_p256_functest.c

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
// SPDX-License-Identifier: Apache-2.0
44

5+
#include "sw/device/lib/base/hardened_memory.h"
56
#include "sw/device/lib/crypto/drivers/otbn.h"
67
#include "sw/device/lib/crypto/impl/keyblob.h"
78
#include "sw/device/lib/crypto/include/config.h"
@@ -124,29 +125,71 @@ static status_t sign_then_verify_test(void) {
124125
return OK_STATUS();
125126
}
126127

128+
/**
129+
* A test where a known input is signed and is compared to the expected output.
130+
* In addition, it draws randomness to share the known input using
131+
* hardened_memshred. The input is shared using the hardened_sub_mod function
132+
* using the P-256 curve order n.
133+
*/
127134
static status_t sign_kat(void) {
128135
uint32_t keyblob_len = 2 * kP256SecretScalarWords;
129136

137+
// P-256 curve order n, padded to 320 bits (10 words) for our math operations.
138+
static const uint32_t kP256Order[kP256SecretScalarWords] = {
139+
0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, 0xFFFFFFFF,
140+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000};
141+
142+
uint32_t unmasked_val[kP256SecretScalarWords];
143+
uint32_t share1_rand[kP256SecretScalarWords];
144+
uint32_t share0[kP256SecretScalarWords];
145+
uint32_t share1[kP256SecretScalarWords];
146+
147+
memset(unmasked_val, 0, kP256SecretScalarBytes);
148+
memcpy(unmasked_val, kKATSecretScalar, kP256TestVectorScalarInpBytes);
149+
150+
// Generate a random value and reduce it modulo n to get a valid share1
151+
TRY(hardened_memshred(share1_rand, kP256SecretScalarWords));
152+
TRY(hardened_mod_reduce(share1_rand, kP256Order, kP256SecretScalarWords,
153+
share1));
154+
155+
// Calculate share0 = (unmasked_val - share1) mod n
156+
TRY(hardened_sub_mod(unmasked_val, share1, kP256Order, kP256SecretScalarWords,
157+
share0));
158+
130159
// Allocate space for a masked secret scalar.
131160
uint32_t keyblob_scalar[keyblob_len];
132161
otcrypto_blinded_key_t secret_scalar = {
133162
.config = kPrivateKeyConfig,
134163
.keyblob_length = sizeof(keyblob_scalar),
135164
.keyblob = keyblob_scalar,
136165
};
137-
memset(keyblob_scalar, 0, 2 * kP256SecretScalarBytes);
138-
memcpy(keyblob_scalar, kKATSecretScalar, kP256TestVectorScalarInpBytes);
166+
memcpy(keyblob_scalar, share0, kP256SecretScalarBytes);
167+
// We copy over the full 320 random bits
168+
memcpy(keyblob_scalar + kP256SecretScalarWords, share1_rand,
169+
kP256SecretScalarBytes);
139170
secret_scalar.checksum = integrity_blinded_checksum(&secret_scalar);
140171

172+
memset(unmasked_val, 0, kP256SecretScalarBytes);
173+
memcpy(unmasked_val, kKATKey, kP256TestVectorScalarInpBytes);
174+
175+
// Generate a random svalue and reduce it modulo n
176+
TRY(hardened_memshred(share1_rand, kP256SecretScalarWords));
177+
TRY(hardened_mod_reduce(share1_rand, kP256Order, kP256SecretScalarWords,
178+
share1));
179+
180+
// Calculate share0 = (unmasked_val - share1) mod n
181+
TRY(hardened_sub_mod(unmasked_val, share1, kP256Order, kP256SecretScalarWords,
182+
share0));
183+
141184
// Allocate space for a masked private key.
142185
uint32_t keyblob_sk[keyblob_len];
143186
otcrypto_blinded_key_t private_key = {
144187
.config = kPrivateKeyConfig,
145188
.keyblob_length = sizeof(keyblob_sk),
146189
.keyblob = keyblob_sk,
147190
};
148-
memset(keyblob_sk, 0, 2 * kP256SecretScalarBytes);
149-
memcpy(keyblob_sk, kKATKey, kP256TestVectorScalarInpBytes);
191+
memcpy(keyblob_sk, share0, kP256SecretScalarBytes);
192+
memcpy(keyblob_sk + kP256SecretScalarWords, share1, kP256SecretScalarBytes);
150193
private_key.checksum = integrity_blinded_checksum(&private_key);
151194

152195
// Hash the message.

sw/device/tests/crypto/ecdsa_p384_functest.c

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
// SPDX-License-Identifier: Apache-2.0
44

5+
#include "sw/device/lib/base/hardened_memory.h"
56
#include "sw/device/lib/crypto/drivers/otbn.h"
67
#include "sw/device/lib/crypto/impl/keyblob.h"
78
#include "sw/device/lib/crypto/include/config.h"
@@ -128,29 +129,72 @@ static status_t sign_then_verify_test(void) {
128129

129130
OTTF_DEFINE_TEST_CONFIG();
130131

132+
/**
133+
* A test where a known input is signed and is compared to the expected output.
134+
* In addition, it draws randomness to share the known input using
135+
* hardened_memshred. The input is shared using the hardened_sub_mod function
136+
* using the P-384 curve order n.
137+
*/
131138
static status_t sign_kat(void) {
132139
uint32_t keyblob_len = 2 * kP384SecretScalarWords;
133140

141+
// P-384 curve order n, padded to 448 bits (14 words) for our math operations.
142+
static const uint32_t kP384Order[kP384SecretScalarWords] = {
143+
0xCCC52973, 0xECEC196A, 0x48B0A77A, 0x581A0DB2, 0xF4372DDF,
144+
0xC7634D81, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
145+
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000};
146+
147+
uint32_t unmasked_val[kP384SecretScalarWords];
148+
uint32_t share1_rand[kP384SecretScalarWords];
149+
uint32_t share0[kP384SecretScalarWords];
150+
uint32_t share1[kP384SecretScalarWords];
151+
152+
memset(unmasked_val, 0, kP384SecretScalarBytes);
153+
memcpy(unmasked_val, kKATSecretScalar, kP384TestVectorScalarInpBytes);
154+
155+
// Generate a random value and reduce it modulo n to get a valid share1
156+
TRY(hardened_memshred(share1_rand, kP384SecretScalarWords));
157+
TRY(hardened_mod_reduce(share1_rand, kP384Order, kP384SecretScalarWords,
158+
share1));
159+
160+
// Calculate share0 = (unmasked_val - share1) mod n
161+
TRY(hardened_sub_mod(unmasked_val, share1, kP384Order, kP384SecretScalarWords,
162+
share0));
163+
134164
// Allocate space for a masked secret scalar.
135165
uint32_t keyblob_scalar[keyblob_len];
136166
otcrypto_blinded_key_t secret_scalar = {
137167
.config = kPrivateKeyConfig,
138168
.keyblob_length = sizeof(keyblob_scalar),
139169
.keyblob = keyblob_scalar,
140170
};
141-
memset(keyblob_scalar, 0, 2 * kP384SecretScalarBytes);
142-
memcpy(keyblob_scalar, kKATSecretScalar, kP384TestVectorScalarInpBytes);
171+
memcpy(keyblob_scalar, share0, kP384SecretScalarBytes);
172+
// We copy over the full random bits
173+
memcpy(keyblob_scalar + kP384SecretScalarWords, share1,
174+
kP384SecretScalarBytes);
143175
secret_scalar.checksum = integrity_blinded_checksum(&secret_scalar);
144176

177+
memset(unmasked_val, 0, kP384SecretScalarBytes);
178+
memcpy(unmasked_val, kKATKey, kP384TestVectorScalarInpBytes);
179+
180+
// Generate new random noise and reduce it modulo n
181+
TRY(hardened_memshred(share1_rand, kP384SecretScalarWords));
182+
TRY(hardened_mod_reduce(share1_rand, kP384Order, kP384SecretScalarWords,
183+
share1));
184+
185+
// Calculate share0 = (unmasked_val - share1) mod n
186+
TRY(hardened_sub_mod(unmasked_val, share1, kP384Order, kP384SecretScalarWords,
187+
share0));
188+
145189
// Allocate space for a masked private key.
146190
uint32_t keyblob_sk[keyblob_len];
147191
otcrypto_blinded_key_t private_key = {
148192
.config = kPrivateKeyConfig,
149193
.keyblob_length = sizeof(keyblob_sk),
150194
.keyblob = keyblob_sk,
151195
};
152-
memset(keyblob_sk, 0, 2 * kP384SecretScalarBytes);
153-
memcpy(keyblob_sk, kKATKey, kP384TestVectorScalarInpBytes);
196+
memcpy(keyblob_sk, share0, kP384SecretScalarBytes);
197+
memcpy(keyblob_sk + kP384SecretScalarWords, share1, kP384SecretScalarBytes);
154198
private_key.checksum = integrity_blinded_checksum(&private_key);
155199

156200
// Hash the message.

0 commit comments

Comments
 (0)