Software APIs
ecc256_modinv_serial.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/sca/otbn_vertical/ecc256_modinv_serial.h"
6 
11 #include "sw/device/lib/testing/entropy_testutils.h"
13 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
14 #include "sw/device/sca/lib/prng.h"
16 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
17 
19 #include "otbn_regs.h"
20 
21 enum {
22  /**
23  * Number of cycles that Ibex should sleep to minimize noise during OTBN
24  * operations. Caution: This number should be chosen to provide enough time
25  * to complete the operation. Otherwise, Ibex might wake up while OTBN is
26  * still busy and disturb the capture.
27  */
28  kIbexOtbnSleepCycles = 50000,
29  /**
30  * Number of bytes for ECDSA P-256 modular inverse input shares (k0,k1).
31  */
32  kEcc256ModInvInputShareNumBytes = 320 / 8,
33  /**
34  * Number of words for ECDSA P-256 modular inverse input shares (k0,k1).
35  */
36  kEcc256ModInvInputShareNumWords =
37  kEcc256ModInvInputShareNumBytes / sizeof(uint32_t),
38  /**
39  * Number of bytes for ECDSA P-256 modular inverse output ((k*alpha)^-1 mod
40  * n).
41  */
42  kEcc256ModInvOutputKAlphaInvNumBytes = 256 / 8,
43  /**
44  * Number of words for ECDSA P-256 modular inverse output ((k*alpha)^-1 mod
45  * n).
46  */
47  kEcc256ModInvOutputKAlphaInvNumWords =
48  kEcc256ModInvOutputKAlphaInvNumBytes / sizeof(uint32_t),
49  /**
50  * Number of bytes for ECDSA P-256 modular inverse output mask (alpha).
51  */
52  kEcc256ModInvOutputAlphaNumBytes = 128 / 8,
53  /**
54  * Number of words for ECDSA P-256 modular inverse output mask (alpha).
55  */
56  kEcc256ModInvOutputAlphaNumWords =
57  kEcc256ModInvOutputAlphaNumBytes / sizeof(uint32_t),
58 };
59 
60 /**
61  * App configuration for p256_mod_inv_sca
62  */
63 const otbn_app_t kOtbnAppP256ModInv = OTBN_APP_T_INIT(p256_mod_inv_sca);
64 
65 static const otbn_addr_t kOtbnVarModInvK0 =
66  OTBN_ADDR_T_INIT(p256_mod_inv_sca, k0);
67 static const otbn_addr_t kOtbnVarModInvK1 =
68  OTBN_ADDR_T_INIT(p256_mod_inv_sca, k1);
69 static const otbn_addr_t kOtbnVarModInvKAplhaInv =
70  OTBN_ADDR_T_INIT(p256_mod_inv_sca, kalpha_inv);
71 static const otbn_addr_t kOtbnVarModInvAlpha =
72  OTBN_ADDR_T_INIT(p256_mod_inv_sca, alpha);
73 
74 /**
75  * Callback wrapper for OTBN manual trigger function.
76  */
77 static void otbn_manual_trigger(void) { SS_CHECK_STATUS_OK(otbn_execute()); }
78 
79 /**
80  * Runs the OTBN modular inverse program.
81  *
82  * The input must be `kEcc256ModInvInputShareNumWords` words long.
83  *
84  * @param[in] input Iput value for the OTBN modular inverse.
85  */
86 static void p256_run_modinv(uint32_t *k0, uint32_t *k1) {
87  // Write input.
89  otbn_dmem_write(kEcc256ModInvInputShareNumWords, k0, kOtbnVarModInvK0));
91  otbn_dmem_write(kEcc256ModInvInputShareNumWords, k1, kOtbnVarModInvK1));
92 
93  // Execute program.
94  pentest_set_trigger_high();
95  pentest_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles, false,
96  false);
97  otbn_busy_wait_for_done();
98  pentest_set_trigger_low();
99 }
100 
101 void ecc256_modinv(const uint8_t *k0_k1, size_t k0_k1_len) {
102  if (k0_k1_len != 2 * kEcc256ModInvInputShareNumBytes) {
103  LOG_ERROR("Invalid input length %hu", (uint8_t)k0_k1_len);
104  return;
105  }
106 
107  // Copy input to an aligned buffer.
108  uint32_t modinv_k0[kEcc256ModInvInputShareNumWords];
109  uint32_t modinv_k1[kEcc256ModInvInputShareNumWords];
110  memcpy(modinv_k0, k0_k1, kEcc256ModInvInputShareNumBytes);
111  memcpy(modinv_k1, (k0_k1 + kEcc256ModInvInputShareNumBytes),
112  kEcc256ModInvInputShareNumBytes);
113 
114  // Run the key generation program.
115  p256_run_modinv(modinv_k0, modinv_k1);
116 
117  // Read result.
118  uint32_t modinv_kalpha_inv[kEcc256ModInvOutputKAlphaInvNumWords];
119  uint32_t modinv_alpha[kEcc256ModInvOutputAlphaNumWords];
120  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256ModInvOutputKAlphaInvNumWords,
121  kOtbnVarModInvKAplhaInv,
122  modinv_kalpha_inv));
123  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256ModInvOutputAlphaNumWords,
124  kOtbnVarModInvAlpha, modinv_alpha));
125 
126  simple_serial_send_packet('r', (unsigned char *)modinv_kalpha_inv,
127  kEcc256ModInvOutputKAlphaInvNumBytes);
128  simple_serial_send_packet('r', (unsigned char *)modinv_alpha,
129  kEcc256ModInvOutputAlphaNumBytes);
130 }