From 65eb01301cf441c89b63a2c7020c975daaf6e2b4 Mon Sep 17 00:00:00 2001 From: Pascal Nasahl Date: Fri, 15 Dec 2023 15:47:40 +0000 Subject: [PATCH] [sca] OTBN uJSON command handler This PR translates the `sw/device/sca/otbn_vertical/` tests from simpleserial to uJSON. Signed-off-by: Pascal Nasahl --- .../tests/crypto/cryptotest/firmware/BUILD | 66 ++ .../cryptotest/firmware/ecc256_keygen_sca.c | 623 ++++++++++++++++++ .../cryptotest/firmware/ecc256_keygen_sca.h | 47 ++ .../cryptotest/firmware/ecc256_modinv_sca.c | 161 +++++ .../cryptotest/firmware/ecc256_modinv_sca.h | 50 ++ .../crypto/cryptotest/firmware/firmware.c | 5 + .../crypto/cryptotest/firmware/otbn_sca.c | 118 ++++ .../crypto/cryptotest/firmware/otbn_sca.h | 23 + sw/device/tests/crypto/cryptotest/json/BUILD | 7 + .../tests/crypto/cryptotest/json/commands.h | 1 + .../cryptotest/json/otbn_sca_commands.c | 6 + .../cryptotest/json/otbn_sca_commands.h | 98 +++ 12 files changed, 1205 insertions(+) create mode 100644 sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.c create mode 100644 sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.h create mode 100644 sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.c create mode 100644 sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.h create mode 100644 sw/device/tests/crypto/cryptotest/firmware/otbn_sca.c create mode 100644 sw/device/tests/crypto/cryptotest/firmware/otbn_sca.h create mode 100644 sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.c create mode 100644 sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.h diff --git a/sw/device/tests/crypto/cryptotest/firmware/BUILD b/sw/device/tests/crypto/cryptotest/firmware/BUILD index f1d7a12845e8a2..f6332a5c3edab3 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/BUILD +++ b/sw/device/tests/crypto/cryptotest/firmware/BUILD @@ -46,6 +46,52 @@ cc_library( ], ) +cc_library( + name = "ecc256_keygen_sca", + srcs = ["ecc256_keygen_sca.c"], + hdrs = ["ecc256_keygen_sca.h"], + deps = [ + "//hw/top_earlgrey/sw/autogen:top_earlgrey", + "//sw/device/lib/base:abs_mmio", + "//sw/device/lib/base:memory", + "//sw/device/lib/crypto/drivers:otbn", + "//sw/device/lib/runtime:ibex", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing:entropy_testutils", + "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a", + "//sw/device/lib/testing/test_framework:ottf_main", + "//sw/device/lib/testing/test_framework:ujson_ottf", + "//sw/device/lib/ujson", + "//sw/device/sca/lib:prng", + "//sw/device/sca/lib:sca", + "//sw/otbn/crypto:p256_key_from_seed_sca", + "//sw/device/tests/crypto/cryptotest/json:otbn_sca_commands", + ], +) + +cc_library( + name = "ecc256_modinv_sca", + srcs = ["ecc256_modinv_sca.c"], + hdrs = ["ecc256_modinv_sca.h"], + deps = [ + "//hw/top_earlgrey/sw/autogen:top_earlgrey", + "//sw/device/lib/base:abs_mmio", + "//sw/device/lib/base:memory", + "//sw/device/lib/crypto/drivers:otbn", + "//sw/device/lib/runtime:ibex", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing:entropy_testutils", + "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a", + "//sw/device/lib/testing/test_framework:ottf_main", + "//sw/device/lib/testing/test_framework:ujson_ottf", + "//sw/device/lib/ujson", + "//sw/device/sca/lib:prng", + "//sw/device/sca/lib:sca", + "//sw/otbn/crypto:p256_mod_inv_sca", + "//sw/device/tests/crypto/cryptotest/json:otbn_sca_commands", + ], +) + cc_library( name = "ibex_fi", srcs = ["ibex_fi.c"], @@ -82,6 +128,25 @@ cc_library( ], ) +cc_library( + name = "otbn_sca", + srcs = ["otbn_sca.c"], + hdrs = ["otbn_sca.h"], + deps = [ + ":ecc256_keygen_sca", + ":ecc256_modinv_sca", + "//sw/device/lib/base:memory", + "//sw/device/lib/base:status", + "//sw/device/lib/crypto/impl:status", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing/test_framework:ujson_ottf", + "//sw/device/lib/ujson", + "//sw/device/sca/lib:prng", + "//sw/device/sca/lib:sca", + "//sw/device/tests/crypto/cryptotest/json:otbn_sca_commands", + ], +) + cc_library( name = "prng_sca", srcs = ["prng_sca.c"], @@ -141,6 +206,7 @@ opentitan_binary( ":aes_sca", ":ibex_fi", ":kmac_sca", + ":otbn_sca", ":prng_sca", ":sha3_sca", ":trigger_sca", diff --git a/sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.c b/sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.c new file mode 100644 index 00000000000000..caf62dee1c95f6 --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.c @@ -0,0 +1,623 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.h" + +#include "sw/device/lib/base/abs_mmio.h" +#include "sw/device/lib/base/memory.h" +#include "sw/device/lib/runtime/ibex.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/entropy_testutils.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" +#include "sw/device/lib/testing/test_framework/ottf_test_config.h" +#include "sw/device/lib/testing/test_framework/ujson_ottf.h" +#include "sw/device/lib/ujson/ujson.h" +#include "sw/device/sca/lib/prng.h" +#include "sw/device/sca/lib/sca.h" +#include "sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.h" + +#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" +#include "otbn_regs.h" + +enum { + /** + * Number of bytes for ECDSA P-256 seeds and masked private keys. + */ + kEcc256SeedNumBytes = 320 / 8, + /** + * Number of 32b words for ECDSA P-256 seeds and masked private keys. + */ + kEcc256SeedNumWords = kEcc256SeedNumBytes / sizeof(uint32_t), + /** + * Number of bytes for ECDSA P-256 point coordinates. + */ + kEcc256CoordNumBytes = 256 / 8, + /** + * Number of 32b words for ECDSA P-256 point coordinates. + */ + kEcc256CoordNumWords = kEcc256CoordNumBytes / sizeof(uint32_t), + /** + * Mode option for the ECDSA keygen app (generates the private key only). + */ + kEcc256ModePrivateKeyOnly = 1, + /** + * Mode option for the ECDSA keygen app (generates the full keypair). + */ + kEcc256ModeKeypair = 2, + /** + * Max number of traces per batch. + */ + kNumBatchOpsMax = 256, + /** + * Number of cycles that Ibex should sleep to minimize noise during OTBN + * operations. Caution: This number should be chosen to provide enough time + * to complete the operation. Otherwise, Ibex might wake up while OTBN is + * still busy and disturb the capture. + */ + kIbexOtbnSleepCycles = 800, +}; + +/** + * App configuration for p256_key_from_seed_sca + */ +const otbn_app_t kOtbnAppP256KeyFromSeed = + OTBN_APP_T_INIT(p256_key_from_seed_sca); + +static const otbn_addr_t kOtbnVarMode = + OTBN_ADDR_T_INIT(p256_key_from_seed_sca, mode); +static const otbn_addr_t kOtbnVarSeed0 = + OTBN_ADDR_T_INIT(p256_key_from_seed_sca, seed0); +static const otbn_addr_t kOtbnVarSeed1 = + OTBN_ADDR_T_INIT(p256_key_from_seed_sca, seed1); +static const otbn_addr_t kOtbnVarD0 = + OTBN_ADDR_T_INIT(p256_key_from_seed_sca, d0); +static const otbn_addr_t kOtbnVarD1 = + OTBN_ADDR_T_INIT(p256_key_from_seed_sca, d1); +static const otbn_addr_t kOtbnVarX = + OTBN_ADDR_T_INIT(p256_key_from_seed_sca, x); +static const otbn_addr_t kOtbnVarY = + OTBN_ADDR_T_INIT(p256_key_from_seed_sca, y); + +/** + * An array of seeds to be used in a batch + */ +uint32_t batch_share0[kNumBatchOpsMax][kEcc256SeedNumWords]; + +/** + * An array of masks to be used in a batch + */ +uint32_t batch_share1[kNumBatchOpsMax][kEcc256SeedNumWords]; + +/** + * Arrays for first and second share of masked private key d to be used in a + * batch + */ +uint32_t d0_batch[kEcc256SeedNumWords]; +uint32_t d1_batch[kEcc256SeedNumWords]; + +/** + * Fixed-message indicator. + * + * Used in the 'b' (batch capture) command for indicating whether to use fixed + * or random message. + */ +static bool run_fixed = true; + +/** + * Masking indicator. + * + * Used in the 'b' (batch capture) command for indicating whether to use masks. + */ +static bool en_masks = false; + +/** + * Seed value. + * + * The default value corresponds to the test data in + * sw/otbn/crypto/test/p256_key_from_seed_test.s + * + * This default value can be overwritten via the simpleserial command `x` + * (see ecc256_set_seed) + */ +uint32_t ecc256_seed[kEcc256SeedNumWords] = { + 0x016064e9, 0x11e3f4d6, 0xac3a6fa7, 0xaba11a1b, 0x8f9271d1, + 0x22b79d5f, 0x1176f31d, 0xb5ac3a51, 0x99a082d7, 0x484eb366, +}; + +uint32_t ecc256_C[kEcc256SeedNumWords] = { + 0x016064e9, 0x11e3f4d6, 0xac3a6fa7, 0xaba11a1b, 0x8f9271d1, + 0x22b79d5f, 0x1176f31d, 0xb5ac3a51, 0x99a082d7, 0x484eb366, +}; + +uint32_t random_number[kEcc256CoordNumWords] = { + 0x016064e9, 0x11e3f4d6, 0xac3a6fa7, 0xaba11a1b, + 0x22b79d5f, 0x1176f31d, 0xb5ac3a51, 0x99a082d7, +}; + +uint32_t ecc256_fixed_number[kEcc256CoordNumWords] = { + 0x04030201, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +/** + * Enable masks handler. + * + * The uJSON data contains: + * - en_masks: Enable masks. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_ecc256_en_masks(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_en_masks"); + cryptotest_otbn_sca_en_masks_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_en_masks_t(uj, &uj_data)); + if (*uj_data.en_masks) { + en_masks = true; + } else { + en_masks = false; + } + LOG_ERROR("Fin handle_otbn_sca_ecc256_en_masks"); + return OK_STATUS(0); +} + +/** + * Set seed command handler. + * + * The seed must be `kEcc256SeedNumBytes` bytes long. + * + * The uJSON data contains: + * - seed: Value for seed share. + * - seed_len: Length of seed share. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_ecc256_set_seed(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_set_seed"); + cryptotest_otbn_sca_seed_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_seed_t(uj, &uj_data)); + + if (*uj_data.seed_len != kEcc256SeedNumBytes) { + return OUT_OF_RANGE(); + } + memcpy(ecc256_seed, uj_data.seed, *uj_data.seed_len); + // Run PRNG once to synch with capture side. There it is used also to + // generate the fixed seed. + uint32_t temp[kEcc256SeedNumWords]; + prng_rand_bytes((unsigned char *)temp, kEcc256SeedNumBytes); + + LOG_ERROR("Fin handle_otbn_sca_ecc256_set_seed"); + return OK_STATUS(0); +} + +/** + * Set constant command handler. + * + * The constant must be `kEcc256SeedNumBytes` bytes long. + * + * @param C Value of the C constant. + * @param len Length of the C constant. + */ +status_t handle_otbn_sca_ecc256_set_c(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_set_c"); + cryptotest_otbn_sca_constant_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_constant_t(uj, &uj_data)); + if (*uj_data.constant_len != kEcc256SeedNumBytes) { + return OUT_OF_RANGE(); + } + memcpy(ecc256_C, uj_data.constant, *uj_data.constant_len); + LOG_ERROR("Fin handle_otbn_sca_ecc256_set_c"); + return OK_STATUS(0); +} + +/** + * Callback wrapper for OTBN manual trigger function. + */ +static void otbn_manual_trigger(void) { otbn_execute(); } + +/** + * Runs the OTBN key generation program. + * + * The seed shares must be `kEcc256SeedNumWords` words long. + * + * @param[in] mode Mode parameter (private key only or full keypair). + * @param[in] seed Seed for key generation. + * @param[in] mask Mask for seed. + */ +static ecc256_keygen_sca_error_t p256_run_keygen(uint32_t mode, + const uint32_t *share0, + const uint32_t *share1) { + // Write mode. + if (otbn_dmem_write(/*num_words=*/1, &mode, kOtbnVarMode).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + + // Write seed shares. + if (otbn_dmem_write(kEcc256SeedNumWords, share0, kOtbnVarSeed0).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + if (otbn_dmem_write(kEcc256SeedNumWords, share1, kOtbnVarSeed1).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + + // Execute program. + sca_set_trigger_high(); + sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles); + otbn_busy_wait_for_done(); + sca_set_trigger_low(); + + return ecc256KeygenOk; +} + +/** + * Ecc256 ecdsa keygen fvsr seed batch command handler. + * + * The uJSON data contains: + * - num_traces: The number of traces. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_seed_batch(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_seed_batch"); + + cryptotest_otbn_sca_num_traces_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_num_traces_t(uj, &uj_data)); + + uint32_t num_traces = 0; + uint32_t batch_digest[kEcc256SeedNumWords]; + uint8_t dummy[kEcc256SeedNumBytes]; + num_traces = *uj_data.num_traces; + LOG_ERROR("num_traces = %d", num_traces); + + if (num_traces > kNumBatchOpsMax) { + return OUT_OF_RANGE(); + } + + // zero the batch digest + for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) { + batch_digest[j] = 0; + } + + for (uint32_t i = 0; i < num_traces; ++i) { + if (run_fixed) { + memcpy(batch_share0[i], ecc256_seed, kEcc256SeedNumBytes); + } else { + prng_rand_bytes((unsigned char *)batch_share0[i], kEcc256SeedNumBytes); + } + if (en_masks) { + prng_rand_bytes((unsigned char *)batch_share1[i], kEcc256SeedNumBytes); + } else { + for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) { + batch_share1[i][j] = 0; + } + } + for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) { + batch_share0[i][j] ^= batch_share1[i][j]; + } + // Another PRNG run to determine 'run_fixed' for the next cycle. + prng_rand_bytes(dummy, kEcc256SeedNumBytes); + run_fixed = dummy[0] & 0x1; + } + + for (uint32_t i = 0; i < num_traces; ++i) { + p256_run_keygen(kEcc256ModePrivateKeyOnly, batch_share0[i], + batch_share1[i]); + + // Read results. + if (otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD0, d0_batch).value != + OTCRYPTO_OK.value) { + return ABORTED(); + } + if (otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD1, d1_batch).value != + OTCRYPTO_OK.value) { + return ABORTED(); + } + + // The correctness of each batch is verified by computing and sending + // the batch digest. This digest is computed by XORing all d0 shares of + // the batch. + for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) { + batch_digest[j] ^= d0_batch[j]; + } + } + + // Send the batch digest to the host for verification. + cryptotest_otbn_sca_batch_digest_t uj_output; + memcpy(uj_output.batch_digest, (uint8_t *)batch_digest, + kEcc256SeedNumWords * 4); + RESP_OK(ujson_serialize_cryptotest_otbn_sca_batch_digest_t, uj, &uj_output); + + LOG_ERROR("Fin handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_seed_batch"); + return OK_STATUS(0); +} + +/** + * Adds two integers storred in byte arrays. + * + * Adds the integer stored in source array to the integer stored in + * destination aray. + * The user needs to ensure that dest_len isenough to store the result + * without overflow. + * + * @param[in] dest Location of the first input array and the result. + * @param[in] source Location of the second input array. + * @param[in] dest_len Length od the dest array in bytes. + * @param[in] source_len Length of the source array in bytes. + */ +static void add_arrays(uint8_t *dest, uint8_t *source, size_t dest_len, + size_t source_len) { + uint16_t temp = 0; + + for (size_t i = 0; i < source_len; i++) { + temp += (uint16_t)source[i] + dest[i]; + dest[i] = (uint8_t)(temp & 0x00FF); + temp >>= 8; + } + + for (size_t i = source_len; i < dest_len; i++) { + temp += (uint16_t)dest[i]; + dest[i] = (uint8_t)(temp & 0x00FF); + temp >>= 8; + } +} + +/** + * Ecc256 ecdsa keygen fvsr key batch command handler. + * + * The uJSON data contains: + * - num_traces: The number of traces. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_key_batch(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_key_batch"); + + cryptotest_otbn_sca_num_traces_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_num_traces_t(uj, &uj_data)); + + uint32_t num_traces = 0; + uint32_t batch_digest[kEcc256SeedNumWords]; + uint8_t dummy[kEcc256SeedNumBytes]; + num_traces = *uj_data.num_traces; + LOG_ERROR("num_traces = %d", num_traces); + + if (num_traces > kNumBatchOpsMax) { + return OUT_OF_RANGE(); + } + + // zero the batch digest + for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) { + batch_digest[j] = 0; + } + + for (uint32_t i = 0; i < num_traces; ++i) { + if (run_fixed) { + memcpy(batch_share0[i], ecc256_seed, kEcc256SeedNumBytes); + } else { + // Here change to random_number + C + // It is necessary to set the C first + memcpy(batch_share0[i], ecc256_C, kEcc256SeedNumBytes); + prng_rand_bytes((unsigned char *)random_number, kEcc256CoordNumBytes); + add_arrays((unsigned char *)batch_share0[i], + (unsigned char *)random_number, kEcc256SeedNumBytes, + kEcc256CoordNumBytes); + } + if (en_masks) { + prng_rand_bytes((unsigned char *)batch_share1[i], kEcc256SeedNumBytes); + } else { + for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) { + batch_share1[i][j] = 0; + } + } + for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) { + batch_share0[i][j] ^= batch_share1[i][j]; + } + // Another PRNG run to determine 'run_fixed' for the next cycle. + prng_rand_bytes(dummy, kEcc256SeedNumBytes); + + run_fixed = dummy[0] & 0x1; + } + + for (uint32_t i = 0; i < num_traces; ++i) { + p256_run_keygen(kEcc256ModePrivateKeyOnly, batch_share0[i], + batch_share1[i]); + + // Read results. + if (otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD0, d0_batch).value != + OTCRYPTO_OK.value) { + return ABORTED(); + } + if (otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD1, d1_batch).value != + OTCRYPTO_OK.value) { + return ABORTED(); + } + + // The correctness of each batch is verified by computing and sending + // the batch digest. This digest is computed by XORing all d0 shares of + // the batch. + for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) { + batch_digest[j] ^= d0_batch[j]; + } + } + // Send the batch digest to the host for verification. + cryptotest_otbn_sca_batch_digest_t uj_output; + memcpy(uj_output.batch_digest, (uint8_t *)batch_digest, + kEcc256SeedNumWords * 4); + RESP_OK(ujson_serialize_cryptotest_otbn_sca_batch_digest_t, uj, &uj_output); + + LOG_ERROR("Fin handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_key_batch"); + return OK_STATUS(0); +} + +/** + * Generates a secret key from a masked seed. + * + * The seed shares must be `kEcc256SeedNumWords` words long, and the caller + * must provide pre-allocated buffers of the same length for the private key + * shares. + * + * @param[in] seed Seed for key generation. + * @param[in] mask Mask for seed. + * @param[out] d0 First share of masked private key d. + * @param[out] d1 Second share of masked private key d. + */ +static ecc256_keygen_sca_error_t p256_ecdsa_gen_secret_key(const uint32_t *seed, + const uint32_t *mask, + uint32_t *d0, + uint32_t *d1) { + // Compute first share of seed (seed ^ mask). + uint32_t share0[kEcc256SeedNumWords]; + for (size_t i = 0; i < kEcc256SeedNumWords; i++) { + share0[i] = seed[i] ^ mask[i]; + } + + // Run the key generation program. + p256_run_keygen(kEcc256ModePrivateKeyOnly, share0, mask); + + // Read results. + if (otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD0, d0).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + if (otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD1, d1).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + + return ecc256KeygenOk; +} + +/** + * Generates a keypair from a masked seed. + * + * The seed shares must be `kEcc256SeedNumWords` words long, and the caller + * must provide pre-allocated buffers of the same length for the private key + * shares and of length `kEcc256CoordNumWords` for the public key coordinates. + * + * @param[in] seed Seed for key generation. + * @param[in] mask Mask for seed. + * @param[out] d0 First share of masked private key d. + * @param[out] d1 Second share of masked private key d. + * @param[out] x x-coordinate of public key Q. + * @param[out] y y-coordinate of public key Q. + */ +static ecc256_keygen_sca_error_t p256_ecdsa_gen_keypair( + const uint32_t *seed, const uint32_t *mask, uint32_t *d0, uint32_t *d1, + uint32_t *x, uint32_t *y) { + // Compute the first share of the seed (seed ^ mask). + uint32_t share0[kEcc256SeedNumWords]; + for (size_t i = 0; i < kEcc256SeedNumWords; i++) { + share0[i] = seed[i] ^ mask[i]; + } + + // Run the key generation program. + p256_run_keygen(kEcc256ModeKeypair, share0, mask); + + // Read results. + if (otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD0, d0).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + if (otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD1, d1).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + if (otbn_dmem_read(kEcc256CoordNumWords, kOtbnVarX, x).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + if (otbn_dmem_read(kEcc256CoordNumWords, kOtbnVarY, y).value != + OTCRYPTO_OK.value) { + return ecc256KeygenAborted; + } + + return ecc256KeygenOk; +} + +/** + * Ecc256 ecdsa secret keygen command handler. + * + * The uJSON data contains: + * - mask: The mask. + * - mask_len: The mask length. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_ecc256_ecdsa_secret_keygen(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_ecdsa_secret_keygen"); + + cryptotest_otbn_sca_mask_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_mask_t(uj, &uj_data)); + + if (*uj_data.mask_len != kEcc256SeedNumBytes) { + return OUT_OF_RANGE(); + } + + // Copy mask to an aligned buffer. + uint32_t ecc256_mask[kEcc256SeedNumWords]; + memcpy(ecc256_mask, uj_data.mask, kEcc256SeedNumBytes); + + uint32_t ecc256_d0[kEcc256SeedNumWords]; + uint32_t ecc256_d1[kEcc256SeedNumWords]; + if (p256_ecdsa_gen_secret_key(ecc256_seed, ecc256_mask, ecc256_d0, + ecc256_d1) != ecc256KeygenOk) { + return ABORTED(); + } + + cryptotest_otbn_sca_ecc_seed_t uj_output; + memcpy(uj_output.d0, (uint8_t *)ecc256_d0, kEcc256SeedNumBytes); + memcpy(uj_output.d1, (uint8_t *)ecc256_d1, kEcc256SeedNumBytes); + RESP_OK(ujson_serialize_cryptotest_otbn_sca_ecc_seed_t, uj, &uj_output); + + LOG_ERROR("Fin handle_otbn_sca_ecc256_ecdsa_secret_keygen"); + return OK_STATUS(0); +} + +/** + * Ecc256 ecdsa gen keypair command handler. + * + * The uJSON data contains: + * - mask: The mask. + * - mask_len: The mask length. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_ecc256_ecdsa_gen_keypair(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_ecdsa_gen_keypair"); + + cryptotest_otbn_sca_mask_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_mask_t(uj, &uj_data)); + if (*uj_data.mask_len != kEcc256SeedNumBytes) { + return OUT_OF_RANGE(); + } + + // Copy mask to an aligned buffer. + uint32_t ecc256_mask[kEcc256SeedNumWords]; + memcpy(ecc256_mask, uj_data.mask, kEcc256SeedNumBytes); + + uint32_t ecc256_d0[kEcc256SeedNumWords]; + uint32_t ecc256_d1[kEcc256SeedNumWords]; + uint32_t ecc256_x[kEcc256CoordNumWords]; + uint32_t ecc256_y[kEcc256CoordNumWords]; + if (p256_ecdsa_gen_keypair(ecc256_seed, ecc256_mask, ecc256_d0, ecc256_d1, + ecc256_x, ecc256_y) != ecc256KeygenOk) { + return ABORTED(); + } + + cryptotest_otbn_sca_ecc_seed_t uj_output_seed; + memcpy(uj_output_seed.d0, (uint8_t *)ecc256_d0, kEcc256SeedNumBytes); + memcpy(uj_output_seed.d1, (uint8_t *)ecc256_d1, kEcc256SeedNumBytes); + RESP_OK(ujson_serialize_cryptotest_otbn_sca_ecc_seed_t, uj, &uj_output_seed); + + cryptotest_otbn_sca_ecc_coord_t uj_output_coord; + memcpy(uj_output_coord.x, (uint8_t *)ecc256_x, kEcc256CoordNumBytes); + memcpy(uj_output_coord.y, (uint8_t *)ecc256_y, kEcc256CoordNumBytes); + RESP_OK(ujson_serialize_cryptotest_otbn_sca_ecc_coord_t, uj, + &uj_output_coord); + + LOG_ERROR("Fin handle_otbn_sca_ecc256_ecdsa_gen_keypair"); + return OK_STATUS(0); +} diff --git a/sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.h b/sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.h new file mode 100644 index 00000000000000..85c933b0a33b0b --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/ecc256_keygen_sca.h @@ -0,0 +1,47 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_SCA_OTBN_VERTICAL_ECC256_KEYGEN_SCA_H_ +#define OPENTITAN_SW_DEVICE_SCA_OTBN_VERTICAL_ECC256_KEYGEN_SCA_H_ + +#include "sw/device/lib/crypto/drivers/otbn.h" + +/** + * The result of an OTBN SCA operation. + */ +typedef enum ecc256_keygen_sca_error { + /** + * Indicates that the operation succeeded. + */ + ecc256KeygenOk = 0, + /** + * Indicates some unspecified failure. + */ + ecc256KeygenAborted = 1, +} ecc256_keygen_sca_error_t; + +/** + * App configuration for p256_key_from_seed_sca + */ +OTBN_DECLARE_APP_SYMBOLS(p256_key_from_seed_sca); + +OTBN_DECLARE_SYMBOL_ADDR(p256_key_from_seed_sca, mode); +OTBN_DECLARE_SYMBOL_ADDR(p256_key_from_seed_sca, seed0); +OTBN_DECLARE_SYMBOL_ADDR(p256_key_from_seed_sca, seed1); +OTBN_DECLARE_SYMBOL_ADDR(p256_key_from_seed_sca, d0); +OTBN_DECLARE_SYMBOL_ADDR(p256_key_from_seed_sca, d1); +OTBN_DECLARE_SYMBOL_ADDR(p256_key_from_seed_sca, x); +OTBN_DECLARE_SYMBOL_ADDR(p256_key_from_seed_sca, y); + +extern const otbn_app_t kOtbnAppP256KeyFromSeed; + +static const otbn_addr_t kOtbnVarMode; +static const otbn_addr_t kOtbnVarSeed0; +static const otbn_addr_t kOtbnVarSeed1; +static const otbn_addr_t kOtbnVarD0; +static const otbn_addr_t kOtbnVarD1; +static const otbn_addr_t kOtbnVarX; +static const otbn_addr_t kOtbnVarY; + +#endif // OPENTITAN_SW_DEVICE_SCA_OTBN_VERTICAL_ECC256_KEYGEN_SCA_H_ diff --git a/sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.c b/sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.c new file mode 100644 index 00000000000000..060a2be5ad6bdc --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.c @@ -0,0 +1,161 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.h" + +#include "sw/device/lib/base/abs_mmio.h" +#include "sw/device/lib/base/memory.h" +#include "sw/device/lib/runtime/ibex.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/entropy_testutils.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" +#include "sw/device/lib/testing/test_framework/ottf_test_config.h" +#include "sw/device/lib/testing/test_framework/ujson_ottf.h" +#include "sw/device/lib/ujson/ujson.h" +#include "sw/device/sca/lib/prng.h" +#include "sw/device/sca/lib/sca.h" +#include "sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.h" + +#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" +#include "otbn_regs.h" + +enum { + /** + * Number of cycles that Ibex should sleep to minimize noise during OTBN + * operations. Caution: This number should be chosen to provide enough time + * to complete the operation. Otherwise, Ibex might wake up while OTBN is + * still busy and disturb the capture. + */ + kIbexOtbnSleepCycles = 50000, + /** + * Number of bytes for ECDSA P-256 modular inverse input shares (k0,k1). + */ + kEcc256ModInvInputShareNumBytes = 320 / 8, + /** + * Number of words for ECDSA P-256 modular inverse input shares (k0,k1). + */ + kEcc256ModInvInputShareNumWords = + kEcc256ModInvInputShareNumBytes / sizeof(uint32_t), + /** + * Number of bytes for ECDSA P-256 modular inverse output ((k*alpha)^-1 mod + * n). + */ + kEcc256ModInvOutputKAlphaInvNumBytes = 256 / 8, + /** + * Number of words for ECDSA P-256 modular inverse output ((k*alpha)^-1 mod + * n). + */ + kEcc256ModInvOutputKAlphaInvNumWords = + kEcc256ModInvOutputKAlphaInvNumBytes / sizeof(uint32_t), + /** + * Number of bytes for ECDSA P-256 modular inverse output mask (alpha). + */ + kEcc256ModInvOutputAlphaNumBytes = 128 / 8, + /** + * Number of words for ECDSA P-256 modular inverse output mask (alpha). + */ + kEcc256ModInvOutputAlphaNumWords = + kEcc256ModInvOutputAlphaNumBytes / sizeof(uint32_t), +}; + +/** + * App configuration for p256_mod_inv_sca + */ +const otbn_app_t kOtbnAppP256ModInv = OTBN_APP_T_INIT(p256_mod_inv_sca); + +static const otbn_addr_t kOtbnVarModInvK0 = + OTBN_ADDR_T_INIT(p256_mod_inv_sca, k0); +static const otbn_addr_t kOtbnVarModInvK1 = + OTBN_ADDR_T_INIT(p256_mod_inv_sca, k1); +static const otbn_addr_t kOtbnVarModInvKAplhaInv = + OTBN_ADDR_T_INIT(p256_mod_inv_sca, kalpha_inv); +static const otbn_addr_t kOtbnVarModInvAlpha = + OTBN_ADDR_T_INIT(p256_mod_inv_sca, alpha); + +/** + * Callback wrapper for OTBN manual trigger function. + */ +static void otbn_manual_trigger(void) { otbn_execute(); } + +/** + * Runs the OTBN modular inverse program. + * + * The input must be `kEcc256ModInvInputShareNumWords` words long. + * + * @param[in] input Iput value for the OTBN modular inverse. + */ +static ecc256_modinv_sca_error_t p256_run_modinv(uint32_t *k0, uint32_t *k1) { + // Write input. + if (otbn_dmem_write(kEcc256ModInvInputShareNumWords, k0, kOtbnVarModInvK0) + .value != OTCRYPTO_OK.value) { + return ecc256ModinvAborted; + } + + if (otbn_dmem_write(kEcc256ModInvInputShareNumWords, k1, kOtbnVarModInvK1) + .value != OTCRYPTO_OK.value) { + return ecc256ModinvAborted; + } + + // Execute program. + sca_set_trigger_high(); + sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles); + otbn_busy_wait_for_done(); + sca_set_trigger_low(); + + return ecc256ModinvOk; +} + +/** + * Computes the modular inverse of a certain input. + * + * The uJSON data contains: + * - k0_k1: Input for modular inverse computation. + * - k0_k1:len: Length. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_ecc256_modinv(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_modinv"); + cryptotest_otbn_sca_k_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_k_t(uj, &uj_data)); + + if (*uj_data.k_len != 2 * kEcc256ModInvInputShareNumBytes) { + return OUT_OF_RANGE(); + } + + // Copy input to an aligned buffer. + uint32_t modinv_k0[kEcc256ModInvInputShareNumWords]; + uint32_t modinv_k1[kEcc256ModInvInputShareNumWords]; + memcpy(modinv_k0, uj_data.k, kEcc256ModInvInputShareNumBytes); + memcpy(modinv_k1, (uj_data.k + kEcc256ModInvInputShareNumBytes), + kEcc256ModInvInputShareNumBytes); + + // Run the key generation program. + if (p256_run_modinv(modinv_k0, modinv_k1) != ecc256ModinvOk) { + return ABORTED(); + }; + + // Read result. + uint32_t modinv_kalpha_inv[kEcc256ModInvOutputKAlphaInvNumWords]; + uint32_t modinv_alpha[kEcc256ModInvOutputAlphaNumWords]; + if (otbn_dmem_read(kEcc256ModInvOutputKAlphaInvNumWords, + kOtbnVarModInvKAplhaInv, modinv_kalpha_inv) + .value != OTCRYPTO_OK.value) { + return ABORTED(); + } + if (otbn_dmem_read(kEcc256ModInvOutputAlphaNumWords, kOtbnVarModInvAlpha, + modinv_alpha) + .value != OTCRYPTO_OK.value) { + return ABORTED(); + } + cryptotest_otbn_sca_alpha_t uj_output; + memcpy(uj_output.alpha_inv, (uint8_t *)modinv_kalpha_inv, + kEcc256ModInvOutputKAlphaInvNumBytes); + memcpy(uj_output.alpha, (uint8_t *)modinv_alpha, + kEcc256ModInvOutputAlphaNumBytes); + RESP_OK(ujson_serialize_cryptotest_otbn_sca_alpha_t, uj, &uj_output); + + LOG_ERROR("Fin handle_otbn_sca_ecc256_modinv"); + return OK_STATUS(0); +} diff --git a/sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.h b/sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.h new file mode 100644 index 00000000000000..ea5e950b0c42c4 --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/ecc256_modinv_sca.h @@ -0,0 +1,50 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_SCA_OTBN_VERTICAL_ECC256_MODINV_SCA_H_ +#define OPENTITAN_SW_DEVICE_SCA_OTBN_VERTICAL_ECC256_MODINV_SCA_H_ + +#include "sw/device/lib/crypto/drivers/otbn.h" + +/** + * The result of an OTBN SCA operation. + */ +typedef enum ecc256_modinv_sca_error { + /** + * Indicates that the operation succeeded. + */ + ecc256ModinvOk = 0, + /** + * Indicates some unspecified failure. + */ + ecc256ModinvAborted = 1, +} ecc256_modinv_sca_error_t; + +/** + * App configuration for p256_mod_inv_sca + */ +OTBN_DECLARE_APP_SYMBOLS(p256_mod_inv_sca); + +OTBN_DECLARE_SYMBOL_ADDR(p256_mod_inv_sca, k0); +OTBN_DECLARE_SYMBOL_ADDR(p256_mod_inv_sca, k1); +OTBN_DECLARE_SYMBOL_ADDR(p256_mod_inv_sca, kalpha_inv); +OTBN_DECLARE_SYMBOL_ADDR(p256_mod_inv_sca, alpha); + +extern const otbn_app_t kOtbnAppP256ModInv; + +static const otbn_addr_t kOtbnVarModInvK0; +static const otbn_addr_t kOtbnVarModInvK1; +static const otbn_addr_t kOtbnVarModInvKAplhaInv; +static const otbn_addr_t kOtbnVarModInvAlpha; + +/** + * Computes the modular inverse of a certain input. + * + * The input must be `kEcc256ModInvInputShareNumWords` words long. + * + * @param[in] input Input for modular inverse computation. + */ +void ecc256_modinv(const uint8_t *k0_k1, size_t k0_k1_len); + +#endif // OPENTITAN_SW_DEVICE_SCA_OTBN_VERTICAL_ECC256_MODINV_SCA_H_ diff --git a/sw/device/tests/crypto/cryptotest/firmware/firmware.c b/sw/device/tests/crypto/cryptotest/firmware/firmware.c index 048bd6cbbbe9fa..b9e7307ece4d9b 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/firmware.c +++ b/sw/device/tests/crypto/cryptotest/firmware/firmware.c @@ -16,6 +16,7 @@ #include "sw/device/tests/crypto/cryptotest/json/commands.h" #include "sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h" #include "sw/device/tests/crypto/cryptotest/json/kmac_sca_commands.h" +#include "sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.h" #include "sw/device/tests/crypto/cryptotest/json/prng_sca_commands.h" #include "sw/device/tests/crypto/cryptotest/json/sha3_sca_commands.h" #include "sw/device/tests/crypto/cryptotest/json/trigger_sca_commands.h" @@ -25,6 +26,7 @@ #include "aes_sca.h" #include "ibex_fi.h" #include "kmac_sca.h" +#include "otbn_sca.h" #include "prng_sca.h" #include "sha3_sca.h" #include "trigger_sca.h" @@ -48,6 +50,9 @@ status_t process_cmd(ujson_t *uj) { case kCryptotestCommandKmacSca: RESP_ERR(uj, handle_kmac_sca(uj)); break; + case kCryptotestCommandOtbnSca: + RESP_ERR(uj, handle_otbn_sca(uj)); + break; case kCryptotestCommandPrngSca: RESP_ERR(uj, handle_prng_sca(uj)); break; diff --git a/sw/device/tests/crypto/cryptotest/firmware/otbn_sca.c b/sw/device/tests/crypto/cryptotest/firmware/otbn_sca.c new file mode 100644 index 00000000000000..83bcc7ace5075e --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/otbn_sca.c @@ -0,0 +1,118 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/tests/crypto/cryptotest/firmware/otbn_sca.h" + +#include "ecc256_keygen_sca.h" +#include "ecc256_modinv_sca.h" +#include "sw/device/lib/base/memory.h" +#include "sw/device/lib/base/status.h" +#include "sw/device/lib/crypto/impl/status.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/test_framework/ottf_test_config.h" +#include "sw/device/lib/testing/test_framework/ujson_ottf.h" +#include "sw/device/lib/ujson/ujson.h" +#include "sw/device/sca/lib/prng.h" +#include "sw/device/sca/lib/sca.h" +#include "sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.h" + +/** + * App select command handler. + * + * This handler has to be called to load a new app to otbn. + * + * The uJSON data contains: + * - app: 0 => ecc256 keygen, 1 => ecc256 modular inverse. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_ecc256_app_select(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_ecc256_app_select"); + cryptotest_otbn_sca_app_select_t uj_data; + TRY(ujson_deserialize_cryptotest_otbn_sca_app_select_t(uj, &uj_data)); + + if (*uj_data.app == 0) { + // load keygen app + if (otbn_load_app(kOtbnAppP256KeyFromSeed).value != OTCRYPTO_OK.value) { + return ABORTED(); + } + } else if (*uj_data.app == 1) { + // load mod inv app + if (otbn_load_app(kOtbnAppP256ModInv).value != OTCRYPTO_OK.value) { + return ABORTED(); + } + LOG_ERROR("Wrong app select command."); + } + LOG_ERROR("In handle_otbn_sca_ecc256_app_select"); + return OK_STATUS(0); +} + +/** + * Initialize OTBN command handler. + * + * This command is designed to setup the AES. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca_init(ujson_t *uj) { + LOG_ERROR("In handle_otbn_sca_init"); + sca_init(kScaTriggerSourceOtbn, kScaPeripheralEntropy | kScaPeripheralIoDiv4 | + kScaPeripheralOtbn | kScaPeripheralCsrng | + kScaPeripheralEdn | kScaPeripheralHmac); + + // Load p256 keygen from seed app into OTBN. + if (otbn_load_app(kOtbnAppP256KeyFromSeed).value != OTCRYPTO_OK.value) { + return ABORTED(); + } + LOG_ERROR("Fin handle_otbn_sca_init"); + return OK_STATUS(0); +} + +/** + * OTBN SCA command handler. + * + * Command hanlder for the OTBN SCA command. + * + * @param uj The received uJSON data. + */ +status_t handle_otbn_sca(ujson_t *uj) { + otbn_sca_subcommand_t cmd; + TRY(ujson_deserialize_otbn_sca_subcommand_t(uj, &cmd)); + switch (cmd) { + case kOtbnScaSubcommandInit: + return handle_otbn_sca_init(uj); + break; + case kOtbnScaSubcommandEcc256EcdsaKeygenFvsrSeedBatch: + return handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_seed_batch(uj); + break; + case kOtbnScaSubcommandEcc256EcdsaKeygenFvsrKeyBatch: + return handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_key_batch(uj); + break; + case kOtbnScaSubcommandEcc256EcdsaSecretKeygen: + return handle_otbn_sca_ecc256_ecdsa_secret_keygen(uj); + break; + case kOtbnScaSubcommandEcc256EcdsaGenKeypair: + return handle_otbn_sca_ecc256_ecdsa_gen_keypair(uj); + break; + case kOtbnScaSubcommandEcc256SetSeed: + return handle_otbn_sca_ecc256_set_seed(uj); + break; + case kOtbnScaSubcommandEcc256SetC: + return handle_otbn_sca_ecc256_set_c(uj); + break; + case kOtbnScaSubcommandEcc256EnMasks: + return handle_otbn_sca_ecc256_en_masks(uj); + break; + case kOtbnScaSubcommandEcc256AppSelect: + return handle_otbn_sca_ecc256_app_select(uj); + break; + case kOtbnScaSubcommandEcc256Modinv: + return handle_otbn_sca_ecc256_modinv(uj); + break; + default: + LOG_ERROR("Unrecognized OTBN SCA subcommand: %d", cmd); + return INVALID_ARGUMENT(); + } + return OK_STATUS(0); +} diff --git a/sw/device/tests/crypto/cryptotest/firmware/otbn_sca.h b/sw/device/tests/crypto/cryptotest/firmware/otbn_sca.h new file mode 100644 index 00000000000000..6128a31bcc0a3d --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/otbn_sca.h @@ -0,0 +1,23 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_OTBN_SCA_H_ +#define OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_OTBN_SCA_H_ + +#include "sw/device/lib/base/status.h" +#include "sw/device/lib/ujson/ujson.h" + +status_t handle_otbn_sca_ecc256_modinv(ujson_t *uj); +status_t handle_otbn_sca_ecc256_app_select(ujson_t *uj); +status_t handle_otbn_sca_ecc256_en_masks(ujson_t *uj); +status_t handle_otbn_sca_ecc256_set_c(ujson_t *uj); +status_t handle_otbn_sca_ecc256_set_seed(ujson_t *uj); +status_t handle_otbn_sca_ecc256_ecdsa_gen_keypair(ujson_t *uj); +status_t handle_otbn_sca_ecc256_ecdsa_secret_keygen(ujson_t *uj); +status_t handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_key_batch(ujson_t *uj); +status_t handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_seed_batch(ujson_t *uj); +status_t handle_otbn_sca_init(ujson_t *uj); +status_t handle_otbn_sca(ujson_t *uj); + +#endif // OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_OTBN_SCA_H_ diff --git a/sw/device/tests/crypto/cryptotest/json/BUILD b/sw/device/tests/crypto/cryptotest/json/BUILD index 01466fd2492e5c..3950e327ee59b0 100644 --- a/sw/device/tests/crypto/cryptotest/json/BUILD +++ b/sw/device/tests/crypto/cryptotest/json/BUILD @@ -39,6 +39,13 @@ cc_library( deps = ["//sw/device/lib/ujson"], ) +cc_library( + name = "otbn_sca_commands", + srcs = ["otbn_sca_commands.c"], + hdrs = ["otbn_sca_commands.h"], + deps = ["//sw/device/lib/ujson"], +) + cc_library( name = "prng_sca_commands", srcs = ["prng_sca_commands.c"], diff --git a/sw/device/tests/crypto/cryptotest/json/commands.h b/sw/device/tests/crypto/cryptotest/json/commands.h index 0338a5b9deeb3e..4f73d393509727 100644 --- a/sw/device/tests/crypto/cryptotest/json/commands.h +++ b/sw/device/tests/crypto/cryptotest/json/commands.h @@ -16,6 +16,7 @@ extern "C" { value(_, AesSca) \ value(_, IbexFi) \ value(_, KmacSca) \ + value(_, OtbnSca) \ value(_, PrngSca) \ value(_, Sha3Sca) \ value(_, TriggerSca) diff --git a/sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.c b/sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.c new file mode 100644 index 00000000000000..b7965b2924947c --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.c @@ -0,0 +1,6 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#define UJSON_SERDE_IMPL 1 +#include "otbn_sca_commands.h" diff --git a/sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.h b/sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.h new file mode 100644 index 00000000000000..3df3cc2a420f8b --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/json/otbn_sca_commands.h @@ -0,0 +1,98 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_JSON_OTBN_SCA_COMMANDS_H_ +#define OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_JSON_OTBN_SCA_COMMANDS_H_ +#include "sw/device/lib/ujson/ujson_derive.h" +#ifdef __cplusplus +extern "C" { +#endif + +#define OTBNSCA_CMD_MAX_APP_SELECT_BYTES 1 +#define OTBNSCA_CMD_MAX_EN_MASKS_BYTES 1 +#define OTBNSCA_CMD_MAX_NUM_TRACES_BYTES 4 +#define OTBNSCA_CMD_MAX_BATCH_DIGEST_BYTES 40 +#define OTBNSCA_CMD_MAX_MASK_BYTES 40 +#define OTBNSCA_CMD_MAX_CONSTANT_BYTES 40 +#define OTBNSCA_CMD_MAX_ECC_SEED_BYTES 40 +#define OTBNSCA_CMD_MAX_ECC_COORD_BYTES 32 +#define OTBNSCA_CMD_MAX_SEED_BYTES 40 +#define OTBNSCA_CMD_MAX_K_BYTES 80 +#define OTBNSCA_CMD_MAX_ALPHA_INV_BYTES 32 +#define OTBNSCA_CMD_MAX_ALPHA_BYTES 16 + +// clang-format off + +// OTBN SCA arguments + +#define OTBNSCA_SUBCOMMAND(_, value) \ + value(_, Init) \ + value(_, Ecc256EcdsaKeygenFvsrSeedBatch) \ + value(_, Ecc256EcdsaKeygenFvsrKeyBatch) \ + value(_, Ecc256EcdsaSecretKeygen) \ + value(_, Ecc256EcdsaGenKeypair) \ + value(_, Ecc256SetSeed) \ + value(_, Ecc256SetC) \ + value(_, Ecc256EnMasks) \ + value(_, Ecc256AppSelect) \ + value(_, Ecc256Modinv) +UJSON_SERDE_ENUM(OtbnScaSubcommand, otbn_sca_subcommand_t, OTBNSCA_SUBCOMMAND); + +#define OTBN_SCA_EN_MASKS(field, string) \ + field(en_masks, uint8_t, OTBNSCA_CMD_MAX_EN_MASKS_BYTES) +UJSON_SERDE_STRUCT(CryptotestOtbnScaEnMasks, cryptotest_otbn_sca_en_masks_t, OTBN_SCA_EN_MASKS); + +#define OTBN_SCA_APP_SELECT(field, string) \ + field(app, uint8_t, OTBNSCA_CMD_MAX_APP_SELECT_BYTES) +UJSON_SERDE_STRUCT(CryptotestOtbnScaAppSelect, cryptotest_otbn_sca_app_select_t, OTBN_SCA_APP_SELECT); + +#define OTBN_SCA_NUM_TRACES(field, string) \ + field(num_traces, uint8_t, OTBNSCA_CMD_MAX_NUM_TRACES_BYTES) +UJSON_SERDE_STRUCT(CryptotestOtbnScaNumTraces, cryptotest_otbn_sca_num_traces_t, OTBN_SCA_NUM_TRACES); + +#define OTBN_SCA_BATCH_DIGEST(field, string) \ + field(batch_digest, uint8_t, OTBNSCA_CMD_MAX_BATCH_DIGEST_BYTES) +UJSON_SERDE_STRUCT(CryptotestOtbnScaBatchDigest, cryptotest_otbn_sca_batch_digest_t, OTBN_SCA_BATCH_DIGEST); + +#define OTBN_SCA_ECC_SEED(field, string) \ + field(d0, uint8_t, OTBNSCA_CMD_MAX_ECC_SEED_BYTES) \ + field(d1, uint8_t, OTBNSCA_CMD_MAX_ECC_SEED_BYTES) +UJSON_SERDE_STRUCT(CryptotestOtbnScaEccSeed, cryptotest_otbn_sca_ecc_seed_t, OTBN_SCA_ECC_SEED); + +#define OTBN_SCA_ECC_COORD(field, string) \ + field(x, uint8_t, OTBNSCA_CMD_MAX_ECC_COORD_BYTES) \ + field(y, uint8_t, OTBNSCA_CMD_MAX_ECC_COORD_BYTES) +UJSON_SERDE_STRUCT(CryptotestOtbnScaEccCoord, cryptotest_otbn_sca_ecc_coord_t, OTBN_SCA_ECC_COORD); + +#define OTBN_SCA_ALPHA(field, string) \ + field(alpha_inv, uint8_t, OTBNSCA_CMD_MAX_ALPHA_INV_BYTES) \ + field(alpha, uint8_t, OTBNSCA_CMD_MAX_ALPHA_BYTES) +UJSON_SERDE_STRUCT(CryptotestOtbnScaAlpha, cryptotest_otbn_sca_alpha_t, OTBN_SCA_ALPHA); + +#define OTBN_SCA_MASK(field, string) \ + field(mask, uint8_t, OTBNSCA_CMD_MAX_MASK_BYTES) \ + field(mask_len, size_t, 4) +UJSON_SERDE_STRUCT(CryptotestOtbnScaMask, cryptotest_otbn_sca_mask_t, OTBN_SCA_MASK); + +#define OTBN_SCA_K(field, string) \ + field(k, uint8_t, OTBNSCA_CMD_MAX_K_BYTES) \ + field(k_len, size_t, 4) +UJSON_SERDE_STRUCT(CryptotestOtbnScaK, cryptotest_otbn_sca_k_t, OTBN_SCA_K); + +#define OTBN_SCA_SEED(field, string) \ + field(seed, uint8_t, OTBNSCA_CMD_MAX_SEED_BYTES) \ + field(seed_len, size_t, 4) +UJSON_SERDE_STRUCT(CryptotestOtbnScaSeed, cryptotest_otbn_sca_seed_t, OTBN_SCA_SEED); + +#define OTBN_SCA_CONSTANT(field, string) \ + field(constant, uint8_t, OTBNSCA_CMD_MAX_CONSTANT_BYTES) \ + field(constant_len, size_t, 4) +UJSON_SERDE_STRUCT(CryptotestOtbnScaConstant, cryptotest_otbn_sca_constant_t, OTBN_SCA_CONSTANT); + +// clang-format on + +#ifdef __cplusplus +} +#endif +#endif // OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_JSON_OTBN_SCA_COMMANDS_H_