Software APIs
address_unittest.cc
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/silicon_creator/lib/sigverify/sphincsplus/address.h"
6 
7 #include <array>
8 
9 #include "gtest/gtest.h"
10 #include "sw/device/silicon_creator/testing/rom_test.h"
11 
12 namespace spx_addr_unittest {
13 namespace {
14 
16  protected:
17  /**
18  * Fetch a specific byte from the internal address buffer.
19  *
20  * @param addr Hypertree address.
21  * @param offset Index of byte to get.
22  * @return Value of the byte within the internal buffer.
23  */
24  uint8_t ByteGet(const spx_addr_t *addr, size_t offset) {
25  unsigned char *buf = (unsigned char *)addr->addr;
26  return buf[offset];
27  }
28 
29  /**
30  * Get the 64-bit `tree` field from the address.
31  *
32  * @param addr Hypertree address.
33  * @return Value of the `tree` field.
34  */
35  uint64_t TreeGet(const spx_addr_t *addr) {
36  unsigned char *buf = (unsigned char *)addr->addr;
37  uint64_t tree = 0;
38  memcpy(&tree, buf + kSpxOffsetTree, sizeof(uint64_t));
39  return tree;
40  }
41 
42  /**
43  * Get the 32-bit `tree_index` field from the address.
44  *
45  * @param addr Hypertree address.
46  * @return Value of the `tree_index` field.
47  */
48  uint32_t TreeIndexGet(const spx_addr_t *addr) {
49  unsigned char *buf = (unsigned char *)addr->addr;
50  uint32_t tree_index = 0;
51  memcpy(&tree_index, buf + kSpxOffsetTreeIndex, sizeof(uint32_t));
52  return tree_index;
53  }
54 
55  /**
56  * Get the 32-bit `keypair_addr` field from the address.
57  *
58  * @param addr Key pair address.
59  * @return Value of the `keypair_addr` field.
60  */
61  uint32_t KeypairAddrGet(const spx_addr_t *addr) {
62  unsigned char *buf = (unsigned char *)addr->addr;
63  uint32_t keypair_addr = 0;
64  memcpy(&keypair_addr, buf + kSpxOffsetKpAddr, sizeof(uint32_t));
65  return keypair_addr;
66  }
67 
68  /**
69  * Checks if the given byte is the same in two addresses.
70  *
71  * @param addr1 First address.
72  * @param addr2 Second address.
73  * @param offset Index of byte to check.
74  */
75  void ExpectByteEq(const spx_addr_t *addr1, const spx_addr_t *addr2,
76  size_t offset) {
77  EXPECT_EQ(ByteGet(addr1, offset), ByteGet(addr2, offset));
78  }
79 
80  /**
81  * Checks if the two addresses are exactly equal.
82  *
83  * @param addr1 First address.
84  * @param addr2 Second address.
85  * @param offset Index of byte to check.
86  */
87  void ExpectAddrEq(const spx_addr_t *addr1, const spx_addr_t *addr2) {
88  EXPECT_EQ(memcmp(addr1->addr, addr2->addr, sizeof(addr1->addr)), 0);
89  }
90 
91  /**
92  * Initializes a default test address.
93  *
94  * The test address is chosen so that all bytes are distinct. This way, if
95  * some address routine mistakenly writes or copies the wrong byte, it will
96  * be more obvious than, for instance, if most bytes were 0.
97  */
98  void TestAddrInit(spx_addr_t *addr) {
99  // Test assumption.
100  EXPECT_LE(sizeof(addr->addr), UINT8_MAX);
101 
102  unsigned char *buf = (unsigned char *)addr->addr;
103  for (size_t i = 0; i < sizeof(addr->addr); i++) {
104  buf[i] = UINT8_MAX - i;
105  }
106  }
107 };
108 
109 TEST_F(SpxAddrTest, LayerSetTest) {
110  uint8_t layer = 0xf0;
111  spx_addr_t test_addr;
112  TestAddrInit(&test_addr);
113  spx_addr_layer_set(&test_addr, layer);
114  EXPECT_EQ(ByteGet(&test_addr, kSpxOffsetLayer), layer);
115 }
116 
117 TEST_F(SpxAddrTest, TreeSetTest) {
118  uint64_t tree = 0x0102030405060708;
119  // Same data in big-endian form.
120  uint64_t tree_be = 0x0807060504030201;
121  spx_addr_t test_addr;
122  TestAddrInit(&test_addr);
123  spx_addr_tree_set(&test_addr, tree);
124 
125  // Expect the tree to be in big-endian form.
126  EXPECT_EQ(TreeGet(&test_addr), tree_be);
127 }
128 
129 TEST_F(SpxAddrTest, TypeSetTest) {
130  spx_addr_t test_addr;
131  TestAddrInit(&test_addr);
132 
133  // Set the type and check its value.
134  spx_addr_type_set(&test_addr, kSpxAddrTypeWotsPk);
135  EXPECT_EQ(ByteGet(&test_addr, kSpxOffsetType), kSpxAddrTypeWotsPk);
136 
137  // Set and check a second time.
138  spx_addr_type_set(&test_addr, kSpxAddrTypeHashTree);
139  EXPECT_EQ(ByteGet(&test_addr, kSpxOffsetType), kSpxAddrTypeHashTree);
140 }
141 
142 TEST_F(SpxAddrTest, SubtreeCopyTest) {
143  spx_addr_t src_addr;
144  TestAddrInit(&src_addr);
145  spx_addr_t dest_addr = {.addr = {1, 2, 3, 4, 5, 6, 7, 8}};
146 
147  // Make a copy of `dest_addr` to preserve the original values.
148  spx_addr_t dest_addr_orig;
149  memcpy(dest_addr_orig.addr, dest_addr.addr, sizeof(dest_addr.addr));
150 
151  // Copy subtree.
152  spx_addr_subtree_copy(&dest_addr, &src_addr);
153 
154  // After copying, the layer and tree should match.
155  ExpectByteEq(&dest_addr, &src_addr, kSpxOffsetLayer);
156  EXPECT_EQ(TreeGet(&dest_addr), TreeGet(&src_addr));
157 
158  // Other fields should be unmodified.
159  ExpectByteEq(&dest_addr, &dest_addr_orig, kSpxOffsetType);
160  ExpectByteEq(&dest_addr, &dest_addr_orig, kSpxOffsetChainAddr);
161  ExpectByteEq(&dest_addr, &dest_addr_orig, kSpxOffsetHashAddr);
162  ExpectByteEq(&dest_addr, &dest_addr_orig, kSpxOffsetTreeHeight);
163  EXPECT_EQ(TreeIndexGet(&dest_addr), TreeIndexGet(&dest_addr_orig));
164  EXPECT_EQ(KeypairAddrGet(&dest_addr), KeypairAddrGet(&dest_addr_orig));
165 }
166 
167 TEST_F(SpxAddrTest, SubtreeCopySelf) {
168  spx_addr_t test_addr;
169  TestAddrInit(&test_addr);
170 
171  // Make a copy to preserve the original values.
172  spx_addr_t test_addr_orig;
173  memcpy(test_addr_orig.addr, test_addr.addr, sizeof(test_addr.addr));
174 
175  // Copy subtree.
176  spx_addr_subtree_copy(&test_addr, &test_addr);
177 
178  // After copying, the entire underlying buffer should match the original.
179  ExpectAddrEq(&test_addr, &test_addr_orig);
180 }
181 
182 TEST_F(SpxAddrTest, KeypairSetTest) {
183  spx_addr_t test_addr;
184  TestAddrInit(&test_addr);
185 
186  // Set keypair.
187  spx_addr_keypair_set(&test_addr, 0xddeeffaa);
188 
189  // Check result (bytes should be reversed for a big-endian representation).
190  EXPECT_EQ(0xaaffeedd, KeypairAddrGet(&test_addr));
191 }
192 
193 TEST_F(SpxAddrTest, ChainSetTest) {
194  uint8_t chain = 0xf0;
195  spx_addr_t test_addr;
196  TestAddrInit(&test_addr);
197 
198  // Set chain and check result.
199  spx_addr_chain_set(&test_addr, chain);
200  EXPECT_EQ(ByteGet(&test_addr, kSpxOffsetChainAddr), chain);
201 }
202 
203 TEST_F(SpxAddrTest, HashSetTest) {
204  uint8_t hash = 0xf0;
205  spx_addr_t test_addr;
206  TestAddrInit(&test_addr);
207 
208  // Set hash and check result.
209  spx_addr_hash_set(&test_addr, hash);
210  EXPECT_EQ(ByteGet(&test_addr, kSpxOffsetHashAddr), hash);
211 }
212 
213 TEST_F(SpxAddrTest, KeypairCopyTest) {
214  spx_addr_t src_addr;
215  TestAddrInit(&src_addr);
216  spx_addr_t dest_addr = {.addr = {1, 2, 3, 4, 5, 6, 7, 8}};
217 
218  // Make a copy of `dest_addr` to preserve the original values.
219  spx_addr_t dest_addr_orig;
220  memcpy(dest_addr_orig.addr, dest_addr.addr, sizeof(dest_addr.addr));
221 
222  // Copy subtree.
223  spx_addr_keypair_copy(&dest_addr, &src_addr);
224 
225  // After copying, the layer and tree should match.
226  ExpectByteEq(&dest_addr, &src_addr, kSpxOffsetLayer);
227  EXPECT_EQ(TreeGet(&dest_addr), TreeGet(&src_addr));
228 
229  // After copying, the keypair address should match.
230  EXPECT_EQ(KeypairAddrGet(&dest_addr), KeypairAddrGet(&src_addr));
231 
232  // Other fields should be unmodified.
233  ExpectByteEq(&dest_addr, &dest_addr_orig, kSpxOffsetType);
234  ExpectByteEq(&dest_addr, &dest_addr_orig, kSpxOffsetChainAddr);
235  ExpectByteEq(&dest_addr, &dest_addr_orig, kSpxOffsetHashAddr);
236  ExpectByteEq(&dest_addr, &dest_addr_orig, kSpxOffsetTreeHeight);
237  EXPECT_EQ(TreeIndexGet(&dest_addr), TreeIndexGet(&dest_addr_orig));
238 }
239 
240 TEST_F(SpxAddrTest, TreeHeightSetTest) {
241  uint8_t tree_height = 0xf0;
242  spx_addr_t test_addr;
243  TestAddrInit(&test_addr);
244 
245  // Set tree height and check result.
246  spx_addr_tree_height_set(&test_addr, tree_height);
247  EXPECT_EQ(ByteGet(&test_addr, kSpxOffsetTreeHeight), tree_height);
248 }
249 
250 TEST_F(SpxAddrTest, TreeIndexSetTest) {
251  uint32_t tree_index = 0x01020304;
252  // Same data in big-endian form.
253  uint32_t tree_index_be = 0x04030201;
254  spx_addr_t test_addr;
255  TestAddrInit(&test_addr);
256 
257  // Set tree index and check result.
258  spx_addr_tree_index_set(&test_addr, tree_index);
259  EXPECT_EQ(TreeIndexGet(&test_addr), tree_index_be);
260 }
261 
262 } // namespace
263 } // namespace spx_addr_unittest