Software APIs
otbn_smoketest.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 "dt/dt_otbn.h"
9 #include "sw/device/lib/testing/entropy_testutils.h"
11 #include "sw/device/lib/testing/test_framework/check.h"
13 
14 OTBN_DECLARE_APP_SYMBOLS(barrett384);
15 OTBN_DECLARE_SYMBOL_ADDR(barrett384, inp_a);
16 OTBN_DECLARE_SYMBOL_ADDR(barrett384, inp_b);
17 OTBN_DECLARE_SYMBOL_ADDR(barrett384, inp_m);
18 OTBN_DECLARE_SYMBOL_ADDR(barrett384, inp_u);
19 OTBN_DECLARE_SYMBOL_ADDR(barrett384, oup_c);
20 
21 static const otbn_app_t kAppBarrett = OTBN_APP_T_INIT(barrett384);
22 static const otbn_addr_t kInpA = OTBN_ADDR_T_INIT(barrett384, inp_a);
23 static const otbn_addr_t kInpB = OTBN_ADDR_T_INIT(barrett384, inp_b);
24 static const otbn_addr_t kInpM = OTBN_ADDR_T_INIT(barrett384, inp_m);
25 static const otbn_addr_t kInpU = OTBN_ADDR_T_INIT(barrett384, inp_u);
26 static const otbn_addr_t kOupC = OTBN_ADDR_T_INIT(barrett384, oup_c);
27 
28 OTBN_DECLARE_APP_SYMBOLS(err_test);
29 
30 static const otbn_app_t kAppErrTest = OTBN_APP_T_INIT(err_test);
31 
32 static_assert(kDtOtbnCount >= 1,
33  "This test requires at least one OTBN instance");
34 
35 static dt_otbn_t kTestOtbn = (dt_otbn_t)0;
36 
37 OTTF_DEFINE_TEST_CONFIG();
38 
39 /**
40  * Gets the OTBN instruction count, checks that it matches expectations.
41  */
42 static void check_otbn_insn_cnt(dif_otbn_t *otbn, uint32_t expected_insn_cnt) {
43  uint32_t insn_cnt;
44  CHECK_DIF_OK(dif_otbn_get_insn_cnt(otbn, &insn_cnt));
45  CHECK(insn_cnt == expected_insn_cnt,
46  "Expected to execute %d instructions, but got %d.", expected_insn_cnt,
47  insn_cnt);
48 }
49 
50 /**
51  * Run a 384-bit Barrett Multiplication on OTBN and check its result.
52  *
53  * This test is not aiming to exhaustively test the Barrett multiplication
54  * itself, but test the interaction between device software and OTBN. As such,
55  * only trivial parameters are used.
56  *
57  * The code executed on OTBN can be found in sw/otbn/code-snippets/barrett384.s.
58  * The entry point wrap_barrett384() is called according to the calling
59  * convention described in the OTBN assembly code file.
60  */
61 static void test_barrett384(dif_otbn_t *otbn) {
62  enum { kDataSizeBytes = 48 };
63 
64  CHECK_STATUS_OK(otbn_testutils_load_app(otbn, kAppBarrett));
65 
66  // a, first operand
67  static const uint8_t a[kDataSizeBytes] = {10};
68 
69  // b, second operand
70  static uint8_t b[kDataSizeBytes] = {20};
71 
72  // m, modulus, max. length 384 bit with 2^384 > m > 2^383
73  // We choose the modulus of P-384: m = 2**384 - 2**128 - 2**96 + 2**32 - 1
74  static const uint8_t m[kDataSizeBytes] = {
75  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
76  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
77  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
78  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};
79 
80  // u, pre-computed Barrett constant (without u[384]/MSb of u which is always 1
81  // for the allowed range but has to be set to 0 here).
82  // u has to be pre-calculated as u = floor(2^768/m).
83  static const uint8_t u[kDataSizeBytes] = {
84  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
87  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01};
88 
89  // c, result, max. length 384 bit.
90  uint8_t c[kDataSizeBytes] = {0};
91 
92  // c = (a * b) % m = (10 * 20) % m = 200
93  static const uint8_t c_expected[kDataSizeBytes] = {200};
94 
95  CHECK_STATUS_OK(otbn_testutils_write_data(otbn, sizeof(a), &a, kInpA));
96  CHECK_STATUS_OK(otbn_testutils_write_data(otbn, sizeof(b), &b, kInpB));
97  CHECK_STATUS_OK(otbn_testutils_write_data(otbn, sizeof(m), &m, kInpM));
98  CHECK_STATUS_OK(otbn_testutils_write_data(otbn, sizeof(u), &u, kInpU));
99 
100  CHECK_DIF_OK(dif_otbn_set_ctrl_software_errs_fatal(otbn, true));
101  CHECK_STATUS_OK(otbn_testutils_execute(otbn));
103  CHECK_STATUS_OK(otbn_testutils_wait_for_done(otbn, kDifOtbnErrBitsNoError));
104 
105  // Reading back result (c).
106  CHECK_STATUS_OK(otbn_testutils_read_data(otbn, sizeof(c), kOupC, &c));
107 
108  for (int i = 0; i < sizeof(c); ++i) {
109  CHECK(c[i] == c_expected[i],
110  "Unexpected result c at byte %d: 0x%x (actual) != 0x%x (expected)", i,
111  c[i], c_expected[i]);
112  }
113 
114  check_otbn_insn_cnt(otbn, 174);
115 }
116 
117 /**
118  * Run err_test on OTBN and check it produces the expected error
119  *
120  * This test tries to load from an invalid address which should result in the
121  * kDifOtbnErrBitsBadDataAddr error bit being set
122  *
123  * The code executed on OTBN can be found in sw/otbn/code-snippets/err_test.s.
124  * The entry point wrap_err_test() is called, no arguments are passed or results
125  * returned.
126  */
127 static void test_err_test(dif_otbn_t *otbn) {
128  CHECK_STATUS_OK(otbn_testutils_load_app(otbn, kAppErrTest));
129 
130  // TODO: Turn on software_errs_fatal for err_test. Currently the model doesn't
131  // support this feature so turning it on leads to a failure when run with the
132  // model.
133  CHECK_DIF_OK(dif_otbn_set_ctrl_software_errs_fatal(otbn, false));
134  CHECK_STATUS_OK(otbn_testutils_execute(otbn));
135  CHECK_STATUS_OK(
137 
138  check_otbn_insn_cnt(otbn, 1);
139 }
140 
141 static void test_sec_wipe(dif_otbn_t *otbn) {
142  dif_otbn_status_t otbn_status;
143 
144  CHECK_DIF_OK(dif_otbn_write_cmd(otbn, kDifOtbnCmdSecWipeDmem));
145  CHECK_DIF_OK(dif_otbn_get_status(otbn, &otbn_status));
146  CHECK(otbn_status == kDifOtbnStatusBusySecWipeDmem);
147  CHECK_STATUS_OK(otbn_testutils_wait_for_done(otbn, kDifOtbnErrBitsNoError));
148 
149  CHECK_DIF_OK(dif_otbn_write_cmd(otbn, kDifOtbnCmdSecWipeImem));
150  CHECK_DIF_OK(dif_otbn_get_status(otbn, &otbn_status));
151  CHECK(otbn_status == kDifOtbnStatusBusySecWipeImem);
152  CHECK_STATUS_OK(otbn_testutils_wait_for_done(otbn, kDifOtbnErrBitsNoError));
153 }
154 
155 bool test_main(void) {
156  CHECK_STATUS_OK(entropy_testutils_auto_mode_init());
157 
158  dif_otbn_t otbn;
159  CHECK_DIF_OK(dif_otbn_init_from_dt(kTestOtbn, &otbn));
160 
161  test_barrett384(&otbn);
162  test_sec_wipe(&otbn);
163  test_err_test(&otbn);
164 
165  return true;
166 }