[sw] Add C wrappers for RSA-3072 operations.

Signed-off-by: Jade Philipoom <jadep@google.com>
diff --git a/sw/device/silicon_creator/lib/crypto/rsa_3072/meson.build b/sw/device/silicon_creator/lib/crypto/rsa_3072/meson.build
index 9674ac4..eddb1cf 100644
--- a/sw/device/silicon_creator/lib/crypto/rsa_3072/meson.build
+++ b/sw/device/silicon_creator/lib/crypto/rsa_3072/meson.build
@@ -4,7 +4,8 @@
 
 # Create otbn sources dictionary
 sw_lib_crypto_rsa_3072_otbn_sources = {
-  'rsa_3072': files(
+  'rsa_3072_verify': files(
+    'rsa_3072_verify.s',
     'rsa_3072.s',
   ),
 }
@@ -59,3 +60,17 @@
   )
 
 endforeach
+
+# C wrapper for RSA-3072 verify
+sw_silicon_creator_lib_crypto_rsa_3072_verify = declare_dependency(
+  link_with: static_library(
+    'sw_silicon_creator_lib_crypto_rsa_3072_verify',
+    sources: [
+      'rsa_3072_verify.c',
+    ],
+    dependencies: [
+      sw_silicon_creator_lib_otbn_util,
+      sw_lib_crypto_rsa_3072_otbn['rsa_3072_verify']['rv32embed_dependency'],
+    ],
+  ),
+)
diff --git a/sw/device/silicon_creator/lib/crypto/rsa_3072/rsa_3072_verify.c b/sw/device/silicon_creator/lib/crypto/rsa_3072/rsa_3072_verify.c
new file mode 100644
index 0000000..bada38a
--- /dev/null
+++ b/sw/device/silicon_creator/lib/crypto/rsa_3072/rsa_3072_verify.c
@@ -0,0 +1,165 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/silicon_creator/lib/crypto/rsa_3072/rsa_3072_verify.h"
+
+#include "sw/device/lib/base/hardened.h"
+#include "sw/device/silicon_creator/lib/error.h"
+#include "sw/device/silicon_creator/lib/otbn_util.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+
+OTBN_DECLARE_APP_SYMBOLS(rsa_3072_verify);  // The OTBN RSA-3072 verify app.
+OTBN_DECLARE_PTR_SYMBOL(rsa_3072_verify, mode);     // Mode (precomp or verify).
+OTBN_DECLARE_PTR_SYMBOL(rsa_3072_verify, out_buf);  // Output buffer (message).
+OTBN_DECLARE_PTR_SYMBOL(rsa_3072_verify, in_mod);   // The RSA modulus (n).
+OTBN_DECLARE_PTR_SYMBOL(rsa_3072_verify, in_buf);   // The signature (s).
+OTBN_DECLARE_PTR_SYMBOL(rsa_3072_verify,
+                        in_rr);  // The Montgomery constant R^2.
+OTBN_DECLARE_PTR_SYMBOL(rsa_3072_verify,
+                        in_m0inv);  // The Montgomery constant m0_inv.
+
+static const otbn_app_t kOtbnAppRsa = OTBN_APP_T_INIT(rsa_3072_verify);
+static const otbn_ptr_t kOtbnVarRsaMode =
+    OTBN_PTR_T_INIT(rsa_3072_verify, mode);
+static const otbn_ptr_t kOtbnVarRsaOutBuf =
+    OTBN_PTR_T_INIT(rsa_3072_verify, out_buf);
+static const otbn_ptr_t kOtbnVarRsaInMod =
+    OTBN_PTR_T_INIT(rsa_3072_verify, in_mod);
+static const otbn_ptr_t kOtbnVarRsaInBuf =
+    OTBN_PTR_T_INIT(rsa_3072_verify, in_buf);
+static const otbn_ptr_t kOtbnVarRsaInRR =
+    OTBN_PTR_T_INIT(rsa_3072_verify, in_rr);
+static const otbn_ptr_t kOtbnVarRsaInM0Inv =
+    OTBN_PTR_T_INIT(rsa_3072_verify, in_m0inv);
+
+/* Mode is represented by a single word, 1 for precomputation and 2 for verify
+ */
+static const uint32_t kOtbnRsaModeNumWords = 1;
+static const uint32_t kOtbnRsaModePrecomp = 1;
+static const uint32_t kOtbnRsaModeVerify = 2;
+
+/**
+ * Copies a 3072-bit number from the CPU memory to OTBN data memory.
+ *
+ * @param otbn The OTBN context object.
+ * @param src Source of the data to copy.
+ * @param dst Pointer to the destination in OTBN's data memory.
+ * @return The result of the operation.
+ */
+rom_error_t write_rsa_3072_int_to_otbn(otbn_t *otbn, const rsa_3072_int_t *src,
+                                       otbn_ptr_t dst) {
+  return otbn_copy_data_to_otbn(otbn, kRsa3072NumWords, src->data, dst);
+}
+
+/**
+ * Copies a 3072-bit number from OTBN data memory to CPU memory.
+ *
+ * @param otbn The OTBN context object.
+ * @param src The pointer in OTBN data memory to copy from.
+ * @param dst The destination of the copied data in main memory (preallocated).
+ * @return The result of the operation.
+ */
+rom_error_t read_rsa_3072_int_from_otbn(otbn_t *otbn, const otbn_ptr_t src,
+                                        rsa_3072_int_t *dst) {
+  return otbn_copy_data_from_otbn(otbn, kRsa3072NumWords, src, dst->data);
+}
+
+// TODO: This implementation waits while OTBN is processing; it should be
+// modified to be non-blocking.
+rom_error_t rsa_3072_precomp(const rsa_3072_public_key_t *public_key,
+                             rsa_3072_constants_t *result) {
+  otbn_t otbn;
+
+  // Initialize OTBN and load the RSA app.
+  otbn_init(&otbn);
+  RETURN_IF_ERROR(otbn_load_app(&otbn, kOtbnAppRsa));
+
+  // Set mode to perform precomputation.
+  RETURN_IF_ERROR(otbn_copy_data_to_otbn(
+      &otbn, kOtbnRsaModeNumWords, &kOtbnRsaModePrecomp, kOtbnVarRsaMode));
+
+  // Set the modulus (n).
+  RETURN_IF_ERROR(
+      write_rsa_3072_int_to_otbn(&otbn, &public_key->n, kOtbnVarRsaInMod));
+
+  // Start the OTBN routine.
+  RETURN_IF_ERROR(otbn_execute_app(&otbn));
+
+  // Spin here waiting for OTBN to complete.
+  RETURN_IF_ERROR(otbn_busy_wait_for_done(&otbn));
+
+  // Read precomputed constant rr out of DMEM.
+  RETURN_IF_ERROR(
+      read_rsa_3072_int_from_otbn(&otbn, kOtbnVarRsaInRR, &result->rr));
+
+  // Read precomputed constant m0_inv out of DMEM.
+  RETURN_IF_ERROR(otbn_copy_data_from_otbn(&otbn, kOtbnWideWordNumWords,
+                                           kOtbnVarRsaInM0Inv, result->m0_inv));
+
+  return kErrorOk;
+}
+
+// TODO: This implementation waits while OTBN is processing; it should be
+// modified to be non-blocking.
+rom_error_t rsa_3072_verify(const rsa_3072_int_t *signature,
+                            const rsa_3072_int_t *message,
+                            const rsa_3072_public_key_t *public_key,
+                            const rsa_3072_constants_t *constants,
+                            hardened_bool_t *result) {
+  otbn_t otbn;
+  rsa_3072_int_t recoveredMessage;
+
+  // For now, only the F4 modulus is supported.
+  if (public_key->e != 65537) {
+    return kErrorOtbnInvalidArgument;
+  }
+
+  // TODO: Check that s < n, reject signature otherwise
+
+  // Initialize OTBN and load the RSA app.
+  otbn_init(&otbn);
+  RETURN_IF_ERROR(otbn_load_app(&otbn, kOtbnAppRsa));
+
+  // Set mode to perform verification.
+  RETURN_IF_ERROR(otbn_copy_data_to_otbn(&otbn, kOtbnRsaModeNumWords,
+                                         &kOtbnRsaModeVerify, kOtbnVarRsaMode));
+
+  // Set the modulus (n).
+  RETURN_IF_ERROR(
+      write_rsa_3072_int_to_otbn(&otbn, &public_key->n, kOtbnVarRsaInMod));
+
+  // Set the signature.
+  RETURN_IF_ERROR(
+      write_rsa_3072_int_to_otbn(&otbn, signature, kOtbnVarRsaInBuf));
+
+  // Set the precomputed constant R^2.
+  RETURN_IF_ERROR(
+      write_rsa_3072_int_to_otbn(&otbn, &constants->rr, kOtbnVarRsaInRR));
+
+  // Set the precomputed constant m0_inv.
+  RETURN_IF_ERROR(otbn_copy_data_to_otbn(
+      &otbn, kOtbnWideWordNumWords, constants->m0_inv, kOtbnVarRsaInM0Inv));
+
+  // Start the OTBN routine.
+  RETURN_IF_ERROR(otbn_execute_app(&otbn));
+
+  // Spin here waiting for OTBN to complete.
+  RETURN_IF_ERROR(otbn_busy_wait_for_done(&otbn));
+
+  // Read recovered message out of OTBN dmem.
+  RETURN_IF_ERROR(
+      read_rsa_3072_int_from_otbn(&otbn, kOtbnVarRsaOutBuf, &recoveredMessage));
+
+  // TODO: harden this memory comparison
+  // Check if recovered message matches expectation
+  *result = kHardenedBoolTrue;
+  for (int i = 0; i < kRsa3072NumWords; i++) {
+    if (recoveredMessage.data[i] != message->data[i]) {
+      *result = kHardenedBoolFalse;
+    }
+  }
+
+  return kErrorOk;
+}
diff --git a/sw/device/silicon_creator/lib/crypto/rsa_3072/rsa_3072_verify.h b/sw/device/silicon_creator/lib/crypto/rsa_3072/rsa_3072_verify.h
new file mode 100644
index 0000000..456b4a2
--- /dev/null
+++ b/sw/device/silicon_creator/lib/crypto/rsa_3072/rsa_3072_verify.h
@@ -0,0 +1,89 @@
+// 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_SILICON_CREATOR_LIB_CRYPTO_RSA_3072_RSA_3072_VERIFY_H_
+#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CRYPTO_RSA_3072_RSA_3072_VERIFY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sw/device/lib/base/hardened.h"
+#include "sw/device/silicon_creator/lib/error.h"
+#include "sw/device/silicon_creator/lib/otbn_util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+enum {
+  /* Length of the RSA-3072 modulus is 3072 bits */
+  kRsa3072NumBits = 3072,
+  /* Length of the RSA-3072 modulus in words */
+  kRsa3072NumWords = kRsa3072NumBits / (sizeof(uint32_t) * 8),
+};
+
+/**
+ * A type that holds an element of the RSA-3072 finite field (i.e. a 3072-bit
+ * number).
+ *
+ * This type can be used for RSA-3072 signatures, keys, and intermediate values
+ * during modular exponentiation.
+ */
+typedef struct rsa_3072_int_t {
+  uint32_t data[kRsa3072NumWords];
+} rsa_3072_int_t;
+
+/**
+ * A type that holds an RSA-3072 public key.
+ *
+ * The public key consists of a 3072-bit modulus n and a public exponent e.
+ */
+typedef struct rsa_3072_public_key_t {
+  rsa_3072_int_t n;
+  uint32_t e;
+} rsa_3072_public_key_t;
+
+/**
+ * A type that holds precomputed Montgomery constants for a RSA-3072 public
+ * key.
+ *
+ * The constants are:
+ *  rr : (2^3072)^2 mod n
+ *  m0_inv : (-(n^(-1))) mod 2^256
+ */
+typedef struct rsa_3072_constants_t {
+  rsa_3072_int_t rr;
+  uint32_t m0_inv[kOtbnWideWordNumWords];
+} rsa_3072_constants_t;
+
+/**
+ * Precomputes Montgomery constants for an RSA-3072 public key.
+ *
+ * @param public_key Key for which to compute constants.
+ * @param result Buffer in which to store output
+ * @return Result of the operation (OK or error).
+ */
+rom_error_t rsa_3072_precomp(const rsa_3072_public_key_t *public_key,
+                             rsa_3072_constants_t *result);
+
+/**
+ * Verifies an RSA-3072 signature.
+ *
+ * @param signature Signature to be verified.
+ * @param message Digest of the message to check the signature against.
+ * @param public_key Key to check the signature against.
+ * @param result Buffer in which to store output (true iff signature is valid)
+ * @return Result of the operation (OK or error).
+ */
+rom_error_t rsa_3072_verify(const rsa_3072_int_t *signature,
+                            const rsa_3072_int_t *message,
+                            const rsa_3072_public_key_t *public_key,
+                            const rsa_3072_constants_t *constants,
+                            hardened_bool_t *result);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
+
+#endif  // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CRYPTO_RSA_3072_RSA_3072_VERIFY_H_
diff --git a/sw/device/silicon_creator/lib/otbn_util.h b/sw/device/silicon_creator/lib/otbn_util.h
index fddff0a..efb3822 100644
--- a/sw/device/silicon_creator/lib/otbn_util.h
+++ b/sw/device/silicon_creator/lib/otbn_util.h
@@ -16,6 +16,16 @@
 #endif
 
 /**
+ * Constants related to OTBN wide words
+ */
+enum {
+  /* Length of an OTBN wide word in bits */
+  kOtbnWideWordNumBits = 256,
+  /* Length of an OTBN wide word in words */
+  kOtbnWideWordNumWords = kOtbnWideWordNumBits / (sizeof(uint32_t) * 8),
+};
+
+/**
  * Information about an embedded OTBN application image.
  *
  * All pointers reference data in the normal CPU address space.