summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosip Sokcevic <sokcevic@google.com>2021-06-17 14:12:54 -0700
committerJosip Sokcevic <sokcevic@google.com>2021-06-17 14:12:54 -0700
commit750140eb3c43026675216bb13ab0deed701af37c (patch)
treec08a3e314715658ccd2745f82d075306e067b701
parent00b712db867e533a12df0f2c7e3c6e6d49fdeac6 (diff)
downloadchrome-ec-750140eb3c43026675216bb13ab0deed701af37c.tar.gz
Restore chip/g/dcrypto
Signed-off-by: Josip Sokcevic <sokcevic@google.com>
-rw-r--r--chip/g/dcrypto/aes.c160
-rw-r--r--chip/g/dcrypto/aes_cmac.c346
-rw-r--r--chip/g/dcrypto/app_cipher.c451
-rw-r--r--chip/g/dcrypto/app_key.c87
-rw-r--r--chip/g/dcrypto/bn.c1244
-rw-r--r--chip/g/dcrypto/compare.c20
-rw-r--r--chip/g/dcrypto/dcrypto.h445
-rw-r--r--chip/g/dcrypto/dcrypto_bn.c1496
-rw-r--r--chip/g/dcrypto/dcrypto_p256.c1018
-rw-r--r--chip/g/dcrypto/dcrypto_runtime.c480
-rw-r--r--chip/g/dcrypto/dcrypto_sha512.c772
-rw-r--r--chip/g/dcrypto/gcm.c345
-rw-r--r--chip/g/dcrypto/hkdf.c83
-rw-r--r--chip/g/dcrypto/hmac.c63
-rw-r--r--chip/g/dcrypto/hmac_drbg.c478
-rw-r--r--chip/g/dcrypto/internal.h219
-rw-r--r--chip/g/dcrypto/key_ladder.c300
-rw-r--r--chip/g/dcrypto/p256.c30
-rw-r--r--chip/g/dcrypto/p256_ec.c39
-rw-r--r--chip/g/dcrypto/p256_ecies.c175
-rw-r--r--chip/g/dcrypto/proofs_p256.md28
-rw-r--r--chip/g/dcrypto/rsa.c743
-rw-r--r--chip/g/dcrypto/sha1.c65
-rw-r--r--chip/g/dcrypto/sha256.c195
-rw-r--r--chip/g/dcrypto/sha384.c20
-rw-r--r--chip/g/dcrypto/sha512.c20
-rw-r--r--chip/g/dcrypto/x509.c545
-rw-r--r--chip/g/trng.c236
28 files changed, 10103 insertions, 0 deletions
diff --git a/chip/g/dcrypto/aes.c b/chip/g/dcrypto/aes.c
new file mode 100644
index 0000000000..f5cc0e6d8f
--- /dev/null
+++ b/chip/g/dcrypto/aes.c
@@ -0,0 +1,160 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+
+static void set_control_register(
+ unsigned mode, unsigned key_size, unsigned encrypt)
+{
+ GWRITE_FIELD(KEYMGR, AES_CTRL, RESET, CTRL_NO_SOFT_RESET);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, KEYSIZE, key_size);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, CIPHER_MODE, mode);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, ENC_MODE, encrypt);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, CTR_ENDIAN, CTRL_CTR_BIG_ENDIAN);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, ENABLE, CTRL_ENABLE);
+
+ /* Turn off random nops (which are enabled by default). */
+ GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, STALL_EN, 0);
+ /* Configure random nop percentage at 25%. */
+ GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, FREQ, 1);
+ /* Now turn on random nops. */
+ GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, STALL_EN, 1);
+}
+
+static int wait_read_data(volatile uint32_t *addr)
+{
+ int empty;
+ int count = 20; /* Wait these many ~cycles. */
+
+ do {
+ empty = REG32(addr);
+ count--;
+ } while (count && empty);
+
+ return empty ? 0 : 1;
+}
+
+int DCRYPTO_aes_init(const uint8_t *key, uint32_t key_len, const uint8_t *iv,
+ enum cipher_mode c_mode, enum encrypt_mode e_mode)
+{
+ int i;
+ const struct access_helper *p;
+ uint32_t key_mode;
+
+ switch (key_len) {
+ case 128:
+ key_mode = 0;
+ break;
+ case 192:
+ key_mode = 1;
+ break;
+ case 256:
+ key_mode = 2;
+ break;
+ default:
+ /* Invalid key length specified. */
+ return 0;
+ }
+ set_control_register(c_mode, key_mode, e_mode);
+
+ /* Initialize hardware with AES key */
+ p = (struct access_helper *) key;
+ for (i = 0; i < (key_len >> 5); i++)
+ GR_KEYMGR_AES_KEY(i) = p[i].udata;
+ /* Trigger key expansion. */
+ GREG32(KEYMGR, AES_KEY_START) = 1;
+
+ /* Wait for key expansion. */
+ if (!wait_read_data(GREG32_ADDR(KEYMGR, AES_KEY_START))) {
+ /* Should not happen. */
+ return 0;
+ }
+
+ /* Initialize IV for modes that require it. */
+ if (iv) {
+ p = (struct access_helper *) iv;
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_AES_CTR(i) = p[i].udata;
+ }
+ return 1;
+}
+
+int DCRYPTO_aes_block(const uint8_t *in, uint8_t *out)
+{
+ int i;
+ struct access_helper *outw;
+ const struct access_helper *inw = (struct access_helper *) in;
+
+ /* Write plaintext. */
+ for (i = 0; i < 4; i++)
+ GREG32(KEYMGR, AES_WFIFO_DATA) = inw[i].udata;
+
+ /* Wait for the result. */
+ if (!wait_read_data(GREG32_ADDR(KEYMGR, AES_RFIFO_EMPTY))) {
+ /* Should not happen, ciphertext not ready. */
+ return 0;
+ }
+
+ /* Read ciphertext. */
+ outw = (struct access_helper *) out;
+ for (i = 0; i < 4; i++)
+ outw[i].udata = GREG32(KEYMGR, AES_RFIFO_DATA);
+ return 1;
+}
+
+void DCRYPTO_aes_write_iv(const uint8_t *iv)
+{
+ int i;
+ const struct access_helper *p = (const struct access_helper *) iv;
+
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_AES_CTR(i) = p[i].udata;
+}
+
+void DCRYPTO_aes_read_iv(uint8_t *iv)
+{
+ int i;
+ struct access_helper *p = (struct access_helper *) iv;
+
+ for (i = 0; i < 4; i++)
+ p[i].udata = GR_KEYMGR_AES_CTR(i);
+}
+
+int DCRYPTO_aes_ctr(uint8_t *out, const uint8_t *key, uint32_t key_bits,
+ const uint8_t *iv, const uint8_t *in, size_t in_len)
+{
+ /* Initialize AES hardware. */
+ if (!DCRYPTO_aes_init(key, key_bits, iv,
+ CIPHER_MODE_CTR, ENCRYPT_MODE))
+ return 0;
+
+ while (in_len > 0) {
+ uint8_t tmpin[16];
+ uint8_t tmpout[16];
+ const uint8_t *inp;
+ uint8_t *outp;
+ const size_t count = MIN(in_len, 16);
+
+ if (count < 16) {
+ memcpy(tmpin, in, count);
+ inp = tmpin;
+ outp = tmpout;
+ } else {
+ inp = in;
+ outp = out;
+ }
+ if (!DCRYPTO_aes_block(inp, outp))
+ return 0;
+ if (outp != out)
+ memcpy(out, outp, count);
+
+ in += count;
+ out += count;
+ in_len -= count;
+ }
+ return 1;
+}
diff --git a/chip/g/dcrypto/aes_cmac.c b/chip/g/dcrypto/aes_cmac.c
new file mode 100644
index 0000000000..4f996f42b6
--- /dev/null
+++ b/chip/g/dcrypto/aes_cmac.c
@@ -0,0 +1,346 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* AES-CMAC-128 implementation according to NIST SP 800-38B, RFC4493 */
+#include "console.h"
+#include "dcrypto.h"
+
+#define BSIZE 16 /* 16 bytes per 128-bit block */
+
+/* Given a 128-bit number in 32-bit chunks, shift to the left by one */
+static void shiftl_1(const uint8_t *in, uint8_t *out)
+{
+ int i;
+ uint8_t carry = 0;
+
+ for (i = 15; i >= 0; i--) {
+ out[i] = in[i] << 1;
+ out[i] |= carry;
+ carry = (in[i] & 0x80) ? 1 : 0;
+ }
+}
+
+static void xor128(const uint32_t in1[4], const uint32_t in2[4],
+ uint32_t out[4])
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ out[i] = in1[i] ^ in2[i];
+}
+
+static void get_and_xor(const uint8_t *arr, const uint32_t nBytes, int i,
+ const uint8_t *xor_term, uint8_t *out)
+{
+ int j;
+ int k;
+
+ for (j = 0; j < 16; j++) {
+ k = i*16 + j; /* index in arr */
+ if (k < nBytes)
+ out[j] = arr[k];
+ else if (k == nBytes)
+ out[j] = 0x80;
+ else
+ out[j] = 0;
+ out[j] = out[j] ^ xor_term[j];
+ }
+}
+
+/* Wrapper for initializing and calling AES-128 */
+static int aes128(const uint8_t *K, const uint32_t in[4], uint32_t out[4])
+{
+ const uint32_t zero[4] = {0, 0, 0, 0};
+
+ if (!DCRYPTO_aes_init((const uint8_t *)K, 128, (const uint8_t *) zero,
+ CIPHER_MODE_ECB, ENCRYPT_MODE))
+ return 0;
+ if (!DCRYPTO_aes_block((const uint8_t *) in, (uint8_t *) out))
+ return 0;
+ return 1;
+}
+
+static int gen_subkey(const uint8_t *K, uint32_t k1[4], uint32_t k2[4])
+{
+ uint32_t L[4];
+ uint32_t tmp[4];
+ const uint32_t *xor_term;
+ static const uint32_t zero[4] = {0, 0, 0, 0};
+ static const uint32_t Rb[4] = {0, 0, 0, 0x87000000};
+
+ if (!aes128(K, zero, L))
+ return 0;
+
+ xor_term = (L[0] & 0x00000080) ? Rb : zero;
+ shiftl_1((const uint8_t *)L, (uint8_t *)tmp);
+ xor128(tmp, xor_term, k1);
+
+ xor_term = (k1[0] & 0x00000080) ? Rb : zero;
+ shiftl_1((const uint8_t *) k1, (uint8_t *) tmp);
+ xor128(tmp, xor_term, k2);
+
+ return 1;
+}
+
+int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len,
+ uint32_t T[4])
+{
+ uint32_t n;
+ int i;
+ int flag;
+ uint32_t k1[4];
+ uint32_t k2[4];
+ uint32_t M_last[4];
+ uint32_t Y[4];
+ uint32_t X[4] = {0, 0, 0, 0};
+
+ /* Generate the subkeys K1 and K2 */
+ if (!gen_subkey(K, k1, k2))
+ return 0;
+
+ /* Set n and flag.
+ * flag = 1 if the last block has a full 128 bits; 0 otherwise
+ * n = number of 128-bit blocks in input = ceil (len / BSIZE)
+ *
+ * Special case: if len = 0, then n = 1 and flag = 0.
+ */
+ flag = (len % BSIZE == 0) ? 1 : 0;
+ n = len / BSIZE + (flag ? 0 : 1); // ceil (len / BSIZE)
+ if (len == 0) {
+ n = 1;
+ flag = 0;
+ }
+
+ /* M_last = padded(last 128-bit block of M) ^ (flag ? k1 : k2) */
+ get_and_xor(M, len, n-1, (uint8_t *) (flag ? k1 : k2),
+ (uint8_t *) M_last);
+
+ for (i = 0; i < n - 1; i++) {
+ /* Y = padded(nth 128-bit block of M) ^ (flag ? k1 : k2) */
+ get_and_xor(M, len, i, (uint8_t *)X, (uint8_t *)Y);
+ if (!aes128(K, Y, X))
+ return 0;
+ }
+
+ /* TODO: This block is separate from the main loop in the RFC. However,
+ * if we set M[n-1] = M_last, then it is equivalent to running the loop
+ * for one more step, which might be a nicer way to write it.
+ */
+ xor128(X, M_last, Y);
+ if (!aes128(K, Y, T))
+ return 0;
+ return 1;
+}
+
+int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len,
+ const uint32_t T[4])
+{
+ int i;
+ uint32_t T2[4];
+ int match = 1;
+
+ if (!DCRYPTO_aes_cmac(key, M, len, T2))
+ return -EC_ERROR_UNKNOWN;
+
+ for (i = 0; i < 4; i++) {
+ if (T[i] != T2[i])
+ match = 0;
+ }
+ return match;
+}
+
+#ifdef CRYPTO_TEST_SETUP
+static int check_answer(const uint32_t expected[4], uint32_t actual[4])
+{
+ int i;
+ int success = 1;
+
+ for (i = 0; i < 4; i++) {
+ if (actual[i] != expected[i])
+ success = 0;
+ }
+ if (success) {
+ ccprintf("SUCCESS\n");
+ } else {
+ ccprintf("FAILURE:\n");
+ ccprintf("actual = 0x%08x 0x%08x 0x%08x 0x%08x\n", actual[0],
+ actual[1], actual[2], actual[3]);
+ ccprintf("expected = 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ expected[0], expected[1], expected[2], expected[3]);
+ }
+ return success;
+}
+
+static int command_test_aes_block(int argc, char **argv)
+{
+ uint32_t actual[4];
+ const uint32_t zero[4] = {0, 0, 0, 0};
+ const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
+ const uint32_t expected[4] = {0x0c6bf77d, 0xb399b81a, 0x47f0423e,
+ 0x6f541bb9};
+
+ aes128((const uint8_t *) K, zero, actual);
+ check_answer(expected, actual);
+
+ return 0;
+}
+
+DECLARE_SAFE_CONSOLE_COMMAND(test_aesbk, command_test_aes_block, NULL,
+ "Test AES block in AES-CMAC subkey generation");
+
+static int command_test_subkey_gen(int argc, char **argv)
+{
+ uint32_t k1[4];
+ uint32_t k2[4];
+ /* K: 2b7e1516 28aed2a6 abf71588 09cf4f3c
+ * k1: fbeed618 35713366 7c85e08f 7236a8de
+ * k2: f7ddac30 6ae266cc f90bc11e e46d513b
+ */
+ const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
+ const uint32_t k1e[4] = {0x18d6eefb, 0x66337135, 0x8fe0857c,
+ 0xdea83672};
+ const uint32_t k2e[4] = {0x30acddf7, 0xcc66e26a, 0x1ec10bf9,
+ 0x3b516de4};
+
+ gen_subkey((const uint8_t *) K, k1, k2);
+
+ ccprintf("Checking K1: ");
+ check_answer(k1e, k1);
+
+ ccprintf("Checking K2: ");
+ check_answer(k2e, k2);
+
+ return 0;
+}
+
+DECLARE_SAFE_CONSOLE_COMMAND(test_skgen, command_test_subkey_gen, NULL,
+ "Test AES-CMAC subkey generation");
+
+struct cmac_test_param {
+ uint32_t len;
+ uint8_t *M;
+ uint32_t Te[4];
+};
+
+/* N.B. The order of bytes in each 32-bit block is reversed from the form in
+ * which they are written in the RFC.
+ */
+const struct cmac_test_param rfctests[4] = {
+ /* --------------------------------------------------
+ * Example 1: len = 0
+ * M <empty string>
+ * AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746
+ * --------------------------------------------------
+ */
+ { .len = 0,
+ .M = (uint8_t *) "",
+ .Te = {0x29691dbb, 0x283759e9, 0x127da37f, 0x4667759b},
+ },
+ /* --------------------------------------------------
+ * Example 2: len = 16
+ * M 6bc1bee2 2e409f96 e93d7e11 7393172a
+ * AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c
+ * --------------------------------------------------
+ */
+ { .len = 16,
+ .M = (uint8_t *) (uint32_t[]) {
+ 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373
+ },
+ .Te = {0xb4160a07, 0x44414d6b, 0x9ddd9bf7, 0x7c284ad0},
+ },
+ /* --------------------------------------------------
+ * Example 3: len = 40
+ * M 6bc1bee2 2e409f96 e93d7e11 7393172a
+ * ae2d8a57 1e03ac9c 9eb76fac 45af8e51
+ * 30c81c46 a35ce411
+ * AES-CMAC dfa66747 de9ae630 30ca3261 1497c827
+ * --------------------------------------------------
+ */
+ { .len = 40,
+ .M = (uint8_t *) (uint32_t[]) {
+ 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373,
+ 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45,
+ 0x461cc830, 0x11e45ca3
+ },
+ .Te = {0x4767a6df, 0x30e69ade, 0x6132ca30, 0x27c89714},
+ },
+ /* --------------------------------------------------
+ * Example 4: len = 64
+ * M 6bc1bee2 2e409f96 e93d7e11 7393172a
+ * ae2d8a57 1e03ac9c 9eb76fac 45af8e51
+ * 30c81c46 a35ce411 e5fbc119 1a0a52ef
+ * f69f2445 df4f9b17 ad2b417b e66c3710
+ * AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe
+ * --------------------------------------------------
+ */
+ { .len = 64,
+ .M = (uint8_t *) (uint32_t[]) {
+ 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373,
+ 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45,
+ 0x461cc830, 0x11e45ca3, 0x19c1fbe5, 0xef520a1a,
+ 0x45249ff6, 0x179b4fdf, 0x7b412bad, 0x10376ce6
+ },
+ .Te = {0xbfbef051, 0x929d3b7e, 0x177449fc, 0xfe3c3679},
+ },
+};
+
+static int command_test_aes_cmac(int argc, char **argv)
+{
+ int i;
+ uint32_t T[4];
+ int testN;
+ struct cmac_test_param param;
+ const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
+
+ for (i = 1; i < argc; i++) {
+ testN = strtoi(argv[i], NULL, 10);
+ param = rfctests[testN - 1];
+
+ ccprintf("Testing RFC Example #%d (%d-byte message)...", testN,
+ param.len);
+
+ DCRYPTO_aes_cmac((const uint8_t *)K, param.M, param.len, T);
+ check_answer(param.Te, T);
+ }
+
+ return 0;
+}
+
+DECLARE_SAFE_CONSOLE_COMMAND(test_cmac, command_test_aes_cmac,
+ "[test cases (1-4)]",
+ "Test AES-CMAC with RFC examples");
+
+static int command_test_verify(int argc, char **argv)
+{
+ int i;
+ int testN;
+ int result;
+ struct cmac_test_param param;
+ const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
+
+ for (i = 1; i < argc; i++) {
+ testN = strtoi(argv[i], NULL, 10);
+ param = rfctests[testN-1];
+
+ ccprintf("Testing RFC Example #%d (%d-byte message)...", testN,
+ param.len);
+
+ result = DCRYPTO_aes_cmac_verify((const uint8_t *)K, param.M,
+ param.len, param.Te);
+ if (result == 1)
+ ccprintf("SUCCESS\n");
+ else if (result == 0)
+ ccprintf("FAILURE: verify returned INVALID\n");
+ else if (result == -EC_ERROR_UNKNOWN)
+ ccprintf("FAILURE: verify returned ERROR\n");
+ }
+
+ return 0;
+}
+
+DECLARE_SAFE_CONSOLE_COMMAND(test_cmac_ver, command_test_verify,
+ "[test cases (1-4)]",
+ "Test AES-CMAC-verify with RFC examples");
+#endif /* CRYPTO_TEST_SETUP */
diff --git a/chip/g/dcrypto/app_cipher.c b/chip/g/dcrypto/app_cipher.c
new file mode 100644
index 0000000000..125b443ee6
--- /dev/null
+++ b/chip/g/dcrypto/app_cipher.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "dcrypto.h"
+#include "registers.h"
+
+/* The default build options compile for size (-Os); instruct the
+ * compiler to optimize for speed here. Incidentally -O produces
+ * faster code than -O2!
+ */
+static int __attribute__((optimize("O")))
+inner_loop(uint32_t **out, const uint32_t **in, size_t len)
+{
+ uint32_t *outw = *out;
+ const uint32_t *inw = *in;
+
+ while (len >= 16) {
+ uint32_t w0, w1, w2, w3;
+
+ w0 = inw[0];
+ w1 = inw[1];
+ w2 = inw[2];
+ w3 = inw[3];
+ GREG32(KEYMGR, AES_WFIFO_DATA) = w0;
+ GREG32(KEYMGR, AES_WFIFO_DATA) = w1;
+ GREG32(KEYMGR, AES_WFIFO_DATA) = w2;
+ GREG32(KEYMGR, AES_WFIFO_DATA) = w3;
+
+ while (GREG32(KEYMGR, AES_RFIFO_EMPTY))
+ ;
+
+ w0 = GREG32(KEYMGR, AES_RFIFO_DATA);
+ w1 = GREG32(KEYMGR, AES_RFIFO_DATA);
+ w2 = GREG32(KEYMGR, AES_RFIFO_DATA);
+ w3 = GREG32(KEYMGR, AES_RFIFO_DATA);
+ outw[0] = w0;
+ outw[1] = w1;
+ outw[2] = w2;
+ outw[3] = w3;
+
+ inw += 4;
+ outw += 4;
+ len -= 16;
+ }
+
+ *in = inw;
+ *out = outw;
+ return len;
+}
+
+static int outer_loop(uint32_t **out, const uint32_t **in, size_t len)
+{
+ uint32_t *outw = *out;
+ const uint32_t *inw = *in;
+
+ if (len >= 16) {
+ GREG32(KEYMGR, AES_WFIFO_DATA) = inw[0];
+ GREG32(KEYMGR, AES_WFIFO_DATA) = inw[1];
+ GREG32(KEYMGR, AES_WFIFO_DATA) = inw[2];
+ GREG32(KEYMGR, AES_WFIFO_DATA) = inw[3];
+ inw += 4;
+ len -= 16;
+
+ len = inner_loop(&outw, &inw, len);
+
+ while (GREG32(KEYMGR, AES_RFIFO_EMPTY))
+ ;
+
+ outw[0] = GREG32(KEYMGR, AES_RFIFO_DATA);
+ outw[1] = GREG32(KEYMGR, AES_RFIFO_DATA);
+ outw[2] = GREG32(KEYMGR, AES_RFIFO_DATA);
+ outw[3] = GREG32(KEYMGR, AES_RFIFO_DATA);
+ outw += 4;
+ }
+
+ *in = inw;
+ *out = outw;
+ return len;
+}
+
+static int aes_init(struct APPKEY_CTX *ctx, enum dcrypto_appid appid,
+ const uint32_t iv[4])
+{
+ /* Setup USR-based application key. */
+ if (!DCRYPTO_appkey_init(appid, ctx))
+ return 0;
+
+ /* Configure AES engine. */
+ GWRITE_FIELD(KEYMGR, AES_CTRL, RESET, CTRL_NO_SOFT_RESET);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, KEYSIZE, 2 /* AES-256 */);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, CIPHER_MODE, CIPHER_MODE_CTR);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, ENC_MODE, ENCRYPT_MODE);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, CTR_ENDIAN, CTRL_CTR_BIG_ENDIAN);
+
+ /*
+ * For fixed-key, bulk ciphering, turn off random nops (which
+ * are enabled by default).
+ */
+ GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, STALL_EN, 0);
+
+ /* Enable hidden key usage, each appid gets its own
+ * USR, with USR0 starting at 0x2a0.
+ */
+ GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, INDEX,
+ 0x2a0 + (appid * 2));
+ GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 1);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, ENABLE, CTRL_ENABLE);
+
+ /* Wait for key-expansion. */
+ GREG32(KEYMGR, AES_KEY_START) = 1;
+ while (GREG32(KEYMGR, AES_KEY_START))
+ ;
+
+ /* Check for errors (e.g. USR not correctly setup. */
+ if (GREG32(KEYMGR, HKEY_ERR_FLAGS))
+ return 0;
+
+ /* Set IV. */
+ GR_KEYMGR_AES_CTR(0) = iv[0];
+ GR_KEYMGR_AES_CTR(1) = iv[1];
+ GR_KEYMGR_AES_CTR(2) = iv[2];
+ GR_KEYMGR_AES_CTR(3) = iv[3];
+
+ return 1;
+}
+
+int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt,
+ void *out, const void *in, size_t len)
+{
+ struct APPKEY_CTX ctx;
+ const uint32_t *inw = in;
+ uint32_t *outw = out;
+
+ /* Test pointers for word alignment. */
+ if (((uintptr_t) in & 0x03) || ((uintptr_t) out & 0x03))
+ return 0;
+
+ {
+ /* Initialize key, and AES engine. */
+ uint32_t iv[4];
+
+ memcpy(iv, salt, sizeof(iv));
+ if (!aes_init(&ctx, appid, iv))
+ return 0;
+ }
+
+ len = outer_loop(&outw, &inw, len);
+
+ if (len) {
+ /* Cipher the final partial block */
+ uint32_t tmpin[4];
+ uint32_t tmpout[4];
+ const uint32_t *tmpinw;
+ uint32_t *tmpoutw;
+
+ tmpinw = tmpin;
+ tmpoutw = tmpout;
+
+ memcpy(tmpin, inw, len);
+ outer_loop(&tmpoutw, &tmpinw, 16);
+ memcpy(outw, tmpout, len);
+ }
+
+ DCRYPTO_appkey_finish(&ctx);
+ return 1;
+}
+
+#ifdef CRYPTO_TEST_SETUP
+
+#include "common.h"
+#include "console.h"
+#include "hooks.h"
+#include "shared_mem.h"
+#include "task.h"
+#include "timer.h"
+#include "watchdog.h"
+
+#define HEAP_HEAD_ROOM 0x400
+static uint32_t number_of_iterations;
+static uint8_t result;
+
+/* Staticstics for ecrypt and decryp passes. */
+struct ciph_stats {
+ uint16_t min_time;
+ uint16_t max_time;
+ uint32_t total_time;
+} __packed; /* Just in case. */
+
+/* A common structure to contain information about the test run. */
+struct test_info {
+ size_t test_blob_size;
+ struct ciph_stats enc_stats;
+ struct ciph_stats dec_stats;
+ char *p; /* Pointer to an allcoated buffer of test_blob_size bytes. */
+};
+
+static void init_stats(struct ciph_stats *stats)
+{
+ stats->min_time = ~0;
+ stats->max_time = 0;
+ stats->total_time = 0;
+}
+
+static void update_stats(struct ciph_stats *stats, uint32_t time)
+{
+ if (time < stats->min_time)
+ stats->min_time = time;
+
+ if (time > stats->max_time)
+ stats->max_time = time;
+
+ stats->total_time += time;
+}
+
+static void report_stats(const char *direction, struct ciph_stats *stats)
+{
+ ccprintf("%s results: min %d us, max %d us, average %d us\n",
+ direction, stats->min_time, stats->max_time,
+ stats->total_time / number_of_iterations);
+}
+
+/*
+ * Prepare to run the test: allocate memory, initialize stats structures.
+ *
+ * Returns EC_SUCCESS if everything is fine, EC_ERROR_OVERFLOW on malloc
+ * failures.
+ */
+static int prepare_running(struct test_info *pinfo)
+{
+ memset(pinfo, 0, sizeof(*pinfo));
+
+
+ pinfo->test_blob_size = shared_mem_size();
+ /*
+ * Leave some room for crypto functions if they need to allocate
+ * something, just in case. 0x20 extra bytes are needed to be able to
+ * modify size alignment of the allocated buffer.
+ */
+ if (pinfo->test_blob_size < (HEAP_HEAD_ROOM + 0x20)) {
+ ccprintf("Not enough memory to run the test\n");
+ return EC_ERROR_OVERFLOW;
+ }
+ pinfo->test_blob_size = (pinfo->test_blob_size - HEAP_HEAD_ROOM);
+
+ if (shared_mem_acquire(pinfo->test_blob_size,
+ (char **)&(pinfo->p)) != EC_SUCCESS) {
+ ccprintf("Failed to allocate %d bytes\n",
+ pinfo->test_blob_size);
+ return EC_ERROR_OVERFLOW;
+ }
+
+ /*
+ * Use odd block size to make sure unaligned length blocks are handled
+ * properly. This leaves room in the end of the buffer to check if the
+ * decryption routine scratches it.
+ */
+ pinfo->test_blob_size &= ~0x1f;
+ pinfo->test_blob_size |= 7;
+
+ ccprintf("running %d iterations\n", number_of_iterations);
+ ccprintf("blob size %d at %pP\n", pinfo->test_blob_size, pinfo->p);
+
+ init_stats(&(pinfo->enc_stats));
+ init_stats(&(pinfo->dec_stats));
+
+ return EC_SUCCESS;
+}
+
+/*
+ * Let's split the buffer in two equal halves, encrypt the lower half into the
+ * upper half and compare them word by word. There should be no repetitions.
+ *
+ * The side effect of this is starting the test with random clear text data.
+ *
+ * The first 16 bytes of the allocated buffer are used as the encryption IV.
+ */
+static int basic_check(struct test_info *pinfo)
+{
+ size_t half;
+ int i;
+ uint32_t *p;
+
+ ccprintf("original data %ph\n", HEX_BUF(pinfo->p, 16));
+
+ half = (pinfo->test_blob_size/2) & ~3;
+ if (!DCRYPTO_app_cipher(NVMEM, pinfo->p, pinfo->p,
+ pinfo->p + half, half)) {
+ ccprintf("first ecnryption run failed\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ p = (uint32_t *)pinfo->p;
+ half /= sizeof(*p);
+
+ for (i = 0; i < half; i++)
+ if (p[i] == p[i + half]) {
+ ccprintf("repeating 32 bit word detected"
+ " at offset 0x%x!\n", i * 4);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ ccprintf("hashed data %ph\n", HEX_BUF(pinfo->p, 16));
+
+ return EC_SUCCESS;
+}
+
+/*
+ * Main iteration of the console command, runs ecnryption/decryption cycles,
+ * vefifying that decrypted text's hash matches the original, and accumulating
+ * timing statistics.
+ */
+static int command_loop(struct test_info *pinfo)
+{
+ uint8_t sha[SHA_DIGEST_SIZE];
+ uint8_t sha_after[SHA_DIGEST_SIZE];
+ uint32_t iteration;
+ uint8_t *p_last_byte;
+ int rv;
+
+ /*
+ * Prepare the hash of the original data to be able to verify
+ * results.
+ */
+ DCRYPTO_SHA1_hash(pinfo->p, pinfo->test_blob_size, sha);
+
+ /* Use the hash as an IV for the cipher. */
+ memcpy(sha_after, sha, sizeof(sha_after));
+
+ iteration = number_of_iterations;
+ p_last_byte = pinfo->p + pinfo->test_blob_size;
+
+ while (iteration--) {
+ char last_byte = (char) iteration;
+ uint32_t tstamp;
+
+ *p_last_byte = last_byte;
+
+ if (!(iteration % 500))
+ watchdog_reload();
+
+ tstamp = get_time().val;
+ rv = DCRYPTO_app_cipher(NVMEM, sha_after, pinfo->p,
+ pinfo->p, pinfo->test_blob_size);
+ tstamp = get_time().val - tstamp;
+
+ if (!rv) {
+ ccprintf("encryption failed\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ if (*p_last_byte != last_byte) {
+ ccprintf("encryption overflowed\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ update_stats(&pinfo->enc_stats, tstamp);
+
+ tstamp = get_time().val;
+ rv = DCRYPTO_app_cipher(NVMEM, sha_after, pinfo->p,
+ pinfo->p, pinfo->test_blob_size);
+ tstamp = get_time().val - tstamp;
+
+ if (!rv) {
+ ccprintf("decryption failed\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ if (*p_last_byte != last_byte) {
+ ccprintf("decryption overflowed\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ DCRYPTO_SHA1_hash(pinfo->p, pinfo->test_blob_size, sha_after);
+ if (memcmp(sha, sha_after, sizeof(sha))) {
+ ccprintf("\n"
+ "sha1 before and after mismatch, %d to go!\n",
+ iteration);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ update_stats(&pinfo->dec_stats, tstamp);
+
+ /* get a new IV */
+ DCRYPTO_SHA1_hash(sha_after, sizeof(sha), sha_after);
+ }
+
+ return EC_SUCCESS;
+}
+
+/*
+ * Run cipher command on the hooks task context, as dcrypto's stack
+ * requirements exceed console tasks' allowance.
+ */
+static void run_cipher_cmd(void)
+{
+ struct test_info info;
+
+ result = prepare_running(&info);
+
+ if (result == EC_SUCCESS)
+ result = basic_check(&info);
+
+ if (result == EC_SUCCESS)
+ result = command_loop(&info);
+
+ if (result == EC_SUCCESS) {
+ report_stats("Encryption", &info.enc_stats);
+ report_stats("Decryption", &info.dec_stats);
+ } else if (info.p) {
+ ccprintf("current data %ph\n", HEX_BUF(info.p, 16));
+ }
+
+ if (info.p)
+ shared_mem_release(info.p);
+
+ task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0);
+}
+DECLARE_DEFERRED(run_cipher_cmd);
+
+static int cmd_cipher(int argc, char **argv)
+{
+ uint32_t events;
+ uint32_t max_time;
+
+ /* Ignore potential input errors, let the user handle them. */
+ if (argc > 1)
+ number_of_iterations = strtoi(argv[1], NULL, 0);
+ else
+ number_of_iterations = 1000;
+
+ if (!number_of_iterations) {
+ ccprintf("not running zero iterations\n");
+ return EC_ERROR_PARAM1;
+ }
+
+ hook_call_deferred(&run_cipher_cmd_data, 0);
+
+ /* Roughly, .5 us per byte should be more than enough. */
+ max_time = number_of_iterations * shared_mem_size() / 2;
+
+ ccprintf("Will wait up to %d ms\n", (max_time + 500)/1000);
+
+ events = task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), max_time);
+ if (!(events & TASK_EVENT_CUSTOM_BIT(0))) {
+ ccprintf("Timed out, you might want to reboot...\n");
+ return EC_ERROR_TIMEOUT;
+ }
+
+ return result;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(cipher, cmd_cipher, NULL, NULL);
+#endif
diff --git a/chip/g/dcrypto/app_key.c b/chip/g/dcrypto/app_key.c
new file mode 100644
index 0000000000..1fafab9d2e
--- /dev/null
+++ b/chip/g/dcrypto/app_key.c
@@ -0,0 +1,87 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "dcrypto.h"
+#include "internal.h"
+#include "endian.h"
+#include "registers.h"
+
+#include "cryptoc/util.h"
+
+#include "console.h"
+
+const char *const dcrypto_app_names[] = {
+ "RESERVED",
+ "NVMEM",
+ "U2F_ATTEST",
+ "U2F_ORIGIN",
+ "U2F_WRAP",
+ /* This key signs data from H1's configured by mn50/scribe. */
+ "PERSO_AUTH",
+ "PINWEAVER",
+};
+
+static void name_hash(enum dcrypto_appid appid,
+ uint32_t digest[SHA256_DIGEST_WORDS])
+{
+ LITE_SHA256_CTX ctx;
+ const char *name = dcrypto_app_names[appid];
+ size_t x;
+
+ /* The PERSO_AUTH digest was improperly defined, so now this exception
+ * exists to prevent data loss.
+ */
+ if (appid == PERSO_AUTH) {
+ digest[0] = 0x2019da34;
+ digest[1] = 0xf1a01a13;
+ digest[2] = 0x0fb9f73f;
+ digest[3] = 0xf2e85f76;
+ digest[4] = 0x5ecb7690;
+ digest[5] = 0x09f732c9;
+ digest[6] = 0xe540bf14;
+ digest[7] = 0xcc46799a;
+ return;
+ }
+
+ DCRYPTO_SHA256_init(&ctx, 0);
+ HASH_update(&ctx, name, strlen(name));
+ memcpy(digest, HASH_final(&ctx), SHA256_DIGEST_SIZE);
+
+ /* The digests were originally endian swapped because xxd was used to
+ * print them so this operation is needed to keep the derived keys the
+ * same. Any changes to they key derivation process must result in the
+ * same keys being produced given the same inputs, or devices will
+ * effectively be reset and user data will be lost by the key change.
+ */
+ for (x = 0; x < SHA256_DIGEST_WORDS; ++x)
+ digest[x] = __builtin_bswap32(digest[x]);
+}
+
+int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx)
+{
+ uint32_t digest[SHA256_DIGEST_WORDS];
+
+ memset(ctx, 0, sizeof(*ctx));
+ name_hash(appid, digest);
+
+ if (!dcrypto_ladder_compute_usr(appid, digest))
+ return 0;
+
+ return 1;
+}
+
+void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx)
+{
+ always_memset(ctx, 0, sizeof(struct APPKEY_CTX));
+ GREG32(KEYMGR, AES_WIPE_SECRETS) = 1;
+}
+
+int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8],
+ uint32_t output[8])
+{
+ uint32_t digest[SHA256_DIGEST_WORDS];
+
+ name_hash(appid, digest);
+ return !!dcrypto_ladder_derive(appid, digest, input, output);
+}
diff --git a/chip/g/dcrypto/bn.c b/chip/g/dcrypto/bn.c
new file mode 100644
index 0000000000..94aafa1799
--- /dev/null
+++ b/chip/g/dcrypto/bn.c
@@ -0,0 +1,1244 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifdef PRINT_PRIMES
+#include "console.h"
+#endif
+
+#include "dcrypto.h"
+#include "internal.h"
+
+#include "trng.h"
+
+#include "cryptoc/util.h"
+
+#include <assert.h>
+
+#ifdef CONFIG_WATCHDOG
+extern void watchdog_reload(void);
+#else
+static inline void watchdog_reload(void) { }
+#endif
+
+void bn_init(struct LITE_BIGNUM *b, void *buf, size_t len)
+{
+ DCRYPTO_bn_wrap(b, buf, len);
+ always_memset(buf, 0x00, len);
+}
+
+void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len)
+{
+ /* Only word-multiple sized buffers accepted. */
+ assert((len & 0x3) == 0);
+ b->dmax = len / LITE_BN_BYTES;
+ b->d = (struct access_helper *) buf;
+}
+
+int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b)
+{
+ int i;
+ uint32_t top = 0;
+
+ for (i = a->dmax - 1; i > b->dmax - 1; --i)
+ top |= BN_DIGIT(a, i);
+ if (top)
+ return 0;
+
+ for (i = b->dmax - 1; i > a->dmax - 1; --i)
+ top |= BN_DIGIT(b, i);
+ if (top)
+ return 0;
+
+ for (i = MIN(a->dmax, b->dmax) - 1; i >= 0; --i)
+ if (BN_DIGIT(a, i) != BN_DIGIT(b, i))
+ return 0;
+
+ return 1;
+}
+
+static void bn_copy(struct LITE_BIGNUM *dst, const struct LITE_BIGNUM *src)
+{
+ dst->dmax = src->dmax;
+ memcpy(dst->d, src->d, bn_size(dst));
+}
+
+int bn_check_topbit(const struct LITE_BIGNUM *N)
+{
+ return BN_DIGIT(N, N->dmax - 1) >> 31;
+}
+
+/* a[n]. */
+int bn_is_bit_set(const struct LITE_BIGNUM *a, int n)
+{
+ int i, j;
+
+ if (n < 0)
+ return 0;
+
+ i = n / LITE_BN_BITS2;
+ j = n % LITE_BN_BITS2;
+ if (a->dmax <= i)
+ return 0;
+
+ return (BN_DIGIT(a, i) >> j) & 1;
+}
+
+static int bn_set_bit(const struct LITE_BIGNUM *a, int n)
+{
+ int i, j;
+
+ if (n < 0)
+ return 0;
+
+ i = n / LITE_BN_BITS2;
+ j = n % LITE_BN_BITS2;
+ if (a->dmax <= i)
+ return 0;
+
+ BN_DIGIT(a, i) |= 1 << j;
+ return 1;
+}
+
+/* a[] >= b[]. */
+/* TODO(ngm): constant time. */
+static int bn_gte(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b)
+{
+ int i;
+ uint32_t top = 0;
+
+ for (i = a->dmax - 1; i > b->dmax - 1; --i)
+ top |= BN_DIGIT(a, i);
+ if (top)
+ return 1;
+
+ for (i = b->dmax - 1; i > a->dmax - 1; --i)
+ top |= BN_DIGIT(b, i);
+ if (top)
+ return 0;
+
+ for (i = MIN(a->dmax, b->dmax) - 1;
+ BN_DIGIT(a, i) == BN_DIGIT(b, i) && i > 0; --i)
+ ;
+ return BN_DIGIT(a, i) >= BN_DIGIT(b, i);
+}
+
+/* c[] = c[] - a[], assumes c > a. */
+uint32_t bn_sub(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a)
+{
+ int64_t A = 0;
+ int i;
+
+ for (i = 0; i < a->dmax; i++) {
+ A += (uint64_t) BN_DIGIT(c, i) - BN_DIGIT(a, i);
+ BN_DIGIT(c, i) = (uint32_t) A;
+ A >>= 32;
+ }
+
+ for (; A && i < c->dmax; i++) {
+ A += (uint64_t) BN_DIGIT(c, i);
+ BN_DIGIT(c, i) = (uint32_t) A;
+ A >>= 32;
+ }
+
+ return (uint32_t) A; /* 0 or -1. */
+}
+
+/* c[] = c[] - a[], negative numbers in 2's complement representation. */
+/* Returns borrow bit. */
+static uint32_t bn_signed_sub(struct LITE_BIGNUM *c, int *c_neg,
+ const struct LITE_BIGNUM *a, int a_neg)
+{
+ uint32_t carry = 0;
+ uint64_t A = 1;
+ int i;
+
+ for (i = 0; i < a->dmax; ++i) {
+ A += (uint64_t) BN_DIGIT(c, i) + ~BN_DIGIT(a, i);
+ BN_DIGIT(c, i) = (uint32_t) A;
+ A >>= 32;
+ }
+
+ for (; i < c->dmax; ++i) {
+ A += (uint64_t) BN_DIGIT(c, i) + 0xFFFFFFFF;
+ BN_DIGIT(c, i) = (uint32_t) A;
+ A >>= 32;
+ }
+
+ A &= 0x01;
+ carry = (!*c_neg && a_neg && A) || (*c_neg && !a_neg && !A);
+ *c_neg = carry ? *c_neg : (*c_neg + !a_neg + A) & 0x01;
+ return carry;
+}
+
+/* c[] = c[] + a[]. */
+uint32_t bn_add(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a)
+{
+ uint64_t A = 0;
+ int i;
+
+ for (i = 0; i < a->dmax; ++i) {
+ A += (uint64_t) BN_DIGIT(c, i) + BN_DIGIT(a, i);
+ BN_DIGIT(c, i) = (uint32_t) A;
+ A >>= 32;
+ }
+
+ for (; A && i < c->dmax; ++i) {
+ A += (uint64_t) BN_DIGIT(c, i);
+ BN_DIGIT(c, i) = (uint32_t) A;
+ A >>= 32;
+ }
+
+ return (uint32_t) A; /* 0 or 1. */
+}
+
+/* c[] = c[] + a[], negative numbers in 2's complement representation. */
+/* Returns carry bit. */
+static uint32_t bn_signed_add(struct LITE_BIGNUM *c, int *c_neg,
+ const struct LITE_BIGNUM *a, int a_neg)
+{
+ uint32_t A = bn_add(c, a);
+ uint32_t carry;
+
+ carry = (!*c_neg && !a_neg && A) || (*c_neg && a_neg && !A);
+ *c_neg = carry ? *c_neg : (*c_neg + a_neg + A) & 0x01;
+ return carry;
+}
+
+/* r[] <<= 1. */
+static uint32_t bn_lshift(struct LITE_BIGNUM *r)
+{
+ int i;
+ uint32_t w;
+ uint32_t carry = 0;
+
+ for (i = 0; i < r->dmax; i++) {
+ w = (BN_DIGIT(r, i) << 1) | carry;
+ carry = BN_DIGIT(r, i) >> 31;
+ BN_DIGIT(r, i) = w;
+ }
+ return carry;
+}
+
+/* r[] >>= 1. Handles 2's complement negative numbers. */
+static void bn_rshift(struct LITE_BIGNUM *r, uint32_t carry, uint32_t neg)
+{
+ int i;
+ uint32_t ones = ~0;
+ uint32_t highbit = (!carry && neg) || (carry && !neg);
+
+ for (i = 0; i < r->dmax - 1; ++i) {
+ uint32_t accu;
+
+ ones &= BN_DIGIT(r, i);
+ accu = (BN_DIGIT(r, i) >> 1);
+ accu |= (BN_DIGIT(r, i + 1) << (LITE_BN_BITS2 - 1));
+ BN_DIGIT(r, i) = accu;
+ }
+ ones &= BN_DIGIT(r, i);
+ BN_DIGIT(r, i) = (BN_DIGIT(r, i) >> 1) |
+ (highbit << (LITE_BN_BITS2 - 1));
+
+ if (ones == ~0 && highbit && neg)
+ memset(r->d, 0x00, bn_size(r)); /* -1 >> 1 = 0. */
+}
+
+/* Montgomery c[] += a * b[] / R % N. */
+/* TODO(ngm): constant time. */
+static void bn_mont_mul_add(struct LITE_BIGNUM *c, const uint32_t a,
+ const struct LITE_BIGNUM *b, const uint32_t nprime,
+ const struct LITE_BIGNUM *N)
+{
+ uint32_t A, B, d0;
+ int i;
+
+ {
+ register uint64_t tmp;
+
+ tmp = BN_DIGIT(c, 0) + (uint64_t) a * BN_DIGIT(b, 0);
+ A = tmp >> 32;
+ d0 = (uint32_t) tmp * (uint32_t) nprime;
+ tmp = (uint32_t)tmp + (uint64_t) d0 * BN_DIGIT(N, 0);
+ B = tmp >> 32;
+ }
+
+ for (i = 0; i < N->dmax - 1;) {
+ register uint64_t tmp;
+
+ tmp = A + (uint64_t) a * BN_DIGIT(b, i + 1) +
+ BN_DIGIT(c, i + 1);
+ A = tmp >> 32;
+ tmp = B + (uint64_t) d0 * BN_DIGIT(N, i + 1) + (uint32_t) tmp;
+ BN_DIGIT(c, i) = (uint32_t) tmp;
+ B = tmp >> 32;
+ ++i;
+ }
+
+ {
+ uint64_t tmp = (uint64_t) A + B;
+
+ BN_DIGIT(c, i) = (uint32_t) tmp;
+ A = tmp >> 32; /* 0 or 1. */
+ if (A)
+ bn_sub(c, N);
+ }
+}
+
+/* Montgomery c[] = a[] * b[] / R % N. */
+static void bn_mont_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a,
+ const struct LITE_BIGNUM *b, const uint32_t nprime,
+ const struct LITE_BIGNUM *N)
+{
+ int i;
+
+ for (i = 0; i < N->dmax; i++)
+ BN_DIGIT(c, i) = 0;
+
+ bn_mont_mul_add(c, a ? BN_DIGIT(a, 0) : 1, b, nprime, N);
+ for (i = 1; i < N->dmax; i++)
+ bn_mont_mul_add(c, a ? BN_DIGIT(a, i) : 0, b, nprime, N);
+}
+
+/* Mongomery R * R % N, R = 1 << (1 + log2N). */
+/* TODO(ngm): constant time. */
+static void bn_compute_RR(struct LITE_BIGNUM *RR, const struct LITE_BIGNUM *N)
+{
+ int i;
+
+ bn_sub(RR, N); /* R - N = R % N since R < 2N */
+
+ /* Repeat 2 * R % N, log2(R) times. */
+ for (i = 0; i < N->dmax * LITE_BN_BITS2; i++) {
+ if (bn_lshift(RR))
+ assert(bn_sub(RR, N) == -1);
+ if (bn_gte(RR, N))
+ bn_sub(RR, N);
+ }
+}
+
+/* Montgomery nprime = -1 / n0 % (2 ^ 32). */
+static uint32_t bn_compute_nprime(const uint32_t n0)
+{
+ int i;
+ uint32_t ninv = 1;
+
+ /* Repeated Hensel lifting. */
+ for (i = 0; i < 5; i++)
+ ninv *= 2 - (n0 * ninv);
+
+ return ~ninv + 1; /* Two's complement. */
+}
+
+/* TODO(ngm): this implementation not timing or side-channel safe by
+ * any measure. */
+static void bn_modexp_internal(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp,
+ const struct LITE_BIGNUM *N)
+{
+ int i;
+ uint32_t nprime;
+ uint32_t RR_buf[RSA_MAX_WORDS];
+ uint32_t acc_buf[RSA_MAX_WORDS];
+ uint32_t aR_buf[RSA_MAX_WORDS];
+
+ struct LITE_BIGNUM RR;
+ struct LITE_BIGNUM acc;
+ struct LITE_BIGNUM aR;
+
+ bn_init(&RR, RR_buf, bn_size(N));
+ bn_init(&acc, acc_buf, bn_size(N));
+ bn_init(&aR, aR_buf, bn_size(N));
+
+ nprime = bn_compute_nprime(BN_DIGIT(N, 0));
+ bn_compute_RR(&RR, N);
+ bn_mont_mul(&acc, NULL, &RR, nprime, N); /* R = 1 * RR / R % N */
+ bn_mont_mul(&aR, input, &RR, nprime, N); /* aR = a * RR / R % N */
+
+ /* TODO(ngm): burn stack space and use windowing. */
+ for (i = exp->dmax * LITE_BN_BITS2 - 1; i >= 0; i--) {
+ bn_mont_mul(output, &acc, &acc, nprime, N);
+ if (bn_is_bit_set(exp, i)) {
+ bn_mont_mul(&acc, output, &aR, nprime, N);
+ } else {
+ struct LITE_BIGNUM tmp = *output;
+
+ *output = acc;
+ acc = tmp;
+ }
+ /* Poke the watchdog.
+ * TODO(ngm): may be unnecessary with
+ * a faster implementation.
+ */
+ watchdog_reload();
+ }
+
+ bn_mont_mul(output, NULL, &acc, nprime, N); /* Convert out. */
+ /* Copy to output buffer if necessary. */
+ if (acc.d != (struct access_helper *) acc_buf) {
+ memcpy(acc.d, acc_buf, bn_size(output));
+ *output = acc;
+ }
+
+ /* TODO(ngm): constant time. */
+ if (bn_sub(output, N))
+ bn_add(output, N); /* Final reduce. */
+ output->dmax = N->dmax;
+
+ always_memset(RR_buf, 0, sizeof(RR_buf));
+ always_memset(acc_buf, 0, sizeof(acc_buf));
+ always_memset(aR_buf, 0, sizeof(aR_buf));
+}
+
+/* output = input ^ exp % N */
+int bn_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N)
+{
+#ifndef CR50_NO_BN_ASM
+ if ((bn_bits(N) & 255) == 0) {
+ /* Use hardware support for standard key sizes. */
+ return dcrypto_modexp(output, input, exp, N);
+ }
+#endif
+ bn_modexp_internal(output, input, exp, N);
+ return 1;
+}
+
+/* output = input ^ exp % N */
+int bn_modexp_word(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input,
+ uint32_t exp, const struct LITE_BIGNUM *N)
+{
+#ifndef CR50_NO_BN_ASM
+ if ((bn_bits(N) & 255) == 0) {
+ /* Use hardware support for standard key sizes. */
+ return dcrypto_modexp_word(output, input, exp, N);
+ }
+#endif
+ {
+ struct LITE_BIGNUM pubexp;
+
+ DCRYPTO_bn_wrap(&pubexp, &exp, sizeof(exp));
+ bn_modexp_internal(output, input, &pubexp, N);
+ return 1;
+ }
+}
+
+/* output = input ^ exp % N */
+int bn_modexp_blinded(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp,
+ const struct LITE_BIGNUM *N,
+ uint32_t pubexp)
+{
+#ifndef CR50_NO_BN_ASM
+ if ((bn_bits(N) & 255) == 0) {
+ /* Use hardware support for standard key sizes. */
+ return dcrypto_modexp_blinded(output, input, exp, N, pubexp);
+ }
+#endif
+ bn_modexp_internal(output, input, exp, N);
+ return 1;
+}
+
+/* c[] += a * b[] */
+static uint32_t bn_mul_add(struct LITE_BIGNUM *c, uint32_t a,
+ const struct LITE_BIGNUM *b, uint32_t offset)
+{
+ int i;
+ uint64_t carry = 0;
+
+ for (i = 0; i < b->dmax; i++) {
+ carry += BN_DIGIT(c, offset + i) +
+ (uint64_t) BN_DIGIT(b, i) * a;
+ BN_DIGIT(c, offset + i) = (uint32_t) carry;
+ carry >>= 32;
+ }
+
+ return carry;
+}
+
+/* c[] = a[] * b[] */
+void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a,
+ const struct LITE_BIGNUM *b)
+{
+ int i;
+ uint32_t carry = 0;
+
+ memset(c->d, 0, bn_size(c));
+ for (i = 0; i < a->dmax; i++) {
+ BN_DIGIT(c, i + b->dmax - 1) = carry;
+ carry = bn_mul_add(c, BN_DIGIT(a, i), b, i);
+ }
+
+ BN_DIGIT(c, i + b->dmax - 1) = carry;
+}
+
+/* c[] = a[] * b[] */
+static void bn_mul_ex(struct LITE_BIGNUM *c,
+ const struct LITE_BIGNUM *a, int a_len,
+ const struct LITE_BIGNUM *b)
+{
+ int i;
+ uint32_t carry = 0;
+
+ memset(c->d, 0, bn_size(c));
+ for (i = 0; i < a_len; i++) {
+ BN_DIGIT(c, i + b->dmax - 1) = carry;
+ carry = bn_mul_add(c, BN_DIGIT(a, i), b, i);
+ }
+
+ BN_DIGIT(c, i + b->dmax - 1) = carry;
+}
+
+static int bn_div_word_ex(struct LITE_BIGNUM *q,
+ struct LITE_BIGNUM *r,
+ const struct LITE_BIGNUM *u, int m,
+ uint32_t div)
+{
+ uint32_t rem = 0;
+ int i;
+
+ for (i = m - 1; i >= 0; --i) {
+ uint64_t tmp = ((uint64_t)rem << 32) + BN_DIGIT(u, i);
+ uint32_t qd = tmp / div;
+
+ BN_DIGIT(q, i) = qd;
+ rem = tmp - (uint64_t)qd * div;
+ }
+
+ if (r != NULL)
+ BN_DIGIT(r, 0) = rem;
+
+ return 1;
+}
+
+/*
+ * Knuth's long division.
+ *
+ * Returns 0 on error.
+ * |u| >= |v|
+ * v[n-1] must not be 0
+ * r gets |v| digits written to.
+ * q gets |u| - |v| + 1 digits written to.
+ */
+static int bn_div_ex(struct LITE_BIGNUM *q,
+ struct LITE_BIGNUM *r,
+ const struct LITE_BIGNUM *u, int m,
+ const struct LITE_BIGNUM *v, int n)
+{
+ uint32_t vtop;
+ int s, i, j;
+ uint32_t vn[RSA_MAX_WORDS]; /* Normalized v */
+ uint32_t un[RSA_MAX_WORDS + 1]; /* Normalized u */
+
+ if (m < n || n <= 0)
+ return 0;
+
+ vtop = BN_DIGIT(v, n - 1);
+
+ if (vtop == 0)
+ return 0;
+
+ if (n == 1)
+ return bn_div_word_ex(q, r, u, m, vtop);
+
+ /* Compute shift factor to make v have high bit set */
+ s = 0;
+ while ((vtop & 0x80000000) == 0) {
+ s = s + 1;
+ vtop = vtop << 1;
+ }
+
+ /* Normalize u and v into un and vn.
+ * Note un always gains a leading digit
+ */
+ if (s != 0) {
+ for (i = n - 1; i > 0; i--)
+ vn[i] = (BN_DIGIT(v, i) << s) |
+ (BN_DIGIT(v, i - 1) >> (32 - s));
+ vn[0] = BN_DIGIT(v, 0) << s;
+
+ un[m] = BN_DIGIT(u, m - 1) >> (32 - s);
+ for (i = m - 1; i > 0; i--)
+ un[i] = (BN_DIGIT(u, i) << s) |
+ (BN_DIGIT(u, i - 1) >> (32 - s));
+ un[0] = BN_DIGIT(u, 0) << s;
+ } else {
+ for (i = 0; i < n; ++i)
+ vn[i] = BN_DIGIT(v, i);
+ for (i = 0; i < m; ++i)
+ un[i] = BN_DIGIT(u, i);
+ un[m] = 0;
+ }
+
+ /* Main loop, reducing un digit by digit */
+ for (j = m - n; j >= 0; j--) {
+ uint32_t qd;
+ int64_t t, k;
+
+ /* Estimate quotient digit */
+ if (un[j + n] == vn[n - 1]) {
+ /* Maxed out */
+ qd = 0xFFFFFFFF;
+ } else {
+ /* Fine tune estimate */
+ uint64_t rhat = ((uint64_t)un[j + n] << 32) +
+ un[j + n - 1];
+
+ qd = rhat / vn[n - 1];
+ rhat = rhat - (uint64_t)qd * vn[n - 1];
+ while ((rhat >> 32) == 0 &&
+ (uint64_t)qd * vn[n - 2] >
+ (rhat << 32) + un[j + n - 2]) {
+ qd = qd - 1;
+ rhat = rhat + vn[n - 1];
+ }
+ }
+
+ /* Multiply and subtract */
+ k = 0;
+ for (i = 0; i < n; i++) {
+ uint64_t p = (uint64_t)qd * vn[i];
+
+ t = un[i + j] - k - (p & 0xFFFFFFFF);
+ un[i + j] = t;
+ k = (p >> 32) - (t >> 32);
+ }
+ t = un[j + n] - k;
+ un[j + n] = t;
+
+ /* If borrowed, add one back and adjust estimate */
+ if (t < 0) {
+ k = 0;
+ qd = qd - 1;
+ for (i = 0; i < n; i++) {
+ t = (uint64_t)un[i + j] + vn[i] + k;
+ un[i + j] = t;
+ k = t >> 32;
+ }
+ un[j + n] = un[j + n] + k;
+ }
+
+ BN_DIGIT(q, j) = qd;
+ }
+
+ if (r != NULL) {
+ /* Denormalize un into r */
+ if (s != 0) {
+ for (i = 0; i < n - 1; i++)
+ BN_DIGIT(r, i) = (un[i] >> s) |
+ (un[i + 1] << (32 - s));
+ BN_DIGIT(r, n - 1) = un[n - 1] >> s;
+ } else {
+ for (i = 0; i < n; i++)
+ BN_DIGIT(r, i) = un[i];
+ }
+ }
+
+ return 1;
+}
+
+static void bn_set_bn(struct LITE_BIGNUM *d, const struct LITE_BIGNUM *src,
+ size_t n)
+{
+ size_t i = 0;
+
+ for (; i < n && i < d->dmax; ++i)
+ BN_DIGIT(d, i) = BN_DIGIT(src, i);
+ for (; i < d->dmax; ++i)
+ BN_DIGIT(d, i) = 0;
+}
+
+static size_t bn_digits(const struct LITE_BIGNUM *a)
+{
+ size_t n = a->dmax - 1;
+
+ while (BN_DIGIT(a, n) == 0 && n)
+ --n;
+ return n + 1;
+}
+
+int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient,
+ struct LITE_BIGNUM *remainder,
+ const struct LITE_BIGNUM *src,
+ const struct LITE_BIGNUM *divisor)
+{
+ int src_len = bn_digits(src);
+ int div_len = bn_digits(divisor);
+ int i, result;
+
+ if (src_len < div_len)
+ return 0;
+
+ result = bn_div_ex(quotient, remainder,
+ src, src_len,
+ divisor, div_len);
+
+ if (!result)
+ return 0;
+
+ /* 0-pad the destinations. */
+ for (i = src_len - div_len + 1; i < quotient->dmax; ++i)
+ BN_DIGIT(quotient, i) = 0;
+ if (remainder) {
+ for (i = div_len; i < remainder->dmax; ++i)
+ BN_DIGIT(remainder, i) = 0;
+ }
+
+ return result;
+}
+
+/*
+ * Extended Euclid modular inverse.
+ *
+ * https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
+ * #Computing_multiplicative_inverses_in_modular_structures:
+
+ * function inverse(a, n)
+ * t := 0; newt := 1;
+ * r := n; newr := a;
+ * while newr ≠ 0
+ * quotient := r div newr
+ * (t, newt) := (newt, t - quotient * newt)
+ * (r, newr) := (newr, r - quotient * newr)
+ * if r > 1 then return "a is not invertible"
+ * if t < 0 then t := t + n
+ * return t
+ */
+int bn_modinv_vartime(struct LITE_BIGNUM *dst, const struct LITE_BIGNUM *src,
+ const struct LITE_BIGNUM *mod)
+{
+ uint32_t R_buf[RSA_MAX_WORDS];
+ uint32_t nR_buf[RSA_MAX_WORDS];
+ uint32_t Q_buf[RSA_MAX_WORDS];
+
+ uint32_t nT_buf[RSA_MAX_WORDS + 1]; /* Can go negative, hence +1 */
+ uint32_t T_buf[RSA_MAX_WORDS + 1]; /* Can go negative */
+ uint32_t tmp_buf[2 * RSA_MAX_WORDS + 1]; /* needs to hold Q*nT */
+
+ struct LITE_BIGNUM R;
+ struct LITE_BIGNUM nR;
+ struct LITE_BIGNUM Q;
+ struct LITE_BIGNUM T;
+ struct LITE_BIGNUM nT;
+ struct LITE_BIGNUM tmp;
+
+ struct LITE_BIGNUM *pT = &T;
+ struct LITE_BIGNUM *pnT = &nT;
+ struct LITE_BIGNUM *pR = &R;
+ struct LITE_BIGNUM *pnR = &nR;
+ struct LITE_BIGNUM *bnswap;
+
+ int t_neg = 0;
+ int nt_neg = 0;
+ int iswap;
+
+ size_t r_len, nr_len;
+
+ bn_init(&R, R_buf, bn_size(mod));
+ bn_init(&nR, nR_buf, bn_size(mod));
+ bn_init(&Q, Q_buf, bn_size(mod));
+ bn_init(&T, T_buf, bn_size(mod) + sizeof(uint32_t));
+ bn_init(&nT, nT_buf, bn_size(mod) + sizeof(uint32_t));
+ bn_init(&tmp, tmp_buf, bn_size(mod) + sizeof(uint32_t));
+
+ r_len = bn_digits(mod);
+ nr_len = bn_digits(src);
+
+ BN_DIGIT(&nT, 0) = 1; /* T = 0, nT = 1 */
+ bn_set_bn(&R, mod, r_len); /* R = n */
+ bn_set_bn(&nR, src, nr_len); /* nR = input */
+
+ /* Trim nR */
+ while (nr_len && BN_DIGIT(&nR, nr_len - 1) == 0)
+ --nr_len;
+
+ while (nr_len) {
+ size_t q_len = r_len - nr_len + 1;
+
+ /* (r, nr) = (nr, r % nr), q = r / nr */
+ if (!bn_div_ex(&Q, pR, pR, r_len, pnR, nr_len))
+ return 0;
+
+ /* swap R and nR */
+ r_len = nr_len;
+ bnswap = pR; pR = pnR; pnR = bnswap;
+
+ /* trim nR and Q */
+ while (nr_len && BN_DIGIT(pnR, nr_len - 1) == 0)
+ --nr_len;
+ while (q_len && BN_DIGIT(&Q, q_len - 1) == 0)
+ --q_len;
+
+ Q.dmax = q_len;
+
+ /* compute t - q*nt */
+ if (q_len == 1 && BN_DIGIT(&Q, 0) <= 2) {
+ /* Doing few direct subs is faster than mul + sub */
+ uint32_t n = BN_DIGIT(&Q, 0);
+
+ while (n--)
+ bn_signed_sub(pT, &t_neg, pnT, nt_neg);
+ } else {
+ /* Call bn_mul_ex with smallest operand first */
+ if (nt_neg) {
+ /* Negative numbers use all digits,
+ * thus pnT is large
+ */
+ bn_mul_ex(&tmp, &Q, q_len, pnT);
+ } else {
+ int nt_len = bn_digits(pnT);
+
+ if (q_len < nt_len)
+ bn_mul_ex(&tmp, &Q, q_len, pnT);
+ else
+ bn_mul_ex(&tmp, pnT, nt_len, &Q);
+ }
+ bn_signed_sub(pT, &t_neg, &tmp, nt_neg);
+ }
+
+ /* swap T and nT */
+ bnswap = pT; pT = pnT; pnT = bnswap;
+ iswap = t_neg; t_neg = nt_neg; nt_neg = iswap;
+ }
+
+ if (r_len != 1 || BN_DIGIT(pR, 0) != 1) {
+ /* gcd not 1; no direct inverse */
+ return 0;
+ }
+
+ if (t_neg)
+ bn_signed_add(pT, &t_neg, mod, 0);
+
+ bn_set_bn(dst, pT, bn_digits(pT));
+
+ return 1;
+}
+
+#define PRIME1 3
+
+/*
+ * The array below is an encoding of the first 4096 primes, starting with
+ * PRIME1. Using 4096 of the first primes results in at least 5% improvement
+ * in running time over using the first 2048.
+ *
+ * Most byte entries in the array contain two sequential differentials between
+ * two adjacent prime numbers, each differential halved (as the difference is
+ * always even) and packed into 4 bits.
+ *
+ * If a halved differential value exceeds 0xf (and as such does not fit into 4
+ * bits), a zero is placed in the array followed by the value literal (no
+ * halving).
+ *
+ * If out of two consecutive differencials only the second one exceeds 0xf,
+ * the first one still is put into the array in its own byte prepended by a
+ * zero.
+ */
+const uint8_t PRIME_DELTAS[] = {
+ 1, 18, 18, 18, 49, 50, 18, 51, 19, 33, 50, 52,
+ 33, 33, 39, 35, 21, 19, 50, 51, 21, 18, 22, 98,
+ 18, 49, 83, 51, 19, 33, 87, 33, 39, 53, 18, 52,
+ 51, 35, 66, 69, 21, 19, 35, 66, 18, 100, 36, 35,
+ 97, 147, 83, 49, 53, 51, 19, 50, 22, 81, 35, 49,
+ 98, 52, 84, 84, 51, 36, 50, 66, 117, 97, 81, 33,
+ 87, 33, 39, 33, 42, 36, 84, 35, 55, 35, 52, 54,
+ 35, 21, 19, 81, 81, 57, 33, 35, 52, 51, 177, 84,
+ 83, 52, 98, 51, 19, 101, 145, 35, 19, 33, 38, 19,
+ 0, 34, 51, 73, 87, 33, 35, 66, 19, 101, 18, 18,
+ 54, 100, 99, 35, 66, 66, 114, 49, 35, 19, 90, 50,
+ 28, 33, 86, 21, 67, 51, 147, 33, 101, 100, 135, 50,
+ 18, 21, 99, 57, 24, 27, 52, 50, 18, 67, 81, 87,
+ 83, 97, 33, 86, 24, 19, 33, 84, 156, 35, 72, 18,
+ 72, 18, 67, 50, 97, 179, 19, 35, 115, 33, 50, 54,
+ 51, 114, 54, 67, 45, 149, 66, 49, 59, 97, 132, 38,
+ 117, 18, 67, 50, 18, 52, 33, 53, 21, 66, 117, 97,
+ 50, 24, 114, 52, 50, 148, 83, 52, 86, 114, 51, 30,
+ 21, 66, 114, 70, 54, 35, 165, 24, 210, 22, 50, 99,
+ 66, 75, 18, 22, 225, 51, 50, 49, 98, 97, 81, 129,
+ 131, 168, 66, 18, 27, 70, 53, 18, 49, 53, 22, 81,
+ 87, 50, 52, 51, 134, 18, 115, 36, 84, 51, 179, 21,
+ 114, 57, 21, 114, 21, 114, 73, 35, 18, 49, 98, 171,
+ 97, 35, 49, 59, 19, 131, 97, 54, 129, 35, 114, 25,
+ 197, 49, 81, 81, 83, 21, 21, 52, 245, 21, 67, 89,
+ 54, 97, 147, 35, 57, 21, 115, 33, 44, 22, 56, 67,
+ 57, 129, 35, 19, 53, 54, 105, 19, 41, 76, 33, 35,
+ 22, 39, 245, 54, 115, 86, 18, 52, 53, 18, 115, 50,
+ 49, 81, 134, 73, 35, 97, 51, 62, 55, 36, 84, 105,
+ 33, 44, 99, 24, 51, 117, 114, 243, 51, 67, 33, 99,
+ 33, 59, 49, 41, 18, 97, 50, 211, 50, 69, 0, 32,
+ 129, 50, 18, 21, 115, 36, 83, 162, 19, 242, 69, 51,
+ 67, 98, 49, 50, 49, 81, 131, 162, 103, 227, 162, 148,
+ 50, 55, 51, 81, 86, 69, 21, 70, 92, 18, 67, 36,
+ 149, 51, 19, 86, 21, 51, 52, 53, 49, 51, 53, 76,
+ 59, 25, 36, 95, 73, 33, 83, 19, 41, 70, 152, 49,
+ 99, 81, 81, 53, 114, 193, 129, 81, 90, 33, 36, 131,
+ 49, 104, 66, 63, 21, 19, 35, 52, 50, 99, 70, 39,
+ 101, 195, 99, 27, 73, 83, 114, 19, 84, 50, 63, 117,
+ 22, 81, 129, 156, 147, 137, 49, 146, 49, 84, 83, 52,
+ 35, 21, 22, 35, 49, 98, 121, 35, 162, 67, 36, 39,
+ 50, 118, 33, 242, 195, 54, 103, 50, 18, 147, 100, 50,
+ 97, 111, 129, 59, 115, 86, 49, 36, 83, 60, 115, 36,
+ 105, 81, 81, 35, 163, 39, 33, 39, 54, 197, 52, 81,
+ 242, 49, 98, 115, 0, 34, 100, 53, 18, 165, 72, 21,
+ 114, 22, 56, 52, 36, 35, 67, 54, 50, 51, 73, 42,
+ 38, 21, 49, 86, 18, 163, 243, 36, 86, 49, 225, 50,
+ 24, 97, 53, 76, 99, 147, 39, 50, 100, 54, 35, 99,
+ 97, 138, 33, 89, 66, 114, 19, 179, 115, 53, 49, 81,
+ 33, 177, 35, 54, 55, 86, 52, 0, 4, 0, 36, 118,
+ 50, 49, 99, 104, 21, 75, 22, 50, 57, 22, 50, 100,
+ 54, 35, 99, 22, 98, 115, 131, 21, 73, 0, 6, 0,
+ 34, 30, 27, 49, 86, 19, 36, 179, 21, 66, 52, 38,
+ 150, 162, 51, 66, 24, 97, 84, 81, 35, 118, 180, 225,
+ 42, 33, 39, 86, 22, 129, 228, 180, 35, 55, 36, 99,
+ 50, 162, 145, 99, 35, 121, 84, 0, 10, 0, 32, 53,
+ 51, 19, 131, 22, 62, 21, 72, 52, 53, 202, 81, 81,
+ 98, 58, 33, 105, 81, 81, 42, 141, 36, 50, 99, 70,
+ 99, 36, 177, 135, 83, 102, 115, 42, 38, 49, 51, 132,
+ 177, 228, 50, 162, 108, 162, 69, 24, 22, 0, 12, 0,
+ 34, 18, 54, 51, 67, 33, 60, 42, 83, 55, 35, 49,
+ 99, 81, 83, 162, 210, 19, 177, 194, 49, 35, 195, 66,
+ 0, 2, 0, 34, 52, 134, 21, 21, 52, 36, 107, 55,
+ 45, 33, 101, 66, 70, 39, 56, 52, 35, 52, 53, 97,
+ 51, 132, 51, 101, 19, 146, 51, 54, 148, 53, 73, 39,
+ 57, 84, 86, 19, 102, 0, 36, 35, 66, 49, 41, 99,
+ 67, 50, 145, 33, 194, 51, 127, 50, 54, 58, 36, 36,
+ 51, 47, 21, 100, 84, 195, 98, 114, 49, 231, 129, 99,
+ 42, 83, 51, 69, 103, 87, 135, 87, 56, 52, 56, 165,
+ 19, 33, 38, 21, 19, 179, 18, 148, 84, 177, 89, 114,
+ 18, 145, 35, 69, 31, 47, 21, 25, 41, 55, 81, 42,
+ 0, 36, 50, 55, 42, 87, 179, 31, 101, 145, 39, 59,
+ 145, 99, 36, 36, 53, 22, 149, 120, 114, 51, 19, 33,
+ 225, 227, 18, 55, 38, 120, 114, 52, 50, 51, 52, 36,
+ 39, 132, 50, 100, 129, 84, 35, 211, 84, 35, 103, 242,
+ 123, 70, 35, 69, 55, 83, 21, 102, 115, 57, 83, 73,
+ 35, 19, 81, 84, 51, 81, 149, 22, 35, 69, 103, 98,
+ 69, 51, 162, 120, 117, 69, 97, 147, 101, 97, 33, 99,
+ 36, 0, 4, 0, 44, 33, 33, 86, 51, 114, 51, 52,
+ 0, 6, 0, 36, 146, 49, 99, 51, 39, 182, 25, 83,
+ 220, 33, 33, 39, 35, 52, 134, 0, 2, 0, 42, 33,
+ 44, 51, 25, 39, 62, 151, 53, 97, 54, 243, 35, 55,
+ 33, 194, 51, 213, 147, 67, 63, 38, 97, 129, 50, 105,
+ 19, 45, 99, 98, 204, 99, 22, 228, 35, 97, 147, 35,
+ 58, 129, 51, 149, 49, 36, 51, 200, 52, 83, 123, 72,
+ 49, 98, 27, 73, 0, 34, 19, 146, 51, 69, 73, 50,
+ 18, 72, 22, 99, 146, 51, 49, 54, 90, 105, 35, 24,
+ 21, 114, 241, 86, 28, 56, 69, 22, 179, 24, 165, 22,
+ 105, 86, 49, 81, 53, 145, 99, 35, 28, 225, 33, 81,
+ 134, 75, 19, 33, 83, 166, 84, 99, 51, 41, 18, 105,
+ 22, 50, 24, 102, 114, 73, 38, 115, 50, 67, 42, 101,
+ 114, 24, 22, 242, 60, 172, 84, 101, 99, 102, 52, 135,
+ 50, 0, 6, 0, 36, 165, 246, 18, 30, 103, 59, 66,
+ 147, 121, 35, 19, 0, 34, 145, 131, 145, 194, 19, 99,
+ 101, 67, 134, 69, 0, 14, 0, 40, 49, 50, 103, 33,
+ 33, 36, 53, 51, 19, 51, 99, 197, 21, 54, 51, 115,
+ 0, 6, 0, 52, 163, 81, 84, 86, 97, 50, 120, 70,
+ 59, 21, 67, 177, 179, 69, 102, 21, 54, 18, 117, 19,
+ 146, 100, 150, 51, 35, 55, 33, 102, 35, 153, 97, 134,
+ 73, 93, 35, 67, 50, 21, 162, 52, 42, 81, 0, 34,
+ 18, 193, 102, 83, 22, 243, 104, 97, 185, 103, 81, 102,
+ 33, 35, 97, 137, 0, 2, 0, 40, 72, 52, 81, 41,
+ 69, 70, 41, 25, 81, 33, 36, 225, 59, 99, 121, 35,
+ 67, 53, 66, 25, 83, 171, 67, 242, 18, 147, 241, 36,
+ 50, 54, 0, 14, 0, 34, 115, 33, 50, 114, 19, 225,
+ 35, 69, 21, 21, 18, 241, 102, 89, 103, 81, 99, 83,
+ 118, 39, 41, 21, 66, 69, 105, 148, 57, 135, 51, 87,
+ 35, 22, 98, 51, 97, 129, 99, 39, 50, 22, 146, 0,
+ 36, 150, 97, 33, 36, 98, 0, 36, 57, 22, 83, 108,
+ 67, 56, 97, 149, 165, 19, 146, 0, 2, 0, 40, 49,
+ 129, 36, 149, 99, 21, 66, 54, 21, 148, 50, 162, 0,
+ 6, 0, 36, 49, 83, 195, 120, 57, 21, 165, 67, 35,
+ 21, 22, 33, 36, 83, 105, 118, 132, 56, 66, 19, 156,
+ 149, 97, 39, 83, 51, 150, 30, 151, 134, 124, 107, 49,
+ 84, 33, 39, 99, 35, 114, 18, 243, 19, 81, 251, 18,
+ 52, 51, 134, 99, 66, 28, 98, 52, 51, 81, 54, 231,
+ 50, 100, 54, 35, 115, 101, 51, 67, 50, 18, 70, 39,
+ 149, 24, 58, 53, 66, 0, 30, 0, 36, 100, 182, 19,
+ 104, 51, 25, 45, 36, 149, 69, 55, 42, 185, 100, 230,
+ 51, 67, 108, 135, 39, 99, 86, 163, 36, 150, 149, 18,
+ 165, 114, 49, 92, 145, 42, 135, 87, 50, 58, 53, 49,
+ 99, 245, 67, 35, 0, 8, 0, 40, 18, 22, 146, 52,
+ 83, 153, 22, 132, 50, 51, 0, 2, 0, 52, 114, 168,
+ 18, 54, 19, 102, 50, 117, 51, 117, 120, 67, 98, 75,
+ 49, 155, 49, 147, 135, 83, 97, 50, 73, 104, 18, 114,
+ 70, 111, 132, 33, 59, 100, 83, 51, 115, 149, 97, 81,
+ 45, 38, 66, 148, 87, 131, 52, 83, 67, 101, 165, 66,
+ 109, 146, 105, 63, 52, 59, 97, 35, 49, 81, 35, 49,
+ 59, 147, 150, 70, 53, 97, 129, 81, 89, 58, 33, 59,
+ 51, 147, 118, 129, 51, 39, 98, 25, 0, 16, 0, 36,
+ 99, 126, 22, 54, 50, 24, 244, 195, 245, 25, 35, 100,
+ 177, 59, 145, 81, 95, 30, 55, 131, 168, 19, 0, 4,
+ 0, 32, 33, 35, 22, 35, 54, 19, 35, 67, 42, 0,
+ 4, 0, 32, 84, 129, 177, 35, 67, 135, 41, 66, 163,
+ 102, 53, 21, 22, 230, 145, 149, 69, 0, 48, 18, 52,
+ 81, 95, 0, 2, 0, 36, 53, 49, 146, 52, 135, 131,
+ 114, 162, 49, 86, 19, 99, 50, 97, 50, 99, 66, 19,
+ 149, 52, 99, 177, 54, 146, 115, 42, 56, 66, 75, 70,
+ 51, 134, 159, 66, 18, 61, 39, 203, 49, 53, 55, 51,
+ 101, 49, 101, 100, 153, 83, 72, 51, 72, 162, 21, 21,
+ 99, 67, 90, 89, 210, 63, 18, 67, 102, 146, 75, 49,
+ 0, 12, 0, 34, 57, 99, 30, 120, 114, 118, 35, 49,
+ 0, 36, 35, 166, 195, 177, 137, 102, 145, 51, 50, 55,
+ 33, 180, 99, 83, 70, 150, 53, 27, 115, 50, 147, 171,
+ 22, 194, 153, 27, 18, 100, 101, 114, 25, 0, 16, 0,
+ 38, 51, 54, 83, 100, 50, 55, 243, 84, 179, 70, 81,
+ 81, 53, 21, 105, 163, 36, 179, 63, 55, 54, 99, 81,
+ 95, 24, 66, 19, 146, 19, 45, 36, 53, 18, 52, 35,
+ 246, 19, 50, 171, 66, 18, 0, 72, 66, 75, 18, 117,
+ 18, 163, 89, 58, 131, 67, 42, 107, 18, 22, 89, 27,
+ 57, 241, 87, 84, 0, 16, 0, 50, 53, 69, 99, 145,
+ 179, 18, 52, 51, 89, 27, 24, 117, 49, 101, 162, 115,
+ 0, 4, 0, 36, 18, 54, 18, 118, 50, 49, 50, 165,
+ 21, 54, 28, 102, 51, 44, 18, 193, 50, 52, 131, 21,
+ 103, 0, 6, 0, 34, 55, 50, 31, 180, 35, 66, 30,
+ 19, 45, 155, 19, 131, 24, 97, 98, 51, 117, 52, 98,
+ 145, 84, 131, 63, 21, 145, 84, 36, 108, 0, 40, 22,
+ 83, 97, 98, 18, 57, 118, 50, 127, 36, 84, 53, 148,
+ 39, 131, 66, 49, 81, 98, 18, 52, 35, 0, 32, 197,
+ 73, 81, 53, 18, 147, 97, 129, 179, 52, 146, 150, 67,
+ 42, 63, 182, 19, 146, 0, 62, 33, 99, 81, 102, 225,
+ 39, 179, 19, 53, 114, 21, 52, 87, 83, 22, 185, 69,
+ 150, 22, 38, 21, 19, 147, 0, 6, 0, 34, 49, 98,
+ 57, 145, 131, 52, 53, 148, 84, 81, 41, 214, 177, 33,
+ 179, 55, 131, 165, 97, 0, 18, 0, 42, 44, 19, 86,
+ 19, 84, 35, 102, 66, 54, 250, 60, 53, 97, 90, 51,
+ 38, 117, 150, 67, 98, 117, 22, 248, 22, 50, 18, 61,
+ 41, 18, 55, 0, 54, 0, 6, 0, 52, 24, 51, 109,
+ 33, 59, 49, 102, 53, 145, 102, 89, 99, 67, 83, 66,
+ 18, 172, 51, 87, 81, 179, 117, 210, 148, 102, 86, 52,
+ 131, 67, 59, 21, 165, 0, 6, 0, 44, 147, 81, 35,
+ 114, 210, 22, 84, 36, 98, 100, 180, 53, 147, 52, 54,
+ 36, 149, 99, 97, 50, 24, 102, 117, 115, 86, 22, 50,
+ 49, 98, 211, 147, 83, 25, 84, 45, 90, 56, 166, 84,
+ 81, 131, 165, 162, 241, 36, 129, 146, 19, 89, 103, 147,
+ 138, 50, 67, 35, 100, 81, 99, 33, 53, 24, 103, 83,
+ 67, 225, 57, 0, 30, 0, 34, 24, 97, 152, 52, 84,
+ 84, 0, 10, 0, 44, 51, 42, 33, 39, 228, 56, 127,
+ 63, 39, 83, 52, 41, 99, 27, 100, 54, 39, 35, 18,
+ 154, 56, 0, 38, 129, 35, 0, 2, 0, 40, 0, 42,
+ 114, 49, 197, 49, 149, 97, 129, 56, 52, 33, 83, 69,
+ 25, 132, 105, 99, 101, 51,
+};
+
+static uint32_t bn_mod_word16(const struct LITE_BIGNUM *p, uint16_t word)
+{
+ int i;
+ uint32_t rem = 0;
+
+ for (i = p->dmax - 1; i >= 0; i--) {
+ rem = ((rem << 16) |
+ ((BN_DIGIT(p, i) >> 16) & 0xFFFFUL)) % word;
+ rem = ((rem << 16) | (BN_DIGIT(p, i) & 0xFFFFUL)) % word;
+ }
+
+ return rem;
+}
+
+static uint32_t bn_mod_f4(const struct LITE_BIGNUM *d)
+{
+ int i = bn_size(d) - 1;
+ const uint8_t *p = (const uint8_t *) (d->d);
+ uint32_t rem = 0;
+
+ for (; i >= 0; --i) {
+ uint32_t q = RSA_F4 * (rem >> 8);
+
+ if (rem < q)
+ q -= RSA_F4;
+ rem <<= 8;
+ rem |= p[i];
+ rem -= q;
+ }
+
+ if (rem >= RSA_F4)
+ rem -= RSA_F4;
+
+ return rem;
+}
+
+#define bn_is_even(b) !bn_is_bit_set((b), 0)
+/* From HAC Fact 4.48 (ii), the following number of
+ * rounds suffice for ~2^145 confidence. Each additional
+ * round provides about another k/100 bits of confidence. */
+#define ROUNDS_1024 7
+#define ROUNDS_512 15
+#define ROUNDS_384 22
+
+/* Miller-Rabin from HAC, algorithm 4.24. */
+static int bn_probable_prime(const struct LITE_BIGNUM *p)
+{
+ int j;
+ int s = 0;
+
+ uint32_t ONE_buf = 1;
+ uint8_t r_buf[RSA_MAX_BYTES / 2];
+ uint8_t A_buf[RSA_MAX_BYTES / 2];
+ uint8_t y_buf[RSA_MAX_BYTES / 2];
+
+ struct LITE_BIGNUM ONE;
+ struct LITE_BIGNUM r;
+ struct LITE_BIGNUM A;
+ struct LITE_BIGNUM y;
+
+ const int rounds = bn_bits(p) >= 1024 ? ROUNDS_1024 :
+ bn_bits(p) >= 512 ? ROUNDS_512 :
+ ROUNDS_384;
+
+ /* Failsafe: update rounds table above to support smaller primes. */
+ if (bn_bits(p) < 384)
+ return 0;
+
+ if (bn_size(p) > sizeof(r_buf))
+ return 0;
+
+ DCRYPTO_bn_wrap(&ONE, &ONE_buf, sizeof(ONE_buf));
+ DCRYPTO_bn_wrap(&r, r_buf, bn_size(p));
+ bn_copy(&r, p);
+
+ /* r * (2 ^ s) = p - 1 */
+ bn_sub(&r, &ONE);
+ while (bn_is_even(&r)) {
+ bn_rshift(&r, 0, 0);
+ s++;
+ }
+
+ DCRYPTO_bn_wrap(&A, A_buf, bn_size(p));
+ DCRYPTO_bn_wrap(&y, y_buf, bn_size(p));
+ for (j = 0; j < rounds; j++) {
+ int i;
+
+ /* pick random A, such that A < p */
+ rand_bytes(A_buf, bn_size(&A));
+ for (i = A.dmax - 1; i >= 0; i--) {
+ while (BN_DIGIT(&A, i) > BN_DIGIT(p, i))
+ BN_DIGIT(&A, i) = rand();
+ if (BN_DIGIT(&A, i) < BN_DIGIT(p, i))
+ break;
+ }
+
+ /* y = a ^ r mod p */
+ bn_modexp(&y, &A, &r, p);
+ if (bn_eq(&y, &ONE))
+ continue;
+ bn_add(&y, &ONE);
+ if (bn_eq(&y, p))
+ continue;
+ bn_sub(&y, &ONE);
+
+ /* y = y ^ 2 mod p */
+ for (i = 0; i < s - 1; i++) {
+ bn_copy(&A, &y);
+ bn_modexp_word(&y, &A, 2, p);
+
+ if (bn_eq(&y, &ONE))
+ return 0;
+
+ bn_add(&y, &ONE);
+ if (bn_eq(&y, p)) {
+ bn_sub(&y, &ONE);
+ break;
+ }
+ bn_sub(&y, &ONE);
+ }
+ bn_add(&y, &ONE);
+ if (!bn_eq(&y, p))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* #define PRINT_PRIMES to enable printing predefined prime numbers' set. */
+static void print_primes(uint16_t prime)
+{
+#ifdef PRINT_PRIMES
+ static uint16_t num_per_line;
+ static uint16_t max_printed;
+
+ if (prime <= max_printed)
+ return;
+
+ if (!(num_per_line++ % 8)) {
+ if (num_per_line == 1)
+ ccprintf("Prime numbers:");
+ ccprintf("\n");
+ cflush();
+ }
+ max_printed = prime;
+ ccprintf(" %6d", prime);
+#endif
+}
+
+int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p)
+{
+ int i;
+ int j;
+ /* Using a sieve size of 2048-bits results in a failure rate
+ * of ~0.5% @ 1024-bit candidates. The failure rate rises to ~6%
+ * if the sieve size is halved. */
+ uint8_t composites_buf[256];
+ struct LITE_BIGNUM composites;
+ uint16_t prime = PRIME1;
+
+ /* Set top two bits, as well as LSB. */
+ bn_set_bit(p, 0);
+ bn_set_bit(p, bn_bits(p) - 1);
+ bn_set_bit(p, bn_bits(p) - 2);
+
+ /* Save on trial division by marking known composites. */
+ bn_init(&composites, composites_buf, sizeof(composites_buf));
+ for (i = 0; i < ARRAY_SIZE(PRIME_DELTAS); i++) {
+ uint16_t rem;
+ uint8_t unpacked_deltas[2];
+ uint8_t packed_deltas = PRIME_DELTAS[i];
+ int k;
+ int m;
+
+ if (packed_deltas) {
+ unpacked_deltas[0] = (packed_deltas >> 4) << 1;
+ unpacked_deltas[1] = (packed_deltas & 0xf) << 1;
+ m = 2;
+ } else {
+ i += 1;
+ unpacked_deltas[0] = PRIME_DELTAS[i];
+ m = 1;
+ }
+
+ for (k = 0; k < m; k++) {
+ prime += unpacked_deltas[k];
+ print_primes(prime);
+ rem = bn_mod_word16(p, prime);
+ /* Skip marking odd offsets (i.e. even candidates). */
+ for (j = (rem == 0) ? 0 : prime - rem;
+ j < bn_bits(&composites) << 1;
+ j += prime) {
+ if ((j & 1) == 0)
+ bn_set_bit(&composites, j >> 1);
+ }
+ }
+ }
+
+ /* composites now marked, apply Miller-Rabin to prime candidates. */
+ j = 0;
+ for (i = 0; i < bn_bits(&composites); i++) {
+ uint32_t diff_buf;
+ struct LITE_BIGNUM diff;
+
+ if (bn_is_bit_set(&composites, i))
+ continue;
+
+ /* Recover increment from the composites sieve. */
+ diff_buf = (i << 1) - j;
+ j = (i << 1);
+ DCRYPTO_bn_wrap(&diff, &diff_buf, sizeof(diff_buf));
+ bn_add(p, &diff);
+ /* Make sure prime will work with F4 public exponent. */
+ if (bn_mod_f4(p) >= 2) {
+ if (bn_probable_prime(p))
+ return 1;
+ }
+ }
+
+ always_memset(composites_buf, 0, sizeof(composites_buf));
+ return 0;
+}
diff --git a/chip/g/dcrypto/compare.c b/chip/g/dcrypto/compare.c
new file mode 100644
index 0000000000..db6193752b
--- /dev/null
+++ b/chip/g/dcrypto/compare.c
@@ -0,0 +1,20 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+
+/* Constant time comparator. */
+int DCRYPTO_equals(const void *a, const void *b, size_t len)
+{
+ size_t i;
+ const uint8_t *pa = a;
+ const uint8_t *pb = b;
+ uint8_t diff = 0;
+
+ for (i = 0; i < len; i++)
+ diff |= pa[i] ^ pb[i];
+
+ return !diff;
+}
diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h
new file mode 100644
index 0000000000..8cf1071090
--- /dev/null
+++ b/chip/g/dcrypto/dcrypto.h
@@ -0,0 +1,445 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Crypto wrapper library for the g chip.
+ */
+#ifndef __EC_CHIP_G_DCRYPTO_DCRYPTO_H
+#define __EC_CHIP_G_DCRYPTO_DCRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(TEST_FUZZ) || !defined(TEST_BUILD)
+
+#include "internal.h"
+
+#include "crypto_api.h"
+
+#include <stddef.h>
+
+#include "cryptoc/hmac.h"
+
+enum cipher_mode {
+ CIPHER_MODE_ECB = 0, /* NIST SP 800-38A */
+ CIPHER_MODE_CTR = 1, /* NIST SP 800-38A */
+ CIPHER_MODE_CBC = 2, /* NIST SP 800-38A */
+ CIPHER_MODE_GCM = 3 /* NIST SP 800-38D */
+};
+
+enum encrypt_mode {
+ DECRYPT_MODE = 0,
+ ENCRYPT_MODE = 1
+};
+
+enum hashing_mode {
+ HASH_SHA1 = 0,
+ HASH_SHA256 = 1,
+ HASH_SHA384 = 2, /* Only supported for PKCS#1 signing */
+ HASH_SHA512 = 3, /* Only supported for PKCS#1 signing */
+ HASH_NULL = 4 /* Only supported for PKCS#1 signing */
+};
+
+/*
+ * AES implementation, based on a hardware AES block.
+ * FIPS Publication 197, The Advanced Encryption Standard (AES)
+ */
+#define AES256_BLOCK_CIPHER_KEY_SIZE 32
+
+int DCRYPTO_aes_init(const uint8_t *key, uint32_t key_len, const uint8_t *iv,
+ enum cipher_mode c_mode, enum encrypt_mode e_mode);
+int DCRYPTO_aes_block(const uint8_t *in, uint8_t *out);
+
+void DCRYPTO_aes_write_iv(const uint8_t *iv);
+void DCRYPTO_aes_read_iv(uint8_t *iv);
+
+/* AES-CTR-128/192/256
+ * NIST Special Publication 800-38A
+ */
+int DCRYPTO_aes_ctr(uint8_t *out, const uint8_t *key, uint32_t key_bits,
+ const uint8_t *iv, const uint8_t *in, size_t in_len);
+
+/* AES-GCM-128/192/256
+ * NIST Special Publication 800-38D, IV is provided externally
+ * Caller should use IV length according to section 8.2 of SP 800-38D
+ * And choose appropriate IV construction method, constrain number
+ * of invocations according to section 8.3 of SP 800-38D
+ */
+struct GCM_CTX {
+ union {
+ uint32_t d[4];
+ uint8_t c[16];
+ } block, Ej0;
+
+ uint64_t aad_len;
+ uint64_t count;
+ size_t remainder;
+};
+
+/* Initialize the GCM context structure. */
+void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits,
+ const uint8_t *key, const uint8_t *iv, size_t iv_len);
+/* Additional authentication data to include in the tag calculation. */
+void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len);
+/* Encrypt & decrypt return the number of bytes written to out
+ * (always an integral multiple of 16), or -1 on error. These functions
+ * may be called repeatedly with incremental data.
+ *
+ * NOTE: if in_len is not a integral multiple of 16, then out_len must
+ * be atleast in_len - (in_len % 16) + 16 bytes.
+ */
+int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len,
+ const uint8_t *in, size_t in_len);
+int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len,
+ const uint8_t *in, size_t in_len);
+/* Encrypt & decrypt a partial final block, if any. These functions
+ * return the number of bytes written to out (<= 15), or -1 on error.
+ */
+int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx,
+ uint8_t *out, size_t out_len);
+int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx,
+ uint8_t *out, size_t out_len);
+/* Compute the tag over AAD + encrypt or decrypt data, and return the
+ * number of bytes written to tag. Returns -1 on error.
+ */
+int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len);
+/* Cleanup secrets. */
+void DCRYPTO_gcm_finish(struct GCM_CTX *ctx);
+
+/* AES-CMAC-128
+ * NIST Special Publication 800-38B, RFC 4493
+ * K: 128-bit key, M: message, len: number of bytes in M
+ * Writes 128-bit tag to T; returns 0 if an error is encountered and 1
+ * otherwise.
+ */
+int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len,
+ uint32_t T[4]);
+/* key: 128-bit key, M: message, len: number of bytes in M,
+ * T: tag to be verified
+ * Returns 1 if the tag is correct and 0 otherwise.
+ */
+int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len,
+ const uint32_t T[4]);
+
+/*
+ * SHA implementation. This abstraction is backed by either a
+ * software or hardware implementation.
+ *
+ * There could be only a single hardware SHA context in progress. The init
+ * functions will try using the HW context, if available, unless 'sw_required'
+ * is TRUE, in which case there will be no attempt to use the hardware for
+ * this particular hashing session.
+ */
+void DCRYPTO_SHA1_init(SHA_CTX *ctx, uint32_t sw_required);
+/* SHA256/384/512 FIPS 180-4
+ */
+void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required);
+void DCRYPTO_SHA384_init(LITE_SHA384_CTX *ctx);
+void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx);
+const uint8_t *DCRYPTO_SHA1_hash(const void *data, uint32_t n,
+ uint8_t *digest);
+const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n,
+ uint8_t *digest);
+const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n,
+ uint8_t *digest);
+const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n,
+ uint8_t *digest);
+/*
+ * HMAC. FIPS 198-1
+ */
+void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key,
+ unsigned int len);
+/* DCRYPTO HMAC-SHA256 final */
+const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx);
+
+/*
+ * BIGNUM utility methods.
+ */
+void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len);
+
+/*
+ * RSA.
+ */
+
+/* Largest supported key size for signing / encryption: 2048-bits.
+ * Verification is a special case and supports 4096-bits (signing /
+ * decryption could also support 4k-RSA, but is disabled since support
+ * is not required, and enabling support would result in increased
+ * stack usage for all key sizes.)
+ */
+#define RSA_BYTES_2K 256
+#define RSA_BYTES_4K 512
+#define RSA_WORDS_2K (RSA_BYTES_2K / sizeof(uint32_t))
+#define RSA_WORDS_4K (RSA_BYTES_4K / sizeof(uint32_t))
+#ifndef RSA_MAX_BYTES
+#define RSA_MAX_BYTES RSA_BYTES_2K
+#endif
+#define RSA_MAX_WORDS (RSA_MAX_BYTES / sizeof(uint32_t))
+#define RSA_F4 65537
+
+struct RSA {
+ uint32_t e;
+ struct LITE_BIGNUM N;
+ struct LITE_BIGNUM d;
+};
+
+enum padding_mode {
+ PADDING_MODE_PKCS1 = 0,
+ PADDING_MODE_OAEP = 1,
+ PADDING_MODE_PSS = 2,
+ /* USE OF NULL PADDING IS NOT RECOMMENDED.
+ * SUPPORT EXISTS AS A REQUIREMENT FOR TPM2 OPERATION. */
+ PADDING_MODE_NULL = 3
+};
+
+/* RSA support, FIPS PUB 186-4 *
+ * Calculate r = m ^ e mod N
+ */
+int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
+ const uint8_t *in, uint32_t in_len,
+ enum padding_mode padding, enum hashing_mode hashing,
+ const char *label);
+
+/* Calculate r = m ^ d mod N
+ * return 0 if error
+ */
+int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
+ const uint8_t *in, const uint32_t in_len,
+ enum padding_mode padding, enum hashing_mode hashing,
+ const char *label);
+
+/* Calculate r = m ^ d mod N
+ * return 0 if error
+ */
+int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
+ const uint8_t *in, const uint32_t in_len,
+ enum padding_mode padding, enum hashing_mode hashing);
+
+/* Calculate r = m ^ e mod N
+ * return 0 if error
+ */
+int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest,
+ uint32_t digest_len, const uint8_t *sig,
+ const uint32_t sig_len, enum padding_mode padding,
+ enum hashing_mode hashing);
+
+/* Calculate n = p * q, d = e ^ -1 mod phi. */
+int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d,
+ struct LITE_BIGNUM *p, struct LITE_BIGNUM *q,
+ uint32_t e);
+
+/*
+ * EC.
+ */
+
+/* DCRYPTO_p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
+ * order of the group.
+ */
+int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y,
+ const p256_int *n);
+
+/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is <
+ * the order of the group.
+ */
+int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y,
+ const p256_int *n, const p256_int *in_x,
+ const p256_int *in_y);
+/*
+ * Key selection based on FIPS-186-4, section B.4.2 (Key Pair
+ * Generation by Testing Candidates).
+ * Produce uniform private key from seed.
+ * If x or y is NULL, the public key part is not computed.
+ * Returns !0 on success.
+ */
+int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
+ const uint8_t bytes[P256_NBYTES]);
+
+
+/* P256 based integration encryption (DH+AES128+SHA256).
+ * Not FIPS 140-2 compliant, not used other than for tests
+ * Authenticated data may be provided, where the first auth_data_len
+ * bytes of in will be authenticated but not encrypted. *
+ * Supports in-place encryption / decryption. *
+ * The output format is:
+ * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) ||
+ * HMAC_SHA256(AUTH_DATA || CIPHERTEXT)
+ */
+size_t DCRYPTO_ecies_encrypt(
+ void *out, size_t out_len, const void *in, size_t in_len,
+ size_t auth_data_len, const uint8_t *iv,
+ const p256_int *pub_x, const p256_int *pub_y,
+ const uint8_t *salt, size_t salt_len,
+ const uint8_t *info, size_t info_len);
+size_t DCRYPTO_ecies_decrypt(
+ void *out, size_t out_len, const void *in, size_t in_len,
+ size_t auth_data_len, const uint8_t *iv,
+ const p256_int *d,
+ const uint8_t *salt, size_t salt_len,
+ const uint8_t *info, size_t info_len);
+
+/*
+ * HKDF as per RFC 5869. Mentioned as conforming NIST SP 800-56C Rev.1
+ * [RFC 5869] specifies a version of the above extraction-then-expansion
+ * key-derivation procedure using HMAC for both the extraction and expansion
+ * steps.
+ */
+int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len,
+ const uint8_t *salt, size_t salt_len,
+ const uint8_t *IKM, size_t IKM_len,
+ const uint8_t *info, size_t info_len);
+
+/*
+ * BN.
+ */
+
+/* Apply Miller-Rabin test for prime candidate p.
+ * Returns 1 if test passed, 0 otherwise
+ */
+int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p);
+void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len);
+void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a,
+ const struct LITE_BIGNUM *b);
+int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient, struct LITE_BIGNUM *remainder,
+ const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *divisor);
+
+/*
+ * ASN.1 DER
+ */
+size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s);
+size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y);
+
+/*
+ * X509.
+ */
+/* DCRYPTO_x509_verify verifies that the provided X509 certificate was issued
+ * by the specified certifcate authority.
+ *
+ * cert is a pointer to a DER encoded X509 certificate, as specified
+ * in https://tools.ietf.org/html/rfc5280#section-4.1. In ASN.1
+ * notation, the certificate has the following structure:
+ *
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+ *
+ * TBSCertificate ::= SEQUENCE { }
+ * AlgorithmIdentifier ::= SEQUENCE { }
+ *
+ * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and
+ * HASH specified by signatureAlgorithm.
+ * Accepts only certs with OID: sha256WithRSAEncryption:
+ * 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00
+ */
+int DCRYPTO_x509_verify(const uint8_t *cert, size_t len,
+ const struct RSA *ca_pub_key);
+
+/* Generate U2F Certificate and sign it
+ * Use ECDSA with NIST P-256 curve, and SHA2-256 digest
+ * @param d: key handle, used for NIST SP 800-90A HMAC DRBG
+ * @param pk_x, pk_y: public key
+ * @param serial: serial number for certificate
+ * @param name: certificate issuer and subject
+ * @param cert: output buffer for certificate
+ * @param n: max size of cert
+ */
+int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x,
+ const p256_int *pk_y, const p256_int *serial,
+ const char *name, uint8_t *cert,
+ const int n);
+
+/* Generate U2F Certificate with DCRYPTO_x509_gen_u2f_cert_name
+ * Providing certificate issuer as BOARD or U2F
+ * @param d: key handle, used for NIST SP 800-90A HMAC DRBG
+ * @param pk_x, pk_y: public key
+ * @param serial: serial number for certificate
+ * @param name: certificate issuer and subject
+ * @param cert: output buffer for certificate
+ * @param n: max size of cert
+ */
+int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x,
+ const p256_int *pk_y, const p256_int *serial,
+ uint8_t *cert, const int n);
+
+/*
+ * Memory related functions.
+ */
+int DCRYPTO_equals(const void *a, const void *b, size_t len);
+
+/*
+ * Key-ladder and application key related functions.
+ */
+enum dcrypto_appid {
+ RESERVED = 0,
+ NVMEM = 1,
+ U2F_ATTEST = 2,
+ U2F_ORIGIN = 3,
+ U2F_WRAP = 4,
+ PERSO_AUTH = 5,
+ PINWEAVER = 6,
+ /* This enum value should not exceed 7. */
+};
+
+struct APPKEY_CTX {
+#ifdef TEST_FUZZ
+ uint8_t unused_for_cxx_compatibility;
+#endif
+};
+
+int DCRYPTO_ladder_compute_frk2(size_t major_fw_version, uint8_t *frk2);
+int DCRYPTO_ladder_random(void *output);
+void DCRYPTO_ladder_revoke(void);
+
+int DCRYPTO_appkey_init(enum dcrypto_appid id, struct APPKEY_CTX *ctx);
+void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx);
+int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8],
+ uint32_t output[8]);
+
+/* Number of bytes in the salt object. */
+#define DCRYPTO_CIPHER_SALT_SIZE 16
+BUILD_ASSERT(DCRYPTO_CIPHER_SALT_SIZE == CIPHER_SALT_SIZE);
+
+/*
+ * Encrypt/decrypt a flat blob.
+ *
+ * Encrypt or decrypt the input buffer, and write the correspondingly
+ * ciphered output to out. The number of bytes produced is equal to
+ * the number of input bytes. Note that the input and output pointers
+ * MUST be word-aligned.
+ *
+ * This API is expected to be applied to a single contiguous region.
+
+ * WARNING: A given salt/"in" pair MUST be unique, i.e. re-using a
+ * salt with a logically different input buffer is catastrophic. An
+ * example of a suitable salt is one that is derived from "in", e.g. a
+ * digest of the input data.
+ *
+ * @param appid the application-id of the calling context.
+ * @param salt pointer to a unique value to be associated with this blob,
+ * used for derivation of the proper IV, the size of the value
+ * is as defined by DCRYPTO_CIPHER_SALT_SIZE above.
+ * @param out Destination pointer where to write plaintext / ciphertext.
+ * @param in Source pointer where to read ciphertext / plaintext.
+ * @param len Number of bytes to read from in / write to out.
+ * @return non-zero on success, and zero otherwise.
+ */
+int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt,
+ void *out, const void *in, size_t len);
+
+#endif /* ^^^^^^^^^^^^^^^^^^^^^ !TEST_BUILD */
+/*
+ * Query whether Key Ladder is enabled.
+ *
+ * @return 1 if Key Ladder is enabled, and 0 otherwise.
+ */
+int DCRYPTO_ladder_is_enabled(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */
diff --git a/chip/g/dcrypto/dcrypto_bn.c b/chip/g/dcrypto/dcrypto_bn.c
new file mode 100644
index 0000000000..b8f8fef4f4
--- /dev/null
+++ b/chip/g/dcrypto/dcrypto_bn.c
@@ -0,0 +1,1496 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+#include "trng.h"
+
+/* Firmware blob for crypto accelerator */
+
+/* AUTO-GENERATED. DO NOT MODIFY. */
+/* clang-format off */
+static const uint32_t IMEM_dcrypto_bn[] = {
+/* @0x0: function tag[1] { */
+#define CF_tag_adr 0
+0xf8000001, /* sigini #1 */
+/* } */
+/* @0x1: function d0inv[14] { */
+#define CF_d0inv_adr 1
+0x4c000000, /* xor r0, r0, r0 */
+0x80000001, /* movi r0.0l, #1 */
+0x7c740000, /* mov r29, r0 */
+0x05100008, /* loop #256 ( */
+0x5807bc00, /* mul128 r1, r28l, r29l */
+0x588bbc00, /* mul128 r2, r28u, r29l */
+0x50044110, /* add r1, r1, r2 << 128 */
+0x590bbc00, /* mul128 r2, r28l, r29u */
+0x50044110, /* add r1, r1, r2 << 128 */
+0x40040100, /* and r1, r1, r0 */
+0x44743d00, /* or r29, r29, r1 */
+0x50000000, /* add r0, r0, r0 */
+/* ) */
+0x5477bf00, /* sub r29, r31, r29 */
+0x0c000000, /* ret */
+/* } */
+/* @0xf: function selcxSub[25] { */
+#define CF_selcxSub_adr 15
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x99100000, /* strnd r4 */
+0x5013e400, /* add r4, r4, r31 */
+0x1000101e, /* bl selcxSub_invsel */
+0x528c8402, /* addcx r3, r4, r4 << 16 */
+0x0600c007, /* loop *6 ( */
+0x8c081800, /* ld *2, *0++ */
+0x7c8c0000, /* ldr *3, *0 */
+0x7c800400, /* ldr *0, *4 */
+0x54906200, /* subb r4, r2, r3 */
+0x990c0000, /* strnd r3 */
+0x660c4401, /* sellx r3, r4, r2 */
+0x7ca00200, /* ldr *0++, *2 */
+/* ) */
+0x0c000000, /* ret */
+/*selcxSub_invsel: */
+0x528c8402, /* addcx r3, r4, r4 << 16 */
+0x0600c007, /* loop *6 ( */
+0x8c081800, /* ld *2, *0++ */
+0x7c8c0000, /* ldr *3, *0 */
+0x7c800400, /* ldr *0, *4 */
+0x54906200, /* subb r4, r2, r3 */
+0x990c0000, /* strnd r3 */
+0x660c8201, /* sellx r3, r2, r4 */
+0x7ca00200, /* ldr *0++, *2 */
+/* ) */
+0x0c000000, /* ret */
+/* } */
+/* @0x28: function computeRR[41] { */
+#define CF_computeRR_adr 40
+0x4c7fff00, /* xor r31, r31, r31 */
+0x84004000, /* ldi r0, [#0] */
+0x95800000, /* lddmp r0 */
+0x4c0c6300, /* xor r3, r3, r3 */
+0x800cffff, /* movi r3.0l, #65535 */
+0x40040398, /* and r1, r3, r0 >> 192 */
+0x480c6000, /* not r3, r3 */
+0x400c0300, /* and r3, r3, r0 */
+0x500c2301, /* add r3, r3, r1 << 8 */
+0x94800300, /* ldlc r3 */
+0x80040005, /* movi r1.0l, #5 */
+0x81040003, /* movi r1.2l, #3 */
+0x81840002, /* movi r1.3l, #2 */
+0x82040004, /* movi r1.4l, #4 */
+0x97800100, /* ldrfp r1 */
+0x4c0c6300, /* xor r3, r3, r3 */
+0x0600c001, /* loop *6 ( */
+0x7ca00200, /* ldr *0++, *2 */
+/* ) */
+0x560c1f00, /* subx r3, r31, r0 */
+0x0800000f, /* call &selcxSub */
+0x06000010, /* loop *0 ( */
+0x97800100, /* ldrfp r1 */
+0x560c6300, /* subx r3, r3, r3 */
+0x0600c003, /* loop *6 ( */
+0x7c8c0000, /* ldr *3, *0 */
+0x52884200, /* addcx r2, r2, r2 */
+0x7ca00300, /* ldr *0++, *3 */
+/* ) */
+0x0800000f, /* call &selcxSub */
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x560c6300, /* subx r3, r3, r3 */
+0x0600c003, /* loop *6 ( */
+0x8c081800, /* ld *2, *0++ */
+0x7c8c0800, /* ldr *3, *0++ */
+0x5e804300, /* cmpbx r3, r2 */
+/* ) */
+0x0800000f, /* call &selcxSub */
+0xfc000000, /* nop */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x0600c001, /* loop *6 ( */
+0x90680800, /* st *0++, *2++ */
+/* ) */
+0x0c000000, /* ret */
+/* } */
+/* @0x51: function dmXd0[9] { */
+#define CF_dmXd0_adr 81
+0x586f3e00, /* mul128 r27, r30l, r25l */
+0x59eb3e00, /* mul128 r26, r30u, r25u */
+0x58df3e00, /* mul128 r23, r30u, r25l */
+0x506efb10, /* add r27, r27, r23 << 128 */
+0x50eafa90, /* addc r26, r26, r23 >> 128 */
+0x595f3e00, /* mul128 r23, r30l, r25u */
+0x506efb10, /* add r27, r27, r23 << 128 */
+0x50eafa90, /* addc r26, r26, r23 >> 128 */
+0x0c000000, /* ret */
+/* } */
+/* @0x5a: function dmXa[9] { */
+#define CF_dmXa_adr 90
+0x586c5e00, /* mul128 r27, r30l, r2l */
+0x59e85e00, /* mul128 r26, r30u, r2u */
+0x58dc5e00, /* mul128 r23, r30u, r2l */
+0x506efb10, /* add r27, r27, r23 << 128 */
+0x50eafa90, /* addc r26, r26, r23 >> 128 */
+0x595c5e00, /* mul128 r23, r30l, r2u */
+0x506efb10, /* add r27, r27, r23 << 128 */
+0x50eafa90, /* addc r26, r26, r23 >> 128 */
+0x0c000000, /* ret */
+/* } */
+/* @0x63: function mma_sub_cx[23] { */
+#define CF_mma_sub_cx_adr 99
+0x99700000, /* strnd r28 */
+0x5073fc00, /* add r28, r28, r31 */
+0x10001070, /* bl mma_invsel */
+0x52f39c02, /* addcx r28, r28, r28 << 16 */
+0x0600c007, /* loop *6 ( */
+0x8c141800, /* ld *5, *0++ */
+0x7c900000, /* ldr *4, *0 */
+0x54f71e00, /* subb r29, r30, r24 */
+0x99600000, /* strnd r24 */
+0x7c800500, /* ldr *0, *5 */
+0x6663dd01, /* sellx r24, r29, r30 */
+0x7ca00500, /* ldr *0++, *5 */
+/* ) */
+0x0c000000, /* ret */
+/*mma_invsel: */
+0x52f39c02, /* addcx r28, r28, r28 << 16 */
+0x0600c007, /* loop *6 ( */
+0x8c141800, /* ld *5, *0++ */
+0x7c900000, /* ldr *4, *0 */
+0x54f71e00, /* subb r29, r30, r24 */
+0x99600000, /* strnd r24 */
+0x7c800500, /* ldr *0, *5 */
+0x6663be01, /* sellx r24, r30, r29 */
+0x7ca00500, /* ldr *0++, *5 */
+/* ) */
+0x0c000000, /* ret */
+/* } */
+/* @0x7a: function mma[39] { */
+#define CF_mma_adr 122
+0x8204001e, /* movi r1.4l, #30 */
+0x82840018, /* movi r1.5l, #24 */
+0x97800100, /* ldrfp r1 */
+0x8c101b00, /* ld *4, *3++ */
+0x0800005a, /* call &dmXa */
+0x7c940800, /* ldr *5, *0++ */
+0x507b1b00, /* add r30, r27, r24 */
+0x50f7fa00, /* addc r29, r26, r31 */
+0x7c640300, /* mov r25, r3 */
+0x08000051, /* call &dmXd0 */
+0x7c641b00, /* mov r25, r27 */
+0x7c701a00, /* mov r28, r26 */
+0x7c601e00, /* mov r24, r30 */
+0x8c101800, /* ld *4, *0++ */
+0x08000051, /* call &dmXd0 */
+0x506f1b00, /* add r27, r27, r24 */
+0x50f3fa00, /* addc r28, r26, r31 */
+0x0600e00e, /* loop *7 ( */
+0x8c101b00, /* ld *4, *3++ */
+0x0800005a, /* call &dmXa */
+0x7c940800, /* ldr *5, *0++ */
+0x506f1b00, /* add r27, r27, r24 */
+0x50ebfa00, /* addc r26, r26, r31 */
+0x5063bb00, /* add r24, r27, r29 */
+0x50f7fa00, /* addc r29, r26, r31 */
+0x8c101800, /* ld *4, *0++ */
+0x08000051, /* call &dmXd0 */
+0x506f1b00, /* add r27, r27, r24 */
+0x50ebfa00, /* addc r26, r26, r31 */
+0x52639b00, /* addx r24, r27, r28 */
+0x7ca80500, /* ldr *2++, *5 */
+0x52f3fa00, /* addcx r28, r26, r31 */
+/* ) */
+0x52e39d00, /* addcx r24, r29, r28 */
+0x7ca80500, /* ldr *2++, *5 */
+0x95800000, /* lddmp r0 */
+0x97800100, /* ldrfp r1 */
+0x08000063, /* call &mma_sub_cx */
+0xfc000000, /* nop */
+0x0c000000, /* ret */
+/* } */
+/* @0xa1: function setupPtrs[11] { */
+#define CF_setupPtrs_adr 161
+0x847c4000, /* ldi r31, [#0] */
+0x4c7fff00, /* xor r31, r31, r31 */
+0x95800000, /* lddmp r0 */
+0x94800000, /* ldlc r0 */
+0x7c041f00, /* mov r1, r31 */
+0x80040004, /* movi r1.0l, #4 */
+0x80840003, /* movi r1.1l, #3 */
+0x81040004, /* movi r1.2l, #4 */
+0x81840002, /* movi r1.3l, #2 */
+0x97800100, /* ldrfp r1 */
+0x0c000000, /* ret */
+/* } */
+/* @0xac: function mulx[19] { */
+#define CF_mulx_adr 172
+0x84004000, /* ldi r0, [#0] */
+0x080000a1, /* call &setupPtrs */
+0x8c041100, /* ld *1, *1 */
+0x7c081f00, /* mov r2, r31 */
+0x0600c001, /* loop *6 ( */
+0x7ca80300, /* ldr *2++, *3 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x0600c004, /* loop *6 ( */
+0x8c0c1c00, /* ld *3, *4++ */
+0x95000000, /* stdmp r0 */
+0x0800007a, /* call &mma */
+0x95800000, /* lddmp r0 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x0600c001, /* loop *6 ( */
+0x90740800, /* st *0++, *5++ */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x0c000000, /* ret */
+/* } */
+/* @0xbf: function mm1_sub_cx[22] { */
+#define CF_mm1_sub_cx_adr 191
+0x990c0000, /* strnd r3 */
+0x500fe300, /* add r3, r3, r31 */
+0x100010cc, /* bl mm1_invsel */
+0x528c6302, /* addcx r3, r3, r3 << 16 */
+0x0600c006, /* loop *6 ( */
+0x8c041800, /* ld *1, *0++ */
+0x7c8c0800, /* ldr *3, *0++ */
+0x548c6200, /* subb r3, r2, r3 */
+0x66084301, /* sellx r2, r3, r2 */
+0x90740300, /* st *3, *5++ */
+0xfc000000, /* nop */
+/* ) */
+0x0c000000, /* ret */
+0xfc000000, /* nop */
+/*mm1_invsel: */
+0x528c6302, /* addcx r3, r3, r3 << 16 */
+0x0600c006, /* loop *6 ( */
+0x8c041800, /* ld *1, *0++ */
+0x7c8c0800, /* ldr *3, *0++ */
+0x548c6200, /* subb r3, r2, r3 */
+0x66086201, /* sellx r2, r2, r3 */
+0x90740300, /* st *3, *5++ */
+0xfc000000, /* nop */
+/* ) */
+0x0c000000, /* ret */
+/* } */
+/* @0xd5: function mul1_exp[23] { */
+#define CF_mul1_exp_adr 213
+0x8c041100, /* ld *1, *1 */
+0x7c081f00, /* mov r2, r31 */
+0x0600c001, /* loop *6 ( */
+0x7ca80300, /* ldr *2++, *3 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x80080001, /* movi r2.0l, #1 */
+0x0600c003, /* loop *6 ( */
+0x95800000, /* lddmp r0 */
+0x0800007a, /* call &mma */
+0x7c081f00, /* mov r2, r31 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x56084200, /* subx r2, r2, r2 */
+0x0600c003, /* loop *6 ( */
+0x8c041800, /* ld *1, *0++ */
+0x7c8c0800, /* ldr *3, *0++ */
+0x5e804300, /* cmpbx r3, r2 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x080000bf, /* call &mm1_sub_cx */
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x0c000000, /* ret */
+/* } */
+/* @0xec: function mul1[4] { */
+#define CF_mul1_adr 236
+0x84004000, /* ldi r0, [#0] */
+0x080000a1, /* call &setupPtrs */
+0x080000d5, /* call &mul1_exp */
+0x0c000000, /* ret */
+/* } */
+/* @0xf0: function sqrx_exp[19] { */
+#define CF_sqrx_exp_adr 240
+0x84004020, /* ldi r0, [#1] */
+0x95800000, /* lddmp r0 */
+0x8c041100, /* ld *1, *1 */
+0x7c081f00, /* mov r2, r31 */
+0x0600c001, /* loop *6 ( */
+0x7ca80300, /* ldr *2++, *3 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x0600c004, /* loop *6 ( */
+0x8c0c1c00, /* ld *3, *4++ */
+0x95000000, /* stdmp r0 */
+0x0800007a, /* call &mma */
+0x95800000, /* lddmp r0 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x0600c001, /* loop *6 ( */
+0x90740800, /* st *0++, *5++ */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x95800000, /* lddmp r0 */
+0x0c000000, /* ret */
+/* } */
+/* @0x103: function mulx_exp[14] { */
+#define CF_mulx_exp_adr 259
+0x84004040, /* ldi r0, [#2] */
+0x95800000, /* lddmp r0 */
+0x8c041100, /* ld *1, *1 */
+0x7c081f00, /* mov r2, r31 */
+0x0600c001, /* loop *6 ( */
+0x7ca80300, /* ldr *2++, *3 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x0600c004, /* loop *6 ( */
+0x8c0c1c00, /* ld *3, *4++ */
+0x95000000, /* stdmp r0 */
+0x0800007a, /* call &mma */
+0x95800000, /* lddmp r0 */
+/* ) */
+0x97800100, /* ldrfp r1 */
+0x0c000000, /* ret */
+/* } */
+/* @0x111: function selOutOrC[30] { */
+#define CF_selOutOrC_adr 273
+0x990c0000, /* strnd r3 */
+0x440c6300, /* or r3, r3, r3 */
+0x10001122, /* bl selOutOrC_invsel */
+0x508c6302, /* addc r3, r3, r3 << 16 */
+0x0600c00a, /* loop *6 ( */
+0x990c0000, /* strnd r3 */
+0x99080000, /* strnd r2 */
+0x8c041500, /* ld *1, *5 */
+0x90540300, /* st *3, *5 */
+0x7c8c0800, /* ldr *3, *0++ */
+0x99000000, /* strnd r0 */
+0x7c000200, /* mov r0, r2 */
+0x99080000, /* strnd r2 */
+0x64086001, /* sell r2, r0, r3 */
+0x90740300, /* st *3, *5++ */
+/* ) */
+0x0c000000, /* ret */
+0xfc000000, /* nop */
+/*selOutOrC_invsel: */
+0x508c6302, /* addc r3, r3, r3 << 16 */
+0x0600c00a, /* loop *6 ( */
+0x990c0000, /* strnd r3 */
+0x99080000, /* strnd r2 */
+0x8c041500, /* ld *1, *5 */
+0x90540300, /* st *3, *5 */
+0x7c8c0800, /* ldr *3, *0++ */
+0x99000000, /* strnd r0 */
+0x7c000200, /* mov r0, r2 */
+0x99080000, /* strnd r2 */
+0x64080301, /* sell r2, r3, r0 */
+0x90740300, /* st *3, *5++ */
+/* ) */
+0x0c000000, /* ret */
+/* } */
+/* @0x12f: function modexp[35] { */
+#define CF_modexp_adr 303
+0x080000ac, /* call &mulx */
+0x84004060, /* ldi r0, [#3] */
+0x95800000, /* lddmp r0 */
+0x54084200, /* sub r2, r2, r2 */
+0x0600c004, /* loop *6 ( */
+0xfc000000, /* nop */
+0x8c0c1800, /* ld *3, *0++ */
+0x54885f00, /* subb r2, r31, r2 */
+0x90740300, /* st *3, *5++ */
+/* ) */
+0xfc000000, /* nop */
+0x7c081f00, /* mov r2, r31 */
+0x8008ffff, /* movi r2.0l, #65535 */
+0x400c0298, /* and r3, r2, r0 >> 192 */
+0x48084000, /* not r2, r2 */
+0x40080200, /* and r2, r2, r0 */
+0x50086201, /* add r2, r2, r3 << 8 */
+0x94800200, /* ldlc r2 */
+0x0600000d, /* loop *0 ( */
+0x080000f0, /* call &sqrx_exp */
+0x08000103, /* call &mulx_exp */
+0x84004060, /* ldi r0, [#3] */
+0x95800000, /* lddmp r0 */
+0x99080000, /* strnd r2 */
+0x50084200, /* add r2, r2, r2 */
+0x0600c004, /* loop *6 ( */
+0x99080000, /* strnd r2 */
+0x8c0c1400, /* ld *3, *4 */
+0x50884200, /* addc r2, r2, r2 */
+0x90700300, /* st *3, *4++ */
+/* ) */
+0x08000111, /* call &selOutOrC */
+0xfc000000, /* nop */
+/* ) */
+0x84004060, /* ldi r0, [#3] */
+0x95800000, /* lddmp r0 */
+0x080000d5, /* call &mul1_exp */
+0x0c000000, /* ret */
+/* } */
+/* @0x152: function modexp_blinded[76] { */
+#define CF_modexp_blinded_adr 338
+0x080000ac, /* call &mulx */
+0x84004060, /* ldi r0, [#3] */
+0x95800000, /* lddmp r0 */
+0x54084200, /* sub r2, r2, r2 */
+0x0600c004, /* loop *6 ( */
+0xfc000000, /* nop */
+0x8c0c1800, /* ld *3, *0++ */
+0x54885f00, /* subb r2, r31, r2 */
+0x90740300, /* st *3, *5++ */
+/* ) */
+0xfc000000, /* nop */
+0x8c0c1900, /* ld *3, *1++ */
+0x8c0c1100, /* ld *3, *1 */
+0x521c5f90, /* addx r7, r31, r2 >> 128 */
+0x590c4200, /* mul128 r3, r2l, r2u */
+0x7c181f00, /* mov r6, r31 */
+0x0600c011, /* loop *6 ( */
+0x99080000, /* strnd r2 */
+0x8c0c1400, /* ld *3, *4 */
+0x58106200, /* mul128 r4, r2l, r3l */
+0x59946200, /* mul128 r5, r2u, r3u */
+0x58806200, /* mul128 r0, r2u, r3l */
+0x50100410, /* add r4, r4, r0 << 128 */
+0x50940590, /* addc r5, r5, r0 >> 128 */
+0x59006200, /* mul128 r0, r2l, r3u */
+0x50100410, /* add r4, r4, r0 << 128 */
+0x50940590, /* addc r5, r5, r0 >> 128 */
+0x5010c400, /* add r4, r4, r6 */
+0x5097e500, /* addc r5, r5, r31 */
+0x50088200, /* add r2, r2, r4 */
+0x509be500, /* addc r6, r5, r31 */
+0x5688e200, /* subbx r2, r2, r7 */
+0x90700300, /* st *3, *4++ */
+0x541ce700, /* sub r7, r7, r7 */
+/* ) */
+0x7c080600, /* mov r2, r6 */
+0x5688e200, /* subbx r2, r2, r7 */
+0x90500300, /* st *3, *4 */
+0xfc000000, /* nop */
+0x84004060, /* ldi r0, [#3] */
+0x7c081f00, /* mov r2, r31 */
+0x8008ffff, /* movi r2.0l, #65535 */
+0x400c0298, /* and r3, r2, r0 >> 192 */
+0x48084000, /* not r2, r2 */
+0x40080200, /* and r2, r2, r0 */
+0x510c0301, /* addi r3, r3, #1 */
+0x50086201, /* add r2, r2, r3 << 8 */
+0x94800200, /* ldlc r2 */
+0x06000019, /* loop *0 ( */
+0x080000f0, /* call &sqrx_exp */
+0x08000103, /* call &mulx_exp */
+0x84004060, /* ldi r0, [#3] */
+0x95800000, /* lddmp r0 */
+0x99080000, /* strnd r2 */
+0x54084200, /* sub r2, r2, r2 */
+0x0600c004, /* loop *6 ( */
+0x99080000, /* strnd r2 */
+0x8c0c1400, /* ld *3, *4 */
+0x50884200, /* addc r2, r2, r2 */
+0x90700300, /* st *3, *4++ */
+/* ) */
+0x99080000, /* strnd r2 */
+0x8c0c1400, /* ld *3, *4 */
+0x50884200, /* addc r2, r2, r2 */
+0x90700300, /* st *3, *4++ */
+0x0600c008, /* loop *6 ( */
+0x99080000, /* strnd r2 */
+0x8c041500, /* ld *1, *5 */
+0x90540300, /* st *3, *5 */
+0x7c8c0800, /* ldr *3, *0++ */
+0x7c000200, /* mov r0, r2 */
+0x99080000, /* strnd r2 */
+0x64086008, /* selc r2, r0, r3 */
+0x90740300, /* st *3, *5++ */
+/* ) */
+0xfc000000, /* nop */
+/* ) */
+0x84004060, /* ldi r0, [#3] */
+0x95800000, /* lddmp r0 */
+0x080000d5, /* call &mul1_exp */
+0x0c000000, /* ret */
+/* } */
+/* @0x19e: function modload[12] { */
+#define CF_modload_adr 414
+0x4c7fff00, /* xor r31, r31, r31 */
+0x84004000, /* ldi r0, [#0] */
+0x95800000, /* lddmp r0 */
+0x94800000, /* ldlc r0 */
+0x8000001c, /* movi r0.0l, #28 */
+0x8080001d, /* movi r0.1l, #29 */
+0x97800000, /* ldrfp r0 */
+0x8c001000, /* ld *0, *0 */
+0x08000001, /* call &d0inv */
+0x90440100, /* st *1, *1 */
+0x08000028, /* call &computeRR */
+0x0c000000, /* ret */
+/* } */
+#ifdef CONFIG_DCRYPTO_RSA_SPEEDUP
+/* @0x1aa: function selA0orC4[16] { */
+#define CF_selA0orC4_adr 426
+0x99000000, /* strnd r0 */
+0x44000000, /* or r0, r0, r0 */
+0x100011b4, /* bl selA0orC4_invsel */
+0x50840002, /* addc r1, r0, r0 << 16 */
+0x6458da01, /* sell r22, r26, r6 */
+0x645cfb01, /* sell r23, r27, r7 */
+0x64611c01, /* sell r24, r28, r8 */
+0x64653d01, /* sell r25, r29, r9 */
+0x0c000000, /* ret */
+0xfc000000, /* nop */
+/*selA0orC4_invsel: */
+0x50840002, /* addc r1, r0, r0 << 16 */
+0x645b4601, /* sell r22, r6, r26 */
+0x645f6701, /* sell r23, r7, r27 */
+0x64638801, /* sell r24, r8, r28 */
+0x6467a901, /* sell r25, r9, r29 */
+0x0c000000, /* ret */
+/* } */
+/* @0x1ba: function mul4[169] { */
+#define CF_mul4_adr 442
+0x58594600, /* mul128 r22, r6l, r10l */
+0x59dd4600, /* mul128 r23, r6u, r10u */
+0x58894600, /* mul128 r2, r6u, r10l */
+0x50585610, /* add r22, r22, r2 << 128 */
+0x50dc5790, /* addc r23, r23, r2 >> 128 */
+0x59094600, /* mul128 r2, r6l, r10u */
+0x50585610, /* add r22, r22, r2 << 128 */
+0x50dc5790, /* addc r23, r23, r2 >> 128 */
+0x58616700, /* mul128 r24, r7l, r11l */
+0x59e56700, /* mul128 r25, r7u, r11u */
+0x58896700, /* mul128 r2, r7u, r11l */
+0x50605810, /* add r24, r24, r2 << 128 */
+0x50e45990, /* addc r25, r25, r2 >> 128 */
+0x59096700, /* mul128 r2, r7l, r11u */
+0x50605810, /* add r24, r24, r2 << 128 */
+0x50e45990, /* addc r25, r25, r2 >> 128 */
+0x58698800, /* mul128 r26, r8l, r12l */
+0x59ed8800, /* mul128 r27, r8u, r12u */
+0x58898800, /* mul128 r2, r8u, r12l */
+0x50685a10, /* add r26, r26, r2 << 128 */
+0x50ec5b90, /* addc r27, r27, r2 >> 128 */
+0x59098800, /* mul128 r2, r8l, r12u */
+0x50685a10, /* add r26, r26, r2 << 128 */
+0x50ec5b90, /* addc r27, r27, r2 >> 128 */
+0x5871a900, /* mul128 r28, r9l, r13l */
+0x59f5a900, /* mul128 r29, r9u, r13u */
+0x5889a900, /* mul128 r2, r9u, r13l */
+0x50705c10, /* add r28, r28, r2 << 128 */
+0x50f45d90, /* addc r29, r29, r2 >> 128 */
+0x5909a900, /* mul128 r2, r9l, r13u */
+0x50705c10, /* add r28, r28, r2 << 128 */
+0x50f45d90, /* addc r29, r29, r2 >> 128 */
+0x58016600, /* mul128 r0, r6l, r11l */
+0x59856600, /* mul128 r1, r6u, r11u */
+0x58896600, /* mul128 r2, r6u, r11l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59096600, /* mul128 r2, r6l, r11u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x505c1700, /* add r23, r23, r0 */
+0x50e03800, /* addc r24, r24, r1 */
+0x508fff00, /* addc r3, r31, r31 */
+0x58014700, /* mul128 r0, r7l, r10l */
+0x59854700, /* mul128 r1, r7u, r10u */
+0x58894700, /* mul128 r2, r7u, r10l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59094700, /* mul128 r2, r7l, r10u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x505c1700, /* add r23, r23, r0 */
+0x50e03800, /* addc r24, r24, r1 */
+0x50e47900, /* addc r25, r25, r3 */
+0x508fff00, /* addc r3, r31, r31 */
+0x58018600, /* mul128 r0, r6l, r12l */
+0x59858600, /* mul128 r1, r6u, r12u */
+0x58898600, /* mul128 r2, r6u, r12l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59098600, /* mul128 r2, r6l, r12u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50601800, /* add r24, r24, r0 */
+0x50e43900, /* addc r25, r25, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x58014800, /* mul128 r0, r8l, r10l */
+0x59854800, /* mul128 r1, r8u, r10u */
+0x58894800, /* mul128 r2, r8u, r10l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59094800, /* mul128 r2, r8l, r10u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50601800, /* add r24, r24, r0 */
+0x50e43900, /* addc r25, r25, r1 */
+0x50e87a00, /* addc r26, r26, r3 */
+0x508fff00, /* addc r3, r31, r31 */
+0x5801a600, /* mul128 r0, r6l, r13l */
+0x5985a600, /* mul128 r1, r6u, r13u */
+0x5889a600, /* mul128 r2, r6u, r13l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x5909a600, /* mul128 r2, r6l, r13u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x58018700, /* mul128 r0, r7l, r12l */
+0x59858700, /* mul128 r1, r7u, r12u */
+0x58898700, /* mul128 r2, r7u, r12l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59098700, /* mul128 r2, r7l, r12u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x58014900, /* mul128 r0, r9l, r10l */
+0x59854900, /* mul128 r1, r9u, r10u */
+0x58894900, /* mul128 r2, r9u, r10l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59094900, /* mul128 r2, r9l, r10u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x58016800, /* mul128 r0, r8l, r11l */
+0x59856800, /* mul128 r1, r8u, r11u */
+0x58896800, /* mul128 r2, r8u, r11l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59096800, /* mul128 r2, r8l, r11u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x50ec7b00, /* addc r27, r27, r3 */
+0x508fff00, /* addc r3, r31, r31 */
+0x5801a700, /* mul128 r0, r7l, r13l */
+0x5985a700, /* mul128 r1, r7u, r13u */
+0x5889a700, /* mul128 r2, r7u, r13l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x5909a700, /* mul128 r2, r7l, r13u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50681a00, /* add r26, r26, r0 */
+0x50ec3b00, /* addc r27, r27, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x58016900, /* mul128 r0, r9l, r11l */
+0x59856900, /* mul128 r1, r9u, r11u */
+0x58896900, /* mul128 r2, r9u, r11l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59096900, /* mul128 r2, r9l, r11u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50681a00, /* add r26, r26, r0 */
+0x50ec3b00, /* addc r27, r27, r1 */
+0x50f07c00, /* addc r28, r28, r3 */
+0x50f7fd00, /* addc r29, r29, r31 */
+0x5801a800, /* mul128 r0, r8l, r13l */
+0x5985a800, /* mul128 r1, r8u, r13u */
+0x5889a800, /* mul128 r2, r8u, r13l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x5909a800, /* mul128 r2, r8l, r13u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x506c1b00, /* add r27, r27, r0 */
+0x50f03c00, /* addc r28, r28, r1 */
+0x50f7fd00, /* addc r29, r29, r31 */
+0x58018900, /* mul128 r0, r9l, r12l */
+0x59858900, /* mul128 r1, r9u, r12u */
+0x58898900, /* mul128 r2, r9u, r12l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59098900, /* mul128 r2, r9l, r12u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x506c1b00, /* add r27, r27, r0 */
+0x50f03c00, /* addc r28, r28, r1 */
+0x50f7fd00, /* addc r29, r29, r31 */
+0x0c000000, /* ret */
+/* } */
+/* @0x263: function sqr4[117] { */
+#define CF_sqr4_adr 611
+0x5858c600, /* mul128 r22, r6l, r6l */
+0x59dcc600, /* mul128 r23, r6u, r6u */
+0x5888c600, /* mul128 r2, r6u, r6l */
+0x50585610, /* add r22, r22, r2 << 128 */
+0x50dc5790, /* addc r23, r23, r2 >> 128 */
+0x50585610, /* add r22, r22, r2 << 128 */
+0x50dc5790, /* addc r23, r23, r2 >> 128 */
+0x5860e700, /* mul128 r24, r7l, r7l */
+0x59e4e700, /* mul128 r25, r7u, r7u */
+0x5888e700, /* mul128 r2, r7u, r7l */
+0x50605810, /* add r24, r24, r2 << 128 */
+0x50e45990, /* addc r25, r25, r2 >> 128 */
+0x50605810, /* add r24, r24, r2 << 128 */
+0x50e45990, /* addc r25, r25, r2 >> 128 */
+0x58690800, /* mul128 r26, r8l, r8l */
+0x59ed0800, /* mul128 r27, r8u, r8u */
+0x58890800, /* mul128 r2, r8u, r8l */
+0x50685a10, /* add r26, r26, r2 << 128 */
+0x50ec5b90, /* addc r27, r27, r2 >> 128 */
+0x50685a10, /* add r26, r26, r2 << 128 */
+0x50ec5b90, /* addc r27, r27, r2 >> 128 */
+0x58712900, /* mul128 r28, r9l, r9l */
+0x59f52900, /* mul128 r29, r9u, r9u */
+0x58892900, /* mul128 r2, r9u, r9l */
+0x50705c10, /* add r28, r28, r2 << 128 */
+0x50f45d90, /* addc r29, r29, r2 >> 128 */
+0x50705c10, /* add r28, r28, r2 << 128 */
+0x50f45d90, /* addc r29, r29, r2 >> 128 */
+0x5800e600, /* mul128 r0, r6l, r7l */
+0x5984e600, /* mul128 r1, r6u, r7u */
+0x5888e600, /* mul128 r2, r6u, r7l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x5908e600, /* mul128 r2, r6l, r7u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x505c1700, /* add r23, r23, r0 */
+0x50e03800, /* addc r24, r24, r1 */
+0x508fff00, /* addc r3, r31, r31 */
+0x505c1700, /* add r23, r23, r0 */
+0x50e03800, /* addc r24, r24, r1 */
+0x50e47900, /* addc r25, r25, r3 */
+0x508fff00, /* addc r3, r31, r31 */
+0x58010600, /* mul128 r0, r6l, r8l */
+0x59850600, /* mul128 r1, r6u, r8u */
+0x58890600, /* mul128 r2, r6u, r8l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59090600, /* mul128 r2, r6l, r8u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50601800, /* add r24, r24, r0 */
+0x50e43900, /* addc r25, r25, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x50601800, /* add r24, r24, r0 */
+0x50e43900, /* addc r25, r25, r1 */
+0x50e87a00, /* addc r26, r26, r3 */
+0x508fff00, /* addc r3, r31, r31 */
+0x58012600, /* mul128 r0, r6l, r9l */
+0x59852600, /* mul128 r1, r6u, r9u */
+0x58892600, /* mul128 r2, r6u, r9l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59092600, /* mul128 r2, r6l, r9u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x58010700, /* mul128 r0, r7l, r8l */
+0x59850700, /* mul128 r1, r7u, r8u */
+0x58890700, /* mul128 r2, r7u, r8l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59090700, /* mul128 r2, r7l, r8u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x50ec7b00, /* addc r27, r27, r3 */
+0x508fff00, /* addc r3, r31, r31 */
+0x58012700, /* mul128 r0, r7l, r9l */
+0x59852700, /* mul128 r1, r7u, r9u */
+0x58892700, /* mul128 r2, r7u, r9l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59092700, /* mul128 r2, r7l, r9u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x50681a00, /* add r26, r26, r0 */
+0x50ec3b00, /* addc r27, r27, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x50681a00, /* add r26, r26, r0 */
+0x50ec3b00, /* addc r27, r27, r1 */
+0x50f07c00, /* addc r28, r28, r3 */
+0x50f7fd00, /* addc r29, r29, r31 */
+0x58012800, /* mul128 r0, r8l, r9l */
+0x59852800, /* mul128 r1, r8u, r9u */
+0x58892800, /* mul128 r2, r8u, r9l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x59092800, /* mul128 r2, r8l, r9u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x506c1b00, /* add r27, r27, r0 */
+0x50f03c00, /* addc r28, r28, r1 */
+0x50f7fd00, /* addc r29, r29, r31 */
+0x506c1b00, /* add r27, r27, r0 */
+0x50f03c00, /* addc r28, r28, r1 */
+0x50f7fd00, /* addc r29, r29, r31 */
+0x0c000000, /* ret */
+/* } */
+/* @0x2d8: function dod0[15] { */
+#define CF_dod0_adr 728
+0x8c0c1100, /* ld *3, *1 */
+0x58140100, /* mul128 r5, r1l, r0l */
+0x58880100, /* mul128 r2, r1u, r0l */
+0x50144510, /* add r5, r5, r2 << 128 */
+0x59080100, /* mul128 r2, r1l, r0u */
+0x50144510, /* add r5, r5, r2 << 128 */
+0x5801c500, /* mul128 r0, r5l, r14l */
+0x5985c500, /* mul128 r1, r5u, r14u */
+0x5889c500, /* mul128 r2, r5u, r14l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x5909c500, /* mul128 r2, r5l, r14u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x0c000000, /* ret */
+/* } */
+/* @0x2e7: function dod1[9] { */
+#define CF_dod1_adr 743
+0x5801e500, /* mul128 r0, r5l, r15l */
+0x5985e500, /* mul128 r1, r5u, r15u */
+0x5889e500, /* mul128 r2, r5u, r15l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x5909e500, /* mul128 r2, r5l, r15u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x0c000000, /* ret */
+/* } */
+/* @0x2f0: function dod2[9] { */
+#define CF_dod2_adr 752
+0x58020500, /* mul128 r0, r5l, r16l */
+0x59860500, /* mul128 r1, r5u, r16u */
+0x588a0500, /* mul128 r2, r5u, r16l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x590a0500, /* mul128 r2, r5l, r16u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x0c000000, /* ret */
+/* } */
+/* @0x2f9: function dod3[9] { */
+#define CF_dod3_adr 761
+0x58022500, /* mul128 r0, r5l, r17l */
+0x59862500, /* mul128 r1, r5u, r17u */
+0x588a2500, /* mul128 r2, r5u, r17l */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x590a2500, /* mul128 r2, r5l, r17u */
+0x50004010, /* add r0, r0, r2 << 128 */
+0x50844190, /* addc r1, r1, r2 >> 128 */
+0x0c000000, /* ret */
+/* } */
+/* @0x302: function redc4[97] { */
+#define CF_redc4_adr 770
+0x7c001600, /* mov r0, r22 */
+0x080002d8, /* call &dod0 */
+0x50581600, /* add r22, r22, r0 */
+0x50dc3700, /* addc r23, r23, r1 */
+0x50e3f800, /* addc r24, r24, r31 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002e7, /* call &dod1 */
+0x505c1700, /* add r23, r23, r0 */
+0x50e03800, /* addc r24, r24, r1 */
+0x50e49900, /* addc r25, r25, r4 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002f0, /* call &dod2 */
+0x50601800, /* add r24, r24, r0 */
+0x50e43900, /* addc r25, r25, r1 */
+0x50e89a00, /* addc r26, r26, r4 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002f9, /* call &dod3 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x50ec9b00, /* addc r27, r27, r4 */
+0x508fff00, /* addc r3, r31, r31 */
+0x7c001700, /* mov r0, r23 */
+0x080002d8, /* call &dod0 */
+0x505c1700, /* add r23, r23, r0 */
+0x50e03800, /* addc r24, r24, r1 */
+0x50e7f900, /* addc r25, r25, r31 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002e7, /* call &dod1 */
+0x50601800, /* add r24, r24, r0 */
+0x50e43900, /* addc r25, r25, r1 */
+0x50e89a00, /* addc r26, r26, r4 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002f0, /* call &dod2 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x50ec9b00, /* addc r27, r27, r4 */
+0x508fff00, /* addc r3, r31, r31 */
+0x080002f9, /* call &dod3 */
+0x50681a00, /* add r26, r26, r0 */
+0x50ec3b00, /* addc r27, r27, r1 */
+0x50f07c00, /* addc r28, r28, r3 */
+0x508fff00, /* addc r3, r31, r31 */
+0x7c001800, /* mov r0, r24 */
+0x080002d8, /* call &dod0 */
+0x50601800, /* add r24, r24, r0 */
+0x50e43900, /* addc r25, r25, r1 */
+0x50ebfa00, /* addc r26, r26, r31 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002e7, /* call &dod1 */
+0x50641900, /* add r25, r25, r0 */
+0x50e83a00, /* addc r26, r26, r1 */
+0x50ec9b00, /* addc r27, r27, r4 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002f0, /* call &dod2 */
+0x50681a00, /* add r26, r26, r0 */
+0x50ec3b00, /* addc r27, r27, r1 */
+0x50f09c00, /* addc r28, r28, r4 */
+0x5093e300, /* addc r4, r3, r31 */
+0x080002f9, /* call &dod3 */
+0x506c1b00, /* add r27, r27, r0 */
+0x50f03c00, /* addc r28, r28, r1 */
+0x50f49d00, /* addc r29, r29, r4 */
+0x508fff00, /* addc r3, r31, r31 */
+0x7c001900, /* mov r0, r25 */
+0x080002d8, /* call &dod0 */
+0x50641900, /* add r25, r25, r0 */
+0x50d83a00, /* addc r22, r26, r1 */
+0x50dffb00, /* addc r23, r27, r31 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002e7, /* call &dod1 */
+0x50581600, /* add r22, r22, r0 */
+0x50dc3700, /* addc r23, r23, r1 */
+0x50e09c00, /* addc r24, r28, r4 */
+0x5093ff00, /* addc r4, r31, r31 */
+0x080002f0, /* call &dod2 */
+0x505c1700, /* add r23, r23, r0 */
+0x50e03800, /* addc r24, r24, r1 */
+0x50e49d00, /* addc r25, r29, r4 */
+0x508fe300, /* addc r3, r3, r31 */
+0x080002f9, /* call &dod3 */
+0x50601800, /* add r24, r24, r0 */
+0x50e43900, /* addc r25, r25, r1 */
+0x508fe300, /* addc r3, r3, r31 */
+0x56007f00, /* subx r0, r31, r3 */
+0x99680000, /* strnd r26 */
+0x996c0000, /* strnd r27 */
+0x99700000, /* strnd r28 */
+0x99740000, /* strnd r29 */
+0x5409d600, /* sub r2, r22, r14 */
+0x54e9f700, /* subb r26, r23, r15 */
+0x54ee1800, /* subb r27, r24, r16 */
+0x54f23900, /* subb r28, r25, r17 */
+0x66773c08, /* selcx r29, r28, r25 */
+0x66731b08, /* selcx r28, r27, r24 */
+0x666efa08, /* selcx r27, r26, r23 */
+0x666ac208, /* selcx r26, r2, r22 */
+0x0c000000, /* ret */
+/* } */
+/* @0x363: function modexp_1024[101] { */
+#define CF_modexp_1024_adr 867
+0x7c081f00, /* mov r2, r31 */
+0x80080006, /* movi r2.0l, #6 */
+0x8088000a, /* movi r2.1l, #10 */
+0x81880001, /* movi r2.3l, #1 */
+0x8208000e, /* movi r2.4l, #14 */
+0x82880016, /* movi r2.5l, #22 */
+0x83080012, /* movi r2.6l, #18 */
+0x97800200, /* ldrfp r2 */
+0x7c001f00, /* mov r0, r31 */
+0x8180ffff, /* movi r0.3l, #65535 */
+0x84044000, /* ldi r1, [#0] */
+0x40040100, /* and r1, r1, r0 */
+0x48000000, /* not r0, r0 */
+0x84084060, /* ldi r2, [#3] */
+0x40080200, /* and r2, r2, r0 */
+0x44082200, /* or r2, r2, r1 */
+0x95800200, /* lddmp r2 */
+0x05004004, /* loop #4 ( */
+0x8c201b00, /* ld *0++, *3++ */
+0x8c241a00, /* ld *1++, *2++ */
+0x8c301800, /* ld *4++, *0++ */
+0x8c381c00, /* ld *6++, *4++ */
+/* ) */
+0x99780000, /* strnd r30 */
+0x507bde00, /* add r30, r30, r30 */
+0x080001ba, /* call &mul4 */
+0x08000302, /* call &redc4 */
+0x7c281a00, /* mov r10, r26 */
+0x7c2c1b00, /* mov r11, r27 */
+0x7c301c00, /* mov r12, r28 */
+0x7c341d00, /* mov r13, r29 */
+0x99180000, /* strnd r6 */
+0x991c0000, /* strnd r7 */
+0x99200000, /* strnd r8 */
+0x99240000, /* strnd r9 */
+0x05400033, /* loop #1024 ( */
+0x08000263, /* call &sqr4 */
+0x08000302, /* call &redc4 */
+0x99180000, /* strnd r6 */
+0x991c0000, /* strnd r7 */
+0x99200000, /* strnd r8 */
+0x99240000, /* strnd r9 */
+0x7c181a00, /* mov r6, r26 */
+0x7c1c1b00, /* mov r7, r27 */
+0x7c201c00, /* mov r8, r28 */
+0x7c241d00, /* mov r9, r29 */
+0x080001ba, /* call &mul4 */
+0x08000302, /* call &redc4 */
+0x99000000, /* strnd r0 */
+0x5002b500, /* add r0, r21, r21 */
+0x99000000, /* strnd r0 */
+0x50825200, /* addc r0, r18, r18 */
+0x99480000, /* strnd r18 */
+0x7c480000, /* mov r18, r0 */
+0x99000000, /* strnd r0 */
+0x50827300, /* addc r0, r19, r19 */
+0x994c0000, /* strnd r19 */
+0x7c4c0000, /* mov r19, r0 */
+0x99000000, /* strnd r0 */
+0x50829400, /* addc r0, r20, r20 */
+0x99500000, /* strnd r20 */
+0x7c500000, /* mov r20, r0 */
+0x99000000, /* strnd r0 */
+0x5082b500, /* addc r0, r21, r21 */
+0x99540000, /* strnd r21 */
+0x7c540000, /* mov r21, r0 */
+0x99580000, /* strnd r22 */
+0x995c0000, /* strnd r23 */
+0x99600000, /* strnd r24 */
+0x99640000, /* strnd r25 */
+0x080001aa, /* call &selA0orC4 */
+0x99180000, /* strnd r6 */
+0x991c0000, /* strnd r7 */
+0x99200000, /* strnd r8 */
+0x99240000, /* strnd r9 */
+0x99000000, /* strnd r0 */
+0x50000000, /* add r0, r0, r0 */
+0x4c001e00, /* xor r0, r30, r0 */
+0x99780000, /* strnd r30 */
+0x507bde00, /* add r30, r30, r30 */
+0x4c781e00, /* xor r30, r30, r0 */
+0x447a5e00, /* or r30, r30, r18 */
+0x4c03c000, /* xor r0, r0, r30 */
+0x641aca01, /* sell r6, r10, r22 */
+0x641eeb01, /* sell r7, r11, r23 */
+0x64230c01, /* sell r8, r12, r24 */
+0x64272d01, /* sell r9, r13, r25 */
+/* ) */
+0x7c281f00, /* mov r10, r31 */
+0x80280001, /* movi r10.0l, #1 */
+0x7c2c1f00, /* mov r11, r31 */
+0x7c301f00, /* mov r12, r31 */
+0x7c341f00, /* mov r13, r31 */
+0x080001ba, /* call &mul4 */
+0x08000302, /* call &redc4 */
+0x5419da00, /* sub r6, r26, r14 */
+0x549dfb00, /* subb r7, r27, r15 */
+0x54a21c00, /* subb r8, r28, r16 */
+0x54a63d00, /* subb r9, r29, r17 */
+0x080001aa, /* call &selA0orC4 */
+0x05004001, /* loop #4 ( */
+0x90740d00, /* st *5++, *5++ */
+/* ) */
+0x0c000000, /* ret */
+/* } */
+#endif // CONFIG_DCRYPTO_RSA_SPEEDUP
+};
+/* clang-format on */
+
+struct DMEM_ctx_ptrs {
+ uint32_t pMod;
+ uint32_t pDinv;
+ uint32_t pRR;
+ uint32_t pA;
+ uint32_t pB;
+ uint32_t pC;
+ uint32_t n;
+ uint32_t n1;
+};
+
+/*
+ * This struct is "calling convention" for passing parameters into the
+ * code block above for RSA operations. Parameters start at &DMEM[0].
+ */
+struct DMEM_ctx {
+ struct DMEM_ctx_ptrs in_ptrs;
+ struct DMEM_ctx_ptrs sqr_ptrs;
+ struct DMEM_ctx_ptrs mul_ptrs;
+ struct DMEM_ctx_ptrs out_ptrs;
+ uint32_t mod[RSA_WORDS_4K];
+ uint32_t dInv[8];
+ uint32_t pubexp;
+ uint32_t _pad1[3];
+ uint32_t rnd[2];
+ uint32_t _pad2[2];
+ uint32_t RR[RSA_WORDS_4K];
+ uint32_t in[RSA_WORDS_4K];
+ uint32_t exp[RSA_WORDS_4K + 8]; /* extra word for randomization */
+ uint32_t out[RSA_WORDS_4K];
+ uint32_t bin[RSA_WORDS_4K];
+ uint32_t bout[RSA_WORDS_4K];
+};
+
+#define DMEM_CELL_SIZE 32
+#define DMEM_INDEX(p, f) \
+ (((const uint8_t *)&(p)->f - (const uint8_t *)(p)) / DMEM_CELL_SIZE)
+
+/* Get non-0 64 bit random */
+static void rand64(uint32_t dst[2])
+{
+ do {
+ dst[0] = rand();
+ dst[1] = rand();
+ } while ((dst[0] | dst[1]) == 0);
+}
+
+/* Grab dcrypto lock and set things up for modulus and input */
+static int setup_and_lock(const struct LITE_BIGNUM *N,
+ const struct LITE_BIGNUM *input)
+{
+ struct DMEM_ctx *ctx =
+ (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+
+ /* Initialize hardware; load code page. */
+ dcrypto_init_and_lock();
+ dcrypto_imem_load(0, IMEM_dcrypto_bn, ARRAY_SIZE(IMEM_dcrypto_bn));
+
+ /* Setup DMEM pointers (as indices into DMEM which are 256-bit cells).
+ */
+ ctx->in_ptrs.pMod = DMEM_INDEX(ctx, mod);
+ ctx->in_ptrs.pDinv = DMEM_INDEX(ctx, dInv);
+ ctx->in_ptrs.pRR = DMEM_INDEX(ctx, RR);
+ ctx->in_ptrs.pA = DMEM_INDEX(ctx, in);
+ ctx->in_ptrs.pB = DMEM_INDEX(ctx, exp);
+ ctx->in_ptrs.pC = DMEM_INDEX(ctx, out);
+ ctx->in_ptrs.n = bn_bits(N) / (DMEM_CELL_SIZE * 8);
+ ctx->in_ptrs.n1 = ctx->in_ptrs.n - 1;
+
+ ctx->sqr_ptrs = ctx->in_ptrs;
+ ctx->mul_ptrs = ctx->in_ptrs;
+ ctx->out_ptrs = ctx->in_ptrs;
+
+ dcrypto_dmem_load(DMEM_INDEX(ctx, in), input->d, bn_words(input));
+ if (dcrypto_dmem_load(DMEM_INDEX(ctx, mod), N->d, bn_words(N)) == 0) {
+ /*
+ * No change detected; assume modulus precomputation is cached.
+ */
+ return 0;
+ }
+
+ /* Calculate RR and d0inv. */
+ return dcrypto_call(CF_modload_adr);
+}
+
+#define MONTMUL(ctx, a, b, c) \
+ montmul(ctx, DMEM_INDEX(ctx, a), DMEM_INDEX(ctx, b), DMEM_INDEX(ctx, c))
+
+static int montmul(struct DMEM_ctx *ctx, uint32_t pA, uint32_t pB,
+ uint32_t pOut)
+{
+
+ ctx->in_ptrs.pA = pA;
+ ctx->in_ptrs.pB = pB;
+ ctx->in_ptrs.pC = pOut;
+
+ return dcrypto_call(CF_mulx_adr);
+}
+
+#define MONTOUT(ctx, a, b) montout(ctx, DMEM_INDEX(ctx, a), DMEM_INDEX(ctx, b))
+
+static int montout(struct DMEM_ctx *ctx, uint32_t pA, uint32_t pOut)
+{
+
+ ctx->in_ptrs.pA = pA;
+ ctx->in_ptrs.pB = 0;
+ ctx->in_ptrs.pC = pOut;
+
+ return dcrypto_call(CF_mul1_adr);
+}
+
+#define MODEXP(ctx, in, exp, out) \
+ modexp(ctx, CF_modexp_adr, DMEM_INDEX(ctx, RR), DMEM_INDEX(ctx, in), \
+ DMEM_INDEX(ctx, exp), DMEM_INDEX(ctx, out))
+
+#define MODEXP1024(ctx, in, exp, out) \
+ modexp(ctx, CF_modexp_1024_adr, DMEM_INDEX(ctx, RR), \
+ DMEM_INDEX(ctx, in), DMEM_INDEX(ctx, exp), \
+ DMEM_INDEX(ctx, out))
+
+#define MODEXP_BLINDED(ctx, in, exp, out) \
+ modexp(ctx, CF_modexp_blinded_adr, DMEM_INDEX(ctx, RR), \
+ DMEM_INDEX(ctx, in), DMEM_INDEX(ctx, exp), \
+ DMEM_INDEX(ctx, out))
+
+static int modexp(struct DMEM_ctx *ctx, uint32_t adr, uint32_t rr, uint32_t pIn,
+ uint32_t pExp, uint32_t pOut)
+{
+ /* in = in * RR */
+ ctx->in_ptrs.pA = pIn;
+ ctx->in_ptrs.pB = rr;
+ ctx->in_ptrs.pC = pIn;
+
+ /* out = out * out */
+ ctx->sqr_ptrs.pA = pOut;
+ ctx->sqr_ptrs.pB = pOut;
+ ctx->sqr_ptrs.pC = pOut;
+
+ /* out = out * in */
+ ctx->mul_ptrs.pA = pIn;
+ ctx->mul_ptrs.pB = pOut;
+ ctx->mul_ptrs.pC = pOut;
+
+ /* out = out / R */
+ ctx->out_ptrs.pA = pOut;
+ ctx->out_ptrs.pB = pExp;
+ ctx->out_ptrs.pC = pOut;
+
+ return dcrypto_call(adr);
+}
+
+/* output = input ** exp % N. */
+int dcrypto_modexp_blinded(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp,
+ const struct LITE_BIGNUM *N, uint32_t pubexp)
+{
+ int i, result;
+ struct DMEM_ctx *ctx =
+ (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+
+ uint32_t r_buf[RSA_MAX_WORDS];
+ uint32_t rinv_buf[RSA_MAX_WORDS];
+
+ struct LITE_BIGNUM r;
+ struct LITE_BIGNUM rinv;
+
+ bn_init(&r, r_buf, bn_size(N));
+ bn_init(&rinv, rinv_buf, bn_size(N));
+
+ /*
+ * pick 64 bit r != 0
+ * We cannot tolerate risk of 0 since 0 breaks computation.
+ */
+ rand64(r_buf);
+
+ /*
+ * compute 1/r mod N
+ * Note this cannot fail since N is product of two large primes
+ * and r != 0, so we can ignore return value.
+ */
+ bn_modinv_vartime(&rinv, &r, N);
+
+ /*
+ * compute r^pubexp mod N
+ */
+ dcrypto_modexp_word(&r, &r, pubexp, N);
+
+ result = setup_and_lock(N, input);
+
+ /* Pick !0 64-bit random for exponent blinding */
+ rand64(ctx->rnd);
+ ctx->pubexp = pubexp;
+
+ ctx->_pad1[0] = ctx->_pad1[1] = ctx->_pad1[2] = 0;
+ ctx->_pad2[0] = ctx->_pad2[1] = 0;
+
+ dcrypto_dmem_load(DMEM_INDEX(ctx, bin), r.d, bn_words(&r));
+ dcrypto_dmem_load(DMEM_INDEX(ctx, bout), rinv.d, bn_words(&rinv));
+ dcrypto_dmem_load(DMEM_INDEX(ctx, exp), exp->d, bn_words(exp));
+
+ /* 0 pad the exponent to full size + 8 */
+ for (i = bn_words(exp); i < bn_words(N) + 8; ++i)
+ ctx->exp[i] = 0;
+
+ /* Blind input */
+ result |= MONTMUL(ctx, in, RR, in);
+ result |= MONTMUL(ctx, in, bin, in);
+
+ result |= MODEXP_BLINDED(ctx, in, exp, out);
+
+ /* remove blinding factor */
+ result |= MONTMUL(ctx, out, RR, out);
+ result |= MONTMUL(ctx, out, bout, out);
+ /* fully reduce out */
+ result |= MONTMUL(ctx, out, RR, out);
+ result |= MONTOUT(ctx, out, out);
+
+ memcpy(output->d, ctx->out, bn_size(output));
+
+ dcrypto_unlock();
+ return result == 0;
+}
+
+/* output = input ** exp % N. */
+int dcrypto_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N)
+{
+ int i, result;
+ struct DMEM_ctx *ctx =
+ (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+
+ result = setup_and_lock(N, input);
+
+ dcrypto_dmem_load(DMEM_INDEX(ctx, exp), exp->d, bn_words(exp));
+
+ /* 0 pad the exponent to full size */
+ for (i = bn_words(exp); i < bn_words(N); ++i)
+ ctx->exp[i] = 0;
+
+#ifdef CONFIG_DCRYPTO_RSA_SPEEDUP
+ if (bn_bits(N) == 1024) { /* special code for 1024 bits */
+ result |= MODEXP1024(ctx, in, exp, out);
+ } else {
+ result |= MODEXP(ctx, in, exp, out);
+ }
+#else
+ result |= MODEXP(ctx, in, exp, out);
+#endif
+
+ memcpy(output->d, ctx->out, bn_size(output));
+
+ dcrypto_unlock();
+ return result == 0;
+}
+
+/* output = input ** exp % N. */
+int dcrypto_modexp_word(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input, uint32_t exp,
+ const struct LITE_BIGNUM *N)
+{
+ int result;
+ uint32_t e = exp;
+ uint32_t b = 0x80000000;
+ struct DMEM_ctx *ctx =
+ (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+
+ result = setup_and_lock(N, input);
+
+ /* Find top bit */
+ while (b != 0 && !(b & e))
+ b >>= 1;
+
+ /* out = in * RR */
+ result |= MONTMUL(ctx, in, RR, out);
+ /* in = in * RR */
+ result |= MONTMUL(ctx, in, RR, in);
+
+ while (b > 1) {
+ b >>= 1;
+
+ /* out = out * out */
+ result |= MONTMUL(ctx, out, out, out);
+
+ if ((b & e) != 0) {
+ /* out = out * in */
+ result |= MONTMUL(ctx, in, out, out);
+ }
+ }
+
+ /* out = out / R */
+ result |= MONTOUT(ctx, out, out);
+
+ memcpy(output->d, ctx->out, bn_size(output));
+
+ dcrypto_unlock();
+ return result == 0;
+}
+
+#ifdef CRYPTO_TEST_SETUP
+#include "console.h"
+#include "shared_mem.h"
+#include "timer.h"
+
+static uint8_t genp_seed[32];
+static uint32_t prime_buf[32];
+static timestamp_t genp_start;
+static timestamp_t genp_end;
+
+static int genp_core(void)
+{
+ struct LITE_BIGNUM prime;
+ int result;
+
+ // Spin seed out into prng candidate prime.
+ DCRYPTO_hkdf((uint8_t *)prime_buf, sizeof(prime_buf), genp_seed,
+ sizeof(genp_seed), 0, 0, 0, 0);
+ DCRYPTO_bn_wrap(&prime, &prime_buf, sizeof(prime_buf));
+
+ genp_start = get_time();
+ result = (DCRYPTO_bn_generate_prime(&prime) != 0) ? EC_SUCCESS
+ : EC_ERROR_UNKNOWN;
+ genp_end = get_time();
+
+ return result;
+}
+
+static int call_on_bigger_stack(int (*func)(void))
+{
+ int result, i;
+ char *new_stack;
+ const int new_stack_size = 4 * 1024;
+
+ result = shared_mem_acquire(new_stack_size, &new_stack);
+ if (result == EC_SUCCESS) {
+ // Paint stack arena
+ memset(new_stack, 0x01, new_stack_size);
+
+ // Call whilst switching stacks
+ __asm__ volatile("mov r4, sp\n" // save sp
+ "mov sp, %[new_stack]\n"
+ "blx %[func]\n"
+ "mov sp, r4\n" // restore sp
+ "mov %[result], r0\n"
+ : [result] "=r"(result)
+ : [new_stack] "r"(new_stack + new_stack_size),
+ [func] "r"(func)
+ : "r0", "r1", "r2", "r3", "r4",
+ "lr" // clobbers
+ );
+
+ // Take guess at amount of stack that got used
+ for (i = 0; i < new_stack_size && new_stack[i] == 0x01; ++i)
+ ;
+ ccprintf("stack: %u/%u\n", new_stack_size - i, new_stack_size);
+
+ shared_mem_release(new_stack);
+ }
+
+ return result;
+}
+
+static int command_genp(int argc, char **argv)
+{
+ int result;
+
+ memset(genp_seed, 0, sizeof(genp_seed));
+ if (argc > 1)
+ memcpy(genp_seed, argv[1], strlen(argv[1]));
+
+ result = call_on_bigger_stack(genp_core);
+
+ if (result == EC_SUCCESS) {
+ ccprintf("prime: %ph (lsb first)\n",
+ HEX_BUF(prime_buf, sizeof(prime_buf)));
+ ccprintf("μs : %llu\n",
+ (long long)(genp_end.val - genp_start.val));
+ }
+
+ return result;
+}
+DECLARE_CONSOLE_COMMAND(genp, command_genp, "[seed]", "Generate prng prime");
+#endif
diff --git a/chip/g/dcrypto/dcrypto_p256.c b/chip/g/dcrypto/dcrypto_p256.c
new file mode 100644
index 0000000000..4de8d22f9a
--- /dev/null
+++ b/chip/g/dcrypto/dcrypto_p256.c
@@ -0,0 +1,1018 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+#include "trng.h"
+
+/* Firmware blob for crypto accelerator */
+
+/* AUTO-GENERATED. DO NOT MODIFY. */
+/* clang-format off */
+static const uint32_t IMEM_dcrypto[] = {
+/* @0x0: function tag[1] { */
+#define CF_tag_adr 0
+ 0xf8000002, /* sigini #2 */
+/* } */
+/* @0x1: function SetupP256PandMuLow[21] { */
+#define CF_SetupP256PandMuLow_adr 1
+ 0x55741f01, /* subi r29, r31, #1 */
+ 0x83750000, /* movi r29.6h, #0 */
+ 0x83740001, /* movi r29.6l, #1 */
+ 0x82f50000, /* movi r29.5h, #0 */
+ 0x82f40000, /* movi r29.5l, #0 */
+ 0x82750000, /* movi r29.4h, #0 */
+ 0x82740000, /* movi r29.4l, #0 */
+ 0x81f50000, /* movi r29.3h, #0 */
+ 0x81f40000, /* movi r29.3l, #0 */
+ 0x98801d00, /* ldmod r29 */
+ 0x55701f01, /* subi r28, r31, #1 */
+ 0x83f10000, /* movi r28.7h, #0 */
+ 0x83f00000, /* movi r28.7l, #0 */
+ 0x82f0fffe, /* movi r28.5l, #65534 */
+ 0x8270fffe, /* movi r28.4l, #65534 */
+ 0x81f0fffe, /* movi r28.3l, #65534 */
+ 0x80f10000, /* movi r28.1h, #0 */
+ 0x80f00000, /* movi r28.1l, #0 */
+ 0x80710000, /* movi r28.0h, #0 */
+ 0x80700003, /* movi r28.0l, #3 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x16: function p256init[22] { */
+#define CF_p256init_adr 22
+ 0x847c4000, /* ldi r31, [#0] */
+ 0x4c7fff00, /* xor r31, r31, r31 */
+ 0x51781f01, /* addi r30, r31, #1 */
+ 0x08000001, /* call &SetupP256PandMuLow */
+ 0x7c6c1f00, /* mov r27, r31 */
+ 0x83ed5ac6, /* movi r27.7h, #23238 */
+ 0x83ec35d8, /* movi r27.7l, #13784 */
+ 0x836daa3a, /* movi r27.6h, #43578 */
+ 0x836c93e7, /* movi r27.6l, #37863 */
+ 0x82edb3eb, /* movi r27.5h, #46059 */
+ 0x82ecbd55, /* movi r27.5l, #48469 */
+ 0x826d7698, /* movi r27.4h, #30360 */
+ 0x826c86bc, /* movi r27.4l, #34492 */
+ 0x81ed651d, /* movi r27.3h, #25885 */
+ 0x81ec06b0, /* movi r27.3l, #1712 */
+ 0x816dcc53, /* movi r27.2h, #52307 */
+ 0x816cb0f6, /* movi r27.2l, #45302 */
+ 0x80ed3bce, /* movi r27.1h, #15310 */
+ 0x80ec3c3e, /* movi r27.1l, #15422 */
+ 0x806d27d2, /* movi r27.0h, #10194 */
+ 0x806c604b, /* movi r27.0l, #24651 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x2c: function MulMod[38] { */
+#define CF_MulMod_adr 44
+ 0x584f3800, /* mul128 r19, r24l, r25l */
+ 0x59d33800, /* mul128 r20, r24u, r25u */
+ 0x58d73800, /* mul128 r21, r24u, r25l */
+ 0x504eb310, /* add r19, r19, r21 << 128 */
+ 0x50d2b490, /* addc r20, r20, r21 >> 128 */
+ 0x59573800, /* mul128 r21, r24l, r25u */
+ 0x504eb310, /* add r19, r19, r21 << 128 */
+ 0x50d2b490, /* addc r20, r20, r21 >> 128 */
+ 0x645bfc02, /* selm r22, r28, r31 */
+ 0x685693ff, /* rshi r21, r19, r20 >> 255 */
+ 0x585f9500, /* mul128 r23, r21l, r28l */
+ 0x59e39500, /* mul128 r24, r21u, r28u */
+ 0x58e79500, /* mul128 r25, r21u, r28l */
+ 0x505f3710, /* add r23, r23, r25 << 128 */
+ 0x50e33890, /* addc r24, r24, r25 >> 128 */
+ 0x59679500, /* mul128 r25, r21l, r28u */
+ 0x505f3710, /* add r23, r23, r25 << 128 */
+ 0x50e33890, /* addc r24, r24, r25 >> 128 */
+ 0x6867f4ff, /* rshi r25, r20, r31 >> 255 */
+ 0x5062b800, /* add r24, r24, r21 */
+ 0x50e7f900, /* addc r25, r25, r31 */
+ 0x5062d800, /* add r24, r24, r22 */
+ 0x50e7f900, /* addc r25, r25, r31 */
+ 0x68573801, /* rshi r21, r24, r25 >> 1 */
+ 0x585abd00, /* mul128 r22, r29l, r21l */
+ 0x59debd00, /* mul128 r23, r29u, r21u */
+ 0x58e2bd00, /* mul128 r24, r29u, r21l */
+ 0x505b1610, /* add r22, r22, r24 << 128 */
+ 0x50df1790, /* addc r23, r23, r24 >> 128 */
+ 0x5962bd00, /* mul128 r24, r29l, r21u */
+ 0x505b1610, /* add r22, r22, r24 << 128 */
+ 0x50df1790, /* addc r23, r23, r24 >> 128 */
+ 0x545ad300, /* sub r22, r19, r22 */
+ 0x54d2f400, /* subb r20, r20, r23 */
+ 0x6457fd01, /* sell r21, r29, r31 */
+ 0x5456b600, /* sub r21, r22, r21 */
+ 0x9c4ff500, /* addm r19, r21, r31 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x52: function p256isoncurve[24] { */
+#define CF_p256isoncurve_adr 82
+ 0x84004000, /* ldi r0, [#0] */
+ 0x95800000, /* lddmp r0 */
+ 0x82800018, /* movi r0.5l, #24 */
+ 0x83000018, /* movi r0.6l, #24 */
+ 0x80000000, /* movi r0.0l, #0 */
+ 0x97800000, /* ldrfp r0 */
+ 0x8c181600, /* ld *6, *6 */
+ 0x7c641800, /* mov r25, r24 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c001300, /* mov r0, r19 */
+ 0x8c141500, /* ld *5, *5 */
+ 0x7c641800, /* mov r25, r24 */
+ 0x0800002c, /* call &MulMod */
+ 0x8c141500, /* ld *5, *5 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x8c141500, /* ld *5, *5 */
+ 0xa04f1300, /* subm r19, r19, r24 */
+ 0xa04f1300, /* subm r19, r19, r24 */
+ 0xa04f1300, /* subm r19, r19, r24 */
+ 0x9c637300, /* addm r24, r19, r27 */
+ 0x904c0500, /* st *5, *3 */
+ 0x90500000, /* st *0, *4 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x6a: function ProjAdd[80] { */
+#define CF_ProjAdd_adr 106
+ 0x7c600b00, /* mov r24, r11 */
+ 0x7c640800, /* mov r25, r8 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c381300, /* mov r14, r19 */
+ 0x7c600c00, /* mov r24, r12 */
+ 0x7c640900, /* mov r25, r9 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c3c1300, /* mov r15, r19 */
+ 0x7c600d00, /* mov r24, r13 */
+ 0x7c640a00, /* mov r25, r10 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c401300, /* mov r16, r19 */
+ 0x9c458b00, /* addm r17, r11, r12 */
+ 0x9c492800, /* addm r18, r8, r9 */
+ 0x7c601100, /* mov r24, r17 */
+ 0x7c641200, /* mov r25, r18 */
+ 0x0800002c, /* call &MulMod */
+ 0x9c49ee00, /* addm r18, r14, r15 */
+ 0xa0465300, /* subm r17, r19, r18 */
+ 0x9c49ac00, /* addm r18, r12, r13 */
+ 0x9c4d4900, /* addm r19, r9, r10 */
+ 0x7c601200, /* mov r24, r18 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c481300, /* mov r18, r19 */
+ 0x9c4e0f00, /* addm r19, r15, r16 */
+ 0xa04a7200, /* subm r18, r18, r19 */
+ 0x9c4dab00, /* addm r19, r11, r13 */
+ 0x9c314800, /* addm r12, r8, r10 */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c640c00, /* mov r25, r12 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c2c1300, /* mov r11, r19 */
+ 0x9c320e00, /* addm r12, r14, r16 */
+ 0xa0318b00, /* subm r12, r11, r12 */
+ 0x7c601b00, /* mov r24, r27 */
+ 0x7c641000, /* mov r25, r16 */
+ 0x0800002c, /* call &MulMod */
+ 0xa02e6c00, /* subm r11, r12, r19 */
+ 0x9c356b00, /* addm r13, r11, r11 */
+ 0x9c2dab00, /* addm r11, r11, r13 */
+ 0xa0356f00, /* subm r13, r15, r11 */
+ 0x9c2d6f00, /* addm r11, r15, r11 */
+ 0x7c601b00, /* mov r24, r27 */
+ 0x7c640c00, /* mov r25, r12 */
+ 0x0800002c, /* call &MulMod */
+ 0x9c3e1000, /* addm r15, r16, r16 */
+ 0x9c420f00, /* addm r16, r15, r16 */
+ 0xa0321300, /* subm r12, r19, r16 */
+ 0xa031cc00, /* subm r12, r12, r14 */
+ 0x9c3d8c00, /* addm r15, r12, r12 */
+ 0x9c318f00, /* addm r12, r15, r12 */
+ 0x9c3dce00, /* addm r15, r14, r14 */
+ 0x9c39cf00, /* addm r14, r15, r14 */
+ 0xa03a0e00, /* subm r14, r14, r16 */
+ 0x7c601200, /* mov r24, r18 */
+ 0x7c640c00, /* mov r25, r12 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c3c1300, /* mov r15, r19 */
+ 0x7c600e00, /* mov r24, r14 */
+ 0x7c640c00, /* mov r25, r12 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c401300, /* mov r16, r19 */
+ 0x7c600b00, /* mov r24, r11 */
+ 0x7c640d00, /* mov r25, r13 */
+ 0x0800002c, /* call &MulMod */
+ 0x9c321300, /* addm r12, r19, r16 */
+ 0x7c601100, /* mov r24, r17 */
+ 0x7c640b00, /* mov r25, r11 */
+ 0x0800002c, /* call &MulMod */
+ 0xa02df300, /* subm r11, r19, r15 */
+ 0x7c601200, /* mov r24, r18 */
+ 0x7c640d00, /* mov r25, r13 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c341300, /* mov r13, r19 */
+ 0x7c601100, /* mov r24, r17 */
+ 0x7c640e00, /* mov r25, r14 */
+ 0x0800002c, /* call &MulMod */
+ 0x9c366d00, /* addm r13, r13, r19 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0xba: function ProjToAffine[116] { */
+#define CF_ProjToAffine_adr 186
+ 0x9c2bea00, /* addm r10, r10, r31 */
+ 0x7c600a00, /* mov r24, r10 */
+ 0x7c640a00, /* mov r25, r10 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c640a00, /* mov r25, r10 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c301300, /* mov r12, r19 */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c640c00, /* mov r25, r12 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c341300, /* mov r13, r19 */
+ 0x05004004, /* loop #4 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c640d00, /* mov r25, r13 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c381300, /* mov r14, r19 */
+ 0x05008004, /* loop #8 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c640e00, /* mov r25, r14 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c3c1300, /* mov r15, r19 */
+ 0x05010004, /* loop #16 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c640f00, /* mov r25, r15 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c401300, /* mov r16, r19 */
+ 0x05020004, /* loop #32 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c441300, /* mov r17, r19 */
+ 0x7c600a00, /* mov r24, r10 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x050c0004, /* loop #192 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c481300, /* mov r18, r19 */
+ 0x7c601100, /* mov r24, r17 */
+ 0x7c641000, /* mov r25, r16 */
+ 0x0800002c, /* call &MulMod */
+ 0x05010004, /* loop #16 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c600f00, /* mov r24, r15 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x05008004, /* loop #8 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c600e00, /* mov r24, r14 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x05004004, /* loop #4 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c600d00, /* mov r24, r13 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x05002004, /* loop #2 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c600c00, /* mov r24, r12 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x05002004, /* loop #2 ( */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x7c600a00, /* mov r24, r10 */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c601300, /* mov r24, r19 */
+ 0x7c641200, /* mov r25, r18 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c381300, /* mov r14, r19 */
+ 0x7c600800, /* mov r24, r8 */
+ 0x7c640e00, /* mov r25, r14 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c2c1300, /* mov r11, r19 */
+ 0x7c600900, /* mov r24, r9 */
+ 0x7c640e00, /* mov r25, r14 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c301300, /* mov r12, r19 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x12e: function ModInv[17] { */
+#define CF_ModInv_adr 302
+ 0x98080000, /* stmod r2 */
+ 0x55080202, /* subi r2, r2, #2 */
+ 0x7c041e00, /* mov r1, r30 */
+ 0x0510000c, /* loop #256 ( */
+ 0x7c600100, /* mov r24, r1 */
+ 0x7c640100, /* mov r25, r1 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c0c1300, /* mov r3, r19 */
+ 0x50084200, /* add r2, r2, r2 */
+ 0x64046108, /* selc r1, r1, r3 */
+ 0x1008813d, /* bnc nomul */
+ 0x7c600300, /* mov r24, r3 */
+ 0x7c640000, /* mov r25, r0 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c041300, /* mov r1, r19 */
+ /*nomul: */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x13f: function FetchBandRandomize[11] { */
+#define CF_FetchBandRandomize_adr 319
+ 0x99080000, /* strnd r2 */
+ 0x9c6be200, /* addm r26, r2, r31 */
+ 0x8c081500, /* ld *2, *5 */
+ 0x7c641a00, /* mov r25, r26 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c181300, /* mov r6, r19 */
+ 0x8c081600, /* ld *2, *6 */
+ 0x7c641a00, /* mov r25, r26 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c1c1300, /* mov r7, r19 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x14a: function ProjDouble[5] { */
+#define CF_ProjDouble_adr 330
+ 0x7c2c0800, /* mov r11, r8 */
+ 0x7c300900, /* mov r12, r9 */
+ 0x7c340a00, /* mov r13, r10 */
+ 0x0800006a, /* call &ProjAdd */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x14f: function SetupP256NandMuLow[25] { */
+#define CF_SetupP256NandMuLow_adr 335
+ 0x55741f01, /* subi r29, r31, #1 */
+ 0x83750000, /* movi r29.6h, #0 */
+ 0x83740000, /* movi r29.6l, #0 */
+ 0x81f5bce6, /* movi r29.3h, #48358 */
+ 0x81f4faad, /* movi r29.3l, #64173 */
+ 0x8175a717, /* movi r29.2h, #42775 */
+ 0x81749e84, /* movi r29.2l, #40580 */
+ 0x80f5f3b9, /* movi r29.1h, #62393 */
+ 0x80f4cac2, /* movi r29.1l, #51906 */
+ 0x8075fc63, /* movi r29.0h, #64611 */
+ 0x80742551, /* movi r29.0l, #9553 */
+ 0x55701f01, /* subi r28, r31, #1 */
+ 0x83f10000, /* movi r28.7h, #0 */
+ 0x83f00000, /* movi r28.7l, #0 */
+ 0x82f0fffe, /* movi r28.5l, #65534 */
+ 0x81f14319, /* movi r28.3h, #17177 */
+ 0x81f00552, /* movi r28.3l, #1362 */
+ 0x8171df1a, /* movi r28.2h, #57114 */
+ 0x81706c21, /* movi r28.2l, #27681 */
+ 0x80f1012f, /* movi r28.1h, #303 */
+ 0x80f0fd85, /* movi r28.1l, #64901 */
+ 0x8071eedf, /* movi r28.0h, #61151 */
+ 0x80709bfe, /* movi r28.0l, #39934 */
+ 0x98801d00, /* ldmod r29 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x168: function ScalarMult_internal[51] { */
+#define CF_ScalarMult_internal_adr 360
+ 0x0800014f, /* call &SetupP256NandMuLow */
+ 0x8c041100, /* ld *1, *1 */
+ 0x9c07e100, /* addm r1, r1, r31 */
+ 0xa0002000, /* subm r0, r0, r1 */
+ 0x08000001, /* call &SetupP256PandMuLow */
+ 0x0800013f, /* call &FetchBandRandomize */
+ 0x7c200600, /* mov r8, r6 */
+ 0x7c240700, /* mov r9, r7 */
+ 0x7c281a00, /* mov r10, r26 */
+ 0x0800014a, /* call &ProjDouble */
+ 0x7c0c0b00, /* mov r3, r11 */
+ 0x7c100c00, /* mov r4, r12 */
+ 0x7c140d00, /* mov r5, r13 */
+ 0x7c201f00, /* mov r8, r31 */
+ 0x7c241e00, /* mov r9, r30 */
+ 0x7c281f00, /* mov r10, r31 */
+ 0x05100020, /* loop #256 ( */
+ 0x0800014a, /* call &ProjDouble */
+ 0x0800013f, /* call &FetchBandRandomize */
+ 0x4c202000, /* xor r8, r0, r1 */
+ 0x64206602, /* selm r8, r6, r3 */
+ 0x64248702, /* selm r9, r7, r4 */
+ 0x6428ba02, /* selm r10, r26, r5 */
+ 0x7c080b00, /* mov r2, r11 */
+ 0x7c180c00, /* mov r6, r12 */
+ 0x7c1c0d00, /* mov r7, r13 */
+ 0x0800006a, /* call &ProjAdd */
+ 0x44202000, /* or r8, r0, r1 */
+ 0x64204b02, /* selm r8, r11, r2 */
+ 0x6424cc02, /* selm r9, r12, r6 */
+ 0x6428ed02, /* selm r10, r13, r7 */
+ 0x680000ff, /* rshi r0, r0, r0 >> 255 */
+ 0x680421ff, /* rshi r1, r1, r1 >> 255 */
+ 0x992c0000, /* strnd r11 */
+ 0x99300000, /* strnd r12 */
+ 0x99340000, /* strnd r13 */
+ 0x99080000, /* strnd r2 */
+ 0x7c600300, /* mov r24, r3 */
+ 0x7c640200, /* mov r25, r2 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c0c1300, /* mov r3, r19 */
+ 0x7c600400, /* mov r24, r4 */
+ 0x7c640200, /* mov r25, r2 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c101300, /* mov r4, r19 */
+ 0x7c600500, /* mov r24, r5 */
+ 0x7c640200, /* mov r25, r2 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c141300, /* mov r5, r19 */
+ /* ) */
+ 0x080000ba, /* call &ProjToAffine */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x19b: function get_P256B[35] { */
+#define CF_get_P256B_adr 411
+ 0x7c201f00, /* mov r8, r31 */
+ 0x83a16b17, /* movi r8.7h, #27415 */
+ 0x83a0d1f2, /* movi r8.7l, #53746 */
+ 0x8321e12c, /* movi r8.6h, #57644 */
+ 0x83204247, /* movi r8.6l, #16967 */
+ 0x82a1f8bc, /* movi r8.5h, #63676 */
+ 0x82a0e6e5, /* movi r8.5l, #59109 */
+ 0x822163a4, /* movi r8.4h, #25508 */
+ 0x822040f2, /* movi r8.4l, #16626 */
+ 0x81a17703, /* movi r8.3h, #30467 */
+ 0x81a07d81, /* movi r8.3l, #32129 */
+ 0x81212deb, /* movi r8.2h, #11755 */
+ 0x812033a0, /* movi r8.2l, #13216 */
+ 0x80a1f4a1, /* movi r8.1h, #62625 */
+ 0x80a03945, /* movi r8.1l, #14661 */
+ 0x8021d898, /* movi r8.0h, #55448 */
+ 0x8020c296, /* movi r8.0l, #49814 */
+ 0x7c241f00, /* mov r9, r31 */
+ 0x83a54fe3, /* movi r9.7h, #20451 */
+ 0x83a442e2, /* movi r9.7l, #17122 */
+ 0x8325fe1a, /* movi r9.6h, #65050 */
+ 0x83247f9b, /* movi r9.6l, #32667 */
+ 0x82a58ee7, /* movi r9.5h, #36583 */
+ 0x82a4eb4a, /* movi r9.5l, #60234 */
+ 0x82257c0f, /* movi r9.4h, #31759 */
+ 0x82249e16, /* movi r9.4l, #40470 */
+ 0x81a52bce, /* movi r9.3h, #11214 */
+ 0x81a43357, /* movi r9.3l, #13143 */
+ 0x81256b31, /* movi r9.2h, #27441 */
+ 0x81245ece, /* movi r9.2l, #24270 */
+ 0x80a5cbb6, /* movi r9.1h, #52150 */
+ 0x80a44068, /* movi r9.1l, #16488 */
+ 0x802537bf, /* movi r9.0h, #14271 */
+ 0x802451f5, /* movi r9.0l, #20981 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x1be: function p256sign[34] { */
+#define CF_p256sign_adr 446
+ 0xfc000000, /* nop */
+ 0x84004000, /* ldi r0, [#0] */
+ 0x95800000, /* lddmp r0 */
+ 0x80000000, /* movi r0.0l, #0 */
+ 0x80800001, /* movi r0.1l, #1 */
+ 0x81000018, /* movi r0.2l, #24 */
+ 0x82000008, /* movi r0.4l, #8 */
+ 0x82800009, /* movi r0.5l, #9 */
+ 0x97800000, /* ldrfp r0 */
+ 0x0800019b, /* call &get_P256B */
+ 0x90540400, /* st *4, *5 */
+ 0x90580500, /* st *5, *6 */
+ 0xfc000000, /* nop */
+ 0x8c001000, /* ld *0, *0 */
+ 0x08000168, /* call &ScalarMult_internal */
+ 0x0800014f, /* call &SetupP256NandMuLow */
+ 0x8c001000, /* ld *0, *0 */
+ 0x0800012e, /* call &ModInv */
+ 0x8c081700, /* ld *2, *7 */
+ 0x7c640100, /* mov r25, r1 */
+ 0x0800002c, /* call &MulMod */
+ 0x9c63eb00, /* addm r24, r11, r31 */
+ 0x904c0200, /* st *2, *3 */
+ 0xfc000000, /* nop */
+ 0x7c641300, /* mov r25, r19 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c001300, /* mov r0, r19 */
+ 0x8c081200, /* ld *2, *2 */
+ 0x7c640100, /* mov r25, r1 */
+ 0x0800002c, /* call &MulMod */
+ 0x9c001300, /* addm r0, r19, r0 */
+ 0x90500000, /* st *0, *4 */
+ 0x08000001, /* call &SetupP256PandMuLow */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x1e0: function p256scalarbasemult[21] { */
+#define CF_p256scalarbasemult_adr 480
+ 0xfc000000, /* nop */
+ 0x84004000, /* ldi r0, [#0] */
+ 0x95800000, /* lddmp r0 */
+ 0x80000000, /* movi r0.0l, #0 */
+ 0x80800001, /* movi r0.1l, #1 */
+ 0x81000018, /* movi r0.2l, #24 */
+ 0x8180000b, /* movi r0.3l, #11 */
+ 0x82000008, /* movi r0.4l, #8 */
+ 0x82800009, /* movi r0.5l, #9 */
+ 0x97800000, /* ldrfp r0 */
+ 0x8c001100, /* ld *0, *1 */
+ 0x99800000, /* ldrnd r0 */
+ 0x0800019b, /* call &get_P256B */
+ 0x90540400, /* st *4, *5 */
+ 0x90580500, /* st *5, *6 */
+ 0xfc000000, /* nop */
+ 0x8c001700, /* ld *0, *7 */
+ 0x08000168, /* call &ScalarMult_internal */
+ 0x90540b00, /* st *3++, *5 */
+ 0x90580b00, /* st *3++, *6 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x1f5: function ModInvVar[37] { */
+#define CF_ModInvVar_adr 501
+ 0x7c081f00, /* mov r2, r31 */
+ 0x7c0c1e00, /* mov r3, r30 */
+ 0x98100000, /* stmod r4 */
+ 0x981c0000, /* stmod r7 */
+ 0x7c140000, /* mov r5, r0 */
+ /*impvt_Loop: */
+ 0x44108400, /* or r4, r4, r4 */
+ 0x10001205, /* bl impvt_Uodd */
+ 0x6813e401, /* rshi r4, r4, r31 >> 1 */
+ 0x44084200, /* or r2, r2, r2 */
+ 0x10001201, /* bl impvt_Rodd */
+ 0x680be201, /* rshi r2, r2, r31 >> 1 */
+ 0x100801fa, /* b impvt_Loop */
+ /*impvt_Rodd: */
+ 0x50084700, /* add r2, r7, r2 */
+ 0x509bff00, /* addc r6, r31, r31 */
+ 0x6808c201, /* rshi r2, r2, r6 >> 1 */
+ 0x100801fa, /* b impvt_Loop */
+ /*impvt_Uodd: */
+ 0x4414a500, /* or r5, r5, r5 */
+ 0x10001210, /* bl impvt_UVodd */
+ 0x6817e501, /* rshi r5, r5, r31 >> 1 */
+ 0x440c6300, /* or r3, r3, r3 */
+ 0x1000120c, /* bl impvt_Sodd */
+ 0x680fe301, /* rshi r3, r3, r31 >> 1 */
+ 0x100801fa, /* b impvt_Loop */
+ /*impvt_Sodd: */
+ 0x500c6700, /* add r3, r7, r3 */
+ 0x509bff00, /* addc r6, r31, r31 */
+ 0x680cc301, /* rshi r3, r3, r6 >> 1 */
+ 0x100801fa, /* b impvt_Loop */
+ /*impvt_UVodd: */
+ 0x5c008500, /* cmp r5, r4 */
+ 0x10088215, /* bnc impvt_V>=U */
+ 0xa0086200, /* subm r2, r2, r3 */
+ 0x5410a400, /* sub r4, r4, r5 */
+ 0x100801fa, /* b impvt_Loop */
+ /*impvt_V>=U: */
+ 0xa00c4300, /* subm r3, r3, r2 */
+ 0x54148500, /* sub r5, r5, r4 */
+ 0x100841fa, /* bnz impvt_Loop */
+ 0x9c07e200, /* addm r1, r2, r31 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x21a: function p256verify[80] { */
+#define CF_p256verify_adr 538
+ 0x84184000, /* ldi r6, [#0] */
+ 0x95800600, /* lddmp r6 */
+ 0x81980018, /* movi r6.3l, #24 */
+ 0x82180000, /* movi r6.4l, #0 */
+ 0x82980008, /* movi r6.5l, #8 */
+ 0x83180009, /* movi r6.6l, #9 */
+ 0x8018000b, /* movi r6.0l, #11 */
+ 0x8398000c, /* movi r6.7l, #12 */
+ 0x81180018, /* movi r6.2l, #24 */
+ 0x97800600, /* ldrfp r6 */
+ 0x8c0c1300, /* ld *3, *3 */
+ 0x7c600600, /* mov r24, r6 */
+ 0x48630000, /* not r24, r24 */
+ 0x0800014f, /* call &SetupP256NandMuLow */
+ 0x5c03e600, /* cmp r6, r31 */
+ 0x10004268, /* bz fail */
+ 0x5c03a600, /* cmp r6, r29 */
+ 0x10088268, /* bnc fail */
+ 0x8c101400, /* ld *4, *4 */
+ 0x5c03e000, /* cmp r0, r31 */
+ 0x10004268, /* bz fail */
+ 0x5c03a000, /* cmp r0, r29 */
+ 0x10088268, /* bnc fail */
+ 0x080001f5, /* call &ModInvVar */
+ 0x8c0c1300, /* ld *3, *3 */
+ 0x7c640100, /* mov r25, r1 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c001300, /* mov r0, r19 */
+ 0x8c081200, /* ld *2, *2 */
+ 0x7c640100, /* mov r25, r1 */
+ 0x0800002c, /* call &MulMod */
+ 0x7c041300, /* mov r1, r19 */
+ 0x08000001, /* call &SetupP256PandMuLow */
+ 0x8c001500, /* ld *0, *5 */
+ 0x8c1c1600, /* ld *7, *6 */
+ 0x7c341e00, /* mov r13, r30 */
+ 0x0800019b, /* call &get_P256B */
+ 0x7c281e00, /* mov r10, r30 */
+ 0x0800006a, /* call &ProjAdd */
+ 0x7c0c0b00, /* mov r3, r11 */
+ 0x7c100c00, /* mov r4, r12 */
+ 0x7c140d00, /* mov r5, r13 */
+ 0x40082000, /* and r2, r0, r1 */
+ 0x7c2c1f00, /* mov r11, r31 */
+ 0x7c301e00, /* mov r12, r30 */
+ 0x7c341f00, /* mov r13, r31 */
+ 0x05100018, /* loop #256 ( */
+ 0x7c200b00, /* mov r8, r11 */
+ 0x7c240c00, /* mov r9, r12 */
+ 0x7c280d00, /* mov r10, r13 */
+ 0x0800006a, /* call &ProjAdd */
+ 0x50084200, /* add r2, r2, r2 */
+ 0x10088254, /* bnc noBoth */
+ 0x7c200300, /* mov r8, r3 */
+ 0x7c240400, /* mov r9, r4 */
+ 0x7c280500, /* mov r10, r5 */
+ 0x0800006a, /* call &ProjAdd */
+ 0x1008025f, /* b noY */
+ /*noBoth: */
+ 0x50180000, /* add r6, r0, r0 */
+ 0x1008825a, /* bnc noG */
+ 0x8c141500, /* ld *5, *5 */
+ 0x8c181600, /* ld *6, *6 */
+ 0x7c281e00, /* mov r10, r30 */
+ 0x0800006a, /* call &ProjAdd */
+ /*noG: */
+ 0x50182100, /* add r6, r1, r1 */
+ 0x1008825f, /* bnc noY */
+ 0x0800019b, /* call &get_P256B */
+ 0x7c281e00, /* mov r10, r30 */
+ 0x0800006a, /* call &ProjAdd */
+ /*noY: */
+ 0x50000000, /* add r0, r0, r0 */
+ 0x50042100, /* add r1, r1, r1 */
+ /* ) */
+ 0x7c000d00, /* mov r0, r13 */
+ 0x080001f5, /* call &ModInvVar */
+ 0x7c600100, /* mov r24, r1 */
+ 0x7c640b00, /* mov r25, r11 */
+ 0x0800002c, /* call &MulMod */
+ 0x0800014f, /* call &SetupP256NandMuLow */
+ 0xa063f300, /* subm r24, r19, r31 */
+ /*fail: */
+ 0x90440300, /* st *3, *1 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x26a: function p256scalarmult[12] { */
+#define CF_p256scalarmult_adr 618
+ 0x84004000, /* ldi r0, [#0] */
+ 0x95800000, /* lddmp r0 */
+ 0x80000000, /* movi r0.0l, #0 */
+ 0x80800001, /* movi r0.1l, #1 */
+ 0x81000018, /* movi r0.2l, #24 */
+ 0x8180000b, /* movi r0.3l, #11 */
+ 0x97800000, /* ldrfp r0 */
+ 0x8c001000, /* ld *0, *0 */
+ 0x08000168, /* call &ScalarMult_internal */
+ 0x90540b00, /* st *3++, *5 */
+ 0x90580b00, /* st *3++, *6 */
+ 0x0c000000, /* ret */
+ /* } */
+};
+/* clang-format on */
+
+/*
+ * This struct is "calling convention" for passing parameters into the
+ * code block above for ecc operations. Writes to this struct should be done
+ * via the cp1w() and cp8w() functions to guarantee that word writes are used,
+ * as the dcrypto peripheral does not support byte writes.
+ */
+struct DMEM_ecc {
+ uint32_t pK;
+ uint32_t pRnd;
+ uint32_t pMsg;
+ uint32_t pR;
+ uint32_t pS;
+ uint32_t pX;
+ uint32_t pY;
+ uint32_t pD;
+ p256_int k;
+ p256_int rnd;
+ p256_int msg;
+ p256_int r;
+ p256_int s;
+ p256_int x;
+ p256_int y;
+ p256_int d;
+};
+
+#define DMEM_CELL_SIZE 32
+#define DMEM_OFFSET(p) (offsetof(struct DMEM_ecc, p))
+#define DMEM_INDEX(p) (DMEM_OFFSET(p) / DMEM_CELL_SIZE)
+
+/* p256 elliptic curve characteristics */
+static const p256_int SECP256r1_nMin1 = {
+ {
+ 0xfc632551 - 1,
+ 0xf3b9cac2,
+ 0xa7179e84,
+ 0xbce6faad,
+ -1,
+ -1,
+ 0,
+ -1,
+ },
+};
+
+/*
+ * Read-only pointer to read-only DMEM_ecc struct, use cp*w()
+ * functions for writes.
+ */
+static const volatile struct DMEM_ecc *dmem_ecc =
+ (const volatile struct DMEM_ecc *)GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+
+/*
+ * Writes one word to DMEM, at the address derived from the base
+ * offset and number of words. These parameters can be used for example
+ * by specifying the offset of a p256_int, and the index of a word within
+ * that p256_int.
+ */
+static void cp1w(size_t base_offset, int word, const uint32_t src)
+{
+ /* Destination address, always 32-bit aligned. */
+ volatile uint32_t *dst =
+ REG32_ADDR((uint8_t *)GREG32_ADDR(CRYPTO, DMEM_DUMMY) +
+ base_offset + (word * sizeof(uint32_t)));
+
+ *dst = src;
+}
+
+/*
+ * Copies the contents of the src p256_int to the specified offset in DMEM.
+ * The src argument does not need to be aligned.
+ */
+static void cp8w(size_t offset, const volatile p256_int *src)
+{
+ int i;
+
+ /*
+ * If p256_int is packed (as it is on cr50), the compiler
+ * cannot assume src will be aligned, and so performs
+ * byte reads into a register before calling cp1w (which
+ * is typically inlined).
+ *
+ * Note that the dcrypto peripheral supports byte reads,
+ * so it is safe to specify a pointer based on dmem_ecc
+ * as the src argument.
+ */
+ for (i = 0; i < P256_NDIGITS; i++)
+ cp1w(offset, i, P256_DIGIT(src, i));
+}
+
+/* Convenience macros for above copy functions. */
+#define CP1W(a, b, c) cp1w(DMEM_OFFSET(a), b, c)
+#define CP8W(a, b) cp8w(DMEM_OFFSET(a), b)
+
+static void dcrypto_ecc_init(void)
+{
+ dcrypto_imem_load(0, IMEM_dcrypto, ARRAY_SIZE(IMEM_dcrypto));
+
+ CP1W(pK, 0, DMEM_INDEX(k));
+ CP1W(pRnd, 0, DMEM_INDEX(rnd));
+ CP1W(pMsg, 0, DMEM_INDEX(msg));
+ CP1W(pR, 0, DMEM_INDEX(r));
+ CP1W(pS, 0, DMEM_INDEX(s));
+ CP1W(pX, 0, DMEM_INDEX(x));
+ CP1W(pY, 0, DMEM_INDEX(y));
+ CP1W(pD, 0, DMEM_INDEX(d));
+
+ /* (over)write first words to ensure pairwise mismatch. */
+ CP1W(k, 0, 1);
+ CP1W(rnd, 0, 2);
+ CP1W(msg, 0, 3);
+ CP1W(r, 0, 4);
+ CP1W(s, 0, 5);
+ CP1W(x, 0, 6);
+ CP1W(y, 0, 7);
+ CP1W(d, 0, 8);
+}
+
+/* Return -1 if a < b */
+static int p256_lt(const p256_int *a, const p256_int *b)
+{
+ p256_sddigit borrow = 0;
+
+ for (int i = 0; i < P256_NDIGITS; ++i) {
+ volatile uint32_t blinder = rand();
+
+ borrow += ((p256_sddigit)P256_DIGIT(a, i) - blinder);
+ borrow -= P256_DIGIT(b, i);
+ borrow += blinder;
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ return (int)borrow;
+}
+
+int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
+ const p256_int *message, p256_int *r, p256_int *s)
+{
+ int i, result;
+ p256_int rnd, k;
+
+ dcrypto_init_and_lock();
+ dcrypto_ecc_init();
+ result = dcrypto_call(CF_p256init_adr);
+
+ /* Pick uniform 0 < k < R */
+ do {
+ hmac_drbg_generate_p256(drbg, &rnd);
+ } while (p256_cmp(&SECP256r1_nMin2, &rnd) < 0);
+ drbg_exit(drbg);
+
+ p256_add_d(&rnd, 1, &k);
+
+ CP8W(k, &k);
+
+ for (i = 0; i < 8; ++i)
+ CP1W(rnd, i, rand());
+
+ /* Wipe temp rnd,k */
+ rnd = dmem_ecc->rnd;
+ k = dmem_ecc->rnd;
+
+ CP8W(msg, message);
+ CP8W(d, key);
+
+ result |= dcrypto_call(CF_p256sign_adr);
+
+ *r = dmem_ecc->r;
+ *s = dmem_ecc->s;
+
+ /* Wipe d,k */
+ CP8W(d, &rnd);
+ CP8W(k, &rnd);
+
+ dcrypto_unlock();
+ return result == 0;
+}
+
+int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y)
+{
+ int i, result;
+
+ dcrypto_init_and_lock();
+ dcrypto_ecc_init();
+ result = dcrypto_call(CF_p256init_adr);
+
+ for (i = 0; i < 8; ++i)
+ CP1W(rnd, i, dmem_ecc->rnd.a[i] ^ rand());
+
+ CP8W(d, k);
+
+ result |= dcrypto_call(CF_p256scalarbasemult_adr);
+
+ *x = dmem_ecc->x;
+ *y = dmem_ecc->y;
+
+ /* Wipe d */
+ CP8W(d, &dmem_ecc->rnd);
+
+ dcrypto_unlock();
+ return result == 0;
+}
+
+int dcrypto_p256_point_mul(const p256_int *k, const p256_int *in_x,
+ const p256_int *in_y, p256_int *x, p256_int *y)
+{
+ int i, result;
+
+ dcrypto_init_and_lock();
+ dcrypto_ecc_init();
+ result = dcrypto_call(CF_p256init_adr);
+
+ for (i = 0; i < 8; ++i)
+ CP1W(rnd, i, dmem_ecc->rnd.a[i] ^ rand());
+
+ CP8W(k, k);
+ CP8W(x, in_x);
+ CP8W(y, in_y);
+
+ result |= dcrypto_call(CF_p256scalarmult_adr);
+
+ *x = dmem_ecc->x;
+ *y = dmem_ecc->y;
+
+ /* Wipe k,x,y */
+ CP8W(k, &dmem_ecc->rnd);
+ CP8W(x, &dmem_ecc->rnd);
+ CP8W(y, &dmem_ecc->rnd);
+
+ dcrypto_unlock();
+ return result == 0;
+}
+
+int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
+ const p256_int *message, const p256_int *r,
+ const p256_int *s)
+{
+ int i, result;
+
+ dcrypto_init_and_lock();
+ dcrypto_ecc_init();
+ result = dcrypto_call(CF_p256init_adr);
+
+ CP8W(msg, message);
+ CP8W(r, r);
+ CP8W(s, s);
+ CP8W(x, key_x);
+ CP8W(y, key_y);
+
+ result |= dcrypto_call(CF_p256verify_adr);
+
+ for (i = 0; i < 8; ++i)
+ result |= (dmem_ecc->rnd.a[i] ^ r->a[i]);
+
+ dcrypto_unlock();
+ return result == 0;
+}
+
+int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y)
+{
+ int i, result;
+
+ dcrypto_init_and_lock();
+ dcrypto_ecc_init();
+ result = dcrypto_call(CF_p256init_adr);
+
+ CP8W(x, x);
+ CP8W(y, y);
+
+ result |= dcrypto_call(CF_p256isoncurve_adr);
+
+ for (i = 0; i < 8; ++i)
+ result |= (dmem_ecc->r.a[i] ^ dmem_ecc->s.a[i]);
+
+ dcrypto_unlock();
+ return result == 0;
+}
+
+int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output)
+{
+ int result = 0;
+
+ /* make sure to return stirred output even if drbg fails */
+ dcrypto_p256_rnd(output);
+
+ do {
+ result = hmac_drbg_generate_p256(drbg, output);
+ } while ((result == 0) && (p256_lt(output, &SECP256r1_nMin1) >= 0));
+ return result;
+}
+
+void dcrypto_p256_rnd(p256_int *output)
+{
+ for (int i = 0; i < 8; ++i)
+ output->a[i] = rand();
+}
diff --git a/chip/g/dcrypto/dcrypto_runtime.c b/chip/g/dcrypto/dcrypto_runtime.c
new file mode 100644
index 0000000000..394293ab83
--- /dev/null
+++ b/chip/g/dcrypto/dcrypto_runtime.c
@@ -0,0 +1,480 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "flash_log.h"
+#include "internal.h"
+#include "registers.h"
+#include "task.h"
+
+#define DMEM_NUM_WORDS 1024
+#define IMEM_NUM_WORDS 1024
+
+static struct mutex dcrypto_mutex;
+static volatile task_id_t my_task_id;
+static uint8_t dcrypto_is_initialized;
+
+static const uint32_t wiped_value = 0xdddddddd;
+
+static void dcrypto_reset_and_wipe(void)
+{
+ int i;
+ volatile uint32_t *ptr;
+
+ /* Reset. */
+ GREG32(CRYPTO, CONTROL) = GC_CRYPTO_CONTROL_RESET_MASK;
+ GREG32(CRYPTO, CONTROL) = 0;
+
+ /* Reset all the status bits. */
+ GREG32(CRYPTO, INT_STATE) = -1;
+
+ /* Wipe state. */
+ GREG32(CRYPTO, WIPE_SECRETS) = 1;
+
+ /* Wipe DMEM. */
+ ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+ for (i = 0; i < DMEM_NUM_WORDS; ++i)
+ *ptr++ = wiped_value;
+}
+
+static void dcrypto_wipe_imem(void)
+{
+ int i;
+ volatile uint32_t *ptr;
+
+ /* Wipe IMEM. */
+ ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY);
+ for (i = 0; i < IMEM_NUM_WORDS; ++i)
+ *ptr++ = wiped_value;
+}
+
+void dcrypto_init_and_lock(void)
+{
+ mutex_lock(&dcrypto_mutex);
+ my_task_id = task_get_current();
+
+ if (dcrypto_is_initialized)
+ return;
+
+ /* Enable PMU. */
+ REG_WRITE_MLV(GR_PMU_PERICLKSET0, GC_PMU_PERICLKSET0_DCRYPTO0_CLK_MASK,
+ GC_PMU_PERICLKSET0_DCRYPTO0_CLK_LSB, 1);
+
+ dcrypto_reset_and_wipe();
+ dcrypto_wipe_imem();
+
+ /* Turn off random nops (which are enabled by default). */
+ GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 0);
+ /* Configure random nop percentage at 6%. */
+ GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, FREQ, 3);
+ /* Now turn on random nops. */
+ GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 1);
+
+ GREG32(CRYPTO, INT_STATE) = -1; /* Reset all the status bits. */
+ GREG32(CRYPTO, INT_ENABLE) = -1; /* Enable all status bits. */
+
+ task_enable_irq(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT);
+
+ dcrypto_is_initialized = 1;
+}
+
+void dcrypto_unlock(void)
+{
+ mutex_unlock(&dcrypto_mutex);
+}
+
+#ifndef DCRYPTO_CALL_TIMEOUT_US
+#define DCRYPTO_CALL_TIMEOUT_US (700 * 1000)
+#endif
+/*
+ * When running on Cr50 this event belongs in the TPM task event space. Make
+ * sure there is no collision with events defined in ./common/tpm_registers.c.
+ */
+#define TASK_EVENT_DCRYPTO_DONE TASK_EVENT_CUSTOM_BIT(0)
+
+uint32_t dcrypto_call(uint32_t adr)
+{
+ uint32_t event;
+ uint32_t state = 0;
+
+ do {
+ /* Reset all the status bits. */
+ GREG32(CRYPTO, INT_STATE) = -1;
+ } while (GREG32(CRYPTO, INT_STATE) & 3);
+
+ GREG32(CRYPTO, HOST_CMD) = 0x08000000 + adr; /* Call imem:adr. */
+
+ event = task_wait_event_mask(TASK_EVENT_DCRYPTO_DONE,
+ DCRYPTO_CALL_TIMEOUT_US);
+ /* TODO(ngm): switch return value to an enum. */
+ switch (event) {
+ case TASK_EVENT_DCRYPTO_DONE:
+ /*
+ * We expect only the CMD_RECV status bit to be set at this
+ * point. CMD_DONE got cleared in the interrupt handler. Any and
+ * all other bits are indicative of error.
+ * Except for MOD_OPERAND_OUT_OF_RANGE, which is noise.
+ */
+ state = GREG32(CRYPTO, INT_STATE);
+ if ((state &
+ ~(GC_CRYPTO_INT_STATE_MOD_OPERAND_OUT_OF_RANGE_MASK |
+ GC_CRYPTO_INT_STATE_HOST_CMD_RECV_MASK)) == 0)
+ return 0;
+ /* fall through */
+ default:
+ dcrypto_reset_and_wipe();
+#ifdef CONFIG_FLASH_LOG
+ /* State value of zero indicates event timeout. */
+ flash_log_add_event(FE_LOG_DCRYPTO_FAILURE,
+ sizeof(state), &state);
+#endif
+ return 1;
+ }
+}
+
+void __keep dcrypto_done_interrupt(void)
+{
+ GREG32(CRYPTO, INT_STATE) = GC_CRYPTO_INT_STATE_HOST_CMD_DONE_MASK;
+ task_set_event(my_task_id, TASK_EVENT_DCRYPTO_DONE, 0);
+}
+DECLARE_IRQ(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT, dcrypto_done_interrupt, 1);
+
+void dcrypto_imem_load(size_t offset, const uint32_t *opcodes,
+ size_t n_opcodes)
+{
+ size_t i;
+ volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY);
+
+ ptr += offset;
+ /* Check first word and copy all only if different. */
+ if (ptr[0] != opcodes[0]) {
+ for (i = 0; i < n_opcodes; ++i)
+ ptr[i] = opcodes[i];
+ }
+}
+
+uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words)
+{
+ size_t i;
+ volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+ const uint32_t *src = (const uint32_t *) words;
+ struct access_helper *word_accessor = (struct access_helper *) src;
+ uint32_t diff = 0;
+
+ ptr += offset * 8; /* Offset is in 256 bit addresses. */
+ for (i = 0; i < n_words; ++i) {
+ /*
+ * The implementation of memcpy makes unaligned writes if src
+ * is unaligned. DMEM on the other hand requires writes to be
+ * aligned, so do a word-by-word copy manually here.
+ */
+ uint32_t v = word_accessor[i].udata;
+
+ diff |= (ptr[i] ^ v);
+ ptr[i] = v;
+ }
+ return diff;
+}
+
+#ifdef CRYPTO_TEST_SETUP
+
+#include "console.h"
+#include "dcrypto.h"
+#include "trng.h"
+#include "shared_mem.h"
+#include "system.h"
+#include "watchdog.h"
+
+/* AUTO-GENERATED. DO NOT MODIFY. */
+/* clang-format off */
+static const uint32_t IMEM_test_hang[] = {
+/* @0x0: function forever[2] { */
+#define CF_forever_adr 0
+/*forever: */
+ 0x10080000, /* b forever */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x2: function func17[2] { */
+#define CF_func17_adr 2
+ 0x08000000, /* call &forever */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x4: function func16[2] { */
+#define CF_func16_adr 4
+ 0x08000002, /* call &func17 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x6: function func15[2] { */
+#define CF_func15_adr 6
+ 0x08000004, /* call &func16 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x8: function func14[2] { */
+#define CF_func14_adr 8
+ 0x08000006, /* call &func15 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0xa: function func13[2] { */
+#define CF_func13_adr 10
+ 0x08000008, /* call &func14 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0xc: function func12[2] { */
+#define CF_func12_adr 12
+ 0x0800000a, /* call &func13 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0xe: function func11[2] { */
+#define CF_func11_adr 14
+ 0x0800000c, /* call &func12 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x10: function func10[2] { */
+#define CF_func10_adr 16
+ 0x0800000e, /* call &func11 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x12: function func9[2] { */
+#define CF_func9_adr 18
+ 0x08000010, /* call &func10 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x14: function func8[2] { */
+#define CF_func8_adr 20
+ 0x08000012, /* call &func9 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x16: function func7[2] { */
+#define CF_func7_adr 22
+ 0x08000014, /* call &func8 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x18: function func6[2] { */
+#define CF_func6_adr 24
+ 0x08000016, /* call &func7 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x1a: function func5[2] { */
+#define CF_func5_adr 26
+ 0x08000018, /* call &func6 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x1c: function func4[2] { */
+#define CF_func4_adr 28
+ 0x0800001a, /* call &func5 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x1e: function func3[2] { */
+#define CF_func3_adr 30
+ 0x0800001c, /* call &func4 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x20: function func2[2] { */
+#define CF_func2_adr 32
+ 0x0800001e, /* call &func3 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x22: function func1[2] { */
+#define CF_func1_adr 34
+ 0x08000020, /* call &func2 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x24: function test[2] { */
+#define CF_test_adr 36
+ 0x08000022, /* call &func1 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x26: function sigchk[2] { */
+#define CF_sigchk_adr 38
+ 0xf8000004, /* sigini #4 */
+ 0xf9ccc3c2, /* sigchk #13419458 */
+/* } */
+};
+/* clang-format on */
+
+/*
+ * Add console command "dcrypto_test" that runs a couple of engine failure
+ * scenarios and checks for adequate handling thereof:
+ * - error return code
+ * - dmem erasure on error
+ * - dmem preservation on success
+ */
+static int command_dcrypto_test(int argc, char *argv[])
+{
+ volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+ uint32_t not_wiped = ~wiped_value;
+ int result;
+
+ dcrypto_init_and_lock();
+ dcrypto_imem_load(0, IMEM_test_hang, ARRAY_SIZE(IMEM_test_hang));
+
+ *ptr = not_wiped;
+ result = dcrypto_call(CF_func2_adr); /* max legal stack, into hang */
+ if (result != 1 || *ptr != wiped_value)
+ ccprintf("dcrypto_test: fail1 %d,%08x\n", result, *ptr);
+
+ *ptr = not_wiped;
+ result = dcrypto_call(CF_test_adr); /* stack overflow */
+ if (result != 1 || *ptr != wiped_value)
+ ccprintf("dcrypto_test: fail2 %d,%08x\n", result, *ptr);
+
+ *ptr = not_wiped;
+ result = dcrypto_call(CF_sigchk_adr); /* cfi trap */
+ if (result != 1 || *ptr != wiped_value)
+ ccprintf("dcrypto_test: fail3 %d,%08x\n", result, *ptr);
+
+ *ptr = not_wiped;
+ result = dcrypto_call(CF_test_adr + 1); /* simple ret should succeed */
+ if (result != 0 || *ptr != not_wiped)
+ ccprintf("dcrypto_test: fail4 %d,%08x\n", result, *ptr);
+
+ dcrypto_unlock();
+
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_test, command_dcrypto_test, "",
+ "dcrypto test");
+
+#define ECDSA_TEST_ITERATIONS 1000
+
+#define ECDSA_TEST_SLEEP_DELAY_IN_US 1000000
+
+static const p256_int r_golden = {
+ .a = { 0xebc04580, 0x996c8634, 0xeaff3cd6, 0x4af33b39, 0xa17da3fb,
+ 0x2c9054f4, 0x3b4dfb95, 0xb3bf339c },
+};
+static const p256_int s_golden = {
+ .a = { 0xac457a6d, 0x8ca854ea, 0xa5877cc1, 0x17bd44f2, 0x77c4c11a,
+ 0xd55d07a0, 0x1efb1274, 0x94afb5c9 },
+};
+
+static int call_on_bigger_stack(uint32_t stack,
+ int (*func)(p256_int *, p256_int *),
+ p256_int *r, p256_int *s)
+{
+ int result = 0;
+
+ /* Move to new stack and call the function */
+ __asm__ volatile("mov r4, sp\n"
+ "mov sp, %[new_stack]\n"
+ "mov r0, %[r]\n"
+ "mov r1, %[s]\n"
+ "blx %[func]\n"
+ "mov sp, r4\n"
+ "mov %[result], r0\n"
+ : [result] "=r"(result) /* output */
+ : [new_stack] "r"(stack), [r] "r"(r), [s] "r"(s),
+ [func] "r"(func) /* input */
+ : "r0", "r1", "r2", "r3", "r4",
+ "lr" /* clobbered registers */
+ );
+
+ return result;
+}
+
+/* Sets up the ecdsa_sign function with proper input conditions to mimic the
+ * ecdsa_verisign execution flow.
+ * in: r - ptr to entropy, s - ptr to message.
+ * out: r,s - generated signature.
+ */
+static int ecdsa_sign_go(p256_int *r, p256_int *s)
+{
+ struct drbg_ctx drbg;
+ p256_int d, tmp;
+ int ret = 0;
+ p256_int message = *s;
+
+ /* drbg init with same entropy */
+ hmac_drbg_init(&drbg, r->a, sizeof(r->a), NULL, 0, NULL, 0);
+
+ /* pick a key */
+ ret = dcrypto_p256_pick(&drbg, &tmp);
+ if (ret) {
+ /* to be consistent with ecdsa_sign error return */
+ ret = 0;
+ goto exit;
+ }
+
+ /* add 1 */
+ p256_add_d(&tmp, 1, &d);
+
+ /* drbg_reseed with entropy and message */
+ hmac_drbg_reseed(&drbg, r->a, sizeof(r->a), s->a, sizeof(s->a), NULL,
+ 0);
+
+ ret = dcrypto_p256_ecdsa_sign(&drbg, &d, &message, r, s);
+
+exit:
+ drbg_exit(&drbg);
+ return ret;
+}
+
+static int command_dcrypto_ecdsa_test(int argc, char *argv[])
+{
+ p256_int entropy, message, r, s;
+ LITE_SHA256_CTX hsh;
+ int result = 0;
+ char *new_stack;
+ const uint32_t new_stack_size = 2 * 1024;
+
+ /* start with some known value for a message */
+ const uint8_t ten = 0x0A;
+
+ for (uint8_t i = 0; i < 8; i++)
+ entropy.a[i] = i;
+
+ DCRYPTO_SHA256_init(&hsh, 0);
+ HASH_update(&hsh, &ten, sizeof(ten));
+ p256_from_bin(HASH_final(&hsh), &message);
+
+ r = entropy;
+ s = message;
+
+ result = shared_mem_acquire(new_stack_size, &new_stack);
+
+ if (result != EC_SUCCESS) {
+ ccprintf("Failed to acquire stack memory: %d\n", result);
+ return result;
+ }
+
+ for (uint32_t i = 0; i < ECDSA_TEST_ITERATIONS; i++) {
+ result = call_on_bigger_stack((uint32_t)new_stack +
+ new_stack_size,
+ ecdsa_sign_go, &r, &s);
+
+ if (!result) {
+ ccprintf("ECDSA TEST fail: %d\n", result);
+ return EC_ERROR_INVAL;
+ }
+
+ watchdog_reload();
+ delay_sleep_by(ECDSA_TEST_SLEEP_DELAY_IN_US);
+ }
+
+ shared_mem_release(new_stack);
+
+ /* compare to the golden r and s values */
+ for (uint8_t i = 0; i < 8; i++) {
+ if (r.a[i] != r_golden.a[i]) {
+ ccprintf("ECDSA TEST r does not match with golden at "
+ "%d: %08x != %08x\n",
+ i, r.a[i], r_golden.a[i]);
+ return EC_ERROR_INVAL;
+ }
+ if (s.a[i] != s_golden.a[i]) {
+ ccprintf("ECDSA TEST s does not match with golden at "
+ "%d: %08x != %08x\n",
+ i, s.a[i], s_golden.a[i]);
+ return EC_ERROR_INVAL;
+ }
+ }
+
+ ccprintf("ECDSA TEST success!!!\n");
+
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_ecdsa, command_dcrypto_ecdsa_test, "",
+ "dcrypto ecdsa test");
+
+#endif
diff --git a/chip/g/dcrypto/dcrypto_sha512.c b/chip/g/dcrypto/dcrypto_sha512.c
new file mode 100644
index 0000000000..bb404b28d7
--- /dev/null
+++ b/chip/g/dcrypto/dcrypto_sha512.c
@@ -0,0 +1,772 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+
+#include "cryptoc/sha512.h"
+
+#ifdef CRYPTO_TEST_SETUP
+
+/* test and benchmark */
+#include "common.h"
+#include "console.h"
+#include "hooks.h"
+#include "task.h"
+
+#define cyclecounter() GREG32(M3, DWT_CYCCNT)
+#define START_PROFILE(x) \
+ { \
+ x -= cyclecounter(); \
+ }
+#define END_PROFILE(x) \
+ { \
+ x += cyclecounter(); \
+ }
+static uint32_t t_sw;
+static uint32_t t_hw;
+static uint32_t t_transform;
+static uint32_t t_dcrypto;
+
+#else /* CRYPTO_TEST_SETUP */
+
+#define START_PROFILE(x)
+#define END_PROFILE(x)
+
+#endif /* CRYPTO_TEST_SETUP */
+
+/* auto-generated from go test haven -test.run=TestSha512 -test.v */
+/* clang-format off */
+static const uint32_t IMEM_dcrypto[] = {
+/* @0x0: function tag[1] { */
+#define CF_tag_adr 0
+ 0xf8000003, /* sigini #3 */
+/* } */
+/* @0x1: function expandw[84] { */
+#define CF_expandw_adr 1
+ 0x4c3def00, /* xor r15, r15, r15 */
+ 0x803c0013, /* movi r15.0l, #19 */
+ 0x80bc0016, /* movi r15.1l, #22 */
+ 0x97800f00, /* ldrfp r15 */
+ 0x05004003, /* loop #4 ( */
+ 0x8c001800, /* ld *0, *0++ */
+ 0x906c0800, /* st *0++, *3++ */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x0501004a, /* loop #16 ( */
+ 0x684a6080, /* rshi r18, r0, r19 >> 128 */
+ 0x68443340, /* rshi r17, r19, r1 >> 64 */
+ 0x683e3201, /* rshi r15, r18, r17 >> 1 */
+ 0x68423208, /* rshi r16, r18, r17 >> 8 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x6843f207, /* rshi r16, r18, r31 >> 7 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x505df398, /* add r23, r19, r15 >> 192 */
+ 0x505eb788, /* add r23, r23, r21 >> 64 */
+ 0x684ac0c0, /* rshi r18, r0, r22 >> 192 */
+ 0x68443680, /* rshi r17, r22, r1 >> 128 */
+ 0x683e3213, /* rshi r15, r18, r17 >> 19 */
+ 0x6842323d, /* rshi r16, r18, r17 >> 61 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x6843f206, /* rshi r16, r18, r31 >> 6 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x505df798, /* add r23, r23, r15 >> 192 */
+ 0x684a60c0, /* rshi r18, r0, r19 >> 192 */
+ 0x68443380, /* rshi r17, r19, r1 >> 128 */
+ 0x683e3201, /* rshi r15, r18, r17 >> 1 */
+ 0x68423208, /* rshi r16, r18, r17 >> 8 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x6843f207, /* rshi r16, r18, r31 >> 7 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x50627f88, /* add r24, r31, r19 >> 64 */
+ 0x5061f898, /* add r24, r24, r15 >> 192 */
+ 0x5062b890, /* add r24, r24, r21 >> 128 */
+ 0x684416c0, /* rshi r17, r22, r0 >> 192 */
+ 0x683e3613, /* rshi r15, r22, r17 >> 19 */
+ 0x6842363d, /* rshi r16, r22, r17 >> 61 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x6843f606, /* rshi r16, r22, r31 >> 6 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x5061f898, /* add r24, r24, r15 >> 192 */
+ 0x684433c0, /* rshi r17, r19, r1 >> 192 */
+ 0x683e3301, /* rshi r15, r19, r17 >> 1 */
+ 0x68423308, /* rshi r16, r19, r17 >> 8 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x6843f307, /* rshi r16, r19, r31 >> 7 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x50667f90, /* add r25, r31, r19 >> 128 */
+ 0x5065f998, /* add r25, r25, r15 >> 192 */
+ 0x5066b998, /* add r25, r25, r21 >> 192 */
+ 0x684ae040, /* rshi r18, r0, r23 >> 64 */
+ 0x683ef213, /* rshi r15, r18, r23 >> 19 */
+ 0x6842f23d, /* rshi r16, r18, r23 >> 61 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x6843f206, /* rshi r16, r18, r31 >> 6 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x5065f998, /* add r25, r25, r15 >> 192 */
+ 0x684a8040, /* rshi r18, r0, r20 >> 64 */
+ 0x683e9201, /* rshi r15, r18, r20 >> 1 */
+ 0x68429208, /* rshi r16, r18, r20 >> 8 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x6843f207, /* rshi r16, r18, r31 >> 7 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x506a7f98, /* add r26, r31, r19 >> 192 */
+ 0x5069fa98, /* add r26, r26, r15 >> 192 */
+ 0x506ada00, /* add r26, r26, r22 */
+ 0x684b0040, /* rshi r18, r0, r24 >> 64 */
+ 0x683f1213, /* rshi r15, r18, r24 >> 19 */
+ 0x6843123d, /* rshi r16, r18, r24 >> 61 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x6843f206, /* rshi r16, r18, r31 >> 6 */
+ 0x4c3e0f00, /* xor r15, r15, r16 */
+ 0x5069fa98, /* add r26, r26, r15 >> 192 */
+ 0x7c4c1400, /* mov r19, r20 */
+ 0x7c501500, /* mov r20, r21 */
+ 0x7c541600, /* mov r21, r22 */
+ 0x685af640, /* rshi r22, r22, r23 >> 64 */
+ 0x685b1640, /* rshi r22, r22, r24 >> 64 */
+ 0x685b3640, /* rshi r22, r22, r25 >> 64 */
+ 0x685b5640, /* rshi r22, r22, r26 >> 64 */
+ 0x906c0100, /* st *1, *3++ */
+ /* ) */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x55: function Sha512_a[125] { */
+#define CF_Sha512_a_adr 85
+ 0x68580c40, /* rshi r22, r12, r0 >> 64 */
+ 0x683c161c, /* rshi r15, r22, r0 >> 28 */
+ 0x68541622, /* rshi r21, r22, r0 >> 34 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x68541627, /* rshi r21, r22, r0 >> 39 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x40402000, /* and r16, r0, r1 */
+ 0x40544000, /* and r21, r0, r2 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x40544100, /* and r21, r1, r2 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x68458fc0, /* rshi r17, r15, r12 >> 192 */
+ 0x50461100, /* add r17, r17, r16 */
+ 0x68588d40, /* rshi r22, r13, r4 >> 64 */
+ 0x6848960e, /* rshi r18, r22, r4 >> 14 */
+ 0x68549612, /* rshi r21, r22, r4 >> 18 */
+ 0x4c4ab200, /* xor r18, r18, r21 */
+ 0x684c9629, /* rshi r19, r22, r4 >> 41 */
+ 0x4c4a7200, /* xor r18, r18, r19 */
+ 0x404ca400, /* and r19, r4, r5 */
+ 0x48548000, /* not r21, r4 */
+ 0x4054d500, /* and r21, r21, r6 */
+ 0x4c4eb300, /* xor r19, r19, r21 */
+ 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */
+ 0x5050f400, /* add r20, r20, r7 */
+ 0x50515480, /* add r20, r20, r10 >> 0 */
+ 0x68558b00, /* rshi r21, r11, r12 >> 0 */
+ 0x50567500, /* add r21, r21, r19 */
+ 0x5052b400, /* add r20, r20, r21 */
+ 0x500e8300, /* add r3, r3, r20 */
+ 0x501e3400, /* add r7, r20, r17 */
+ 0x6858ec40, /* rshi r22, r12, r7 >> 64 */
+ 0x683cf61c, /* rshi r15, r22, r7 >> 28 */
+ 0x6854f622, /* rshi r21, r22, r7 >> 34 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x6854f627, /* rshi r21, r22, r7 >> 39 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x40400700, /* and r16, r7, r0 */
+ 0x40542700, /* and r21, r7, r1 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x40542000, /* and r21, r0, r1 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x68458fc0, /* rshi r17, r15, r12 >> 192 */
+ 0x50461100, /* add r17, r17, r16 */
+ 0x68586d40, /* rshi r22, r13, r3 >> 64 */
+ 0x6848760e, /* rshi r18, r22, r3 >> 14 */
+ 0x68547612, /* rshi r21, r22, r3 >> 18 */
+ 0x4c4ab200, /* xor r18, r18, r21 */
+ 0x684c7629, /* rshi r19, r22, r3 >> 41 */
+ 0x4c4a7200, /* xor r18, r18, r19 */
+ 0x404c8300, /* and r19, r3, r4 */
+ 0x48546000, /* not r21, r3 */
+ 0x4054b500, /* and r21, r21, r5 */
+ 0x4c4eb300, /* xor r19, r19, r21 */
+ 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */
+ 0x5050d400, /* add r20, r20, r6 */
+ 0x50515488, /* add r20, r20, r10 >> 64 */
+ 0x68558b40, /* rshi r21, r11, r12 >> 64 */
+ 0x50567500, /* add r21, r21, r19 */
+ 0x5052b400, /* add r20, r20, r21 */
+ 0x500a8200, /* add r2, r2, r20 */
+ 0x501a3400, /* add r6, r20, r17 */
+ 0x6858cc40, /* rshi r22, r12, r6 >> 64 */
+ 0x683cd61c, /* rshi r15, r22, r6 >> 28 */
+ 0x6854d622, /* rshi r21, r22, r6 >> 34 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x6854d627, /* rshi r21, r22, r6 >> 39 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x4040e600, /* and r16, r6, r7 */
+ 0x40540600, /* and r21, r6, r0 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x40540700, /* and r21, r7, r0 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x68458fc0, /* rshi r17, r15, r12 >> 192 */
+ 0x50461100, /* add r17, r17, r16 */
+ 0x68584d40, /* rshi r22, r13, r2 >> 64 */
+ 0x6848560e, /* rshi r18, r22, r2 >> 14 */
+ 0x68545612, /* rshi r21, r22, r2 >> 18 */
+ 0x4c4ab200, /* xor r18, r18, r21 */
+ 0x684c5629, /* rshi r19, r22, r2 >> 41 */
+ 0x4c4a7200, /* xor r18, r18, r19 */
+ 0x404c6200, /* and r19, r2, r3 */
+ 0x48544000, /* not r21, r2 */
+ 0x40549500, /* and r21, r21, r4 */
+ 0x4c4eb300, /* xor r19, r19, r21 */
+ 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */
+ 0x5050b400, /* add r20, r20, r5 */
+ 0x50515490, /* add r20, r20, r10 >> 128 */
+ 0x68558b80, /* rshi r21, r11, r12 >> 128 */
+ 0x50567500, /* add r21, r21, r19 */
+ 0x5052b400, /* add r20, r20, r21 */
+ 0x50068100, /* add r1, r1, r20 */
+ 0x50163400, /* add r5, r20, r17 */
+ 0x6858ac40, /* rshi r22, r12, r5 >> 64 */
+ 0x683cb61c, /* rshi r15, r22, r5 >> 28 */
+ 0x6854b622, /* rshi r21, r22, r5 >> 34 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x6854b627, /* rshi r21, r22, r5 >> 39 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x4040c500, /* and r16, r5, r6 */
+ 0x4054e500, /* and r21, r5, r7 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x4054e600, /* and r21, r6, r7 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x68458fc0, /* rshi r17, r15, r12 >> 192 */
+ 0x50461100, /* add r17, r17, r16 */
+ 0x68582d40, /* rshi r22, r13, r1 >> 64 */
+ 0x6848360e, /* rshi r18, r22, r1 >> 14 */
+ 0x68543612, /* rshi r21, r22, r1 >> 18 */
+ 0x4c4ab200, /* xor r18, r18, r21 */
+ 0x684c3629, /* rshi r19, r22, r1 >> 41 */
+ 0x4c4a7200, /* xor r18, r18, r19 */
+ 0x404c4100, /* and r19, r1, r2 */
+ 0x48542000, /* not r21, r1 */
+ 0x40547500, /* and r21, r21, r3 */
+ 0x4c4eb300, /* xor r19, r19, r21 */
+ 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */
+ 0x50509400, /* add r20, r20, r4 */
+ 0x50515498, /* add r20, r20, r10 >> 192 */
+ 0x68558bc0, /* rshi r21, r11, r12 >> 192 */
+ 0x50567500, /* add r21, r21, r19 */
+ 0x5052b400, /* add r20, r20, r21 */
+ 0x50028000, /* add r0, r0, r20 */
+ 0x50123400, /* add r4, r20, r17 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0xd2: function Sha512_b[125] { */
+#define CF_Sha512_b_adr 210
+ 0x68588d40, /* rshi r22, r13, r4 >> 64 */
+ 0x683c961c, /* rshi r15, r22, r4 >> 28 */
+ 0x68549622, /* rshi r21, r22, r4 >> 34 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x68549627, /* rshi r21, r22, r4 >> 39 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x4040a400, /* and r16, r4, r5 */
+ 0x4054c400, /* and r21, r4, r6 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x4054c500, /* and r21, r5, r6 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x6845afc0, /* rshi r17, r15, r13 >> 192 */
+ 0x50461100, /* add r17, r17, r16 */
+ 0x68580c40, /* rshi r22, r12, r0 >> 64 */
+ 0x6848160e, /* rshi r18, r22, r0 >> 14 */
+ 0x68541612, /* rshi r21, r22, r0 >> 18 */
+ 0x4c4ab200, /* xor r18, r18, r21 */
+ 0x684c1629, /* rshi r19, r22, r0 >> 41 */
+ 0x4c4a7200, /* xor r18, r18, r19 */
+ 0x404c2000, /* and r19, r0, r1 */
+ 0x48540000, /* not r21, r0 */
+ 0x40545500, /* and r21, r21, r2 */
+ 0x4c4eb300, /* xor r19, r19, r21 */
+ 0x685192c0, /* rshi r20, r18, r12 >> 192 */
+ 0x50507400, /* add r20, r20, r3 */
+ 0x50515480, /* add r20, r20, r10 >> 0 */
+ 0x6855ab00, /* rshi r21, r11, r13 >> 0 */
+ 0x50567500, /* add r21, r21, r19 */
+ 0x5052b400, /* add r20, r20, r21 */
+ 0x501e8700, /* add r7, r7, r20 */
+ 0x500e3400, /* add r3, r20, r17 */
+ 0x68586d40, /* rshi r22, r13, r3 >> 64 */
+ 0x683c761c, /* rshi r15, r22, r3 >> 28 */
+ 0x68547622, /* rshi r21, r22, r3 >> 34 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x68547627, /* rshi r21, r22, r3 >> 39 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x40408300, /* and r16, r3, r4 */
+ 0x4054a300, /* and r21, r3, r5 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x4054a400, /* and r21, r4, r5 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x6845afc0, /* rshi r17, r15, r13 >> 192 */
+ 0x50461100, /* add r17, r17, r16 */
+ 0x6858ec40, /* rshi r22, r12, r7 >> 64 */
+ 0x6848f60e, /* rshi r18, r22, r7 >> 14 */
+ 0x6854f612, /* rshi r21, r22, r7 >> 18 */
+ 0x4c4ab200, /* xor r18, r18, r21 */
+ 0x684cf629, /* rshi r19, r22, r7 >> 41 */
+ 0x4c4a7200, /* xor r18, r18, r19 */
+ 0x404c0700, /* and r19, r7, r0 */
+ 0x4854e000, /* not r21, r7 */
+ 0x40543500, /* and r21, r21, r1 */
+ 0x4c4eb300, /* xor r19, r19, r21 */
+ 0x685192c0, /* rshi r20, r18, r12 >> 192 */
+ 0x50505400, /* add r20, r20, r2 */
+ 0x50515488, /* add r20, r20, r10 >> 64 */
+ 0x6855ab40, /* rshi r21, r11, r13 >> 64 */
+ 0x50567500, /* add r21, r21, r19 */
+ 0x5052b400, /* add r20, r20, r21 */
+ 0x501a8600, /* add r6, r6, r20 */
+ 0x500a3400, /* add r2, r20, r17 */
+ 0x68584d40, /* rshi r22, r13, r2 >> 64 */
+ 0x683c561c, /* rshi r15, r22, r2 >> 28 */
+ 0x68545622, /* rshi r21, r22, r2 >> 34 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x68545627, /* rshi r21, r22, r2 >> 39 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x40406200, /* and r16, r2, r3 */
+ 0x40548200, /* and r21, r2, r4 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x40548300, /* and r21, r3, r4 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x6845afc0, /* rshi r17, r15, r13 >> 192 */
+ 0x50461100, /* add r17, r17, r16 */
+ 0x6858cc40, /* rshi r22, r12, r6 >> 64 */
+ 0x6848d60e, /* rshi r18, r22, r6 >> 14 */
+ 0x6854d612, /* rshi r21, r22, r6 >> 18 */
+ 0x4c4ab200, /* xor r18, r18, r21 */
+ 0x684cd629, /* rshi r19, r22, r6 >> 41 */
+ 0x4c4a7200, /* xor r18, r18, r19 */
+ 0x404ce600, /* and r19, r6, r7 */
+ 0x4854c000, /* not r21, r6 */
+ 0x40541500, /* and r21, r21, r0 */
+ 0x4c4eb300, /* xor r19, r19, r21 */
+ 0x685192c0, /* rshi r20, r18, r12 >> 192 */
+ 0x50503400, /* add r20, r20, r1 */
+ 0x50515490, /* add r20, r20, r10 >> 128 */
+ 0x6855ab80, /* rshi r21, r11, r13 >> 128 */
+ 0x50567500, /* add r21, r21, r19 */
+ 0x5052b400, /* add r20, r20, r21 */
+ 0x50168500, /* add r5, r5, r20 */
+ 0x50063400, /* add r1, r20, r17 */
+ 0x68582d40, /* rshi r22, r13, r1 >> 64 */
+ 0x683c361c, /* rshi r15, r22, r1 >> 28 */
+ 0x68543622, /* rshi r21, r22, r1 >> 34 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x68543627, /* rshi r21, r22, r1 >> 39 */
+ 0x4c3eaf00, /* xor r15, r15, r21 */
+ 0x40404100, /* and r16, r1, r2 */
+ 0x40546100, /* and r21, r1, r3 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x40546200, /* and r21, r2, r3 */
+ 0x4c42b000, /* xor r16, r16, r21 */
+ 0x6845afc0, /* rshi r17, r15, r13 >> 192 */
+ 0x50461100, /* add r17, r17, r16 */
+ 0x6858ac40, /* rshi r22, r12, r5 >> 64 */
+ 0x6848b60e, /* rshi r18, r22, r5 >> 14 */
+ 0x6854b612, /* rshi r21, r22, r5 >> 18 */
+ 0x4c4ab200, /* xor r18, r18, r21 */
+ 0x684cb629, /* rshi r19, r22, r5 >> 41 */
+ 0x4c4a7200, /* xor r18, r18, r19 */
+ 0x404cc500, /* and r19, r5, r6 */
+ 0x4854a000, /* not r21, r5 */
+ 0x4054f500, /* and r21, r21, r7 */
+ 0x4c4eb300, /* xor r19, r19, r21 */
+ 0x685192c0, /* rshi r20, r18, r12 >> 192 */
+ 0x50501400, /* add r20, r20, r0 */
+ 0x50515498, /* add r20, r20, r10 >> 192 */
+ 0x6855abc0, /* rshi r21, r11, r13 >> 192 */
+ 0x50567500, /* add r21, r21, r19 */
+ 0x5052b400, /* add r20, r20, r21 */
+ 0x50128400, /* add r4, r4, r20 */
+ 0x50023400, /* add r0, r20, r17 */
+ 0x0c000000, /* ret */
+/* } */
+/* @0x14f: function compress[70] { */
+#define CF_compress_adr 335
+ 0xfc000000, /* nop */
+ 0x4c7fff00, /* xor r31, r31, r31 */
+ 0x4c000000, /* xor r0, r0, r0 */
+ 0x4c042100, /* xor r1, r1, r1 */
+ 0x55000001, /* subi r0, r0, #1 */
+ 0x55040101, /* subi r1, r1, #1 */
+ 0x84204100, /* ldi r8, [#8] */
+ 0x94800800, /* ldlc r8 */
+ 0x4c3def00, /* xor r15, r15, r15 */
+ 0x803c000a, /* movi r15.0l, #10 */
+ 0x95800f00, /* lddmp r15 */
+ 0x06000039, /* loop *0 ( */
+ 0x953c0000, /* stdmp r15 */
+ 0x81bc002a, /* movi r15.3l, #42 */
+ 0x95800f00, /* lddmp r15 */
+ 0x08000001, /* call &expandw */
+ 0x84004000, /* ldi r0, [#0] */
+ 0x84044020, /* ldi r1, [#1] */
+ 0x84084040, /* ldi r2, [#2] */
+ 0x840c4060, /* ldi r3, [#3] */
+ 0x84104080, /* ldi r4, [#4] */
+ 0x841440a0, /* ldi r5, [#5] */
+ 0x841840c0, /* ldi r6, [#6] */
+ 0x841c40e0, /* ldi r7, [#7] */
+ 0x4c3def00, /* xor r15, r15, r15 */
+ 0x803c0060, /* movi r15.0l, #96 */
+ 0x80bc000a, /* movi r15.1l, #10 */
+ 0x813c000b, /* movi r15.2l, #11 */
+ 0x96800f00, /* lddrp r15 */
+ 0x97800f00, /* ldrfp r15 */
+ 0x953c0000, /* stdmp r15 */
+ 0x81bc002a, /* movi r15.3l, #42 */
+ 0x95800f00, /* lddmp r15 */
+ 0x4c318c00, /* xor r12, r12, r12 */
+ 0x4c35ad00, /* xor r13, r13, r13 */
+ 0x55300c01, /* subi r12, r12, #1 */
+ 0x55340d01, /* subi r13, r13, #1 */
+ 0x0500a007, /* loop #10 ( */
+ 0x8c440800, /* ldc *1, *0++ */
+ 0x8c081b00, /* ld *2, *3++ */
+ 0x08000055, /* call &Sha512_a */
+ 0x8c440800, /* ldc *1, *0++ */
+ 0x8c081b00, /* ld *2, *3++ */
+ 0x080000d2, /* call &Sha512_b */
+ 0xfc000000, /* nop */
+ /* ) */
+ 0x843c4000, /* ldi r15, [#0] */
+ 0x5001e000, /* add r0, r0, r15 */
+ 0x843c4020, /* ldi r15, [#1] */
+ 0x5005e100, /* add r1, r1, r15 */
+ 0x843c4040, /* ldi r15, [#2] */
+ 0x5009e200, /* add r2, r2, r15 */
+ 0x843c4060, /* ldi r15, [#3] */
+ 0x500de300, /* add r3, r3, r15 */
+ 0x843c4080, /* ldi r15, [#4] */
+ 0x5011e400, /* add r4, r4, r15 */
+ 0x843c40a0, /* ldi r15, [#5] */
+ 0x5015e500, /* add r5, r5, r15 */
+ 0x843c40c0, /* ldi r15, [#6] */
+ 0x5019e600, /* add r6, r6, r15 */
+ 0x843c40e0, /* ldi r15, [#7] */
+ 0x501de700, /* add r7, r7, r15 */
+ 0x88004000, /* sti r0, [#0] */
+ 0x88044020, /* sti r1, [#1] */
+ 0x88084040, /* sti r2, [#2] */
+ 0x880c4060, /* sti r3, [#3] */
+ 0x88104080, /* sti r4, [#4] */
+ 0x881440a0, /* sti r5, [#5] */
+ 0x881840c0, /* sti r6, [#6] */
+ 0x881c40e0, /* sti r7, [#7] */
+ /* ) */
+ 0x0c000000, /* ret */
+ /* } */
+};
+/* clang-format on */
+
+struct DMEM_sha512 {
+ uint64_t H0[4];
+ uint64_t H1[4];
+ uint64_t H2[4];
+ uint64_t H3[4];
+ uint64_t H4[4];
+ uint64_t H5[4];
+ uint64_t H6[4];
+ uint64_t H7[4];
+ uint32_t nblocks;
+ uint32_t unused[2 * 8 - 1];
+ uint32_t input[4 * 8 * 8]; // dmem[10..41]
+};
+
+static void copy_words(const void *in, uint32_t *dst, size_t nwords)
+{
+ const uint32_t *src = (const uint32_t *) in;
+
+ do {
+ uint32_t w1 = __builtin_bswap32(*src++);
+ uint32_t w2 = __builtin_bswap32(*src++);
+ *dst++ = w2;
+ *dst++ = w1;
+ } while (nwords -= 2);
+}
+
+static void dcrypto_SHA512_setup(void)
+{
+ dcrypto_imem_load(0, IMEM_dcrypto, ARRAY_SIZE(IMEM_dcrypto));
+}
+
+static void dcrypto_SHA512_Transform(LITE_SHA512_CTX *ctx, const uint32_t *buf,
+ size_t nwords)
+{
+ int result = 0;
+ struct DMEM_sha512 *p512 =
+ (struct DMEM_sha512 *) GREG32_ADDR(CRYPTO, DMEM_DUMMY);
+
+ START_PROFILE(t_transform)
+
+ /* Pass in H[] */
+ p512->H0[0] = ctx->state[0];
+ p512->H1[0] = ctx->state[1];
+ p512->H2[0] = ctx->state[2];
+ p512->H3[0] = ctx->state[3];
+ p512->H4[0] = ctx->state[4];
+ p512->H5[0] = ctx->state[5];
+ p512->H6[0] = ctx->state[6];
+ p512->H7[0] = ctx->state[7];
+
+ p512->nblocks = nwords / 32;
+
+ /* Pass in buf[] */
+ copy_words(buf, p512->input, nwords);
+
+ START_PROFILE(t_dcrypto)
+ result |= dcrypto_call(CF_compress_adr);
+ END_PROFILE(t_dcrypto)
+
+ /* Retrieve new H[] */
+ ctx->state[0] = p512->H0[0];
+ ctx->state[1] = p512->H1[0];
+ ctx->state[2] = p512->H2[0];
+ ctx->state[3] = p512->H3[0];
+ ctx->state[4] = p512->H4[0];
+ ctx->state[5] = p512->H5[0];
+ ctx->state[6] = p512->H6[0];
+ ctx->state[7] = p512->H7[0];
+
+ /* TODO: errno or such to capture errors */
+ (void) (result == 0);
+
+ END_PROFILE(t_transform)
+}
+
+static void dcrypto_SHA512_update(LITE_SHA512_CTX *ctx, const void *data,
+ size_t len)
+{
+ int i = (int) (ctx->count & (sizeof(ctx->buf) - 1));
+ const uint8_t *p = (const uint8_t *) data;
+ uint8_t *d = &ctx->buf[i];
+
+ ctx->count += len;
+
+ dcrypto_init_and_lock();
+ dcrypto_SHA512_setup();
+
+ /* Take fast path for 32-bit aligned 1KB inputs */
+ if (i == 0 && len == 1024 && (((intptr_t) data) & 3) == 0) {
+ dcrypto_SHA512_Transform(ctx, (const uint32_t *) data, 8 * 32);
+ } else {
+ if (len <= sizeof(ctx->buf) - i) {
+ memcpy(d, p, len);
+ if (len == sizeof(ctx->buf) - i) {
+ dcrypto_SHA512_Transform(
+ ctx, (uint32_t *) (ctx->buf), 32);
+ }
+ } else {
+ memcpy(d, p, sizeof(ctx->buf) - i);
+ dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf),
+ 32);
+ d = ctx->buf;
+ len -= (sizeof(ctx->buf) - i);
+ p += (sizeof(ctx->buf) - i);
+ while (len >= sizeof(ctx->buf)) {
+ memcpy(d, p, sizeof(ctx->buf));
+ p += sizeof(ctx->buf);
+ len -= sizeof(ctx->buf);
+ dcrypto_SHA512_Transform(
+ ctx, (uint32_t *) (ctx->buf), 32);
+ }
+ /* Leave remainder in ctx->buf */
+ memcpy(d, p, len);
+ }
+ }
+ dcrypto_unlock();
+}
+
+static const uint8_t *dcrypto_SHA512_final(LITE_SHA512_CTX *ctx)
+{
+ uint64_t cnt = ctx->count * 8;
+ int i = (int) (ctx->count & (sizeof(ctx->buf) - 1));
+ uint8_t *p = &ctx->buf[i];
+
+ *p++ = 0x80;
+ i++;
+
+ dcrypto_init_and_lock();
+ dcrypto_SHA512_setup();
+
+ if (i > sizeof(ctx->buf) - 16) {
+ memset(p, 0, sizeof(ctx->buf) - i);
+ dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), 32);
+ i = 0;
+ p = ctx->buf;
+ }
+
+ memset(p, 0, sizeof(ctx->buf) - 8 - i);
+ p += sizeof(ctx->buf) - 8 - i;
+
+ for (i = 0; i < 8; ++i) {
+ uint8_t tmp = (uint8_t)(cnt >> 56);
+ cnt <<= 8;
+ *p++ = tmp;
+ }
+
+ dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), 32);
+
+ p = ctx->buf;
+ for (i = 0; i < 8; i++) {
+ uint64_t tmp = ctx->state[i];
+ *p++ = (uint8_t)(tmp >> 56);
+ *p++ = (uint8_t)(tmp >> 48);
+ *p++ = (uint8_t)(tmp >> 40);
+ *p++ = (uint8_t)(tmp >> 32);
+ *p++ = (uint8_t)(tmp >> 24);
+ *p++ = (uint8_t)(tmp >> 16);
+ *p++ = (uint8_t)(tmp >> 8);
+ *p++ = (uint8_t)(tmp >> 0);
+ }
+
+ dcrypto_unlock();
+ return ctx->buf;
+}
+
+const uint8_t *DCRYPTO_SHA512_hash(const void *data, size_t len,
+ uint8_t *digest)
+{
+ LITE_SHA512_CTX ctx;
+
+ DCRYPTO_SHA512_init(&ctx);
+ dcrypto_SHA512_update(&ctx, data, len);
+ memcpy(digest, dcrypto_SHA512_final(&ctx), SHA512_DIGEST_SIZE);
+
+ return digest;
+}
+
+static const HASH_VTAB dcrypto_SHA512_VTAB = {
+ DCRYPTO_SHA512_init, dcrypto_SHA512_update, dcrypto_SHA512_final,
+ DCRYPTO_SHA512_hash, SHA512_DIGEST_SIZE};
+
+void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx)
+{
+ SHA512_init(ctx);
+ ctx->f = &dcrypto_SHA512_VTAB;
+}
+
+#ifdef CRYPTO_TEST_SETUP
+
+static uint32_t msg[256]; // 1KB
+static int msg_len;
+static int msg_loops;
+static LITE_SHA512_CTX sw;
+static LITE_SHA512_CTX hw;
+static const uint8_t *sw_digest;
+static const uint8_t *hw_digest;
+static uint32_t t_sw;
+static uint32_t t_hw;
+
+static void run_sha512_cmd(void)
+{
+ int i;
+
+ t_transform = 0;
+ t_dcrypto = 0;
+ t_sw = 0;
+ t_hw = 0;
+
+ START_PROFILE(t_sw)
+ SHA512_init(&sw);
+ for (i = 0; i < msg_loops; ++i) {
+ HASH_update(&sw, msg, msg_len);
+ }
+ sw_digest = HASH_final(&sw);
+ END_PROFILE(t_sw)
+
+ START_PROFILE(t_hw)
+ DCRYPTO_SHA512_init(&hw);
+ for (i = 0; i < msg_loops; ++i) {
+ HASH_update(&hw, msg, msg_len);
+ }
+ hw_digest = HASH_final(&hw);
+ END_PROFILE(t_hw)
+
+ ccprintf("sw(%u):\n", t_sw);
+ for (i = 0; i < 64; ++i)
+ ccprintf("%02x", sw_digest[i]);
+ ccprintf("\n");
+
+ ccprintf("hw(%u/%u/%u):\n", t_hw, t_transform, t_dcrypto);
+ for (i = 0; i < 64; ++i)
+ ccprintf("%02x", hw_digest[i]);
+ ccprintf("\n");
+
+ task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0);
+}
+DECLARE_DEFERRED(run_sha512_cmd);
+
+static int cmd_sha512_bench(int argc, char *argv[])
+{
+ const int max_time = 1000000;
+ uint32_t events;
+
+ memset(msg, '!', sizeof(msg));
+
+ if (argc > 1) {
+ msg_loops = 1;
+ msg_len = strlen(argv[1]);
+ memcpy(msg, argv[1], msg_len);
+ } else {
+ msg_loops = 64; // benchmark 64K
+ msg_len = sizeof(msg);
+ }
+
+ hook_call_deferred(&run_sha512_cmd_data, 0);
+ ccprintf("Will wait up to %d ms\n", (max_time + 500) / 1000);
+
+ events = task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), max_time);
+ if (!(events & TASK_EVENT_CUSTOM_BIT(0))) {
+ ccprintf("Timed out, you might want to reboot...\n");
+ return EC_ERROR_TIMEOUT;
+ }
+
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(sha512_bench, cmd_sha512_bench, NULL, NULL);
+
+static void run_sha512_test(void)
+{
+ int i;
+
+ for (i = 0; i < 129; ++i) {
+ memset(msg, i, i);
+
+ SHA512_init(&sw);
+ HASH_update(&sw, msg, i);
+ sw_digest = HASH_final(&sw);
+
+ DCRYPTO_SHA512_init(&hw);
+ HASH_update(&hw, msg, i);
+ hw_digest = HASH_final(&hw);
+
+ if (memcmp(sw_digest, hw_digest, SHA512_DIGEST_SIZE) != 0) {
+ ccprintf("sha512 self-test fail at %d!\n", i);
+ cflush();
+ }
+ }
+
+ ccprintf("sha512 self-test PASS!\n");
+ task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0);
+}
+DECLARE_DEFERRED(run_sha512_test);
+
+static int cmd_sha512_test(int argc, char *argv[])
+{
+ hook_call_deferred(&run_sha512_test_data, 0);
+ task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), 1000000);
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(sha512_test, cmd_sha512_test, NULL, NULL);
+
+#endif /* CRYPTO_TEST_SETUP */
diff --git a/chip/g/dcrypto/gcm.c b/chip/g/dcrypto/gcm.c
new file mode 100644
index 0000000000..cd035bbd54
--- /dev/null
+++ b/chip/g/dcrypto/gcm.c
@@ -0,0 +1,345 @@
+/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+
+#include "endian.h"
+
+#include "cryptoc/util.h"
+
+static void gcm_mul(uint32_t *counter)
+{
+ int i;
+ volatile uint32_t *p;
+
+ /* Set HASH to zero. */
+ p = GREG32_ADDR(KEYMGR, GCM_HASH_IN0);
+ for (i = 0; i < 4; i++)
+ *p++ = 0;
+
+ /* Initialize GMAC. */
+ p = GREG32_ADDR(KEYMGR, GCM_MAC0);
+ for (i = 0; i < 4; i++)
+ *p++ = counter[i];
+
+ /* Crank GMAC. */
+ GREG32(KEYMGR, GCM_DO_ACC) = 1;
+
+ /* Read GMAC. */
+ p = GREG32_ADDR(KEYMGR, GCM_MAC0);
+ for (i = 0; i < 4; i++)
+ counter[i] = *p++;
+
+ /* Reset GMAC. */
+ p = GREG32_ADDR(KEYMGR, GCM_MAC0);
+ for (i = 0; i < 4; ++i)
+ *p++ = 0;
+}
+
+static void gcm_init_iv(
+ const uint8_t *iv, uint32_t iv_len, uint32_t *counter)
+{
+
+ if (iv_len == 12) {
+ memcpy(counter, iv, 12);
+ counter[3] = BIT(24);
+ } else {
+ size_t i;
+ uint32_t len = iv_len;
+ uint64_t len0 = len;
+ uint8_t *ctr = (uint8_t *) counter;
+
+ memset(ctr, 0, 16);
+ while (len >= 16) {
+ for (i = 0; i < 16; ++i)
+ ctr[i] ^= iv[i];
+
+ gcm_mul(counter);
+ iv += 16;
+ len -= 16;
+ }
+ if (len) {
+ for (i = 0; i < len; ++i)
+ ctr[i] ^= iv[i];
+
+ gcm_mul(counter);
+ }
+ len0 <<= 3;
+ ctr[8] ^= (uint8_t)(len0 >> 56);
+ ctr[9] ^= (uint8_t)(len0 >> 48);
+ ctr[10] ^= (uint8_t)(len0 >> 40);
+ ctr[11] ^= (uint8_t)(len0 >> 32);
+ ctr[12] ^= (uint8_t)(len0 >> 24);
+ ctr[13] ^= (uint8_t)(len0 >> 16);
+ ctr[14] ^= (uint8_t)(len0 >> 8);
+ ctr[15] ^= (uint8_t)(len0);
+
+ gcm_mul(counter);
+ }
+}
+
+void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits,
+ const uint8_t *key, const uint8_t *iv, size_t iv_len)
+{
+ int i;
+ const uint32_t zero[4] = {0, 0, 0, 0};
+ uint32_t H[4];
+ uint32_t counter[4];
+
+ memset(ctx, 0, sizeof(struct GCM_CTX));
+
+ /* Initialize AES engine in CTR mode, and set the counter to 0. */
+ DCRYPTO_aes_init(key, key_bits, (const uint8_t *) zero,
+ CIPHER_MODE_CTR, ENCRYPT_MODE);
+ /* Set H to AES(ZERO). */
+ DCRYPTO_aes_block((const uint8_t *) zero, (uint8_t *) H);
+
+ /* Initialize the GMAC accumulator to ZERO. */
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_GCM_MAC(i) = zero[i];
+
+ /* Initialize H. */
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_GCM_H(i) = H[i];
+
+ /* Map the IV to a 128-bit counter. */
+ gcm_init_iv(iv, iv_len, counter);
+
+ /* Re-initialize the IV counter. */
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_AES_CTR(i) = counter[i];
+
+ /* Calculate Ej0: encrypt IV counter XOR ZERO. */
+ DCRYPTO_aes_block((const uint8_t *) zero, ctx->Ej0.c);
+}
+
+static void gcm_aad_block(const struct GCM_CTX *ctx, const uint32_t *block)
+{
+ int i;
+ const struct access_helper *p = (struct access_helper *) block;
+
+ if (ctx->aad_len == 0 && ctx->count <= 16) {
+ /* Update GMAC. */
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_GCM_MAC(i) = p[i].udata;
+ } else {
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_GCM_HASH_IN(i) = p[i].udata;
+
+ /* Crank GMAC. */
+ GREG32(KEYMGR, GCM_DO_ACC) = 1;
+ }
+}
+
+void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len)
+{
+ uint32_t block[4];
+
+ while (len) {
+ size_t count;
+
+ memset(block, 0, sizeof(block));
+ count = MIN(16, len);
+ memcpy(block, aad_data, count);
+
+ gcm_aad_block(ctx, block);
+ ctx->aad_len += count;
+
+ len -= count;
+ aad_data += count;
+ }
+
+ always_memset(block, 0, sizeof(block));
+}
+
+int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len,
+ const uint8_t *in, size_t in_len)
+{
+ uint8_t *outp = out;
+
+ if (out_len < (in_len & ~0x0F) + ((in_len & 0x0F) ? 16 : 0))
+ return -1;
+
+ /* Process a previous partial block, if any. */
+ if (ctx->remainder) {
+ size_t count = MIN(in_len, 16 - ctx->remainder);
+
+ memcpy(ctx->block.c + ctx->remainder, in, count);
+ ctx->remainder += count;
+ if (ctx->remainder < 16)
+ return 0;
+
+ DCRYPTO_aes_block(ctx->block.c, outp);
+ ctx->count += 16;
+ gcm_aad_block(ctx, (uint32_t *) outp);
+ ctx->remainder = 0;
+ in += count;
+ in_len -= count;
+ outp += 16;
+ }
+
+ while (in_len >= 16) {
+ DCRYPTO_aes_block(in, outp);
+ ctx->count += 16;
+
+ gcm_aad_block(ctx, (uint32_t *) outp);
+
+ in_len -= 16;
+ in += 16;
+ outp += 16;
+ }
+
+ if (in_len) {
+ memcpy(ctx->block.c, in, in_len);
+ ctx->remainder = in_len;
+ }
+
+ return outp - out;
+}
+
+int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx, uint8_t *out, size_t out_len)
+{
+ if (out_len < ctx->remainder)
+ return -1;
+
+ if (ctx->remainder) {
+ size_t remainder = ctx->remainder;
+ uint8_t out_block[16];
+
+ DCRYPTO_aes_block(ctx->block.c, out_block);
+ ctx->count += ctx->remainder;
+ memcpy(out, out_block, ctx->remainder);
+
+ memset(out_block + ctx->remainder, 0, 16 - ctx->remainder);
+ gcm_aad_block(ctx, (uint32_t *) out_block);
+ ctx->remainder = 0;
+ return remainder;
+ }
+
+ return 0;
+}
+
+int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len,
+ const uint8_t *in, size_t in_len)
+{
+ uint8_t *outp = out;
+
+ if (out_len < (in_len & ~0x0F) + ((in_len & 0x0F) ? 16 : 0))
+ return -1;
+
+ if (ctx->remainder) {
+ size_t count = MIN(in_len, 16 - ctx->remainder);
+
+ memcpy(ctx->block.c + ctx->remainder, in, count);
+ ctx->remainder += count;
+
+ if (ctx->remainder < 16)
+ return 0;
+
+ DCRYPTO_aes_block(ctx->block.c, outp);
+ ctx->remainder = 0;
+ ctx->count += 16;
+ gcm_aad_block(ctx, ctx->block.d);
+ in += count;
+ in_len -= count;
+ outp += count;
+ }
+
+ while (in_len >= 16) {
+ DCRYPTO_aes_block(in, outp);
+ ctx->count += 16;
+ gcm_aad_block(ctx, (uint32_t *) in);
+ in += 16;
+ in_len -= 16;
+ outp += 16;
+ }
+
+ if (in_len) {
+ memcpy(ctx->block.c, in, in_len);
+ ctx->remainder = in_len;
+ }
+
+ return outp - out;
+}
+
+int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx,
+ uint8_t *out, size_t out_len)
+{
+ if (out_len < ctx->remainder)
+ return -1;
+
+ if (ctx->remainder) {
+ size_t remainder = ctx->remainder;
+ uint8_t out_block[16];
+
+ DCRYPTO_aes_block(ctx->block.c, out_block);
+ ctx->count += ctx->remainder;
+ memcpy(out, out_block, ctx->remainder);
+
+ memset(ctx->block.c + ctx->remainder, 0, 16 - ctx->remainder);
+ gcm_aad_block(ctx, ctx->block.d);
+ ctx->remainder = 0;
+ return remainder;
+ }
+
+ return 0;
+}
+
+static void dcrypto_gcm_len_vector(
+ const struct GCM_CTX *ctx, void *len_vector) {
+ uint64_t aad_be;
+ uint64_t count_be;
+
+ /* Serialize counters to bit-count (big-endian). */
+ aad_be = ctx->aad_len * 8;
+ aad_be = htobe64(aad_be);
+ count_be = ctx->count * 8;
+ count_be = htobe64(count_be);
+
+ memcpy(len_vector, &aad_be, 8);
+ memcpy(((uint8_t *)len_vector) + 8, &count_be, 8);
+}
+
+static void dcrypto_gcm_tag(const struct GCM_CTX *ctx,
+ const uint32_t *len_vector, uint32_t *tag) {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_GCM_HASH_IN(i) = len_vector[i];
+
+ /* Crank GMAC. */
+ GREG32(KEYMGR, GCM_DO_ACC) = 1;
+
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_GCM_HASH_IN(i) = ctx->Ej0.d[i];
+
+ /* Crank GMAC. */
+ GREG32(KEYMGR, GCM_DO_ACC) = 1;
+
+ /* Read tag. */
+ for (i = 0; i < 4; i++)
+ tag[i] = GR_KEYMGR_GCM_MAC(i);
+}
+
+int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len)
+{
+ uint32_t len_vector[4];
+ uint32_t local_tag[4];
+ size_t count = MIN(tag_len, sizeof(local_tag));
+
+ dcrypto_gcm_len_vector(ctx, len_vector);
+ dcrypto_gcm_tag(ctx, len_vector, local_tag);
+
+ memcpy(tag, local_tag, count);
+ return count;
+}
+
+void DCRYPTO_gcm_finish(struct GCM_CTX *ctx)
+{
+ always_memset(ctx, 0, sizeof(struct GCM_CTX));
+ GREG32(KEYMGR, AES_WIPE_SECRETS) = 1;
+}
diff --git a/chip/g/dcrypto/hkdf.c b/chip/g/dcrypto/hkdf.c
new file mode 100644
index 0000000000..3afdc6b2eb
--- /dev/null
+++ b/chip/g/dcrypto/hkdf.c
@@ -0,0 +1,83 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+/* An implementation of HKDF as per RFC 5869. */
+
+#include "dcrypto.h"
+#include "internal.h"
+
+#include "cryptoc/sha256.h"
+#include "cryptoc/util.h"
+
+static int hkdf_extract(uint8_t *PRK, const uint8_t *salt, size_t salt_len,
+ const uint8_t *IKM, size_t IKM_len)
+{
+ LITE_HMAC_CTX ctx;
+
+ if (PRK == NULL)
+ return 0;
+ if (salt == NULL && salt_len > 0)
+ return 0;
+ if (IKM == NULL && IKM_len > 0)
+ return 0;
+
+ DCRYPTO_HMAC_SHA256_init(&ctx, salt, salt_len);
+ HASH_update(&ctx.hash, IKM, IKM_len);
+ memcpy(PRK, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE);
+ return 1;
+}
+
+static int hkdf_expand(uint8_t *OKM, size_t OKM_len, const uint8_t *PRK,
+ const uint8_t *info, size_t info_len)
+{
+ uint8_t count = 1;
+ const uint8_t *T = OKM;
+ size_t T_len = 0;
+ uint32_t num_blocks = (OKM_len / SHA256_DIGEST_SIZE) +
+ (OKM_len % SHA256_DIGEST_SIZE ? 1 : 0);
+
+ if (OKM == NULL || OKM_len == 0)
+ return 0;
+ if (PRK == NULL)
+ return 0;
+ if (info == NULL && info_len > 0)
+ return 0;
+ if (num_blocks > 255)
+ return 0;
+
+ while (OKM_len > 0) {
+ LITE_HMAC_CTX ctx;
+ const size_t block_size = OKM_len < SHA256_DIGEST_SIZE ?
+ OKM_len : SHA256_DIGEST_SIZE;
+
+ DCRYPTO_HMAC_SHA256_init(&ctx, PRK, SHA256_DIGEST_SIZE);
+ HASH_update(&ctx.hash, T, T_len);
+ HASH_update(&ctx.hash, info, info_len);
+ HASH_update(&ctx.hash, &count, sizeof(count));
+ memcpy(OKM, DCRYPTO_HMAC_final(&ctx), block_size);
+
+ T += T_len;
+ T_len = SHA256_DIGEST_SIZE;
+ count += 1;
+ OKM += block_size;
+ OKM_len -= block_size;
+ }
+ return 1;
+}
+
+int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len,
+ const uint8_t *salt, size_t salt_len,
+ const uint8_t *IKM, size_t IKM_len,
+ const uint8_t *info, size_t info_len)
+{
+ int result;
+ uint8_t PRK[SHA256_DIGEST_SIZE];
+
+ if (!hkdf_extract(PRK, salt, salt_len, IKM, IKM_len))
+ return 0;
+
+ result = hkdf_expand(OKM, OKM_len, PRK, info, info_len);
+ always_memset(PRK, 0, sizeof(PRK));
+ return result;
+}
diff --git a/chip/g/dcrypto/hmac.c b/chip/g/dcrypto/hmac.c
new file mode 100644
index 0000000000..7cc45a03ba
--- /dev/null
+++ b/chip/g/dcrypto/hmac.c
@@ -0,0 +1,63 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "internal.h"
+#include "dcrypto.h"
+
+#include <stdint.h>
+
+#include "cryptoc/sha256.h"
+#include "cryptoc/util.h"
+
+/* TODO(sukhomlinov): add support for hardware hmac. */
+static void hmac_sha256_init(LITE_HMAC_CTX *ctx, const void *key,
+ unsigned int len)
+{
+ unsigned int i;
+
+ BUILD_ASSERT(sizeof(ctx->opad) >= SHA256_BLOCK_SIZE);
+
+ memset(&ctx->opad[0], 0, SHA256_BLOCK_SIZE);
+
+ if (len > SHA256_BLOCK_SIZE) {
+ DCRYPTO_SHA256_init(&ctx->hash, 0);
+ HASH_update(&ctx->hash, key, len);
+ memcpy(&ctx->opad[0], HASH_final(&ctx->hash),
+ HASH_size(&ctx->hash));
+ } else {
+ memcpy(&ctx->opad[0], key, len);
+ }
+
+ for (i = 0; i < SHA256_BLOCK_SIZE; ++i)
+ ctx->opad[i] ^= 0x36;
+
+ DCRYPTO_SHA256_init(&ctx->hash, 0);
+ /* hash ipad */
+ HASH_update(&ctx->hash, ctx->opad, SHA256_BLOCK_SIZE);
+
+ for (i = 0; i < SHA256_BLOCK_SIZE; ++i)
+ ctx->opad[i] ^= (0x36 ^ 0x5c);
+}
+
+void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key,
+ unsigned int len)
+{
+ hmac_sha256_init(ctx, key, len);
+}
+
+const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx)
+{
+ uint8_t digest[SHA256_DIGEST_SIZE]; /* up to SHA256 */
+
+ memcpy(digest, HASH_final(&ctx->hash),
+ (HASH_size(&ctx->hash) <= sizeof(digest) ?
+ HASH_size(&ctx->hash) :
+ sizeof(digest)));
+ DCRYPTO_SHA256_init(&ctx->hash, 0);
+ HASH_update(&ctx->hash, ctx->opad, SHA256_BLOCK_SIZE);
+ HASH_update(&ctx->hash, digest, HASH_size(&ctx->hash));
+ always_memset(&ctx->opad[0], 0, SHA256_BLOCK_SIZE); /* wipe key */
+ return HASH_final(&ctx->hash);
+}
diff --git a/chip/g/dcrypto/hmac_drbg.c b/chip/g/dcrypto/hmac_drbg.c
new file mode 100644
index 0000000000..2ca20e03ff
--- /dev/null
+++ b/chip/g/dcrypto/hmac_drbg.c
@@ -0,0 +1,478 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "console.h"
+#include "cryptoc/util.h"
+#include "dcrypto.h"
+#include "extension.h"
+#include "internal.h"
+#include "trng.h"
+
+/* HMAC_DRBG flow in NIST SP 800-90Ar1, 10.2, RFC 6979
+ */
+/* V = HMAC(K, V) */
+static void update_v(const uint32_t *k, uint32_t *v)
+{
+ LITE_HMAC_CTX ctx;
+
+ DCRYPTO_HMAC_SHA256_init(&ctx, k, SHA256_DIGEST_SIZE);
+ HASH_update(&ctx.hash, v, SHA256_DIGEST_SIZE);
+ memcpy(v, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE);
+}
+
+/* K = HMAC(K, V || tag || p0 || p1 || p2) */
+/* V = HMAC(K, V) */
+static void update_kv(uint32_t *k, uint32_t *v, uint8_t tag,
+ const void *p0, size_t p0_len,
+ const void *p1, size_t p1_len,
+ const void *p2, size_t p2_len)
+{
+ LITE_HMAC_CTX ctx;
+
+ DCRYPTO_HMAC_SHA256_init(&ctx, k, SHA256_DIGEST_SIZE);
+ HASH_update(&ctx.hash, v, SHA256_DIGEST_SIZE);
+ HASH_update(&ctx.hash, &tag, 1);
+ HASH_update(&ctx.hash, p0, p0_len);
+ HASH_update(&ctx.hash, p1, p1_len);
+ HASH_update(&ctx.hash, p2, p2_len);
+ memcpy(k, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE);
+
+ update_v(k, v);
+}
+
+static void update(struct drbg_ctx *ctx,
+ const void *p0, size_t p0_len,
+ const void *p1, size_t p1_len,
+ const void *p2, size_t p2_len)
+{
+ /* K = HMAC(K, V || 0x00 || provided_data) */
+ /* V = HMAC(K, V) */
+ update_kv(ctx->k, ctx->v, 0x00,
+ p0, p0_len, p1, p1_len, p2, p2_len);
+
+ /* If no provided_data, stop. */
+ if (p0_len + p1_len + p2_len == 0)
+ return;
+
+ /* K = HMAC(K, V || 0x01 || provided_data) */
+ /* V = HMAC(K, V) */
+ update_kv(ctx->k, ctx->v,
+ 0x01,
+ p0, p0_len, p1, p1_len, p2, p2_len);
+}
+
+void hmac_drbg_init(struct drbg_ctx *ctx,
+ const void *p0, size_t p0_len,
+ const void *p1, size_t p1_len,
+ const void *p2, size_t p2_len)
+{
+ /* K = 0x00 0x00 0x00 ... 0x00 */
+ always_memset(ctx->k, 0x00, sizeof(ctx->k));
+ /* V = 0x01 0x01 0x01 ... 0x01 */
+ always_memset(ctx->v, 0x01, sizeof(ctx->v));
+
+ update(ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+
+ ctx->reseed_counter = 1;
+}
+
+void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key,
+ const p256_int *message)
+{
+ hmac_drbg_init(ctx,
+ key->a, sizeof(key->a),
+ message->a, sizeof(message->a),
+ NULL, 0);
+}
+
+void hmac_drbg_init_rand(struct drbg_ctx *ctx, size_t nbits)
+{
+ int i;
+ uint32_t x[(nbits + 31) / 32];
+
+ for (i = 0; i < ARRAY_SIZE(x); ++i)
+ x[i] = rand();
+
+ hmac_drbg_init(ctx, &x, sizeof(x), NULL, 0, NULL, 0);
+}
+
+void hmac_drbg_reseed(struct drbg_ctx *ctx,
+ const void *p0, size_t p0_len,
+ const void *p1, size_t p1_len,
+ const void *p2, size_t p2_len)
+{
+ update(ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ ctx->reseed_counter = 1;
+}
+
+enum hmac_result hmac_drbg_generate(struct drbg_ctx *ctx,
+ void *out, size_t out_len,
+ const void *input, size_t input_len)
+{
+ /* According to NIST SP 800-90A rev 1 B.2
+ * Maximum number of bits per request = 7500 bits
+ * Reseed_interval = 10 000 requests.
+ */
+ if (out_len > 7500 / 8)
+ return HMAC_DRBG_INVALID_PARAM;
+
+ if (ctx->reseed_counter++ >= 10000)
+ return HMAC_DRBG_RESEED_REQUIRED;
+
+ if (input_len)
+ update(ctx, input, input_len, NULL, 0, NULL, 0);
+
+ while (out_len) {
+ size_t n = out_len > sizeof(ctx->v) ? sizeof(ctx->v) : out_len;
+
+ update_v(ctx->k, ctx->v);
+
+ memcpy(out, ctx->v, n);
+ out += n;
+ out_len -= n;
+ }
+
+ update(ctx, input, input_len, NULL, 0, NULL, 0);
+
+ return HMAC_DRBG_SUCCESS;
+}
+
+enum hmac_result hmac_drbg_generate_p256(struct drbg_ctx *ctx, p256_int *k_out)
+{
+ return hmac_drbg_generate(ctx, k_out->a, sizeof(k_out->a), NULL, 0);
+}
+
+void drbg_exit(struct drbg_ctx *ctx)
+{
+ always_memset(ctx->k, 0x00, sizeof(ctx->k));
+ always_memset(ctx->v, 0x00, sizeof(ctx->v));
+}
+
+#ifdef CRYPTO_TEST_SETUP
+
+/*
+ * from the RFC 6979 A.2.5 example:
+ *
+ * curve: NIST P-256
+ *
+ * q = FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
+ * (qlen = 256 bits)
+ *
+ * private key:
+ * x = C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721
+ *
+ * public key: U = xG
+ * Ux = 60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6
+ * Uy = 7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299
+ *
+ * Signature:
+ * With SHA-256, message = "sample":
+ * k = A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60
+ * r = EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716
+ * s = F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8
+ */
+static int cmd_rfc6979(int argc, char **argv)
+{
+ static p256_int h1;
+ static p256_int k;
+ static const char message[] = "sample";
+ static struct drbg_ctx drbg;
+
+ static HASH_CTX ctx;
+ int result;
+ static const uint8_t priv_from_rfc[] = {
+ 0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16,
+ 0x6B, 0x5C, 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93,
+ 0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12,
+ 0x7B, 0x8A, 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21
+ };
+ static const uint8_t k_from_rfc[] = {
+ 0xA6, 0xE3, 0xC5, 0x7D, 0xD0, 0x1A, 0xBE, 0x90,
+ 0x08, 0x65, 0x38, 0x39, 0x83, 0x55, 0xDD, 0x4C,
+ 0x3B, 0x17, 0xAA, 0x87, 0x33, 0x82, 0xB0, 0xF2,
+ 0x4D, 0x61, 0x29, 0x49, 0x3D, 0x8A, 0xAD, 0x60
+ };
+ p256_int *x = (p256_int *)priv_from_rfc;
+ p256_int *reference_k = (p256_int *)k_from_rfc;
+
+ /* h1 = H(m) */
+ DCRYPTO_SHA256_init(&ctx, 1);
+ HASH_update(&ctx, message, sizeof(message) - 1);
+ memcpy(&h1, HASH_final(&ctx), SHA256_DIGEST_SIZE);
+
+ hmac_drbg_init_rfc6979(&drbg, x, &h1);
+ do {
+ hmac_drbg_generate_p256(&drbg, &k);
+ ccprintf("K = %ph\n", HEX_BUF(&k, 32));
+ } while (p256_cmp(&SECP256r1_nMin2, &k) < 0);
+ drbg_exit(&drbg);
+ result = p256_cmp(&k, reference_k);
+ ccprintf("K generation: %s\n", result ? "FAIL" : "PASS");
+
+ return result ? EC_ERROR_INVAL : EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(rfc6979, cmd_rfc6979, NULL, NULL);
+
+/*
+ * Test vectors from the NIST Cryptographic Algorithm Validation Program.
+ *
+ * These are the first two examples from the SHA-256, without prediction
+ * resistance, and with reseed supported.
+ */
+#define HMAC_TEST_COUNT 2
+static int cmd_hmac_drbg(int argc, char **argv)
+{
+ static struct drbg_ctx ctx;
+
+ static const uint8_t init_entropy[HMAC_TEST_COUNT][32] = {
+ {
+ 0x06, 0x03, 0x2C, 0xD5, 0xEE, 0xD3, 0x3F, 0x39, 0x26,
+ 0x5F, 0x49, 0xEC, 0xB1, 0x42, 0xC5, 0x11, 0xDA, 0x9A,
+ 0xFF, 0x2A, 0xF7, 0x12, 0x03, 0xBF, 0xFA, 0xF3, 0x4A,
+ 0x9C, 0xA5, 0xBD, 0x9C, 0x0D
+ },
+ {
+ 0xAA, 0xDC, 0xF3, 0x37, 0x78, 0x8B, 0xB8, 0xAC, 0x01,
+ 0x97, 0x66, 0x40, 0x72, 0x6B, 0xC5, 0x16, 0x35, 0xD4,
+ 0x17, 0x77, 0x7F, 0xE6, 0x93, 0x9E, 0xDE, 0xD9, 0xCC,
+ 0xC8, 0xA3, 0x78, 0xC7, 0x6A
+ },
+ };
+
+ static const uint8_t init_nonce[HMAC_TEST_COUNT][16] = {
+ {
+ 0x0E, 0x66, 0xF7, 0x1E, 0xDC, 0x43, 0xE4, 0x2A, 0x45,
+ 0xAD, 0x3C, 0x6F, 0xC6, 0xCD, 0xC4, 0xDF
+ },
+ {
+ 0x9C, 0xCC, 0x9D, 0x80, 0xC8, 0x9A, 0xC5, 0x5A, 0x8C,
+ 0xFE, 0x0F, 0x99, 0x94, 0x2F, 0x5A, 0x4D
+ },
+ };
+
+ static const uint8_t reseed_entropy[HMAC_TEST_COUNT][32] = {
+ {
+ 0x01, 0x92, 0x0A, 0x4E, 0x66, 0x9E, 0xD3, 0xA8, 0x5A,
+ 0xE8, 0xA3, 0x3B, 0x35, 0xA7, 0x4A, 0xD7, 0xFB, 0x2A,
+ 0x6B, 0xB4, 0xCF, 0x39, 0x5C, 0xE0, 0x03, 0x34, 0xA9,
+ 0xC9, 0xA5, 0xA5, 0xD5, 0x52
+ },
+ {
+ 0x03, 0xA5, 0x77, 0x92, 0x54, 0x7E, 0x0C, 0x98, 0xEA,
+ 0x17, 0x76, 0xE4, 0xBA, 0x80, 0xC0, 0x07, 0x34, 0x62,
+ 0x96, 0xA5, 0x6A, 0x27, 0x0A, 0x35, 0xFD, 0x9E, 0xA2,
+ 0x84, 0x5C, 0x7E, 0x81, 0xE2
+ }
+ };
+
+ static const uint8_t expected_output[HMAC_TEST_COUNT][128] = {
+ {
+ 0x76, 0xFC, 0x79, 0xFE, 0x9B, 0x50, 0xBE, 0xCC, 0xC9,
+ 0x91, 0xA1, 0x1B, 0x56, 0x35, 0x78, 0x3A, 0x83, 0x53,
+ 0x6A, 0xDD, 0x03, 0xC1, 0x57, 0xFB, 0x30, 0x64, 0x5E,
+ 0x61, 0x1C, 0x28, 0x98, 0xBB, 0x2B, 0x1B, 0xC2, 0x15,
+ 0x00, 0x02, 0x09, 0x20, 0x8C, 0xD5, 0x06, 0xCB, 0x28,
+ 0xDA, 0x2A, 0x51, 0xBD, 0xB0, 0x38, 0x26, 0xAA, 0xF2,
+ 0xBD, 0x23, 0x35, 0xD5, 0x76, 0xD5, 0x19, 0x16, 0x08,
+ 0x42, 0xE7, 0x15, 0x8A, 0xD0, 0x94, 0x9D, 0x1A, 0x9E,
+ 0xC3, 0xE6, 0x6E, 0xA1, 0xB1, 0xA0, 0x64, 0xB0, 0x05,
+ 0xDE, 0x91, 0x4E, 0xAC, 0x2E, 0x9D, 0x4F, 0x2D, 0x72,
+ 0xA8, 0x61, 0x6A, 0x80, 0x22, 0x54, 0x22, 0x91, 0x82,
+ 0x50, 0xFF, 0x66, 0xA4, 0x1B, 0xD2, 0xF8, 0x64, 0xA6,
+ 0xA3, 0x8C, 0xC5, 0xB6, 0x49, 0x9D, 0xC4, 0x3F, 0x7F,
+ 0x2B, 0xD0, 0x9E, 0x1E, 0x0F, 0x8F, 0x58, 0x85, 0x93,
+ 0x51, 0x24
+ },
+ {
+ 0x17, 0xD0, 0x9F, 0x40, 0xA4, 0x37, 0x71, 0xF4, 0xA2,
+ 0xF0, 0xDB, 0x32, 0x7D, 0xF6, 0x37, 0xDE, 0xA9, 0x72,
+ 0xBF, 0xFF, 0x30, 0xC9, 0x8E, 0xBC, 0x88, 0x42, 0xDC,
+ 0x7A, 0x9E, 0x3D, 0x68, 0x1C, 0x61, 0x90, 0x2F, 0x71,
+ 0xBF, 0xFA, 0xF5, 0x09, 0x36, 0x07, 0xFB, 0xFB, 0xA9,
+ 0x67, 0x4A, 0x70, 0xD0, 0x48, 0xE5, 0x62, 0xEE, 0x88,
+ 0xF0, 0x27, 0xF6, 0x30, 0xA7, 0x85, 0x22, 0xEC, 0x6F,
+ 0x70, 0x6B, 0xB4, 0x4A, 0xE1, 0x30, 0xE0, 0x5C, 0x8D,
+ 0x7E, 0xAC, 0x66, 0x8B, 0xF6, 0x98, 0x0D, 0x99, 0xB4,
+ 0xC0, 0x24, 0x29, 0x46, 0x45, 0x23, 0x99, 0xCB, 0x03,
+ 0x2C, 0xC6, 0xF9, 0xFD, 0x96, 0x28, 0x47, 0x09, 0xBD,
+ 0x2F, 0xA5, 0x65, 0xB9, 0xEB, 0x9F, 0x20, 0x04, 0xBE,
+ 0x6C, 0x9E, 0xA9, 0xFF, 0x91, 0x28, 0xC3, 0xF9, 0x3B,
+ 0x60, 0xDC, 0x30, 0xC5, 0xFC, 0x85, 0x87, 0xA1, 0x0D,
+ 0xE6, 0x8C
+ }
+ };
+
+ static uint8_t output[128];
+
+ int i, cmp_result;
+
+ for (i = 0; i < HMAC_TEST_COUNT; i++) {
+ hmac_drbg_init(&ctx,
+ init_entropy[i], sizeof(init_entropy[i]),
+ init_nonce[i], sizeof(init_nonce[i]),
+ NULL, 0);
+
+ hmac_drbg_reseed(&ctx,
+ reseed_entropy[i], sizeof(reseed_entropy[i]),
+ NULL, 0,
+ NULL, 0);
+
+ hmac_drbg_generate(&ctx,
+ output, sizeof(output),
+ NULL, 0);
+
+ hmac_drbg_generate(&ctx,
+ output, sizeof(output),
+ NULL, 0);
+
+ cmp_result = memcmp(output, expected_output[i], sizeof(output));
+ ccprintf("HMAC DRBG generate test %d, %s\n",
+ i, cmp_result ? "failed" : "passed");
+ }
+
+ return 0;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg, cmd_hmac_drbg, NULL, NULL);
+
+/*
+ * Sanity check to exercise random initialization.
+ */
+static int cmd_hmac_drbg_rand(int argc, char **argv)
+{
+ static struct drbg_ctx ctx;
+ static uint8_t output[128];
+
+ int i;
+
+ hmac_drbg_init_rand(&ctx, 256);
+
+ hmac_drbg_generate(&ctx, output, sizeof(output), NULL, 0);
+
+ ccprintf("Randomly initialized HMAC DRBG, 1024 bit output: ");
+
+ for (i = 0; i < sizeof(output); i++)
+ ccprintf("%x", output[i]);
+ ccprintf("\n");
+
+ return 0;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg_rand, cmd_hmac_drbg_rand, NULL, NULL);
+
+enum drbg_command {
+ DRBG_INIT = 0,
+ DRBG_RESEED = 1,
+ DRBG_GENERATE = 2
+};
+
+/*
+ * DRBG_TEST command structure:
+ *
+ * field | size | note
+ * ==========================================================================
+ * mode | 1 | 0 - DRBG_INIT, 1 - DRBG_RESEED, 2 - DRBG_GENERATE
+ * p0_len | 2 | size of first input in bytes
+ * p0 | p0_len | entropy for INIT & SEED, input for GENERATE
+ * p1_len | 2 | size of second input in bytes (for INIT & RESEED)
+ * | | or size of expected output for GENERATE
+ * p1 | p1_len | nonce for INIT & SEED
+ * p2_len | 2 | size of third input in bytes for DRBG_INIT
+ * p2 | p2_len | personalization for INIT & SEED
+ *
+ * DRBG_INIT (entropy, nonce, perso)
+ * DRBG_RESEED (entropy, additional input 1, additional input 2)
+ * DRBG_INIT and DRBG_RESEED returns empty response
+ * DRBG_GENERATE (p0_len, p0 - additional input 1, p1_len - size of output)
+ * DRBG_GENERATE returns p1_len bytes of generated data
+ * (up to a maximum of 128 bytes)
+ */
+static enum vendor_cmd_rc drbg_test(enum vendor_cmd_cc code, void *buf,
+ size_t input_size, size_t *response_size)
+{
+ static struct drbg_ctx drbg_ctx;
+ static uint8_t output[512];
+ uint8_t *p0 = NULL, *p1 = NULL, *p2 = NULL;
+ uint16_t p0_len = 0, p1_len = 0, p2_len = 0;
+ uint8_t *cmd = (uint8_t *)buf;
+ size_t max_out_len = *response_size;
+ enum drbg_command drbg_op;
+
+ *response_size = 0;
+ /* there is always op + first parameter, even if zero length */
+ if (input_size < sizeof(p0_len) + 1)
+ return VENDOR_RC_BOGUS_ARGS;
+ drbg_op = *cmd++;
+ p0_len = *cmd++;
+ p0_len = p0_len * 256 + *cmd++;
+ input_size -= 3;
+ if (p0_len > input_size)
+ return VENDOR_RC_BOGUS_ARGS;
+ input_size -= p0_len;
+ if (p0_len)
+ p0 = cmd;
+ cmd += p0_len;
+
+ /* there should be enough space for p1_len */
+ if (input_size && input_size < sizeof(p1_len))
+ return VENDOR_RC_BOGUS_ARGS;
+
+ /* DRBG_GENERATE should just have p1_len defined */
+ if (drbg_op == DRBG_GENERATE && input_size != sizeof(p1_len))
+ return VENDOR_RC_BOGUS_ARGS;
+
+ if (input_size) {
+ p1_len = *cmd++;
+ p1_len = p1_len * 256 + *cmd++;
+ input_size -= 2;
+
+ if (drbg_op != DRBG_GENERATE) {
+ if (p1_len > input_size)
+ return VENDOR_RC_BOGUS_ARGS;
+ input_size -= p1_len;
+ if (p1_len)
+ p1 = cmd;
+ cmd += p1_len;
+ }
+ }
+
+ if (input_size) {
+ if (drbg_op == DRBG_GENERATE)
+ return VENDOR_RC_BOGUS_ARGS;
+ p2_len = *cmd++;
+ p2_len = p2_len * 256 + *cmd++;
+ input_size -= 2;
+ if (p2_len > input_size)
+ return VENDOR_RC_BOGUS_ARGS;
+ if (p2_len)
+ p2 = cmd;
+ }
+
+ switch (drbg_op) {
+ case DRBG_INIT: {
+ hmac_drbg_init(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ break;
+ }
+ case DRBG_RESEED: {
+ hmac_drbg_reseed(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ break;
+ }
+ case DRBG_GENERATE: {
+ if (p1_len > sizeof(output) || max_out_len < p1_len)
+ return VENDOR_RC_BOGUS_ARGS;
+
+ hmac_drbg_generate(&drbg_ctx, output, p1_len, p0, p0_len);
+
+ memcpy(buf, output, p1_len);
+ *response_size = p1_len;
+ break;
+ }
+ default:
+ return VENDOR_RC_BOGUS_ARGS;
+ }
+
+ return VENDOR_RC_SUCCESS;
+}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_DRBG_TEST, drbg_test);
+
+#endif /* CRYPTO_TEST_SETUP */
diff --git a/chip/g/dcrypto/internal.h b/chip/g/dcrypto/internal.h
new file mode 100644
index 0000000000..1811426f2a
--- /dev/null
+++ b/chip/g/dcrypto/internal.h
@@ -0,0 +1,219 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __EC_CHIP_G_DCRYPTO_INTERNAL_H
+#define __EC_CHIP_G_DCRYPTO_INTERNAL_H
+
+#include <stddef.h>
+#include <string.h>
+
+#include "common.h"
+#include "util.h"
+
+#include "cryptoc/p256.h"
+#include "cryptoc/sha.h"
+#include "cryptoc/sha256.h"
+#include "cryptoc/sha384.h"
+#include "cryptoc/sha512.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SHA.
+ */
+#define CTRL_CTR_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define CTRL_ENABLE 1
+#define CTRL_ENCRYPT 1
+#define CTRL_NO_SOFT_RESET 0
+
+#define SHA_DIGEST_WORDS (SHA_DIGEST_SIZE / sizeof(uint32_t))
+#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / sizeof(uint32_t))
+
+#ifdef SHA512_SUPPORT
+#define SHA_DIGEST_MAX_BYTES SHA512_DIGEST_SIZE
+#else
+#define SHA_DIGEST_MAX_BYTES SHA256_DIGEST_SIZE
+#endif
+
+enum sha_mode {
+ SHA1_MODE = 0,
+ SHA256_MODE = 1
+};
+
+/*
+ * Use this structure to avoid alignment problems with input and output
+ * pointers.
+ */
+struct access_helper {
+ uint32_t udata;
+} __packed;
+
+#ifndef SECTION_IS_RO
+int dcrypto_grab_sha_hw(void);
+void dcrypto_release_sha_hw(void);
+#endif
+void dcrypto_sha_hash(enum sha_mode mode, const uint8_t *data,
+ uint32_t n, uint8_t *digest);
+void dcrypto_sha_init(enum sha_mode mode);
+void dcrypto_sha_update(struct HASH_CTX *unused,
+ const void *data, uint32_t n);
+void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest);
+
+/*
+ * BIGNUM.
+ */
+#define LITE_BN_BITS2 32
+#define LITE_BN_BYTES 4
+
+struct LITE_BIGNUM {
+ uint32_t dmax; /* Size of d, in 32-bit words. */
+ struct access_helper *d; /* Word array, little endian format ... */
+};
+
+#define BN_DIGIT(b, i) ((b)->d[(i)].udata)
+
+void bn_init(struct LITE_BIGNUM *bn, void *buf, size_t len);
+#define bn_size(b) ((b)->dmax * LITE_BN_BYTES)
+#define bn_words(b) ((b)->dmax)
+#define bn_bits(b) ((b)->dmax * LITE_BN_BITS2)
+int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b);
+int bn_check_topbit(const struct LITE_BIGNUM *N);
+int bn_modexp(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp,
+ const struct LITE_BIGNUM *N);
+int bn_modexp_word(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ uint32_t pubexp,
+ const struct LITE_BIGNUM *N);
+int bn_modexp_blinded(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp,
+ const struct LITE_BIGNUM *N,
+ uint32_t pubexp);
+uint32_t bn_add(struct LITE_BIGNUM *c,
+ const struct LITE_BIGNUM *a);
+uint32_t bn_sub(struct LITE_BIGNUM *c,
+ const struct LITE_BIGNUM *a);
+int bn_modinv_vartime(struct LITE_BIGNUM *r,
+ const struct LITE_BIGNUM *e,
+ const struct LITE_BIGNUM *MOD);
+int bn_is_bit_set(const struct LITE_BIGNUM *a, int n);
+
+/*
+ * Accelerated bn.
+ */
+int dcrypto_modexp(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp,
+ const struct LITE_BIGNUM *N);
+int dcrypto_modexp_word(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ uint32_t pubexp,
+ const struct LITE_BIGNUM *N);
+int dcrypto_modexp_blinded(struct LITE_BIGNUM *output,
+ const struct LITE_BIGNUM *input,
+ const struct LITE_BIGNUM *exp,
+ const struct LITE_BIGNUM *N,
+ uint32_t pubexp);
+
+struct drbg_ctx {
+ uint32_t k[SHA256_DIGEST_WORDS];
+ uint32_t v[SHA256_DIGEST_WORDS];
+ uint32_t reseed_counter;
+};
+
+/*
+ * NIST SP 800-90A HMAC DRBG.
+ */
+enum hmac_result {
+ HMAC_DRBG_SUCCESS = 0,
+ HMAC_DRBG_INVALID_PARAM = 1,
+ HMAC_DRBG_RESEED_REQUIRED = 2
+};
+
+/* Standard initialization. */
+void hmac_drbg_init(struct drbg_ctx *ctx,
+ const void *p0, size_t p0_len,
+ const void *p1, size_t p1_len,
+ const void *p2, size_t p2_len);
+/* Initialize for use as RFC6979 DRBG. */
+void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx,
+ const p256_int *key,
+ const p256_int *message);
+/* Initialize with at least nbits of random entropy. */
+void hmac_drbg_init_rand(struct drbg_ctx *ctx, size_t nbits);
+void hmac_drbg_reseed(struct drbg_ctx *ctx,
+ const void *p0, size_t p0_len,
+ const void *p1, size_t p1_len,
+ const void *p2, size_t p2_len);
+enum hmac_result hmac_drbg_generate(struct drbg_ctx *ctx, void *out,
+ size_t out_len, const void *input,
+ size_t input_len);
+/* Generate p256, with no additional input. */
+enum hmac_result hmac_drbg_generate_p256(struct drbg_ctx *ctx, p256_int *k_out);
+void drbg_exit(struct drbg_ctx *ctx);
+
+/*
+ * Accelerated p256. FIPS PUB 186-4
+ */
+int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
+ const p256_int *message, p256_int *r, p256_int *s)
+ __attribute__((warn_unused_result));
+int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y)
+ __attribute__((warn_unused_result));
+int dcrypto_p256_point_mul(const p256_int *k,
+ const p256_int *in_x, const p256_int *in_y,
+ p256_int *x, p256_int *y)
+ __attribute__((warn_unused_result));
+int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
+ const p256_int *message, const p256_int *r,
+ const p256_int *s)
+ __attribute__((warn_unused_result));
+int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y)
+ __attribute__((warn_unused_result));
+
+/* Pick a p256 number between 1 < k < |p256| */
+int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output);
+
+/* Overwrite with random p256 value */
+void dcrypto_p256_rnd(p256_int *output);
+
+/*
+ * Accelerator runtime.
+ *
+ * Note dcrypto_init_and_lock grabs a mutex and dcrypto_unlock releases it.
+ * Do not use dcrypto_call, dcrypto_imem_load or dcrypto_dmem_load w/o holding
+ * the mutex.
+ */
+void dcrypto_init_and_lock(void);
+void dcrypto_unlock(void);
+uint32_t dcrypto_call(uint32_t adr) __attribute__((warn_unused_result));
+void dcrypto_imem_load(size_t offset, const uint32_t *opcodes,
+ size_t n_opcodes);
+/*
+ * Returns 0 iff no difference was observed between existing and new content.
+ */
+uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words);
+
+/*
+ * Key ladder.
+ */
+#ifndef __cplusplus
+enum dcrypto_appid; /* Forward declaration. */
+
+int dcrypto_ladder_compute_usr(enum dcrypto_appid id,
+ const uint32_t usr_salt[8]);
+int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8],
+ const uint32_t input[8], uint32_t output[8]);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! __EC_CHIP_G_DCRYPTO_INTERNAL_H */
diff --git a/chip/g/dcrypto/key_ladder.c b/chip/g/dcrypto/key_ladder.c
new file mode 100644
index 0000000000..77055e4159
--- /dev/null
+++ b/chip/g/dcrypto/key_ladder.c
@@ -0,0 +1,300 @@
+/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "dcrypto.h"
+#include "internal.h"
+#include "endian.h"
+#include "registers.h"
+#include "trng.h"
+
+static void ladder_init(void)
+{
+ /* Do not reset keyladder engine here, as before.
+ *
+ * Should not be needed and if it is, it is indicative
+ * of sync error between this and sha engine usage.
+ * Reset will make this flow work, but will have broken
+ * the other pending sha flow.
+ * Hence leave as is and observe the error.
+ */
+
+ /* Enable random stalls for key-ladder usage. Note that
+ * the stall rate used for key-ladder operations is
+ * 25% (vs. 12% for generic SHA operations). This distinction
+ * is made so as to increase the difficulty in characterizng
+ * the key-ladder engine via random inputs provided over the
+ * generic SHA interface.
+ */
+ /* Turn off random nops (which are enabled by default). */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 0);
+ /* Configure random nop percentage at 25%. */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, FREQ, 1);
+ /* Now turn on random nops. */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 1);
+}
+
+static int ladder_step(uint32_t cert, const uint32_t input[8])
+{
+ GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */
+
+ GREG32(KEYMGR, SHA_USE_CERT_INDEX) =
+ (cert << GC_KEYMGR_SHA_USE_CERT_INDEX_LSB) |
+ GC_KEYMGR_SHA_USE_CERT_ENABLE_MASK;
+
+ GREG32(KEYMGR, SHA_CFG_EN) =
+ GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK;
+ GREG32(KEYMGR, SHA_TRIG) =
+ GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK;
+
+ if (input) {
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = input[0];
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = input[1];
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = input[2];
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = input[3];
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = input[4];
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = input[5];
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = input[6];
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = input[7];
+
+ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK;
+ }
+
+ while (!GREG32(KEYMGR, SHA_ITOP))
+ ;
+
+ GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */
+
+ return !!GREG32(KEYMGR, HKEY_ERR_FLAGS);
+}
+
+static int compute_certs(const uint32_t *certs, size_t num_certs)
+{
+ int i;
+
+ for (i = 0; i < num_certs; i++) {
+ if (ladder_step(certs[i], NULL))
+ return 0;
+ }
+
+ return 1;
+}
+
+#define KEYMGR_CERT_0 0
+#define KEYMGR_CERT_3 3
+#define KEYMGR_CERT_4 4
+#define KEYMGR_CERT_5 5
+#define KEYMGR_CERT_7 7
+#define KEYMGR_CERT_15 15
+#define KEYMGR_CERT_20 20
+#define KEYMGR_CERT_25 25
+#define KEYMGR_CERT_26 26
+#define KEYMGR_CERT_27 27
+#define KEYMGR_CERT_28 28
+#define KEYMGR_CERT_34 34
+#define KEYMGR_CERT_35 35
+#define KEYMGR_CERT_38 38
+
+static const uint32_t FRK2_CERTS_PREFIX[] = {
+ KEYMGR_CERT_0,
+ KEYMGR_CERT_3,
+ KEYMGR_CERT_4,
+ KEYMGR_CERT_5,
+ KEYMGR_CERT_7,
+ KEYMGR_CERT_15,
+ KEYMGR_CERT_20,
+};
+
+static const uint32_t FRK2_CERTS_POSTFIX[] = {
+ KEYMGR_CERT_26,
+};
+
+#define MAX_MAJOR_FW_VERSION 254
+
+int DCRYPTO_ladder_compute_frk2(size_t fw_version, uint8_t *frk2)
+{
+ int result = 0;
+
+ if (fw_version > MAX_MAJOR_FW_VERSION)
+ return 0;
+
+ if (!dcrypto_grab_sha_hw())
+ return 0;
+
+ do {
+ int i;
+
+ ladder_init();
+
+ if (!compute_certs(FRK2_CERTS_PREFIX,
+ ARRAY_SIZE(FRK2_CERTS_PREFIX)))
+ break;
+
+ for (i = 0; i < MAX_MAJOR_FW_VERSION - fw_version; i++) {
+ if (ladder_step(KEYMGR_CERT_25, NULL))
+ break;
+ }
+
+ if (!compute_certs(FRK2_CERTS_POSTFIX,
+ ARRAY_SIZE(FRK2_CERTS_POSTFIX)))
+ break;
+
+ memcpy(frk2, (void *) GREG32_ADDR(KEYMGR, HKEY_FRR0),
+ AES256_BLOCK_CIPHER_KEY_SIZE);
+
+ result = 1;
+ } while (0);
+
+ dcrypto_release_sha_hw();
+ return result;
+}
+
+/* ISR salt (SHA256("ISR_SALT")) to use for USR generation. */
+static const uint32_t ISR_SALT[8] = {
+ 0x6ba1b495, 0x4b7ca214, 0xfe07e922, 0x09735185,
+ 0xfcca43ca, 0xc6d4dfd9, 0x5fc2fcca, 0xaa45400b
+};
+
+/* Map of populated USR registers. */
+static int usr_ready[8] = {};
+
+int dcrypto_ladder_compute_usr(enum dcrypto_appid id,
+ const uint32_t usr_salt[8])
+{
+ int result = 0;
+
+ /* Check for USR readiness. */
+ if (usr_ready[id])
+ return 1;
+
+ if (!dcrypto_grab_sha_hw())
+ return 0;
+
+ do {
+ int i;
+
+ /* The previous check performed without lock acquisition. */
+ if (usr_ready[id]) {
+ result = 1;
+ break;
+ }
+
+ ladder_init();
+
+ if (!compute_certs(FRK2_CERTS_PREFIX,
+ ARRAY_SIZE(FRK2_CERTS_PREFIX)))
+ break;
+
+ /* USR generation requires running the key-ladder till
+ * the end (version 0), plus one additional iteration.
+ */
+ for (i = 0; i < MAX_MAJOR_FW_VERSION - 0 + 1; i++) {
+ if (ladder_step(KEYMGR_CERT_25, NULL))
+ break;
+ }
+ if (i != MAX_MAJOR_FW_VERSION - 0 + 1)
+ break;
+
+ if (ladder_step(KEYMGR_CERT_34, ISR_SALT))
+ break;
+
+ /* Output goes to USR[appid] (the multiply by 2 is an
+ * artifact of slot addressing).
+ */
+ GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, DIGEST_PTR, 2 * id);
+ if (ladder_step(KEYMGR_CERT_35, usr_salt))
+ break;
+
+ /* Check for key-ladder errors. */
+ if (GREG32(KEYMGR, HKEY_ERR_FLAGS))
+ break;
+
+ /* Key deposited in USR[id], and ready to use. */
+ usr_ready[id] = 1;
+
+ result = 1;
+ } while (0);
+
+ dcrypto_release_sha_hw();
+ return result;
+}
+
+static void ladder_out(uint32_t output[8])
+{
+ output[0] = GREG32(KEYMGR, SHA_STS_H0);
+ output[1] = GREG32(KEYMGR, SHA_STS_H1);
+ output[2] = GREG32(KEYMGR, SHA_STS_H2);
+ output[3] = GREG32(KEYMGR, SHA_STS_H3);
+ output[4] = GREG32(KEYMGR, SHA_STS_H4);
+ output[5] = GREG32(KEYMGR, SHA_STS_H5);
+ output[6] = GREG32(KEYMGR, SHA_STS_H6);
+ output[7] = GREG32(KEYMGR, SHA_STS_H7);
+}
+
+/*
+ * Stir TRNG entropy into RSR and pull some out.
+ */
+int DCRYPTO_ladder_random(void *output)
+{
+ int error = 1;
+ uint32_t tmp[8];
+
+ if (!dcrypto_grab_sha_hw())
+ goto fail;
+
+ rand_bytes(tmp, sizeof(tmp));
+ /* Mix TRNG bytes with RSR entropy */
+ error = ladder_step(KEYMGR_CERT_27, tmp);
+ if (!error)
+ ladder_out(output);
+
+fail:
+ dcrypto_release_sha_hw();
+ return !error;
+}
+
+int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8],
+ const uint32_t input[8], uint32_t output[8])
+{
+ int error;
+
+ if (!dcrypto_grab_sha_hw())
+ return 0;
+
+ GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, KEY_PTR, 2 * appid);
+ error = ladder_step(KEYMGR_CERT_38, input); /* HMAC */
+ if (!error)
+ ladder_out(output);
+
+ dcrypto_release_sha_hw();
+ return !error;
+}
+
+void DCRYPTO_ladder_revoke(void)
+{
+ /* Revoke certificates */
+ GWRITE(KEYMGR, CERT_REVOKE_CTRL0, 0xffffffff);
+ GWRITE(KEYMGR, CERT_REVOKE_CTRL1, 0xffffffff);
+
+ /* Wipe out the hidden keys cached in AES and SHA engines. */
+ GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 0);
+ GWRITE_FIELD(KEYMGR, SHA_USE_HIDDEN_KEY, ENABLE, 0);
+
+ /* Clear usr_ready[] */
+ memset(usr_ready, 0, sizeof(usr_ready));
+}
+
+#define KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL 0xa8028a82
+#define KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL 0xaaaaaaaa
+
+int DCRYPTO_ladder_is_enabled(void)
+{
+ uint32_t ctrl0;
+ uint32_t ctrl1;
+
+ ctrl0 = GREAD(KEYMGR, CERT_REVOKE_CTRL0);
+ ctrl1 = GREAD(KEYMGR, CERT_REVOKE_CTRL1);
+
+ return ctrl0 == KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL &&
+ ctrl1 == KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL;
+}
diff --git a/chip/g/dcrypto/p256.c b/chip/g/dcrypto/p256.c
new file mode 100644
index 0000000000..665144e31b
--- /dev/null
+++ b/chip/g/dcrypto/p256.c
@@ -0,0 +1,30 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+
+#include "cryptoc/p256.h"
+#include "cryptoc/util.h"
+
+static const p256_int p256_one = P256_ONE;
+
+/*
+ * Key selection based on FIPS-186-4, section B.4.2 (Key Pair
+ * Generation by Testing Candidates).
+ */
+int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
+ const uint8_t key_bytes[P256_NBYTES])
+{
+ p256_int key;
+
+ p256_from_bin(key_bytes, &key);
+ if (p256_cmp(&SECP256r1_nMin2, &key) < 0)
+ return 0;
+ p256_add(&key, &p256_one, d);
+ always_memset(&key, 0, sizeof(key));
+ if (x == NULL || y == NULL)
+ return 1;
+ return dcrypto_p256_base_point_mul(d, x, y);
+}
diff --git a/chip/g/dcrypto/p256_ec.c b/chip/g/dcrypto/p256_ec.c
new file mode 100644
index 0000000000..cb33a15774
--- /dev/null
+++ b/chip/g/dcrypto/p256_ec.c
@@ -0,0 +1,39 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+
+#include <stdint.h>
+
+#include "cryptoc/p256.h"
+
+/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
+ * order of the group. */
+int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y,
+ const p256_int *n)
+{
+ if (p256_is_zero(n) != 0) {
+ p256_clear(out_x);
+ p256_clear(out_y);
+ return 0;
+ }
+
+ return dcrypto_p256_base_point_mul(n, out_x, out_y);
+}
+
+/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is <
+ * the order of the group. */
+int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y,
+ const p256_int *n, const p256_int *in_x,
+ const p256_int *in_y)
+{
+ if (p256_is_zero(n) != 0) {
+ p256_clear(out_x);
+ p256_clear(out_y);
+ return 0;
+ }
+
+ return dcrypto_p256_point_mul(n, in_x, in_y, out_x, out_y);
+}
diff --git a/chip/g/dcrypto/p256_ecies.c b/chip/g/dcrypto/p256_ecies.c
new file mode 100644
index 0000000000..30a410d828
--- /dev/null
+++ b/chip/g/dcrypto/p256_ecies.c
@@ -0,0 +1,175 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "internal.h"
+#include "dcrypto.h"
+
+#include "trng.h"
+#include "util.h"
+
+#include "cryptoc/p256.h"
+#include "cryptoc/sha256.h"
+
+#define AES_KEY_BYTES 16
+#define HMAC_KEY_BYTES 32
+
+#define AES_BLOCK_BYTES 16
+
+/* P256 based hybrid encryption. The output format is:
+ *
+ * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) ||
+ * HMAC_SHA256(AUTH_DATA || CIPHERTEXT)
+ */
+size_t DCRYPTO_ecies_encrypt(
+ void *out, size_t out_len, const void *in, size_t in_len,
+ size_t auth_data_len, const uint8_t *iv,
+ const p256_int *pub_x, const p256_int *pub_y,
+ const uint8_t *salt, size_t salt_len,
+ const uint8_t *info, size_t info_len)
+{
+ p256_int eph_d;
+ p256_int eph_x;
+ p256_int eph_y;
+ uint8_t seed[P256_NBYTES];
+ p256_int secret_x;
+ p256_int secret_y;
+ /* Key bytes to be extracted from HKDF. */
+ uint8_t key[AES_KEY_BYTES + HMAC_KEY_BYTES];
+ const uint8_t *aes_key;
+ const uint8_t *hmac_key;
+ LITE_HMAC_CTX ctx;
+ uint8_t *outp = out;
+ uint8_t *ciphertext;
+
+ if (auth_data_len > in_len)
+ return 0;
+ if (out_len < 1 + P256_NBYTES + P256_NBYTES +
+ in_len + SHA256_DIGEST_SIZE)
+ return 0;
+
+ /* Generate emphemeral EC key. */
+ rand_bytes(seed, sizeof(seed));
+ if (!DCRYPTO_p256_key_from_bytes(&eph_x, &eph_y, &eph_d, seed))
+ return 0;
+ /* Compute DH point. */
+ if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y,
+ &eph_d, pub_x, pub_y))
+ return 0;
+ /* Check for computational errors. */
+ if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y))
+ return 0;
+ /* Convert secret to big-endian. */
+ reverse(&secret_x, sizeof(secret_x));
+ /* Derive shared secret. */
+ if (!DCRYPTO_hkdf(key, sizeof(key), salt, salt_len,
+ (uint8_t *) &secret_x, sizeof(secret_x),
+ info, info_len))
+ return 0;
+
+ aes_key = &key[0];
+ hmac_key = &key[AES_KEY_BYTES];
+
+ if (out == in)
+ ciphertext = out + auth_data_len; /* In place encrypt. */
+ else
+ ciphertext = out + 1 + P256_NBYTES + P256_NBYTES +
+ auth_data_len;
+
+ /* Compute ciphertext. */
+ if (!DCRYPTO_aes_ctr(ciphertext, aes_key, AES_KEY_BYTES * 8, iv,
+ in + auth_data_len, in_len - auth_data_len))
+ return 0;
+
+ /* Write out auth_data / ciphertext. */
+ outp = out + 1 + P256_NBYTES + P256_NBYTES;
+ if (out == in)
+ memmove(outp, in, in_len);
+ else
+ memcpy(outp, in, auth_data_len);
+
+ /* Write out ephemeral pub key. */
+ outp = out;
+ *outp++ = 0x04; /* uncompressed EC public key. */
+ p256_to_bin(&eph_x, outp);
+ outp += P256_NBYTES;
+ p256_to_bin(&eph_y, outp);
+ outp += P256_NBYTES;
+
+ /* Calculate HMAC(auth_data || ciphertext). */
+ DCRYPTO_HMAC_SHA256_init(&ctx, hmac_key, HMAC_KEY_BYTES);
+ HASH_update(&ctx.hash, outp, in_len);
+ outp += in_len;
+ memcpy(outp, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE);
+ outp += SHA256_DIGEST_SIZE;
+
+ return outp - (uint8_t *) out;
+}
+
+size_t DCRYPTO_ecies_decrypt(
+ void *out, size_t out_len, const void *in, size_t in_len,
+ size_t auth_data_len, const uint8_t *iv,
+ const p256_int *d,
+ const uint8_t *salt, size_t salt_len,
+ const uint8_t *info, size_t info_len)
+{
+ p256_int eph_x;
+ p256_int eph_y;
+ p256_int secret_x;
+ p256_int secret_y;
+ uint8_t key[AES_KEY_BYTES + HMAC_KEY_BYTES];
+ const uint8_t *aes_key;
+ const uint8_t *hmac_key;
+ LITE_HMAC_CTX ctx;
+ const uint8_t *inp = in;
+ uint8_t *outp = out;
+
+ if (in_len < 1 + P256_NBYTES + P256_NBYTES + auth_data_len +
+ SHA256_DIGEST_SIZE)
+ return 0;
+ if (inp[0] != 0x04)
+ return 0;
+
+ in_len -= 1 + P256_NBYTES + P256_NBYTES + SHA256_DIGEST_SIZE;
+
+ inp++;
+ p256_from_bin(inp, &eph_x);
+ inp += P256_NBYTES;
+ p256_from_bin(inp, &eph_y);
+ inp += P256_NBYTES;
+
+ /* Verify that the public point is on the curve. */
+ if (!dcrypto_p256_is_valid_point(&eph_x, &eph_y))
+ return 0;
+ /* Compute the DH point. */
+ if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y,
+ d, &eph_x, &eph_y))
+ return 0;
+ /* Check for computational errors. */
+ if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y))
+ return 0;
+ /* Convert secret to big-endian. */
+ reverse(&secret_x, sizeof(secret_x));
+ /* Derive shared secret. */
+ if (!DCRYPTO_hkdf(key, sizeof(key), salt, salt_len,
+ (uint8_t *) &secret_x, sizeof(secret_x),
+ info, info_len))
+ return 0;
+
+ aes_key = &key[0];
+ hmac_key = &key[AES_KEY_BYTES];
+ DCRYPTO_HMAC_SHA256_init(&ctx, hmac_key, HMAC_KEY_BYTES);
+ HASH_update(&ctx.hash, inp, in_len);
+ if (!DCRYPTO_equals(inp + in_len, DCRYPTO_HMAC_final(&ctx),
+ SHA256_DIGEST_SIZE))
+ return 0;
+
+ memmove(outp, inp, auth_data_len);
+ inp += auth_data_len;
+ outp += auth_data_len;
+ if (!DCRYPTO_aes_ctr(outp, aes_key, AES_KEY_BYTES * 8, iv,
+ inp, in_len - auth_data_len))
+ return 0;
+ return in_len;
+}
diff --git a/chip/g/dcrypto/proofs_p256.md b/chip/g/dcrypto/proofs_p256.md
new file mode 100644
index 0000000000..c0fa7ef6ad
--- /dev/null
+++ b/chip/g/dcrypto/proofs_p256.md
@@ -0,0 +1,28 @@
+Proving P256 dcrypto code
+=========================
+
+In 2018, partial proofs of modular reduction were written in the Coq proof
+assistant.
+They can be used against the crypto accelerator code in [chip/g/dcrypto/dcrypto_p256.c](dcrypto_p256.c).
+
+The Coq code is in this file:
+[github.com/mit-plv/fiat-crypto/.../Experiments/SimplyTypedArithmetic.v](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v)
+
+Specific lines of interest:
+
+Instruction specifications:
+[fiat-crypto/.../Experiments/SimplyTypedArithmetic.v#L10014](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v#L10014)
+
+Printouts of verified code versions with explanatory comments are at the very
+end of the same file (which GitHub cuts off, so here is the link to the raw
+version):
+https://raw.githubusercontent.com/mit-plv/fiat-crypto/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v
+
+Additionally, the MulMod procedure in p256 uses a non-standard Barrett
+reduction optimization. In particular, it assumes that the quotient estimate is
+off by no more than 1, while most resources say it can be off by 2. This
+assumption was proven correct for most primes (including p256) here:
+
+[fiat-crypto/.../Arithmetic/BarrettReduction/Generalized.v#L140](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Arithmetic/BarrettReduction/Generalized.v#L140)
+
+The proofs can be re-checked using Coq version 8.7 or 8.8 (or above, probably).
diff --git a/chip/g/dcrypto/rsa.c b/chip/g/dcrypto/rsa.c
new file mode 100644
index 0000000000..8a4115398d
--- /dev/null
+++ b/chip/g/dcrypto/rsa.c
@@ -0,0 +1,743 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+
+#include "trng.h"
+#include "util.h"
+
+#include <assert.h>
+
+#include "cryptoc/sha.h"
+#include "cryptoc/sha256.h"
+#include "cryptoc/sha384.h"
+#include "cryptoc/sha512.h"
+#include "cryptoc/util.h"
+
+/* Extend the MSB throughout the word. */
+static uint32_t msb_extend(uint32_t a)
+{
+ return 0u - (a >> 31);
+}
+
+/* Return 0xFF..FF if a is zero, and zero otherwise. */
+static uint32_t is_zero(uint32_t a)
+{
+ return msb_extend(~a & (a - 1));
+}
+
+/* Select a or b based on mask. Mask expected to be 0xFF..FF or 0. */
+static uint32_t select(uint32_t mask, uint32_t a, uint32_t b)
+{
+ return (mask & a) | (~mask & b);
+}
+
+static void MGF1_xor(uint8_t *dst, uint32_t dst_len,
+ const uint8_t *seed, uint32_t seed_len,
+ enum hashing_mode hashing)
+{
+ HASH_CTX ctx;
+ struct {
+ uint8_t b3;
+ uint8_t b2;
+ uint8_t b1;
+ uint8_t b0;
+ } cnt;
+ const uint8_t *digest;
+ const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE
+ : SHA256_DIGEST_SIZE;
+
+ cnt.b0 = cnt.b1 = cnt.b2 = cnt.b3 = 0;
+ while (dst_len) {
+ int i;
+
+ if (hashing == HASH_SHA1)
+ DCRYPTO_SHA1_init(&ctx, 0);
+ else
+ DCRYPTO_SHA256_init(&ctx, 0);
+
+ HASH_update(&ctx, seed, seed_len);
+ HASH_update(&ctx, (uint8_t *) &cnt, sizeof(cnt));
+ digest = HASH_final(&ctx);
+ for (i = 0; i < dst_len && i < hash_size; ++i)
+ *dst++ ^= *digest++;
+ dst_len -= i;
+ if (!++cnt.b0)
+ ++cnt.b1;
+ }
+}
+
+/*
+ * struct OAEP { // MSB to LSB.
+ * uint8_t zero;
+ * uint8_t seed[HASH_SIZE];
+ * uint8_t phash[HASH_SIZE];
+ * uint8_t PS[]; // Variable length (optional) zero-pad.
+ * uint8_t one; // 0x01, message demarcator.
+ * uint8_t msg[]; // Input message.
+ * };
+ */
+/* encrypt */
+static int oaep_pad(uint8_t *output, uint32_t output_len,
+ const uint8_t *msg, uint32_t msg_len,
+ enum hashing_mode hashing, const char *label)
+{
+ int i;
+ const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE
+ : SHA256_DIGEST_SIZE;
+ uint8_t *const seed = output + 1;
+ uint8_t *const phash = seed + hash_size;
+ uint8_t *const PS = phash + hash_size;
+ const uint32_t max_msg_len = output_len - 2 - 2 * hash_size;
+ const uint32_t ps_len = max_msg_len - msg_len;
+ uint8_t *const one = PS + ps_len;
+ struct HASH_CTX ctx;
+
+ if (output_len < 2 + 2 * hash_size)
+ return 0; /* Key size too small for chosen hash. */
+ if (msg_len > output_len - 2 - 2 * hash_size)
+ return 0; /* Input message too large for key size. */
+
+ always_memset(output, 0, output_len);
+ for (i = 0; i < hash_size;) {
+ uint32_t r = rand();
+
+ seed[i++] = r >> 0;
+ seed[i++] = r >> 8;
+ seed[i++] = r >> 16;
+ seed[i++] = r >> 24;
+ }
+
+ if (hashing == HASH_SHA1)
+ DCRYPTO_SHA1_init(&ctx, 0);
+ else
+ DCRYPTO_SHA256_init(&ctx, 0);
+
+ HASH_update(&ctx, label, label ? strlen(label) + 1 : 0);
+ memcpy(phash, HASH_final(&ctx), hash_size);
+ *one = 1;
+ memcpy(one + 1, msg, msg_len);
+ MGF1_xor(phash, hash_size + 1 + max_msg_len,
+ seed, hash_size, hashing);
+ MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len,
+ hashing);
+ return 1;
+}
+
+/* decrypt */
+static int check_oaep_pad(uint8_t *out, uint32_t *out_len,
+ uint8_t *padded, uint32_t padded_len,
+ enum hashing_mode hashing, const char *label)
+{
+ const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE
+ : SHA256_DIGEST_SIZE;
+ uint8_t *seed = padded + 1;
+ uint8_t *phash = seed + hash_size;
+ uint8_t *PS = phash + hash_size;
+ const uint32_t max_msg_len = padded_len - 2 - 2 * hash_size;
+ struct HASH_CTX ctx;
+ size_t one_index = 0;
+ uint32_t looking_for_one_byte = ~0;
+ int bad;
+ int i;
+
+ if (padded_len < 2 + 2 * hash_size)
+ return 0; /* Invalid input size. */
+
+ /* Recover seed. */
+ MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, hashing);
+ /* Recover db. */
+ MGF1_xor(phash, hash_size + 1 + max_msg_len, seed, hash_size, hashing);
+
+ if (hashing == HASH_SHA1)
+ DCRYPTO_SHA1_init(&ctx, 0);
+ else
+ DCRYPTO_SHA256_init(&ctx, 0);
+ HASH_update(&ctx, label, label ? strlen(label) + 1 : 0);
+
+ bad = !DCRYPTO_equals(phash, HASH_final(&ctx), hash_size);
+ bad |= padded[0];
+
+ for (i = PS - padded; i < padded_len; i++) {
+ uint32_t equals0 = is_zero(padded[i]);
+ uint32_t equals1 = is_zero(padded[i] ^ 1);
+
+ one_index = select(looking_for_one_byte & equals1,
+ i, one_index);
+ looking_for_one_byte = select(equals1, 0, looking_for_one_byte);
+
+ /* Bad padding if padded[i] is neither 1 nor 0. */
+ bad |= looking_for_one_byte & ~equals0;
+ }
+
+ bad |= looking_for_one_byte;
+
+ if (bad)
+ return 0;
+
+ one_index++;
+ if (*out_len < padded_len - one_index)
+ return 0;
+ memcpy(out, padded + one_index, padded_len - one_index);
+ *out_len = padded_len - one_index;
+ return 1;
+}
+
+/* Constants from RFC 3447. */
+#define RSA_PKCS1_PADDING_SIZE 11
+
+/* encrypt */
+static int pkcs1_type2_pad(uint8_t *padded, uint32_t padded_len,
+ const uint8_t *in, uint32_t in_len)
+{
+ uint32_t PS_len;
+
+ if (padded_len < RSA_PKCS1_PADDING_SIZE)
+ return 0;
+ if (in_len > padded_len - RSA_PKCS1_PADDING_SIZE)
+ return 0;
+ PS_len = padded_len - 3 - in_len;
+
+ *(padded++) = 0;
+ *(padded++) = 2;
+ while (PS_len) {
+ int i;
+ uint32_t r = rand();
+
+ for (i = 0; i < 4 && PS_len; i++) {
+ uint8_t b = ((uint8_t *) &r)[i];
+
+ if (b) {
+ *padded++ = b;
+ PS_len--;
+ }
+ }
+ }
+ *(padded++) = 0;
+ memcpy(padded, in, in_len);
+ return 1;
+}
+
+/* decrypt */
+static int check_pkcs1_type2_pad(uint8_t *out, uint32_t *out_len,
+ const uint8_t *padded, uint32_t padded_len)
+{
+ int i;
+ int valid;
+ uint32_t zero_index = 0;
+ uint32_t looking_for_index = ~0;
+
+ if (padded_len < RSA_PKCS1_PADDING_SIZE)
+ return 0;
+
+ valid = (padded[0] == 0);
+ valid &= (padded[1] == 2);
+
+ for (i = 2; i < padded_len; i++) {
+ uint32_t found = is_zero(padded[i]);
+
+ zero_index = select(looking_for_index & found, i, zero_index);
+ looking_for_index = select(found, 0, looking_for_index);
+ }
+
+ zero_index++;
+
+ valid &= ~looking_for_index;
+ valid &= (zero_index >= RSA_PKCS1_PADDING_SIZE);
+ if (!valid)
+ return 0;
+
+ if (*out_len < padded_len - zero_index)
+ return 0;
+ memcpy(out, &padded[zero_index], padded_len - zero_index);
+ *out_len = padded_len - zero_index;
+ return 1;
+}
+
+static const uint8_t SHA1_DER[] = {
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
+ 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
+};
+static const uint8_t SHA256_DER[] = {
+ 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20
+};
+static const uint8_t SHA384_DER[] = {
+ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30
+};
+static const uint8_t SHA512_DER[] = {
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40
+};
+
+static int pkcs1_get_der(enum hashing_mode hashing, const uint8_t **der,
+ uint32_t *der_size, uint32_t *hash_size)
+{
+ switch (hashing) {
+ case HASH_SHA1:
+ *der = &SHA1_DER[0];
+ *der_size = sizeof(SHA1_DER);
+ *hash_size = SHA_DIGEST_SIZE;
+ break;
+ case HASH_SHA256:
+ *der = &SHA256_DER[0];
+ *der_size = sizeof(SHA256_DER);
+ *hash_size = SHA256_DIGEST_SIZE;
+ break;
+ case HASH_SHA384:
+ *der = &SHA384_DER[0];
+ *der_size = sizeof(SHA384_DER);
+ *hash_size = SHA384_DIGEST_SIZE;
+ break;
+ case HASH_SHA512:
+ *der = &SHA512_DER[0];
+ *der_size = sizeof(SHA512_DER);
+ *hash_size = SHA512_DIGEST_SIZE;
+ break;
+ case HASH_NULL:
+ *der = NULL;
+ *der_size = 0;
+ *hash_size = 0; /* any size allowed */
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* sign */
+static int pkcs1_type1_pad(uint8_t *padded, uint32_t padded_len,
+ const uint8_t *in, uint32_t in_len,
+ enum hashing_mode hashing)
+{
+ const uint8_t *der;
+ uint32_t der_size;
+ uint32_t hash_size;
+ uint32_t ps_len;
+
+ if (!pkcs1_get_der(hashing, &der, &der_size, &hash_size))
+ return 0;
+ if (padded_len < RSA_PKCS1_PADDING_SIZE + der_size)
+ return 0;
+ if (!in_len || (hash_size && in_len != hash_size))
+ return 0;
+ if (in_len > padded_len - RSA_PKCS1_PADDING_SIZE - der_size)
+ return 0;
+ ps_len = padded_len - 3 - der_size - in_len;
+
+ *(padded++) = 0;
+ *(padded++) = 1;
+ always_memset(padded, 0xFF, ps_len);
+ padded += ps_len;
+ *(padded++) = 0;
+ memcpy(padded, der, der_size);
+ padded += der_size;
+ memcpy(padded, in, in_len);
+ return 1;
+}
+
+/* verify */
+static int check_pkcs1_type1_pad(const uint8_t *msg, uint32_t msg_len,
+ const uint8_t *padded, uint32_t padded_len,
+ enum hashing_mode hashing)
+{
+ int i;
+ const uint8_t *der;
+ uint32_t der_size;
+ uint32_t hash_size;
+ uint32_t ps_len;
+
+ if (!pkcs1_get_der(hashing, &der, &der_size, &hash_size))
+ return 0;
+ if (msg_len != hash_size)
+ return 0;
+ if (padded_len < RSA_PKCS1_PADDING_SIZE + der_size + hash_size)
+ return 0;
+ ps_len = padded_len - 3 - der_size - hash_size;
+
+ if (padded[0] != 0 || padded[1] != 1)
+ return 0;
+ for (i = 2; i < ps_len + 2; i++) {
+ if (padded[i] != 0xFF)
+ return 0;
+ }
+
+ if (padded[i++] != 0)
+ return 0;
+ if (!DCRYPTO_equals(&padded[i], der, der_size))
+ return 0;
+ i += der_size;
+ return DCRYPTO_equals(msg, &padded[i], hash_size);
+}
+
+/* sign */
+static int pkcs1_pss_pad(uint8_t *padded, uint32_t padded_len,
+ const uint8_t *in, uint32_t in_len,
+ enum hashing_mode hashing)
+{
+ const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE
+ : SHA256_DIGEST_SIZE;
+ const uint32_t salt_len = MIN(padded_len - hash_size - 2, hash_size);
+ uint32_t db_len;
+ uint32_t ps_len;
+ struct HASH_CTX ctx;
+
+ if (in_len != hash_size)
+ return 0;
+ if (padded_len < hash_size + 2)
+ return 0;
+ db_len = padded_len - hash_size - 1;
+
+ if (hashing == HASH_SHA1)
+ DCRYPTO_SHA1_init(&ctx, 0);
+ else
+ DCRYPTO_SHA256_init(&ctx, 0);
+
+ /* Pilfer bits of output for temporary use. */
+ memset(padded, 0, 8);
+ HASH_update(&ctx, padded, 8);
+ HASH_update(&ctx, in, in_len);
+ /* Pilfer bits of output for temporary use. */
+ rand_bytes(padded, salt_len);
+ HASH_update(&ctx, padded, salt_len);
+
+ /* Output hash. */
+ memcpy(padded + db_len, HASH_final(&ctx), hash_size);
+
+ /* Prepare DB. */
+ ps_len = db_len - salt_len - 1;
+ memmove(padded + ps_len + 1, padded, salt_len);
+ memset(padded, 0, ps_len);
+ padded[ps_len] = 0x01;
+ MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing);
+
+ /* Clear most significant bit. */
+ padded[0] &= 0x7F;
+ /* Set trailing byte. */
+ padded[padded_len - 1] = 0xBC;
+ return 1;
+}
+
+/* verify */
+static int check_pkcs1_pss_pad(const uint8_t *in, uint32_t in_len,
+ uint8_t *padded, uint32_t padded_len,
+ enum hashing_mode hashing)
+{
+ const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE
+ : SHA256_DIGEST_SIZE;
+ const uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t db_len;
+ uint32_t max_ps_len;
+ uint32_t salt_len;
+ HASH_CTX ctx;
+ int bad = 0;
+ int i;
+
+ if (in_len != hash_size)
+ return 0;
+ if (padded_len < hash_size + 2)
+ return 0;
+ db_len = padded_len - hash_size - 1;
+
+ /* Top bit should be zero. */
+ bad |= padded[0] & 0x80;
+ /* Check trailing byte. */
+ bad |= padded[padded_len - 1] ^ 0xBC;
+
+ /* Recover DB. */
+ MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing);
+ /* Clear top bit. */
+ padded[0] &= 0x7F;
+ /* Verify padding2. */
+ max_ps_len = db_len - 1;
+ for (i = 0; i < max_ps_len; i++) {
+ if (padded[i] == 0x01)
+ break;
+ else
+ bad |= padded[i];
+ }
+ bad |= (padded[i] ^ 0x01);
+ /* Continue with zero-length salt if 0x01 was not found. */
+ salt_len = max_ps_len - i;
+
+ if (hashing == HASH_SHA1)
+ DCRYPTO_SHA1_init(&ctx, 0);
+ else
+ DCRYPTO_SHA256_init(&ctx, 0);
+ HASH_update(&ctx, zeros, sizeof(zeros));
+ HASH_update(&ctx, in, in_len);
+ HASH_update(&ctx, padded + db_len - salt_len, salt_len);
+ bad |= !DCRYPTO_equals(padded + db_len, HASH_final(&ctx), hash_size);
+ return !bad;
+}
+
+static int check_modulus_params(
+ const struct LITE_BIGNUM *N, size_t rsa_max_bytes, uint32_t *out_len)
+{
+ if (bn_size(N) > rsa_max_bytes)
+ return 0; /* Unsupported key size. */
+ if (!bn_check_topbit(N)) /* Check that top bit is set. */
+ return 0;
+ if (out_len && *out_len < bn_size(N))
+ return 0; /* Output buffer too small. */
+ return 1;
+}
+
+int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
+ const uint8_t *in, uint32_t in_len,
+ enum padding_mode padding, enum hashing_mode hashing,
+ const char *label)
+{
+ uint8_t *p;
+ uint32_t padded_buf[RSA_MAX_WORDS];
+ uint32_t e_buf[LITE_BN_BYTES / sizeof(uint32_t)];
+
+ struct LITE_BIGNUM padded;
+ struct LITE_BIGNUM encrypted;
+ int ret;
+
+ if (!check_modulus_params(&rsa->N, sizeof(padded_buf), out_len))
+ return 0;
+
+ bn_init(&padded, padded_buf, bn_size(&rsa->N));
+ bn_init(&encrypted, out, bn_size(&rsa->N));
+
+ switch (padding) {
+ case PADDING_MODE_OAEP:
+ if (!oaep_pad((uint8_t *) padded.d, bn_size(&padded),
+ (const uint8_t *) in, in_len, hashing, label))
+ return 0;
+ break;
+ case PADDING_MODE_PKCS1:
+ if (!pkcs1_type2_pad((uint8_t *) padded.d, bn_size(&padded),
+ (const uint8_t *) in, in_len))
+ return 0;
+ break;
+ case PADDING_MODE_NULL:
+ /* Input is allowed to have more bytes than N, in
+ * which case the excess must be zero. */
+ for (; in_len > bn_size(&padded); in_len--)
+ if (*in++ != 0)
+ return 0;
+ p = (uint8_t *) padded.d;
+ /* If in_len < bn_size(&padded), padded will
+ * have leading zero bytes. */
+ memcpy(&p[bn_size(&padded) - in_len], in, in_len);
+ /* TODO(ngm): in may be > N, bn_mod_exp() should
+ * handle this case. */
+ break;
+ default:
+ return 0; /* Unsupported padding mode. */
+ }
+
+ /* Reverse from big-endian to little-endian notation. */
+ reverse((uint8_t *) padded.d, bn_size(&padded));
+ ret = bn_modexp_word(&encrypted, &padded, rsa->e, &rsa->N);
+ /* Back to big-endian notation. */
+ reverse((uint8_t *) encrypted.d, bn_size(&encrypted));
+ *out_len = bn_size(&encrypted);
+
+ always_memset(padded_buf, 0, sizeof(padded_buf));
+ always_memset(e_buf, 0, sizeof(e_buf));
+ return ret;
+}
+
+int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
+ const uint8_t *in, const uint32_t in_len,
+ enum padding_mode padding, enum hashing_mode hashing,
+ const char *label)
+{
+ uint32_t encrypted_buf[RSA_MAX_WORDS];
+ uint32_t padded_buf[RSA_MAX_WORDS];
+
+ struct LITE_BIGNUM encrypted;
+ struct LITE_BIGNUM padded;
+ int ret;
+
+ if (!check_modulus_params(&rsa->N, sizeof(padded_buf), NULL))
+ return 0;
+ if (in_len != bn_size(&rsa->N))
+ return 0; /* Invalid input length. */
+
+ /* TODO(ngm): this copy can be eliminated if input may be modified. */
+ bn_init(&encrypted, encrypted_buf, in_len);
+ memcpy(encrypted_buf, in, in_len);
+ bn_init(&padded, padded_buf, in_len);
+
+ /* Reverse from big-endian to little-endian notation. */
+ reverse((uint8_t *) encrypted.d, encrypted.dmax * LITE_BN_BYTES);
+ ret = bn_modexp_blinded(&padded, &encrypted, &rsa->d, &rsa->N, rsa->e);
+ /* Back to big-endian notation. */
+ reverse((uint8_t *) padded.d, padded.dmax * LITE_BN_BYTES);
+
+ switch (padding) {
+ case PADDING_MODE_OAEP:
+ if (!check_oaep_pad(out, out_len, (uint8_t *) padded.d,
+ bn_size(&padded), hashing, label))
+ ret = 0;
+ break;
+ case PADDING_MODE_PKCS1:
+ if (!check_pkcs1_type2_pad(
+ out, out_len, (const uint8_t *) padded.d,
+ bn_size(&padded)))
+ ret = 0;
+ break;
+ case PADDING_MODE_NULL:
+ if (*out_len < bn_size(&padded)) {
+ ret = 0;
+ } else {
+ *out_len = bn_size(&padded);
+ memcpy(out, padded.d, *out_len);
+ }
+ break;
+ default:
+ /* Unsupported padding mode. */
+ ret = 0;
+ break;
+ }
+
+ always_memset(encrypted_buf, 0, sizeof(encrypted_buf));
+ always_memset(padded_buf, 0, sizeof(padded_buf));
+ return ret;
+}
+
+int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
+ const uint8_t *in, const uint32_t in_len,
+ enum padding_mode padding, enum hashing_mode hashing)
+{
+ uint32_t padded_buf[RSA_MAX_WORDS];
+
+ struct LITE_BIGNUM padded;
+ struct LITE_BIGNUM signature;
+ int ret;
+
+ if (!check_modulus_params(&rsa->N, sizeof(padded_buf), out_len))
+ return 0;
+
+ bn_init(&padded, padded_buf, bn_size(&rsa->N));
+ bn_init(&signature, out, bn_size(&rsa->N));
+
+ switch (padding) {
+ case PADDING_MODE_PKCS1:
+ if (!pkcs1_type1_pad((uint8_t *) padded.d, bn_size(&padded),
+ (const uint8_t *) in, in_len, hashing))
+ return 0;
+ break;
+ case PADDING_MODE_PSS:
+ if (!pkcs1_pss_pad((uint8_t *) padded.d, bn_size(&padded),
+ (const uint8_t *) in, in_len, hashing))
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ /* Reverse from big-endian to little-endian notation. */
+ reverse((uint8_t *) padded.d, bn_size(&padded));
+ ret = bn_modexp_blinded(&signature, &padded, &rsa->d, &rsa->N, rsa->e);
+ /* Back to big-endian notation. */
+ reverse((uint8_t *) signature.d, bn_size(&signature));
+ *out_len = bn_size(&rsa->N);
+
+ always_memset(padded_buf, 0, sizeof(padded_buf));
+ return ret;
+}
+
+int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest,
+ uint32_t digest_len, const uint8_t *sig,
+ const uint32_t sig_len, enum padding_mode padding,
+ enum hashing_mode hashing)
+{
+ uint32_t padded_buf[RSA_WORDS_4K];
+ uint32_t signature_buf[RSA_WORDS_4K];
+
+ struct LITE_BIGNUM padded;
+ struct LITE_BIGNUM signature;
+ int ret;
+
+ if (!check_modulus_params(&rsa->N, sizeof(padded_buf), NULL))
+ return 0;
+ if (sig_len != bn_size(&rsa->N))
+ return 0; /* Invalid input length. */
+
+ bn_init(&signature, signature_buf, bn_size(&rsa->N));
+ memcpy(signature_buf, sig, bn_size(&rsa->N));
+ bn_init(&padded, padded_buf, bn_size(&rsa->N));
+
+ /* Reverse from big-endian to little-endian notation. */
+ reverse((uint8_t *) signature.d, bn_size(&signature));
+ ret = bn_modexp_word(&padded, &signature, rsa->e, &rsa->N);
+ /* Back to big-endian notation. */
+ reverse((uint8_t *) padded.d, bn_size(&padded));
+
+ switch (padding) {
+ case PADDING_MODE_PKCS1:
+ if (!check_pkcs1_type1_pad(
+ digest, digest_len, (uint8_t *) padded.d,
+ bn_size(&padded), hashing))
+ ret = 0;
+ break;
+ case PADDING_MODE_PSS:
+ if (!check_pkcs1_pss_pad(
+ digest, digest_len, (uint8_t *) padded.d,
+ bn_size(&padded), hashing))
+ ret = 0;
+ break;
+ default:
+ /* Unsupported padding mode. */
+ ret = 0;
+ break;
+ }
+
+ always_memset(padded_buf, 0, sizeof(padded_buf));
+ always_memset(signature_buf, 0, sizeof(signature_buf));
+ return ret;
+}
+
+int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d,
+ struct LITE_BIGNUM *p, struct LITE_BIGNUM *q,
+ uint32_t e_buf)
+{
+ uint32_t ONE_buf = 1;
+ uint32_t phi_buf[RSA_MAX_WORDS];
+ uint32_t q_buf[RSA_MAX_WORDS / 2 + 1];
+
+ struct LITE_BIGNUM ONE;
+ struct LITE_BIGNUM e;
+ struct LITE_BIGNUM phi;
+ struct LITE_BIGNUM q_local;
+
+ DCRYPTO_bn_wrap(&ONE, &ONE_buf, sizeof(ONE_buf));
+ DCRYPTO_bn_wrap(&phi, phi_buf, bn_size(N));
+ if (!q) {
+ /* q not provided, calculate it. */
+ memcpy(phi_buf, N->d, bn_size(N));
+ bn_init(&q_local, q_buf, bn_size(p));
+ q = &q_local;
+
+ if (!DCRYPTO_bn_div(q, NULL, &phi, p))
+ return 0;
+
+ /* Check that p * q == N */
+ DCRYPTO_bn_mul(&phi, p, q);
+ if (!bn_eq(N, &phi))
+ return 0;
+ } else {
+ DCRYPTO_bn_mul(N, p, q);
+ memcpy(phi_buf, N->d, bn_size(N));
+ }
+
+ bn_sub(&phi, p);
+ bn_sub(&phi, q);
+ bn_add(&phi, &ONE);
+ DCRYPTO_bn_wrap(&e, &e_buf, sizeof(e_buf));
+ return bn_modinv_vartime(d, &e, &phi);
+}
diff --git a/chip/g/dcrypto/sha1.c b/chip/g/dcrypto/sha1.c
new file mode 100644
index 0000000000..07ef3a34ef
--- /dev/null
+++ b/chip/g/dcrypto/sha1.c
@@ -0,0 +1,65 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+
+#include "cryptoc/sha.h"
+
+static void dcrypto_sha1_init(SHA_CTX *ctx);
+static const uint8_t *dcrypto_sha1_final(SHA_CTX *unused);
+
+/*
+ * Hardware SHA implementation.
+ */
+static const HASH_VTAB HW_SHA1_VTAB = {
+ dcrypto_sha1_init,
+ dcrypto_sha_update,
+ dcrypto_sha1_final,
+ DCRYPTO_SHA1_hash,
+ SHA_DIGEST_SIZE
+};
+
+/* Requires dcrypto_grab_sha_hw() to be called first. */
+static void dcrypto_sha1_init(SHA_CTX *ctx)
+{
+ ctx->f = &HW_SHA1_VTAB;
+ dcrypto_sha_init(SHA1_MODE);
+}
+
+/* Select and initialize either the software or hardware
+ * implementation. If "multi-threaded" behaviour is required, then
+ * callers must set sw_required to 1. This is because SHA1 state
+ * internal to the hardware cannot be extracted, so it is not possible
+ * to suspend and resume a hardware based SHA operation.
+ *
+ * If the caller has no preference as to implementation, then hardware
+ * is preferred based on availability. Hardware is considered to be
+ * in use between init() and finished() calls. */
+void DCRYPTO_SHA1_init(SHA_CTX *ctx, uint32_t sw_required)
+{
+ if (!sw_required && dcrypto_grab_sha_hw())
+ dcrypto_sha1_init(ctx);
+ else
+ SHA_init(ctx);
+}
+
+static const uint8_t *dcrypto_sha1_final(SHA_CTX *ctx)
+{
+ dcrypto_sha_wait(SHA1_MODE, (uint32_t *) ctx->buf);
+ return ctx->buf;
+}
+
+const uint8_t *DCRYPTO_SHA1_hash(const void *data, uint32_t n,
+ uint8_t *digest)
+{
+ if (dcrypto_grab_sha_hw())
+ /* dcrypto_sha_wait() will release the hw. */
+ dcrypto_sha_hash(SHA1_MODE, data, n, digest);
+ else
+ SHA_hash(data, n, digest);
+ return digest;
+}
diff --git a/chip/g/dcrypto/sha256.c b/chip/g/dcrypto/sha256.c
new file mode 100644
index 0000000000..f127ab445a
--- /dev/null
+++ b/chip/g/dcrypto/sha256.c
@@ -0,0 +1,195 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+#include "util.h"
+
+#include "cryptoc/sha256.h"
+
+static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx);
+static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx);
+
+#ifdef SECTION_IS_RO
+/* RO is single threaded. */
+#define mutex_lock(x)
+#define mutex_unlock(x)
+static inline int dcrypto_grab_sha_hw(void)
+{
+ return 1;
+}
+static inline void dcrypto_release_sha_hw(void)
+{
+}
+#else
+#include "task.h"
+static struct mutex hw_busy_mutex;
+
+static int hw_busy;
+
+int dcrypto_grab_sha_hw(void)
+{
+ int rv = 0;
+
+ mutex_lock(&hw_busy_mutex);
+ if (!hw_busy) {
+ rv = 1;
+ hw_busy = 1;
+ }
+ mutex_unlock(&hw_busy_mutex);
+
+ return rv;
+}
+
+void dcrypto_release_sha_hw(void)
+{
+ mutex_lock(&hw_busy_mutex);
+ hw_busy = 0;
+ mutex_unlock(&hw_busy_mutex);
+}
+
+#endif /* ! SECTION_IS_RO */
+
+void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest)
+{
+ int i;
+ const int digest_len = (mode == SHA1_MODE) ?
+ SHA_DIGEST_SIZE :
+ SHA256_DIGEST_SIZE;
+
+ /* Stop LIVESTREAM mode. */
+ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK;
+
+ /* Wait for SHA DONE interrupt. */
+ while (!GREG32(KEYMGR, SHA_ITOP))
+ ;
+
+ /* Read out final digest. */
+ for (i = 0; i < digest_len / 4; ++i)
+ *digest++ = GR_KEYMGR_SHA_HASH(i);
+ dcrypto_release_sha_hw();
+}
+
+/* Hardware SHA implementation. */
+static const HASH_VTAB HW_SHA256_VTAB = {
+ dcrypto_sha256_init,
+ dcrypto_sha_update,
+ dcrypto_sha256_final,
+ DCRYPTO_SHA256_hash,
+ SHA256_DIGEST_SIZE
+};
+
+void dcrypto_sha_hash(enum sha_mode mode, const uint8_t *data, uint32_t n,
+ uint8_t *digest)
+{
+ dcrypto_sha_init(mode);
+ dcrypto_sha_update(NULL, data, n);
+ dcrypto_sha_wait(mode, (uint32_t *) digest);
+}
+
+void dcrypto_sha_update(struct HASH_CTX *unused,
+ const void *data, uint32_t n)
+{
+ const uint8_t *bp = (const uint8_t *) data;
+ const uint32_t *wp;
+
+ /* Feed unaligned start bytes. */
+ while (n != 0 && ((uint32_t)bp & 3)) {
+ GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++;
+ n -= 1;
+ }
+
+ /* Feed groups of aligned words. */
+ wp = (uint32_t *)bp;
+ while (n >= 8*4) {
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ n -= 8*4;
+ }
+ /* Feed individual aligned words. */
+ while (n >= 4) {
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ n -= 4;
+ }
+
+ /* Feed remaing bytes. */
+ bp = (uint8_t *) wp;
+ while (n != 0) {
+ GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++;
+ n -= 1;
+ }
+}
+
+void dcrypto_sha_init(enum sha_mode mode)
+{
+ int val;
+
+ /* Stop LIVESTREAM mode, in case final() was not called. */
+ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK;
+ /* Clear interrupt status. */
+ GREG32(KEYMGR, SHA_ITOP) = 0;
+
+ /* Enable streaming mode. */
+ val = GC_KEYMGR_SHA_CFG_EN_LIVESTREAM_MASK;
+ /* Enable SHA DONE interrupt. */
+ val |= GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK;
+ /* Select SHA mode. */
+ if (mode == SHA1_MODE)
+ val |= GC_KEYMGR_SHA_CFG_EN_SHA1_MASK;
+ GREG32(KEYMGR, SHA_CFG_EN) = val;
+
+ /* Turn off random nops (which are enabled by default). */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 0);
+ /* Configure random nop percentage at 12%. */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, FREQ, 2);
+ /* Now turn on random nops. */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 1);
+
+ /* Start SHA engine. */
+ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK;
+}
+
+static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx)
+{
+ ctx->f = &HW_SHA256_VTAB;
+ dcrypto_sha_init(SHA256_MODE);
+}
+
+/* Requires dcrypto_grab_sha_hw() to be called first. */
+void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required)
+{
+ if (!sw_required && dcrypto_grab_sha_hw())
+ dcrypto_sha256_init(ctx);
+#ifndef SECTION_IS_RO
+ else
+ SHA256_init(ctx);
+#endif
+}
+
+static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx)
+{
+ dcrypto_sha_wait(SHA256_MODE, (uint32_t *) ctx->buf);
+ return ctx->buf;
+}
+
+const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n,
+ uint8_t *digest)
+{
+ if (dcrypto_grab_sha_hw())
+ /* dcrypto_sha_wait() will release the hw. */
+ dcrypto_sha_hash(SHA256_MODE, data, n, digest);
+#ifndef SECTION_IS_RO
+ else
+ SHA256_hash(data, n, digest);
+#endif
+ return digest;
+}
diff --git a/chip/g/dcrypto/sha384.c b/chip/g/dcrypto/sha384.c
new file mode 100644
index 0000000000..6f3c6ca096
--- /dev/null
+++ b/chip/g/dcrypto/sha384.c
@@ -0,0 +1,20 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+
+#include "cryptoc/sha384.h"
+
+void DCRYPTO_SHA384_init(LITE_SHA512_CTX *ctx)
+{
+ SHA384_init(ctx);
+}
+
+const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n,
+ uint8_t *digest)
+{
+ return SHA384_hash(data, n, digest);
+}
diff --git a/chip/g/dcrypto/sha512.c b/chip/g/dcrypto/sha512.c
new file mode 100644
index 0000000000..1446970174
--- /dev/null
+++ b/chip/g/dcrypto/sha512.c
@@ -0,0 +1,20 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+
+#include "cryptoc/sha512.h"
+
+void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx)
+{
+ SHA512_init(ctx);
+}
+
+const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n,
+ uint8_t *digest)
+{
+ return SHA512_hash(data, n, digest);
+}
diff --git a/chip/g/dcrypto/x509.c b/chip/g/dcrypto/x509.c
new file mode 100644
index 0000000000..81f1674db1
--- /dev/null
+++ b/chip/g/dcrypto/x509.c
@@ -0,0 +1,545 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+
+#include <stdint.h>
+
+/* Limit the size of long form encoded objects to < 64 kB. */
+#define MAX_ASN1_OBJ_LEN_BYTES 3
+
+/* Reserve space for TLV encoding */
+#define SEQ_SMALL 2 /* < 128 bytes (1B type, 1B 7-bit length) */
+#define SEQ_MEDIUM 3 /* < 256 bytes (1B type, 1B length size, 1B length) */
+#define SEQ_LARGE 4 /* < 65536 bytes (1B type, 1B length size, 2B length) */
+
+/* Tag related constants. */
+enum {
+ V_ASN1_INT = 0x02,
+ V_ASN1_BIT_STRING = 0x03,
+ V_ASN1_BYTES = 0x04,
+ V_ASN1_OBJ = 0x06,
+ V_ASN1_UTF8 = 0x0c,
+ V_ASN1_SEQUENCE = 0x10,
+ V_ASN1_SET = 0x11,
+ V_ASN1_ASCII = 0x13,
+ V_ASN1_TIME = 0x18,
+ V_ASN1_CONSTRUCTED = 0x20,
+ /* short helpers */
+ V_BITS = V_ASN1_BIT_STRING,
+ V_SEQ = V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE,
+ V_SET = V_ASN1_CONSTRUCTED | V_ASN1_SET,
+};
+
+struct asn1 {
+ uint8_t *p;
+ size_t n;
+};
+
+
+#define SEQ_START(X, T, L) \
+ do { \
+ int __old = (X).n; \
+ uint8_t __t = (T); \
+ int __l = (L); \
+ (X).n += __l;
+#define SEQ_END(X) \
+ (X).n = asn1_seq((X).p + __old, __t, __l, (X).n - __old - __l) + __old;\
+ } \
+ while (0)
+
+/* The SHA256 OID, from https://tools.ietf.org/html/rfc5754#section-3.2
+ * Only the object bytes below, the DER encoding header ([0x30 0x0d])
+ * is verified by the parser. */
+static const uint8_t OID_SHA256_WITH_RSA_ENCRYPTION[13] = {
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x0b, 0x05, 0x00
+};
+static const uint8_t OID_commonName[3] = {0x55, 0x04, 0x03};
+static const uint8_t OID_ecdsa_with_SHA256[8] = {0x2A, 0x86, 0x48, 0xCE,
+ 0x3D, 0x04, 0x03, 0x02};
+static const uint8_t OID_id_ecPublicKey[7] = {0x2A, 0x86, 0x48, 0xCE, 0x3D,
+ 0x02, 0x01};
+static const uint8_t OID_prime256v1[8] = {0x2A, 0x86, 0x48, 0xCE,
+ 0x3D, 0x03, 0x01, 0x07};
+static const uint8_t OID_fido_u2f[11] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x82,
+ 0xE5, 0x1C, 0x02, 0x01, 0x01};
+#define OID(X) sizeof(OID_##X), OID_##X
+
+/* ---- ASN.1 Generation ---- */
+
+/* start a tag and return write ptr */
+static uint8_t *asn1_tag(struct asn1 *ctx, uint8_t tag)
+{
+ ctx->p[(ctx->n)++] = tag;
+ return ctx->p + ctx->n;
+}
+
+/* DER encode length and return encoded size thereof */
+static int asn1_len(uint8_t *p, size_t size)
+{
+ if (size < 128) {
+ p[0] = size;
+ return 1;
+ } else if (size < 256) {
+ p[0] = 0x81;
+ p[1] = size;
+ return 2;
+ } else {
+ p[0] = 0x82;
+ p[1] = size >> 8;
+ p[2] = size;
+ return 3;
+ }
+}
+
+/*
+ * close sequence and move encapsulated data if needed
+ * return total length.
+ */
+static size_t asn1_seq(uint8_t *p, uint8_t tag, size_t l, size_t size)
+{
+ size_t tl;
+
+ p[0] = tag;
+ tl = asn1_len(p + 1, size) + 1;
+ /* TODO: tl > l fail */
+ if (tl < l)
+ memmove(p + tl, p + l, size);
+
+ return tl + size;
+}
+
+/* DER encode (small positive) integer */
+static void asn1_int(struct asn1 *ctx, uint32_t val)
+{
+ uint8_t *p = asn1_tag(ctx, V_ASN1_INT);
+
+ if (!val) {
+ *p++ = 1;
+ *p++ = 0;
+ } else {
+ int nbits = 32 - __builtin_clz(val);
+ int nbytes = (nbits + 7) / 8;
+
+ if ((nbits & 7) == 0) {
+ *p++ = nbytes + 1;
+ *p++ = 0;
+ } else {
+ *p++ = nbytes;
+ }
+ while (nbytes--)
+ *p++ = val >> (nbytes * 8);
+ }
+
+ ctx->n = p - ctx->p;
+}
+
+/* DER encode positive p256_int */
+static void asn1_p256_int(struct asn1 *ctx, const p256_int *n)
+{
+ uint8_t *p = asn1_tag(ctx, V_ASN1_INT);
+ uint8_t bn[P256_NBYTES];
+ int i;
+
+ p256_to_bin(n, bn);
+ for (i = 0; i < P256_NBYTES; ++i) {
+ if (bn[i] != 0)
+ break;
+ }
+ if (bn[i] & 0x80) {
+ *p++ = P256_NBYTES - i + 1;
+ *p++ = 0;
+ } else {
+ *p++ = P256_NBYTES - i;
+ }
+ for (; i < P256_NBYTES; ++i)
+ *p++ = bn[i];
+
+ ctx->n = p - ctx->p;
+}
+
+/* DER encode p256 signature */
+static void asn1_sig(struct asn1 *ctx, const p256_int *r, const p256_int *s)
+{
+ SEQ_START(*ctx, V_SEQ, SEQ_SMALL) {
+ asn1_p256_int(ctx, r);
+ asn1_p256_int(ctx, s);
+ }
+ SEQ_END(*ctx);
+}
+
+/* DER encode printable string */
+static void asn1_string(struct asn1 *ctx, uint8_t tag, const char *s)
+{
+ uint8_t *p = asn1_tag(ctx, tag);
+ size_t n = strlen(s);
+
+ p += asn1_len(p, n);
+ while (n--)
+ *p++ = *s++;
+
+ ctx->n = p - ctx->p;
+}
+
+/* DER encode bytes */
+static void asn1_object(struct asn1 *ctx, size_t n, const uint8_t *b)
+{
+ uint8_t *p = asn1_tag(ctx, V_ASN1_OBJ);
+
+ p += asn1_len(p, n);
+ while (n--)
+ *p++ = *b++;
+
+ ctx->n = p - ctx->p;
+}
+
+/* DER encode p256 pk */
+static void asn1_pub(struct asn1 *ctx, const p256_int *x, const p256_int *y)
+{
+ uint8_t *p = asn1_tag(ctx, 4); /* uncompressed format */
+
+ p256_to_bin(x, p); p += P256_NBYTES;
+ p256_to_bin(y, p); p += P256_NBYTES;
+
+ ctx->n = p - ctx->p;
+}
+
+size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s)
+{
+ struct asn1 asn1 = {buf, 0};
+
+ asn1_sig(&asn1, r, s);
+ return asn1.n;
+}
+
+size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y)
+{
+ struct asn1 asn1 = {buf, 0};
+
+ asn1_pub(&asn1, x, y);
+ return asn1.n;
+}
+
+/* ---- ASN.1 Parsing ---- */
+
+/*
+ * An ASN.1 DER (Definite Encoding Rules) parser.
+ * Details about the format are available here:
+ * https://en.wikipedia.org/wiki/X.690#Definite_form
+ */
+static size_t asn1_parse(const uint8_t **p, size_t available,
+ uint8_t expected_type, const uint8_t **out,
+ size_t *out_len, size_t *remaining)
+{
+ const size_t tag_len = 1;
+ const uint8_t *in = *p;
+ size_t obj_len = 0;
+ size_t obj_len_bytes;
+ size_t consumed;
+
+ if (available < 2)
+ return 0;
+ if (in[0] != expected_type) /* in[0] specifies the tag. */
+ return 0;
+
+ if ((in[1] & 128) == 0) {
+ /* Short-length encoding (i.e. obj_len <= 127). */
+ obj_len = in[1];
+ obj_len_bytes = 1;
+ } else {
+ int i;
+
+ obj_len_bytes = 1 + (in[1] & 127);
+ if (obj_len_bytes > MAX_ASN1_OBJ_LEN_BYTES ||
+ tag_len + obj_len_bytes > available)
+ return 0;
+
+ if (in[2] == 0)
+ /* Definite form encoding requires minimal
+ * length encoding. */
+ return 0;
+ for (i = 0; i < obj_len_bytes - 1; i++) {
+ obj_len <<= 8;
+ obj_len |= in[tag_len + 1 + i];
+ }
+ }
+
+ consumed = tag_len + obj_len_bytes + obj_len;
+ if (consumed > available)
+ return 0; /* Invalid object length.*/
+ if (out)
+ *out = &in[tag_len + obj_len_bytes];
+ if (out_len)
+ *out_len = obj_len;
+
+ *p = in + consumed;
+ if (remaining)
+ *remaining = available - consumed;
+ return consumed;
+}
+
+static size_t asn1_parse_certificate(const uint8_t **p, size_t *available)
+{
+ size_t consumed;
+ size_t obj_len;
+ const uint8_t *in = *p;
+
+ consumed = asn1_parse(&in, *available,
+ V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE,
+ NULL, &obj_len, NULL);
+ if (consumed == 0 || consumed != *available) /* Invalid SEQUENCE. */
+ return 0;
+ *p += consumed - obj_len;
+ *available -= consumed - obj_len;
+ return 1;
+}
+
+static size_t asn1_parse_tbs(const uint8_t **p, size_t *available,
+ size_t *tbs_len)
+{
+ size_t consumed;
+
+ consumed = asn1_parse(p, *available,
+ V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE,
+ NULL, NULL, available);
+ if (consumed == 0)
+ return 0;
+ *tbs_len = consumed;
+ return 1;
+}
+
+static size_t asn1_parse_signature_algorithm(const uint8_t **p,
+ size_t *available)
+{
+ const uint8_t *alg_oid;
+ size_t alg_oid_len;
+
+ if (!asn1_parse(p, *available, V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE,
+ &alg_oid, &alg_oid_len, available))
+ return 0;
+ if (alg_oid_len != sizeof(OID_SHA256_WITH_RSA_ENCRYPTION))
+ return 0;
+ if (memcmp(alg_oid, OID_SHA256_WITH_RSA_ENCRYPTION,
+ sizeof(OID_SHA256_WITH_RSA_ENCRYPTION)) != 0)
+ return 0;
+ return 1;
+}
+
+static size_t asn1_parse_signature_value(const uint8_t **p, size_t *available,
+ const uint8_t **sig, size_t *sig_len)
+{
+ if (!asn1_parse(p, *available, V_ASN1_BIT_STRING,
+ sig, sig_len, available))
+ return 0;
+ if (*available != 0)
+ return 0; /* Not all input bytes consumed. */
+ return 1;
+}
+
+/* This method verifies that the provided X509 certificate was issued
+ * by the specified certifcate authority.
+ *
+ * cert is a pointer to a DER encoded X509 certificate, as specified
+ * in https://tools.ietf.org/html/rfc5280#section-4.1. In ASN.1
+ * notation, the certificate has the following structure:
+ *
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+ *
+ * TBSCertificate ::= SEQUENCE { }
+ * AlgorithmIdentifier ::= SEQUENCE { }
+ *
+ * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and
+ * HASH specified by signatureAlgorithm.
+ */
+int DCRYPTO_x509_verify(const uint8_t *cert, size_t len,
+ const struct RSA *ca_pub_key)
+{
+ const uint8_t *p = cert;
+ const uint8_t *tbs;
+ size_t tbs_len;
+ const uint8_t *sig;
+ size_t sig_len;
+
+ uint8_t digest[SHA256_DIGEST_SIZE];
+
+ /* Read Certificate SEQUENCE. */
+ if (!asn1_parse_certificate(&p, &len))
+ return 0;
+
+ /* Read tbsCertificate SEQUENCE. */
+ tbs = p;
+ if (!asn1_parse_tbs(&p, &len, &tbs_len))
+ return 0;
+
+ /* Read signatureAlgorithm SEQUENCE. */
+ if (!asn1_parse_signature_algorithm(&p, &len))
+ return 0;
+
+ /* Read signatureValue BIT STRING. */
+ if (!asn1_parse_signature_value(&p, &len, &sig, &sig_len))
+ return 0;
+
+ /* Check that the signature length corresponds to the issuer's
+ * public key size. */
+ if (sig_len != bn_size(&ca_pub_key->N) &&
+ sig_len != bn_size(&ca_pub_key->N) + 1)
+ return 0;
+ /* Check that leading signature bytes (if any) are zero. */
+ if (sig_len == bn_size(&ca_pub_key->N) + 1) {
+ if (sig[0] != 0)
+ return 0;
+ sig++;
+ sig_len--;
+ }
+
+ DCRYPTO_SHA256_hash(tbs, tbs_len, digest);
+ return DCRYPTO_rsa_verify(ca_pub_key, digest, sizeof(digest),
+ sig, sig_len, PADDING_MODE_PKCS1, HASH_SHA256);
+}
+
+/* ---- Certificate generation ---- */
+
+static void add_common_name(struct asn1 *ctx, const char *cname)
+{
+ SEQ_START(*ctx, V_SEQ, SEQ_SMALL) {
+ SEQ_START(*ctx, V_SET, SEQ_SMALL) {
+ SEQ_START(*ctx, V_SEQ, SEQ_SMALL) {
+ asn1_object(ctx, OID(commonName));
+ asn1_string(ctx, V_ASN1_ASCII, cname);
+ }
+ SEQ_END(*ctx);
+ }
+ SEQ_END(*ctx);
+ }
+ SEQ_END(*ctx);
+}
+
+int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x,
+ const p256_int *pk_y, const p256_int *serial,
+ const char *name, uint8_t *cert, const int n)
+{
+ struct asn1 ctx = {cert, 0};
+ HASH_CTX sha;
+ p256_int h, r, s;
+ struct drbg_ctx drbg;
+
+ SEQ_START(ctx, V_SEQ, SEQ_LARGE) { /* outer seq */
+ /*
+ * Grab current pointer to data to hash later.
+ * Note this will fail if cert body + cert sign is less
+ * than 256 bytes (SEQ_MEDIUM) -- not likely.
+ */
+ uint8_t *body = ctx.p + ctx.n;
+
+ /* Cert body seq */
+ SEQ_START(ctx, V_SEQ, SEQ_MEDIUM) {
+ /* X509 v3 */
+ SEQ_START(ctx, 0xa0, SEQ_SMALL) {
+ asn1_int(&ctx, 2);
+ }
+ SEQ_END(ctx);
+
+ /* Serial number */
+ if (serial)
+ asn1_p256_int(&ctx, serial);
+ else
+ asn1_int(&ctx, 1);
+
+ /* Signature algo */
+ SEQ_START(ctx, V_SEQ, SEQ_SMALL) {
+ asn1_object(&ctx, OID(ecdsa_with_SHA256));
+ }
+ SEQ_END(ctx);
+
+ /* Issuer */
+ add_common_name(&ctx, name);
+
+ /* Expiry */
+ SEQ_START(ctx, V_SEQ, SEQ_SMALL) {
+ asn1_string(&ctx, V_ASN1_TIME, "20000101000000Z");
+ asn1_string(&ctx, V_ASN1_TIME, "20991231235959Z");
+ }
+ SEQ_END(ctx);
+
+ /* Subject */
+ add_common_name(&ctx, name);
+
+ /* Subject pk */
+ SEQ_START(ctx, V_SEQ, SEQ_SMALL) {
+ /* pk parameters */
+ SEQ_START(ctx, V_SEQ, SEQ_SMALL) {
+ asn1_object(&ctx, OID(id_ecPublicKey));
+ asn1_object(&ctx, OID(prime256v1));
+ }
+ SEQ_END(ctx);
+ /* pk bits */
+ SEQ_START(ctx, V_BITS, SEQ_SMALL) {
+ /* No unused bit at the end */
+ asn1_tag(&ctx, 0);
+ asn1_pub(&ctx, pk_x, pk_y);
+ }
+ SEQ_END(ctx);
+ }
+ SEQ_END(ctx);
+
+ /* U2F transports indicator extension */
+ SEQ_START(ctx, 0xa3, SEQ_SMALL) {
+ SEQ_START(ctx, V_SEQ, SEQ_SMALL) {
+ SEQ_START(ctx, V_SEQ, SEQ_SMALL) {
+ asn1_object(&ctx, OID(fido_u2f));
+ SEQ_START(ctx, V_ASN1_BYTES, SEQ_SMALL) {
+ SEQ_START(ctx, V_BITS, SEQ_SMALL) {
+ /* 3 zero bits */
+ asn1_tag(&ctx, 3);
+ /* usb-internal transport */
+ asn1_tag(&ctx, 0x08);
+ }
+ SEQ_END(ctx);
+ }
+ SEQ_END(ctx);
+ }
+ SEQ_END(ctx);
+ }
+ SEQ_END(ctx);
+ }
+ SEQ_END(ctx);
+ }
+ SEQ_END(ctx); /* Cert body */
+
+ /* Sign all of cert body */
+ DCRYPTO_SHA256_init(&sha, 0);
+ HASH_update(&sha, body, (ctx.p + ctx.n) - body);
+ p256_from_bin(HASH_final(&sha), &h);
+ hmac_drbg_init_rfc6979(&drbg, d, &h);
+ if (!dcrypto_p256_ecdsa_sign(&drbg, d, &h, &r, &s))
+ return 0;
+
+ /* Append X509 signature */
+ SEQ_START(ctx, V_SEQ, SEQ_SMALL);
+ asn1_object(&ctx, OID(ecdsa_with_SHA256));
+ SEQ_END(ctx);
+ SEQ_START(ctx, V_BITS, SEQ_SMALL) {
+ /* no unused/zero bit at the end */
+ asn1_tag(&ctx, 0);
+ asn1_sig(&ctx, &r, &s);
+ } SEQ_END(ctx);
+
+ } SEQ_END(ctx); /* end of outer seq */
+
+ return ctx.n;
+}
+
+int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x,
+ const p256_int *pk_y, const p256_int *serial,
+ uint8_t *cert, const int n)
+{
+ return DCRYPTO_x509_gen_u2f_cert_name(d, pk_x, pk_y, serial,
+ serial ? STRINGIFY(BOARD) : "U2F",
+ cert, n);
+}
diff --git a/chip/g/trng.c b/chip/g/trng.c
new file mode 100644
index 0000000000..94363b29c4
--- /dev/null
+++ b/chip/g/trng.c
@@ -0,0 +1,236 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "flash_log.h"
+#include "init_chip.h"
+#include "registers.h"
+#include "trng.h"
+#include "watchdog.h"
+#include "console.h"
+
+/**
+ * The H1 TRNG uses the collapse time of a ring oscillator (RO) that is
+ * initialized in a 3x mode (three enable pulses) and eventually collapses
+ * to a stable 1x mode as a result of accumulated jitter (thermal noise).
+ * A Phase-Frequency Detector (PFD) compares the 3x RO to a reference
+ * RO (1.5x) and captures the state of a counter that is incremented
+ * from the reference RO. The resulting reference-cycles-to-collapse
+ * distribution is log-normal, and truncation of the counter bits results in
+ * a distribution that approaches uniform.
+ *
+ * TRNG_SAMPLE_BITS defines how many bits to use from the 16 bit counter
+ * output coming from the analog unit. Entropy is highest in least significant
+ * bits of counter. For FIPS-certified code use just Bit 0 - it provides
+ * highest entropy, allows better security settings for TRNG and simplifies
+ * implementation of continuous health tests.
+ */
+#ifndef TRNG_SAMPLE_BITS
+#define TRNG_SAMPLE_BITS 1
+#endif
+
+/**
+ * Attempts to read TRNG_EMPTY before reporting a stall. Practically data should
+ * be available in less than 0x7ff cycles under normal conditions. 0x7ff was
+ * chosen to match the hardware TRNG TIMEOUT_COUNTER. Test on boards with slow
+ * TRNG before reducing this number.
+ */
+#define TRNG_EMPTY_COUNT 0x7ff
+
+void init_trng(void)
+{
+#if (!(defined(CONFIG_CUSTOMIZED_RO) && defined(SECTION_IS_RO)))
+ /*
+ * Most of the trng initialization requires high permissions. If RO has
+ * dropped the permission level, dont try to read or write these high
+ * permission registers because it will cause rolling reboots. RO
+ * should do the TRNG initialization before dropping the level.
+ */
+ if (!runlevel_is_high())
+ return;
+#endif
+ /**
+ * According to NIST SP 800-90B only vetted conditioning mechanism
+ * should be used for post-processing raw entropy.
+ * See SP 800-90B, 3.1.5.1 Using Vetted Conditioning Components.
+ * Use of non-vetted algorithms is governed in 3.1.5.2, but
+ * assumes conservative coefficient 0.85 for entropy estimate,
+ * which increase number of requests to TRNG to get desirable
+ * entropy and prevents from getting full entropy.
+ */
+ GWRITE(TRNG, POST_PROCESSING_CTRL, 0);
+
+ /**
+ * TRNG can return up to 16 bits at a time, but highest bits
+ * have lower entropy. Practically on Cr50 only 13 bits can be
+ * used - setting to higher value makes TRNG_EMPTY always set.
+ * Entropy assessed to be reasonable (one bit H > 0.85)
+ * for up to 8 bits [7..0].
+ * Time to get 32bit random is roughly 160/TRNG_SAMPLE_BITS us.
+ */
+ GWRITE(TRNG, SLICE_MAX_UPPER_LIMIT, TRNG_SAMPLE_BITS - 1);
+
+ /* lowest bit have highest entropy, so always start from it */
+ GWRITE(TRNG, SLICE_MIN_LOWER_LIMIT, 0);
+
+ /**
+ * Analog logic cannot create a value < 8 under normal operating
+ * conditions, but there's a chance that an attacker could coax
+ * them out.
+ * Bit 0 - Enable rejection for values outside of range specified
+ * by TRNG_ALLOWED_VALUES register
+ */
+ GWRITE(TRNG, SECURE_POST_PROCESSING_CTRL, 0x1);
+
+ /**
+ * Since for FIPS settings we use TRNG_SAMPLE_BITS = 1,
+ * and take only bit 0 from internal 16 bit reading, no bias is
+ * created for bit 0 if allowed_min is set to 6, which
+ * actually means min accepted value is 8 (RTL adds +2).
+ * TRNG_ALLOWED_VALUES_MAX=0x04 (accept all values up to 2^16-1).
+ * So, range will be [8..65535], with probability for bit 0 and 1
+ * remaining 50/50.
+ */
+ GWRITE(TRNG, ALLOWED_VALUES_MIN, 0x26);
+
+ GWRITE(TRNG, TIMEOUT_COUNTER, 0x7ff);
+ GWRITE(TRNG, TIMEOUT_MAX_TRY_NUM, 4);
+ GWRITE(TRNG, POWER_DOWN_B, 1);
+ GWRITE(TRNG, GO_EVENT, 1);
+}
+
+uint32_t rand(void)
+{ uint32_t empty_count = 0;
+
+ while (GREAD(TRNG, EMPTY)) {
+ if (GREAD_FIELD(TRNG, FSM_STATE, FSM_IDLE) ||
+ empty_count > TRNG_EMPTY_COUNT) {
+ /* TRNG timed out, restart */
+ GWRITE(TRNG, STOP_WORK, 1);
+#if !defined(SECTION_IS_RO) && defined(CONFIG_FLASH_LOG)
+ flash_log_add_event(FE_LOG_TRNG_STALL, 0, NULL);
+#endif
+ GWRITE(TRNG, GO_EVENT, 1);
+ empty_count = 0;
+ }
+ empty_count++;
+ }
+ return GREAD(TRNG, READ_DATA);
+}
+
+void rand_bytes(void *buffer, size_t len)
+{
+ int random_togo = 0;
+ int buffer_index = 0;
+ uint32_t random_value;
+ uint8_t *buf = (uint8_t *) buffer;
+
+ /*
+ * Retrieve random numbers in 4 byte quantities and pack as many bytes
+ * as needed into 'buffer'. If len is not divisible by 4, the
+ * remaining random bytes get dropped.
+ */
+ while (buffer_index < len) {
+ if (!random_togo) {
+ random_value = rand();
+ random_togo = sizeof(random_value);
+ }
+ buf[buffer_index++] = random_value >>
+ ((random_togo-- - 1) * 8);
+ }
+}
+
+#if !defined(SECTION_IS_RO) && defined(CRYPTO_TEST_SETUP)
+#include "console.h"
+#include "watchdog.h"
+
+static void print_rand_stat(uint32_t *histogram, size_t size)
+{
+ struct pair {
+ uint32_t value;
+ uint32_t count;
+ };
+ struct pair min;
+ struct pair max;
+ size_t count;
+
+ min.count = ~0;
+ max.count = 0;
+ max.value = ~0;
+ min.value = ~0;
+
+ for (count = 0; count < size; count++) {
+ if (histogram[count] > max.count) {
+ max.count = histogram[count];
+ max.value = count;
+ }
+ if (histogram[count] < min.count) {
+ min.count = histogram[count];
+ min.value = count;
+ }
+ }
+
+ ccprintf("min %d(%d), max %d(%d)", min.count, min.value,
+ max.count, max.value);
+
+ for (count = 0; count < size; count++) {
+ if (!(count % 8)) {
+ ccprintf("\n");
+ cflush();
+ }
+ ccprintf(" %6d", histogram[count]);
+ }
+ ccprintf("\n");
+}
+
+/* histogram at byte level */
+static uint32_t histogram[256];
+/* histogram at level of TRNG samples */
+static uint32_t histogram_trng[1 << TRNG_SAMPLE_BITS];
+
+static int command_rand(int argc, char **argv)
+{
+ int count = 1000; /* Default number of cycles. */
+ uint32_t val = 0, bits = 0;
+
+ if (argc == 2)
+ count = strtoi(argv[1], NULL, 10);
+
+ memset(histogram, 0, sizeof(histogram));
+ memset(histogram_trng, 0, sizeof(histogram_trng));
+ ccprintf("Retrieving %d 32-bit random words.\n", count);
+ while (count-- > 0) {
+ uint32_t rvalue;
+ int size;
+
+ rvalue = rand();
+ /* update byte-level histogram */
+ for (size = 0; size < sizeof(rvalue); size++)
+ histogram[((uint8_t *)&rvalue)[size]]++;
+
+ /* update histogram on TRNG sample size level */
+ val = (val | (rvalue << bits)) & ((1 << TRNG_SAMPLE_BITS) - 1);
+ rvalue >>= TRNG_SAMPLE_BITS - bits;
+ bits += 32;
+ while (bits >= TRNG_SAMPLE_BITS) {
+ histogram_trng[val]++;
+ val = rvalue & ((1 << TRNG_SAMPLE_BITS) - 1);
+ rvalue >>= TRNG_SAMPLE_BITS;
+ bits -= TRNG_SAMPLE_BITS;
+ };
+
+ if (!(count % 10000))
+ watchdog_reload();
+ }
+ ccprintf("Byte-level histogram:\n");
+ print_rand_stat(histogram, ARRAY_SIZE(histogram));
+ ccprintf("\nSample-level (%d bits) histogram:\n", TRNG_SAMPLE_BITS);
+ print_rand_stat(histogram_trng, ARRAY_SIZE(histogram_trng));
+
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(rand, command_rand, NULL, NULL);
+
+#endif /* CRYPTO_TEST_SETUP */