summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagendra modadugu <ngm@google.com>2016-01-22 11:37:48 -0800
committerchrome-bot <chrome-bot@chromium.org>2016-02-08 15:24:29 -0800
commit7ac69e594b9a092dfeb76a4969396f7ddde4fbee (patch)
treec8c9eb1d45a74fbc9b9892e28a0c75b46818cb2a
parent89424bfbedba6c06f4a4ef9e444a2c4d0575883a (diff)
downloadchrome-ec-7ac69e594b9a092dfeb76a4969396f7ddde4fbee.tar.gz
CR50: Add initial elliptic curve crypto implementation.
This change adds support for NIST-P256 curve operations. BRANCH=none BUG=chrome-os-partner:43025,chrome-os-partner:47524 TEST=new tests under test/tpm2/ pass. Change-Id: I03a35ff3ab8af3c52282d882937880bfa2bdcd32 Signed-off-by: nagendra modadugu <ngm@google.com> Reviewed-on: https://chromium-review.googlesource.com/324540 Commit-Ready: Nagendra Modadugu <ngm@google.com> Tested-by: Nagendra Modadugu <ngm@google.com> Reviewed-by: Marius Schilder <mschilder@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--board/cr50/build.mk1
-rw-r--r--board/cr50/ec.tasklist2
-rw-r--r--board/cr50/tpm2/ecc.c464
-rw-r--r--board/cr50/tpm2/stubs.c80
-rw-r--r--chip/g/build.mk4
-rw-r--r--chip/g/dcrypto/dcrypto.h18
-rw-r--r--chip/g/dcrypto/hmac.c56
-rw-r--r--chip/g/dcrypto/internal.h62
-rw-r--r--chip/g/dcrypto/p256.c444
-rw-r--r--chip/g/dcrypto/p256_ec.c1403
-rw-r--r--chip/g/dcrypto/p256_ecdsa.c103
-rw-r--r--include/extension.h1
-rw-r--r--test/tpm_test/ecc_test.py169
-rw-r--r--test/tpm_test/subcmd.py1
-rwxr-xr-xtest/tpm_test/tpmtest.py2
15 files changed, 2729 insertions, 81 deletions
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index b8f15919d6..9960700996 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -31,6 +31,7 @@ dirs-y += $(BDIR)/tpm2
board-y = board.o
board-y += tpm2/NVMem.o
board-y += tpm2/aes.o
+board-y += tpm2/ecc.o
board-y += tpm2/hash.o
board-y += tpm2/hash_data.o
board-y += tpm2/platform.o
diff --git a/board/cr50/ec.tasklist b/board/cr50/ec.tasklist
index f48774f1b8..52f4af3000 100644
--- a/board/cr50/ec.tasklist
+++ b/board/cr50/ec.tasklist
@@ -19,6 +19,6 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(BLOB, blob_task, NULL, TASK_STACK_SIZE) \
- TASK_NOTEST(TPM, tpm_task, NULL, 4096) \
+ TASK_NOTEST(TPM, tpm_task, NULL, 8192) \
TASK_NOTEST(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)
diff --git a/board/cr50/tpm2/ecc.c b/board/cr50/tpm2/ecc.c
new file mode 100644
index 0000000000..d3ca3069f8
--- /dev/null
+++ b/board/cr50/tpm2/ecc.c
@@ -0,0 +1,464 @@
+/* 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.
+ */
+/*
+ * TODO(ngm): only the NIST-P256 curve is currently supported.
+ */
+
+#include "CryptoEngine.h"
+#include "TPMB.h"
+
+#include "trng.h"
+#include "dcrypto.h"
+
+TPM2B_BYTE_VALUE(4);
+
+static int check_p256_param(const TPM2B_ECC_PARAMETER *a)
+{
+ return a->b.size == sizeof(p256_int);
+}
+
+static int check_p256_point(const TPMS_ECC_POINT *a)
+{
+ return check_p256_param(&a->x) &&
+ check_p256_param(&a->y);
+}
+
+BOOL _cpri__EccIsPointOnCurve(TPM_ECC_CURVE curve_id, TPMS_ECC_POINT *q)
+{
+ switch (curve_id) {
+ case TPM_ECC_NIST_P256:
+ if (!check_p256_point(q))
+ return FALSE;
+
+ if (DCRYPTO_p256_valid_point((p256_int *) q->x.b.buffer,
+ (p256_int *) q->y.b.buffer))
+ return TRUE;
+ else
+ return FALSE;
+ default:
+ return FALSE;
+ }
+}
+
+/* out = n1*G + n2*in */
+CRYPT_RESULT _cpri__EccPointMultiply(
+ TPMS_ECC_POINT *out, TPM_ECC_CURVE curve_id,
+ TPM2B_ECC_PARAMETER *n1, TPMS_ECC_POINT *in, TPM2B_ECC_PARAMETER *n2)
+{
+ int result;
+
+ switch (curve_id) {
+ case TPM_ECC_NIST_P256:
+ if (!check_p256_param(n1))
+ return CRYPT_PARAMETER;
+ if (in != NULL && !check_p256_point(in))
+ return CRYPT_PARAMETER;
+ if (n2 != NULL && !check_p256_param(n2))
+ return CRYPT_PARAMETER;
+
+ if (in == NULL || n2 == NULL)
+ result = DCRYPTO_p256_base_point_mul(
+ (p256_int *) out->x.b.buffer,
+ (p256_int *) out->y.b.buffer,
+ (p256_int *) n1->b.buffer);
+ else
+ result = DCRYPTO_p256_points_mul(
+ (p256_int *) out->x.b.buffer,
+ (p256_int *) out->y.b.buffer,
+ (p256_int *) n1->b.buffer,
+ (p256_int *) n2->b.buffer,
+ (p256_int *) in->x.b.buffer,
+ (p256_int *) in->y.b.buffer);
+
+ if (result) {
+ out->x.b.size = sizeof(p256_int);
+ out->y.b.size = sizeof(p256_int);
+ return CRYPT_SUCCESS;
+ } else {
+ return CRYPT_NO_RESULT;
+ }
+ default:
+ return CRYPT_FAIL;
+ }
+}
+
+/* Key generation based on FIPS-186.4 section B.1.2 (Key Generation by
+ * Testing Candidates) */
+CRYPT_RESULT _cpri__GenerateKeyEcc(
+ TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d,
+ TPM_ECC_CURVE curve_id, TPM_ALG_ID hash_alg,
+ TPM2B *seed, const char *label, TPM2B *extra, UINT32 *counter)
+{
+ TPM2B_4_BYTE_VALUE marshaled_counter = { .t = {4} };
+ uint32_t count = 0;
+ uint8_t key_bytes[P256_NBYTES];
+
+ if (curve_id != TPM_ECC_NIST_P256)
+ return CRYPT_PARAMETER;
+
+ /* extra may be empty, but seed must be specified. */
+ if (seed == NULL || seed->size < PRIMARY_SEED_SIZE)
+ return CRYPT_PARAMETER;
+
+ if (counter != NULL)
+ count = *counter;
+ if (count == 0)
+ count++;
+
+ for (; count != 0; count++) {
+ memcpy(marshaled_counter.t.buffer, &count, sizeof(count));
+ _cpri__KDFa(hash_alg, seed, label, extra, &marshaled_counter.b,
+ sizeof(key_bytes) * 8, key_bytes, NULL, FALSE);
+ if (DCRYPTO_p256_key_from_bytes(
+ (p256_int *) q->x.b.buffer,
+ (p256_int *) q->y.b.buffer,
+ (p256_int *) d->b.buffer, key_bytes))
+ break;
+ }
+
+ if (count == 0)
+ FAIL(FATAL_ERROR_INTERNAL);
+ if (counter != NULL)
+ *counter = count;
+ return CRYPT_SUCCESS;
+}
+
+CRYPT_RESULT _cpri__SignEcc(
+ TPM2B_ECC_PARAMETER *r, TPM2B_ECC_PARAMETER *s,
+ TPM_ALG_ID scheme, TPM_ALG_ID hash_alg, TPM_ECC_CURVE curve_id,
+ TPM2B_ECC_PARAMETER *d, TPM2B *digest, TPM2B_ECC_PARAMETER *k)
+{
+ uint8_t digest_local[sizeof(p256_int)];
+ const size_t digest_len = MIN(digest->size, sizeof(digest_local));
+ p256_int p256_digest;
+
+ if (curve_id != TPM_ECC_NIST_P256)
+ return CRYPT_PARAMETER;
+
+ switch (scheme) {
+ case TPM_ALG_ECDSA:
+ if (!check_p256_param(d))
+ return CRYPT_PARAMETER;
+ /* Trucate / zero-pad the digest as appropriate. */
+ memset(digest_local, 0, sizeof(digest_local));
+ memcpy(digest_local + sizeof(digest_local) - digest_len,
+ digest->buffer, digest_len);
+ p256_from_bin(digest_local, &p256_digest);
+ DCRYPTO_p256_ecdsa_sign((p256_int *) d->b.buffer,
+ &p256_digest,
+ (p256_int *) r->b.buffer,
+ (p256_int *) s->b.buffer);
+ r->b.size = sizeof(p256_int);
+ s->b.size = sizeof(p256_int);
+ return CRYPT_SUCCESS;
+ default:
+ return CRYPT_PARAMETER;
+ }
+}
+
+CRYPT_RESULT _cpri__ValidateSignatureEcc(
+ TPM2B_ECC_PARAMETER *r, TPM2B_ECC_PARAMETER *s,
+ TPM_ALG_ID scheme, TPM_ALG_ID hash_alg,
+ TPM_ECC_CURVE curve_id, TPMS_ECC_POINT *q, TPM2B *digest)
+{
+ uint8_t digest_local[sizeof(p256_int)];
+ const size_t digest_len = MIN(digest->size, sizeof(digest_local));
+ p256_int p256_digest;
+
+ if (curve_id != TPM_ECC_NIST_P256)
+ return CRYPT_PARAMETER;
+
+ switch (scheme) {
+ case TPM_ALG_ECDSA:
+ /* Trucate / zero-pad the digest as appropriate. */
+ memset(digest_local, 0, sizeof(digest_local));
+ memcpy(digest_local + sizeof(digest_local) - digest_len,
+ digest->buffer, digest_len);
+ p256_from_bin(digest_local, &p256_digest);
+ if (DCRYPTO_p256_ecdsa_verify(
+ (p256_int *) q->x.b.buffer,
+ (p256_int *) q->y.b.buffer,
+ &p256_digest,
+ (p256_int *) r->b.buffer,
+ (p256_int *) s->b.buffer))
+ return CRYPT_SUCCESS;
+ else
+ return CRYPT_FAIL;
+ default:
+ return CRYPT_PARAMETER;
+ }
+}
+
+CRYPT_RESULT _cpri__GetEphemeralEcc(TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d,
+ TPM_ECC_CURVE curve_id)
+{
+ uint8_t key_bytes[P256_NBYTES] __aligned(4);
+
+ if (curve_id != TPM_ECC_NIST_P256)
+ return CRYPT_PARAMETER;
+
+ rand_bytes(key_bytes, sizeof(key_bytes));
+ if (DCRYPTO_p256_key_from_bytes((p256_int *) q->x.b.buffer,
+ (p256_int *) q->y.b.buffer,
+ (p256_int *) d->b.buffer,
+ key_bytes))
+ return CRYPT_SUCCESS;
+ else
+ return CRYPT_FAIL;
+}
+
+#ifdef CRYPTO_TEST_SETUP
+
+#include "extension.h"
+
+enum {
+ TEST_SIGN = 0,
+ TEST_VERIFY = 1,
+ TEST_KEYGEN = 2,
+ TEST_KEYDERIVE = 3
+};
+
+struct TPM2B_ECC_PARAMETER_aligned {
+ uint16_t pad;
+ TPM2B_ECC_PARAMETER d;
+} __packed __aligned(4);
+
+struct TPM2B_MAX_BUFFER_aligned {
+ uint16_t pad;
+ TPM2B_MAX_BUFFER d;
+} __packed __aligned(4);
+
+static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_d = {
+ .d = {
+ .t = {32, {
+ 0x0a, 0xd2, 0xa0, 0xfe, 0x89, 0xb2, 0x91, 0x09,
+ 0x87, 0xd4, 0x7f, 0xa2, 0x1f, 0xc9, 0x3e, 0x7e,
+ 0x7b, 0x2f, 0x48, 0x29, 0x6b, 0xe6, 0xb7, 0x09,
+ 0xf1, 0x48, 0x4e, 0x74, 0x07, 0x1e, 0x44, 0xfc
+ }
+ }
+ }
+};
+
+static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_qx = {
+ .d = {
+ .t = {32, {
+ 0xde, 0x81, 0x07, 0xe1, 0xe9, 0xb3, 0x6a, 0xa3,
+ 0xb2, 0x02, 0xac, 0xb0, 0x04, 0x7a, 0x57, 0xb4,
+ 0xbc, 0xd5, 0x4e, 0x20, 0x7f, 0x92, 0x4d, 0x3c,
+ 0xee, 0xa8, 0x9c, 0x67, 0xa2, 0xd6, 0xc3, 0x12
+ }
+ }
+ }
+};
+
+static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_qy = {
+ .d = {
+ .t = {32, {
+ 0x1d, 0x52, 0x65, 0x86, 0xb5, 0xa4, 0xcc, 0xc6,
+ 0x9b, 0x68, 0x6d, 0x62, 0x8a, 0xfd, 0x9f, 0xc5,
+ 0x7b, 0x0e, 0x9d, 0xee, 0x8f, 0x73, 0xa5, 0xfc,
+ 0x72, 0x11, 0x97, 0x13, 0x74, 0xad, 0x85, 0x5c
+ }
+ }
+ }
+};
+
+#define MAX_MSG_BYTES MAX_DIGEST_BUFFER
+
+static int point_equals(const TPMS_ECC_POINT *a, const TPMS_ECC_POINT *b)
+{
+ return a->x.b.size == b->x.b.size &&
+ a->y.b.size == b->y.b.size &&
+ memcmp(a->x.b.buffer, b->x.b.buffer, a->x.b.size) == 0 &&
+ memcmp(a->y.b.buffer, b->y.b.buffer, a->y.b.size) == 0;
+
+}
+
+static void ec_command_handler(void *cmd_body, size_t cmd_size,
+ size_t *response_size_out)
+{
+ uint8_t *cmd;
+ uint8_t op;
+ uint8_t curve_id;
+ uint8_t sign_mode;
+ uint8_t hashing;
+ uint16_t in_len;
+ uint8_t in[MAX_MSG_BYTES];
+ uint16_t digest_len;
+ struct TPM2B_MAX_BUFFER_aligned digest;
+ uint8_t *out = (uint8_t *) cmd_body;
+ uint32_t *response_size = (uint32_t *) response_size_out;
+
+ TPMS_ECC_POINT q;
+ TPM2B_ECC_PARAMETER *d;
+ TPM2B_ECC_PARAMETER *qx;
+ TPM2B_ECC_PARAMETER *qy;
+ struct TPM2B_ECC_PARAMETER_aligned r;
+ struct TPM2B_ECC_PARAMETER_aligned s;
+
+ /* Command format.
+ *
+ * OFFSET FIELD
+ * 0 OP
+ * 1 CURVE_ID
+ * 2 SIGN_MODE
+ * 3 HASHING
+ * 4 MSB IN LEN
+ * 5 LSB IN LEN
+ * 6 IN
+ * 6 + IN_LEN MSB DIGEST LEN
+ * 7 + IN_LEN LSB DIGEST LEN
+ * 8 + IN_LEN DIGEST
+ */
+
+ cmd = (uint8_t *) cmd_body;
+ op = *cmd++;
+ curve_id = *cmd++;
+ sign_mode = *cmd++;
+ hashing = *cmd++;
+ in_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
+ cmd += 2;
+ if (in_len > sizeof(in)) {
+ *response_size = 0;
+ return;
+ }
+ memcpy(in, cmd, in_len);
+ cmd += in_len;
+
+ digest_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
+ cmd += 2;
+ if (digest_len > sizeof(digest.d.t.buffer)) {
+ *response_size = 0;
+ return;
+ }
+ digest.d.t.size = digest_len;
+ memcpy(digest.d.t.buffer, cmd, digest_len);
+ cmd += digest_len;
+
+ switch (curve_id) {
+ case TPM_ECC_NIST_P256:
+ d = (TPM2B_ECC_PARAMETER *) &NIST_P256_d.d;
+ qx = (TPM2B_ECC_PARAMETER *) &NIST_P256_qx.d;
+ qy = (TPM2B_ECC_PARAMETER *) &NIST_P256_qy.d;
+ q.x = *qx;
+ q.y = *qy;
+ break;
+ default:
+ *response_size = 0;
+ return;
+ }
+
+ switch (op) {
+ case TEST_SIGN:
+ if (_cpri__SignEcc(&r.d, &s.d, sign_mode, hashing,
+ curve_id, d, &digest.d.b, NULL)
+ != CRYPT_SUCCESS) {
+ *response_size = 0;
+ return;
+ }
+ memcpy(out, r.d.b.buffer, r.d.b.size);
+ out += r.d.b.size;
+ memcpy(out, s.d.b.buffer, s.d.b.size);
+ *response_size = r.d.b.size + s.d.b.size;
+ break;
+ case TEST_VERIFY:
+ r.d.b.size = in_len / 2;
+ memcpy(r.d.b.buffer, in, r.d.b.size);
+ s.d.b.size = in_len / 2;
+ memcpy(s.d.b.buffer, in + r.d.b.size, s.d.b.size);
+ if (_cpri__ValidateSignatureEcc(
+ &r.d, &s.d, sign_mode, hashing, curve_id,
+ &q, &digest.d.b) != CRYPT_SUCCESS) {
+ *response_size = 0;
+ } else {
+ *out = 1;
+ *response_size = 1;
+ }
+ return;
+ case TEST_KEYGEN:
+ {
+ struct TPM2B_ECC_PARAMETER_aligned d_local;
+ TPMS_ECC_POINT q_local;
+
+ if (_cpri__GetEphemeralEcc(&q, &d_local.d, curve_id)
+ != CRYPT_SUCCESS) {
+ *response_size = 0;
+ return;
+ }
+
+ if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE) {
+ *response_size = 0;
+ return;
+ }
+
+ /* Verify correspondence of secret with the public point. */
+ if (_cpri__EccPointMultiply(
+ &q_local, curve_id, &d_local.d,
+ NULL, NULL) != CRYPT_SUCCESS) {
+ *response_size = 0;
+ return;
+ }
+ if (!point_equals(&q, &q_local)) {
+ *response_size = 0;
+ return;
+ }
+ *out = 1;
+ *response_size = 1;
+ return;
+ }
+ case TEST_KEYDERIVE:
+ {
+ /* Random seed. */
+ TPM2B_SEED seed;
+ struct TPM2B_ECC_PARAMETER_aligned d_local;
+ TPMS_ECC_POINT q_local;
+ const char *label = "ec_test";
+
+
+ if (in_len > PRIMARY_SEED_SIZE) {
+ *response_size = 0;
+ return;
+ }
+ seed.t.size = in_len;
+ memcpy(seed.t.buffer, in, in_len);
+
+ if (_cpri__GenerateKeyEcc(
+ &q, &d_local.d, curve_id, hashing,
+ &seed.b, label, NULL, NULL) != CRYPT_SUCCESS) {
+ *response_size = 0;
+ return;
+ }
+
+ if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE) {
+ *response_size = 0;
+ return;
+ }
+
+ /* Verify correspondence of secret with the public point. */
+ if (_cpri__EccPointMultiply(
+ &q_local, curve_id, &d_local.d,
+ NULL, NULL) != CRYPT_SUCCESS) {
+ *response_size = 0;
+ return;
+ }
+ if (!point_equals(&q, &q_local)) {
+ *response_size = 0;
+ return;
+ }
+
+ *out = 1;
+ *response_size = 1;
+ return;
+ }
+ default:
+ *response_size = 0;
+ return;
+ }
+}
+
+DECLARE_EXTENSION_COMMAND(EXTENSION_EC, ec_command_handler);
+
+#endif /* CRYPTO_TEST_SETUP */
diff --git a/board/cr50/tpm2/stubs.c b/board/cr50/tpm2/stubs.c
index 37259d49fd..2ffb1d40ba 100644
--- a/board/cr50/tpm2/stubs.c
+++ b/board/cr50/tpm2/stubs.c
@@ -46,45 +46,6 @@ CRYPT_RESULT _cpri__EccCommitCompute(
return CRYPT_FAIL;
}
-BOOL _cpri__EccIsPointOnCurve(
- TPM_ECC_CURVE curveId, // IN: the curve selector
- TPMS_ECC_POINT * Q // IN: the point.
- )
-{
- ecprintf("%s called\n", __func__);
- return 0;
-}
-
-CRYPT_RESULT _cpri__EccPointMultiply(
- TPMS_ECC_POINT * Rout, // OUT: the product point R
- TPM_ECC_CURVE curveId, // IN: the curve to use
- TPM2B_ECC_PARAMETER * dIn, // IN: value to multiply against the
- // curve generator
- TPMS_ECC_POINT * Qin, // IN: point Q
- TPM2B_ECC_PARAMETER * uIn // IN: scalar value for the multiplier of Q
- )
-{
- ecprintf("%s called\n", __func__);
- return CRYPT_FAIL;
-}
-
-CRYPT_RESULT _cpri__GenerateKeyEcc(
- TPMS_ECC_POINT * Qout, // OUT: the public point
- TPM2B_ECC_PARAMETER * dOut, // OUT: the private scalar
- TPM_ECC_CURVE curveId, // IN: the curve identifier
- TPM_ALG_ID hashAlg, // IN: hash algorithm to use in the key
- // generation process
- TPM2B * seed, // IN: the seed to use
- const char *label, // IN: A label for the generation process.
- TPM2B * extra, // IN: Party 1 data for the KDF
- UINT32 * counter // IN/OUT: Counter value to allow KDF
- // iteration to be propagated across multiple functions
- )
-{
- ecprintf("%s called\n", __func__);
- return CRYPT_FAIL;
-}
-
CRYPT_RESULT _cpri__GenerateKeyRSA(
TPM2B * n, // OUT: The public modulu
TPM2B * p, // OUT: One of the prime factors of n
@@ -102,31 +63,6 @@ CRYPT_RESULT _cpri__GenerateKeyRSA(
return CRYPT_FAIL;
}
-CRYPT_RESULT _cpri__GetEphemeralEcc(
- TPMS_ECC_POINT * Qout, // OUT: the public point
- TPM2B_ECC_PARAMETER * dOut, // OUT: the private scalar
- TPM_ECC_CURVE curveId // IN: the curve for the key
- )
-{
- ecprintf("%s called\n", __func__);
- return CRYPT_FAIL;
-}
-
-CRYPT_RESULT _cpri__SignEcc(
- TPM2B_ECC_PARAMETER * rOut, // OUT: r component of the signature
- TPM2B_ECC_PARAMETER * sOut, // OUT: s component of the signature
- TPM_ALG_ID scheme, // IN: the scheme selector
- TPM_ALG_ID hashAlg, // IN: the hash algorithm if need
- TPM_ECC_CURVE curveId, // IN: the curve used in the signature process
- TPM2B_ECC_PARAMETER * dIn, // IN: the private key
- TPM2B * digest, // IN: the digest to sign
- TPM2B_ECC_PARAMETER * kIn // IN: k for input
- )
-{
- ecprintf("%s called\n", __func__);
- return CRYPT_FAIL;
-}
-
BOOL _cpri__Startup(
void)
{
@@ -159,22 +95,6 @@ CRYPT_RESULT _cpri__TestKeyRSA(
return CRYPT_FAIL;
}
-CRYPT_RESULT _cpri__ValidateSignatureEcc(
- TPM2B_ECC_PARAMETER * rIn, // IN: r component of the signature
- TPM2B_ECC_PARAMETER * sIn, // IN: s component of the signature
- TPM_ALG_ID scheme, // IN: the scheme selector
- TPM_ALG_ID hashAlg, // IN: the hash algorithm used (not used
- // in all schemes)
- TPM_ECC_CURVE curveId, // IN: the curve used in the
- // signature process
- TPMS_ECC_POINT * Qin, // IN: the public point of the key
- TPM2B * digest // IN: the digest that was signed
- )
-{
- ecprintf("%s called\n", __func__);
- return CRYPT_FAIL;
-}
-
int _math__Comp(
const UINT32 aSize, // IN: size of a
const BYTE * a, // IN: a buffer
diff --git a/chip/g/build.mk b/chip/g/build.mk
index 6db09c1307..d615a927ed 100644
--- a/chip/g/build.mk
+++ b/chip/g/build.mk
@@ -27,6 +27,10 @@ endif
chip-$(CONFIG_DCRYPTO)+= dcrypto/aes.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/bn.o
+chip-$(CONFIG_DCRYPTO)+= dcrypto/hmac.o
+chip-$(CONFIG_DCRYPTO)+= dcrypto/p256.o
+chip-$(CONFIG_DCRYPTO)+= dcrypto/p256_ec.o
+chip-$(CONFIG_DCRYPTO)+= dcrypto/p256_ecdsa.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/rsa.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/sha1.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/sha256.o
diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h
index 3d8e78ab96..c0422208ae 100644
--- a/chip/g/dcrypto/dcrypto.h
+++ b/chip/g/dcrypto/dcrypto.h
@@ -119,4 +119,22 @@ int DCRYPTO_rsa_verify(struct RSA *rsa, const uint8_t *digest,
const uint32_t sig_len, enum padding_mode padding,
enum hashing_mode hashing);
+/*
+ * EC.
+ */
+int DCRYPTO_p256_valid_point(const p256_int *x, const p256_int *y);
+int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y,
+ const p256_int *n);
+int DCRYPTO_p256_points_mul(p256_int *out_x, p256_int *out_y,
+ const p256_int *n1, const p256_int *n2,
+ const p256_int *in_x, const p256_int *in_y);
+int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
+ const uint8_t key_bytes[P256_NBYTES]);
+
+void DCRYPTO_p256_ecdsa_sign(const p256_int *d, const p256_int *digest,
+ p256_int *r, p256_int *s);
+int DCRYPTO_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
+ const p256_int *digest, const p256_int *r,
+ const p256_int *s);
+
#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */
diff --git a/chip/g/dcrypto/hmac.c b/chip/g/dcrypto/hmac.c
new file mode 100644
index 0000000000..1b6a820159
--- /dev/null
+++ b/chip/g/dcrypto/hmac.c
@@ -0,0 +1,56 @@
+/* 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 <stdint.h>
+
+#include "internal.h"
+#include "dcrypto.h"
+
+static void HMAC_init(struct HMAC_CTX *ctx, const void *key, unsigned int len)
+{
+ unsigned int i;
+
+ memset(&ctx->opad[0], 0, sizeof(ctx->opad));
+
+ if (len > sizeof(ctx->opad)) {
+ DCRYPTO_SHA256_init(&ctx->hash, 0);
+ DCRYPTO_HASH_update(&ctx->hash, key, len);
+ memcpy(&ctx->opad[0], DCRYPTO_HASH_final(&ctx->hash),
+ DCRYPTO_HASH_size(&ctx->hash));
+ } else {
+ memcpy(&ctx->opad[0], key, len);
+ }
+
+ for (i = 0; i < sizeof(ctx->opad); ++i)
+ ctx->opad[i] ^= 0x36;
+
+ DCRYPTO_SHA256_init(&ctx->hash, 0);
+ /* hash ipad */
+ DCRYPTO_HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
+
+ for (i = 0; i < sizeof(ctx->opad); ++i)
+ ctx->opad[i] ^= (0x36 ^ 0x5c);
+}
+
+void dcrypto_HMAC_SHA256_init(struct HMAC_CTX *ctx, const void *key,
+ unsigned int len)
+{
+ DCRYPTO_SHA256_init(&ctx->hash, 0);
+ HMAC_init(ctx, key, len);
+}
+
+const uint8_t *dcrypto_HMAC_final(struct HMAC_CTX *ctx)
+{
+ uint8_t digest[SHA_DIGEST_MAX_BYTES]; /* upto SHA2 */
+
+ memcpy(digest, DCRYPTO_HASH_final(&ctx->hash),
+ (DCRYPTO_HASH_size(&ctx->hash) <= sizeof(digest) ?
+ DCRYPTO_HASH_size(&ctx->hash) : sizeof(digest)));
+ DCRYPTO_SHA256_init(&ctx->hash, 0);
+ DCRYPTO_HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
+ DCRYPTO_HASH_update(&ctx->hash, digest, DCRYPTO_HASH_size(&ctx->hash));
+ memset(&ctx->opad[0], 0, sizeof(ctx->opad)); /* wipe key */
+ return DCRYPTO_HASH_final(&ctx->hash);
+}
diff --git a/chip/g/dcrypto/internal.h b/chip/g/dcrypto/internal.h
index 36aa35f6bf..09685c3004 100644
--- a/chip/g/dcrypto/internal.h
+++ b/chip/g/dcrypto/internal.h
@@ -83,6 +83,21 @@ void dcrypto_sha_update(struct HASH_CTX *unused,
void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest);
/*
+ * HMAC.
+ */
+struct HMAC_CTX {
+ struct HASH_CTX hash;
+ uint8_t opad[64];
+};
+
+#define HASH_update(ctx, data, len) \
+ ((ctx)->vtab->update((ctx), (data), (len)))
+void dcrypto_HMAC_SHA256_init(struct HMAC_CTX *ctx, const void *key,
+ unsigned int len);
+#define dcrypto_HMAC_update(ctx, data, len) HASH_update(&(ctx)->hash, data, len)
+const uint8_t *dcrypto_HMAC_final(struct HMAC_CTX *ctx);
+
+/*
* BIGNUM.
*/
#define BN_BITS2 32
@@ -102,6 +117,53 @@ void bn_mont_modexp(struct BIGNUM *output, const struct BIGNUM *input,
const struct BIGNUM *exp, const struct BIGNUM *N);
/*
+ * EC.
+ */
+#define P256_BITSPERDIGIT 32
+#define P256_NDIGITS 8
+#define P256_NBYTES 32
+
+typedef uint32_t p256_digit;
+typedef int32_t p256_sdigit;
+typedef uint64_t p256_ddigit;
+typedef int64_t p256_sddigit;
+
+/* Define p256_int as a struct to leverage struct assignment. */
+typedef struct {
+ p256_digit a[P256_NDIGITS] __packed;
+} p256_int;
+
+#define P256_DIGITS(x) ((x)->a)
+#define P256_DIGIT(x, y) ((x)->a[y])
+
+#define P256_ZERO { {0} }
+#define P256_ONE { {1} }
+
+/* Curve constants. */
+extern const p256_int SECP256r1_n;
+extern const p256_int SECP256r1_p;
+extern const p256_int SECP256r1_b;
+
+void p256_init(p256_int *a);
+void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst);
+#define p256_clear(a) p256_init((a))
+int p256_is_zero(const p256_int *a);
+int p256_cmp(const p256_int *a, const p256_int *b);
+int p256_get_bit(const p256_int *scalar, int bit);
+p256_digit p256_shl(const p256_int *a, int n, p256_int *b);
+void p256_shr(const p256_int *a, int n, p256_int *b);
+int p256_add(const p256_int *a, const p256_int *b, p256_int *c);
+int p256_add_d(const p256_int *a, p256_digit d, p256_int *b);
+void p256_points_mul_vartime(
+ const p256_int *n1, const p256_int *n2, const p256_int *in_x,
+ const p256_int *in_y, p256_int *out_x, p256_int *out_y);
+void p256_mod(const p256_int *MOD, const p256_int *in, p256_int *out);
+void p256_modmul(const p256_int *MOD, const p256_int *a,
+ const p256_digit top_b, const p256_int *b, p256_int *c);
+void p256_modinv(const p256_int *MOD, const p256_int *a, p256_int *b);
+void p256_modinv_vartime(const p256_int *MOD, const p256_int *a, p256_int *b);
+
+/*
* Utility functions.
*/
/* TODO(ngm): memset that doesn't get optimized out. */
diff --git a/chip/g/dcrypto/p256.c b/chip/g/dcrypto/p256.c
new file mode 100644
index 0000000000..9c3af545bc
--- /dev/null
+++ b/chip/g/dcrypto/p256.c
@@ -0,0 +1,444 @@
+/* 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 <assert.h>
+
+const p256_int SECP256r1_n = /* curve order */
+ { {0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1} };
+static const p256_int SECP256r1_nMin2 = /* curve order - 2 */
+ { {0xfc632551 - 2, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1} };
+const p256_int SECP256r1_p = /* curve field size */
+ { {-1, -1, -1, 0, 0, 0, 1, -1 } };
+const p256_int SECP256r1_b = /* curve b */
+ { {0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
+ 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8} };
+static const p256_int p256_one = P256_ONE;
+
+void p256_init(p256_int *a)
+{
+ memset(a, 0, sizeof(*a));
+}
+
+int p256_get_bit(const p256_int *scalar, int bit)
+{
+ return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
+ >> (bit & (P256_BITSPERDIGIT - 1))) & 1;
+}
+
+p256_digit p256_shl(const p256_int *a, int n, p256_int *b)
+{
+ int i;
+ p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
+
+ n %= P256_BITSPERDIGIT;
+ for (i = P256_NDIGITS - 1; i > 0; --i) {
+ p256_digit accu = (P256_DIGIT(a, i) << n);
+
+ accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
+ P256_DIGIT(b, i) = accu;
+ }
+ P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
+
+ top >>= (P256_BITSPERDIGIT - n);
+
+ return top;
+}
+
+void p256_shr(const p256_int *a, int n, p256_int *b)
+{
+ int i;
+
+ n %= P256_BITSPERDIGIT;
+ for (i = 0; i < P256_NDIGITS - 1; ++i) {
+ p256_digit accu = (P256_DIGIT(a, i) >> n);
+
+ accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
+ P256_DIGIT(b, i) = accu;
+ }
+ P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
+}
+
+int p256_is_zero(const p256_int *a)
+{
+ int i, result = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i)
+ result |= P256_DIGIT(a, i);
+ return !result;
+}
+
+int p256_cmp(const p256_int *a, const p256_int *b)
+{
+ int i;
+ p256_sddigit borrow = 0;
+ p256_digit notzero = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ borrow += (p256_sddigit) P256_DIGIT(a, i) - P256_DIGIT(b, i);
+ /* Track whether any result digit is ever not zero.
+ * Relies on !!(non-zero) evaluating to 1, e.g., !!(-1)
+ * evaluating to 1. */
+ notzero |= !!((p256_digit) borrow);
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ return (int) borrow | notzero;
+}
+
+/* c = a - b. Returns borrow: 0 or -1. */
+int p256_sub(const p256_int *a, const p256_int *b, p256_int *c)
+{
+ int i;
+ p256_sddigit borrow = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ borrow += (p256_sddigit) P256_DIGIT(a, i) - P256_DIGIT(b, i);
+ if (c)
+ P256_DIGIT(c, i) = (p256_digit) borrow;
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ return (int) borrow;
+}
+
+/* c = a + b. Returns carry: 0 or 1. */
+int p256_add(const p256_int *a, const p256_int *b, p256_int *c)
+{
+ int i;
+ p256_ddigit carry = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ carry += (p256_ddigit) P256_DIGIT(a, i) + P256_DIGIT(b, i);
+ if (c)
+ P256_DIGIT(c, i) = (p256_digit) carry;
+ carry >>= P256_BITSPERDIGIT;
+ }
+ return (int) carry;
+}
+
+/* b = a + d. Returns carry, 0 or 1. */
+int p256_add_d(const p256_int *a, p256_digit d, p256_int *b)
+{
+ int i;
+ p256_ddigit carry = d;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ carry += (p256_ddigit) P256_DIGIT(a, i);
+ if (b)
+ P256_DIGIT(b, i) = (p256_digit) carry;
+ carry >>= P256_BITSPERDIGIT;
+ }
+ return (int) carry;
+}
+
+/* top, c[] += a[] * b */
+/* Returns new top. */
+static p256_digit p256_muladd(const p256_int *a, p256_digit b,
+ p256_digit top, p256_digit *c)
+{
+ int i;
+ p256_ddigit carry = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ carry += *c;
+ carry += (p256_ddigit) P256_DIGIT(a, i) * b;
+ *c++ = (p256_digit) carry;
+ carry >>= P256_BITSPERDIGIT;
+ }
+ return top + (p256_digit) carry;
+}
+
+/* top, c[] -= top_a, a[] */
+static p256_digit p256_subtop(p256_digit top_a, const p256_digit *a,
+ p256_digit top_c, p256_digit *c)
+{
+ int i;
+ p256_sddigit borrow = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ borrow += *c;
+ borrow -= *a++;
+ *c++ = (p256_digit) borrow;
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ borrow += top_c;
+ borrow -= top_a;
+ top_c = (p256_digit) borrow;
+ assert((borrow >> P256_BITSPERDIGIT) == 0);
+ return top_c;
+}
+
+/* top, c[] += MOD[] & mask (0 or -1) */
+/* returns new top. */
+static p256_digit p256_addM(const p256_int *MOD, p256_digit top,
+ p256_digit *c, p256_digit mask)
+{
+ int i;
+ p256_ddigit carry = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ carry += *c;
+ carry += P256_DIGIT(MOD, i) & mask;
+ *c++ = (p256_digit) carry;
+ carry >>= P256_BITSPERDIGIT;
+ }
+ return top + (p256_digit) carry;
+}
+
+/* top, c[] -= MOD[] & mask (0 or -1) */
+/* returns new top. */
+static p256_digit p256_subM(const p256_int *MOD, p256_digit top,
+ p256_digit *c, p256_digit mask)
+{
+ int i;
+ p256_sddigit borrow = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ borrow += *c;
+ borrow -= P256_DIGIT(MOD, i) & mask;
+ *c++ = (p256_digit) borrow;
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ return top + (p256_digit) borrow;
+}
+
+/* Convert in. */
+void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst)
+{
+ int i;
+ const uint8_t *p = &src[0];
+
+ for (i = P256_NDIGITS - 1; i >= 0; --i) {
+ P256_DIGIT(dst, i) =
+ (p[0] << 24) |
+ (p[1] << 16) |
+ (p[2] << 8) |
+ p[3];
+ p += 4;
+ }
+}
+
+void p256_mod(const p256_int *MOD, const p256_int *in, p256_int *out)
+{
+ if (out != in)
+ *out = *in;
+ p256_addM(MOD, 0, P256_DIGITS(out),
+ p256_subM(MOD, 0, P256_DIGITS(out), -1));
+}
+
+
+void p256_modmul(const p256_int *MOD, const p256_int *a,
+ const p256_digit top_b, const p256_int *b, p256_int *c)
+{
+ p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
+ p256_digit top = 0;
+ int i;
+
+ /* Multiply/add into tmp. */
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ if (i)
+ tmp[i + P256_NDIGITS - 1] = top;
+ top = p256_muladd(a, P256_DIGIT(b, i), 0, tmp + i);
+ }
+
+ /* Multiply/add top digit. */
+ tmp[i + P256_NDIGITS - 1] = top;
+ top = p256_muladd(a, top_b, 0, tmp + i);
+
+ /* Reduce tmp, digit by digit. */
+ for (; i >= 0; --i) {
+ p256_digit reducer[P256_NDIGITS] = { 0 };
+ p256_digit top_reducer;
+
+ /* top can be any value at this point.
+ * Guestimate reducer as top * MOD, since msw of MOD is -1. */
+ top_reducer = p256_muladd(MOD, top, 0, reducer);
+
+ /* Subtract reducer from top | tmp. */
+ top = p256_subtop(top_reducer, reducer, top, tmp + i);
+
+ /* top is now either 0 or 1. Make it 0, fixed-timing. */
+ assert(top <= 1);
+
+ top = p256_subM(MOD, top, tmp + i, ~(top - 1));
+
+ assert(top == 0);
+
+ /* We have now reduced the top digit off tmp. Fetch
+ * new top digit. */
+ top = tmp[i + P256_NDIGITS - 1];
+ }
+
+ /* tmp might still be larger than MOD, yet same bit length.
+ * Make sure it is less, fixed-timing. */
+ p256_addM(MOD, 0, tmp, p256_subM(MOD, 0, tmp, -1));
+
+ memcpy(c, tmp, P256_NBYTES);
+}
+
+/* if (mask) dst = src, fixed-timing style. */
+static void conditional_copy(const p256_int *src, p256_int *dst, int mask)
+{
+ int i;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ p256_digit b = P256_DIGIT(src, i) & mask; /* 0 or src[i] */
+
+ b |= P256_DIGIT(dst, i) & ~mask; /* dst[i] or 0 */
+ P256_DIGIT(dst, i) = b;
+ }
+}
+
+/* -1 iff (x & 15) == 0, 0 otherwise. */
+/* Relies on arithmetic shift right behavior. */
+#define ZEROtoONES(x) (((int32_t)(((x) & 15) - 1)) >> 31)
+
+/* tbl[0] = tbl[idx], fixed-timing style. */
+static void set0ToIdx(p256_int tbl[16], int idx)
+{
+ int32_t i;
+
+ tbl[0] = p256_one;
+ for (i = 1; i < 16; ++i)
+ conditional_copy(&tbl[i], &tbl[0], ZEROtoONES(i - idx));
+}
+
+/* b = 1/a mod MOD, fixed timing, Fermat's little theorem. */
+void p256_modinv(const p256_int *MOD, const p256_int *a, p256_int *b)
+{
+ int i;
+ p256_int tbl[16];
+
+ /* tbl[i] = a**i, tbl[0] unused. */
+ tbl[1] = *a;
+ for (i = 2; i < 16; ++i)
+ p256_modmul(MOD, &tbl[i-1], 0, a, &tbl[i]);
+
+ *b = p256_one;
+ for (i = 256; i > 0; i -= 4) {
+ int32_t idx = 0;
+
+ p256_modmul(MOD, b, 0, b, b);
+ p256_modmul(MOD, b, 0, b, b);
+ p256_modmul(MOD, b, 0, b, b);
+ p256_modmul(MOD, b, 0, b, b);
+ idx |= p256_get_bit(&SECP256r1_nMin2, i - 1) << 3;
+ idx |= p256_get_bit(&SECP256r1_nMin2, i - 2) << 2;
+ idx |= p256_get_bit(&SECP256r1_nMin2, i - 3) << 1;
+ idx |= p256_get_bit(&SECP256r1_nMin2, i - 4) << 0;
+ set0ToIdx(tbl, idx); /* tbl[0] = tbl[idx] */
+ p256_modmul(MOD, b, 0, &tbl[0], &tbl[0]);
+ conditional_copy(&tbl[0], b, ~ZEROtoONES(idx));
+ }
+}
+
+static int p256_is_even(const p256_int *a)
+{
+ return !(P256_DIGIT(a, 0) & 1);
+}
+
+static void p256_shr1(const p256_int *a, int highbit, p256_int *b)
+{
+ int i;
+
+ for (i = 0; i < P256_NDIGITS - 1; ++i) {
+ p256_digit accu = (P256_DIGIT(a, i) >> 1);
+
+ accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
+ P256_DIGIT(b, i) = accu;
+ }
+ P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
+ (highbit << (P256_BITSPERDIGIT - 1));
+}
+
+/* b = 1/a mod MOD, binary euclid. */
+void p256_modinv_vartime(const p256_int *MOD, const p256_int *a, p256_int *b)
+{
+ p256_int R = P256_ZERO;
+ p256_int S = P256_ONE;
+ p256_int U = *MOD;
+ p256_int V = *a;
+
+ for (;;) {
+ if (p256_is_even(&U)) {
+ p256_shr1(&U, 0, &U);
+ if (p256_is_even(&R)) {
+ p256_shr1(&R, 0, &R);
+ } else {
+ /* R = (R + MOD)/2 */
+ p256_shr1(&R, p256_add(&R, MOD, &R), &R);
+ }
+ } else if (p256_is_even(&V)) {
+ p256_shr1(&V, 0, &V);
+ if (p256_is_even(&S)) {
+ p256_shr1(&S, 0, &S);
+ } else {
+ /* S = (S + MOD)/2 */
+ p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
+ }
+ } else { /* U, V both odd. */
+ if (!p256_sub(&V, &U, NULL)) {
+ p256_sub(&V, &U, &V);
+ if (p256_sub(&S, &R, &S))
+ p256_add(&S, MOD, &S);
+ if (p256_is_zero(&V))
+ break; /* done. */
+ } else {
+ p256_sub(&U, &V, &U);
+ if (p256_sub(&R, &S, &R))
+ p256_add(&R, MOD, &R);
+ }
+ }
+ }
+
+ p256_mod(MOD, &R, b);
+}
+
+int DCRYPTO_p256_valid_point(const p256_int *x, const p256_int *y)
+{
+ p256_int y2, x3;
+
+ if (p256_cmp(&SECP256r1_p, x) <= 0 || p256_cmp(&SECP256r1_p, y) <= 0 ||
+ p256_is_zero(x) || p256_is_zero(y))
+ return 0;
+
+ p256_modmul(&SECP256r1_p, y, 0, y, &y2); /* y^2 */
+
+ p256_modmul(&SECP256r1_p, x, 0, x, &x3); /* x^2 */
+ p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); /* x^3 */
+ if (p256_sub(&x3, x, &x3))
+ p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - x */
+ if (p256_sub(&x3, x, &x3))
+ p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - 2x */
+ if (p256_sub(&x3, x, &x3))
+ p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - 3x */
+ if (p256_add(&x3, &SECP256r1_b, &x3)) /* x^3 - 3x + b */
+ p256_sub(&x3, &SECP256r1_p, &x3);
+ if (p256_sub(&x3, &SECP256r1_p, &x3)) /* make sure 0 <= x3 < p */
+ p256_add(&x3, &SECP256r1_p, &x3);
+
+ return p256_cmp(&y2, &x3) == 0;
+}
+
+/*
+ * 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])
+{
+ int valid;
+ p256_int key;
+
+ p256_from_bin(key_bytes, &key);
+ if (p256_cmp(&SECP256r1_nMin2, &key) < 0)
+ return 0;
+ p256_add(&key, &p256_one, &key);
+ valid = DCRYPTO_p256_base_point_mul(x, y, &key);
+ if (valid)
+ *d = key;
+ return valid;
+}
diff --git a/chip/g/dcrypto/p256_ec.c b/chip/g/dcrypto/p256_ec.c
new file mode 100644
index 0000000000..8bb4a0e308
--- /dev/null
+++ b/chip/g/dcrypto/p256_ec.c
@@ -0,0 +1,1403 @@
+/* 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 <stdint.h>
+
+#include "dcrypto.h"
+
+typedef uint8_t u8;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+
+/* Our field elements are represented as nine 32-bit limbs.
+ *
+ * The value of an felem (field element) is:
+ * x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228)
+ *
+ * That is, each limb is alternately 29 or 28-bits wide in little-endian
+ * order.
+ *
+ * This means that an felem hits 2**257, rather than 2**256 as we would like. A
+ * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems
+ * when multiplying as terms end up one bit short of a limb which would require
+ * much bit-shifting to correct.
+ *
+ * Finally, the values stored in an felem are in Montgomery form. So the value
+ * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257.
+ */
+typedef u32 limb;
+#define NLIMBS 9
+typedef limb felem[NLIMBS];
+
+static const limb kBottom28Bits = 0xfffffff;
+static const limb kBottom29Bits = 0x1fffffff;
+
+/* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and
+ * 28-bit words. */
+static const felem kOne = {
+ 2, 0, 0, 0xffff800,
+ 0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff,
+ 0
+};
+static const felem kZero = {0};
+static const felem kP = {
+ 0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff,
+ 0, 0, 0x200000, 0xf000000,
+ 0xfffffff
+};
+static const felem k2P = {
+ 0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff,
+ 0, 0, 0x400000, 0xe000000,
+ 0x1fffffff
+};
+/* kPrecomputed contains precomputed values to aid the calculation of scalar
+ * multiples of the base point, G. It's actually two, equal length, tables
+ * concatenated.
+ *
+ * The first table contains (x,y) felem pairs for 16 multiples of the base
+ * point, G.
+ *
+ * Index | Index (binary) | Value
+ * 0 | 0000 | 0G (all zeros, omitted)
+ * 1 | 0001 | G
+ * 2 | 0010 | 2**64G
+ * 3 | 0011 | 2**64G + G
+ * 4 | 0100 | 2**128G
+ * 5 | 0101 | 2**128G + G
+ * 6 | 0110 | 2**128G + 2**64G
+ * 7 | 0111 | 2**128G + 2**64G + G
+ * 8 | 1000 | 2**192G
+ * 9 | 1001 | 2**192G + G
+ * 10 | 1010 | 2**192G + 2**64G
+ * 11 | 1011 | 2**192G + 2**64G + G
+ * 12 | 1100 | 2**192G + 2**128G
+ * 13 | 1101 | 2**192G + 2**128G + G
+ * 14 | 1110 | 2**192G + 2**128G + 2**64G
+ * 15 | 1111 | 2**192G + 2**128G + 2**64G + G
+ *
+ * The second table follows the same style, but the terms are 2**32G,
+ * 2**96G, 2**160G, 2**224G.
+ *
+ * This is ~2KB of data. */
+static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = {
+ 0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88,
+ 0x119e7edc, 0xd4a6eab, 0x3120bee, 0x1d2aac15, 0xf25357c, 0x19e45cdd,
+ 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3,
+ 0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18,
+ 0x1fe49073, 0x3fa36cc, 0x5ebcd2c, 0xb402f2f, 0x15c70bf, 0x1561925c,
+ 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22,
+ 0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c,
+ 0x56c7109, 0xa267a00, 0xb57c050, 0x98fb57, 0xaa837cc, 0x60c0792,
+ 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b,
+ 0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1,
+ 0x1d96a5a9, 0x843a649, 0xc3ab0fa, 0x6e2e7d5, 0x7673a2a, 0x178b65e8,
+ 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2,
+ 0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17,
+ 0x172db40f, 0x83e277d, 0xb0dd609, 0xfd1da12, 0x35c6e52, 0x19ede20c,
+ 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581,
+ 0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b,
+ 0xc35df9f, 0x48764cd, 0x76dbcca, 0xca4b366, 0xe9303ab, 0x1a7480e7,
+ 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33,
+ 0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e,
+ 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6, 0x14e614aa, 0x9246317, 0x1bc83aca,
+ 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd,
+ 0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672,
+ 0x6a2901a, 0x69a8556, 0x7e7c0, 0x9b7d8d3, 0x309a80, 0x1ad05f7f,
+ 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881,
+ 0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1,
+ 0xbe80c51, 0xc22be3e, 0xe35e65a, 0x1aeb7aa0, 0xc375315, 0xf67bc99,
+ 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26,
+ 0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989,
+ 0x1a90c502, 0x2f32042, 0xa17769b, 0xafd8c7c, 0x8191c6e, 0x1dcdb237,
+ 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023,
+ 0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b,
+ 0x2fc513c, 0x407f75c, 0xbaab133, 0x9705fe9, 0xb88b8e7, 0x734c993,
+ 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa,
+ 0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29,
+ 0xbc62f16, 0x2b6fcc7, 0xf5a4e29, 0x13560b66, 0xc0b6ac2, 0x51ae690,
+ 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc,
+ 0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416,
+ 0x1f83de85, 0x27de188, 0x66f70b8, 0x181cd51f, 0x96b6e4c, 0x188f2335,
+ 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59,
+ 0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f,
+ 0x79061, 0x823d9d2, 0x8213f39, 0x1128ae0b, 0xd095d05, 0xb85c0c2,
+ 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689,
+ 0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41,
+ 0x1051a729, 0x4be3499, 0x52b23aa, 0x109f307e, 0x6f5b6bb, 0x1f84e1e7,
+ 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3,
+ 0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17,
+ 0x1a4a7529, 0xcb7beb1, 0xb2a78a1, 0x1ab21f1f, 0x6361ccf, 0x6c9179d,
+ 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f,
+ 0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e,
+ 0xc50124c, 0x50daa90, 0xb13f72, 0xb06aa75, 0x70f5cc6, 0x1649e5aa,
+ 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d,
+ 0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070,
+ 0x18c9e11e, 0x20bca9a, 0x66f496b, 0x3eef294, 0x67500d2, 0xd7f613c,
+ 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a,
+ 0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847,
+ 0x17fa56ff, 0x65ef930, 0x21dc4a, 0x2b37659, 0x450fe17, 0xb357b65,
+ 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f,
+ 0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910,
+ 0x725522b, 0xdc78583, 0x40eeabb, 0x1fde328a, 0xbd61d96, 0xd28c387,
+ 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc,
+ 0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49,
+ 0x6316abb, 0x2413c8e, 0x5425bf9, 0x1bed3e3a, 0xf272274, 0x1f5e7326,
+ 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce,
+ 0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175,
+ 0x1dc4ef73, 0x8956f34, 0xe4b5cf2, 0x1b0d3a18, 0x3194a36, 0x6c2641f,
+ 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca,
+ 0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d,
+ 0x10e3edc9, 0x9c19bf2, 0x5882229, 0x1b2b4162, 0xa5cef1a, 0x1543622b,
+ 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57,
+ 0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d,
+ 0xa038113, 0xa4a1769, 0x11fbc6c, 0x917e50e, 0xeec3da8, 0x169d6eac,
+ 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa,
+ 0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca,
+ 0x196142cc, 0x7bf0fa9, 0x957651, 0x4e0f215, 0xed439f8, 0x3f46bd5,
+ 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec,
+ 0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804,
+ 0x19d1c12d, 0xf20bd46, 0x1951fa7, 0xa3656c3, 0x523a425, 0xfcd0692,
+ 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c,
+ 0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b,
+ 0x2e74779, 0x576138, 0x9587927, 0x133130fa, 0xbe05516, 0x9f4d619,
+ 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298,
+ 0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e,
+ 0x14e2f5d8, 0xf858d3a, 0x942eea8, 0xda5b765, 0x6edafff, 0xa9d18cc,
+ 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2,
+ 0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13,
+ 0x4c146c0, 0x6bdf55a, 0x4e4457d, 0x16152289, 0xac78ec2, 0x1a59c5a2,
+ 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4,
+ 0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8,
+ 0x81d55d7, 0xa5bef68, 0xb7b30d8, 0xbe73d6f, 0xaa88141, 0xd976c81,
+ 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78,
+};
+
+
+/* Field element operations: */
+
+/* NON_ZERO_TO_ALL_ONES returns:
+ * 0xffffffff for 0 < x <= 2**31
+ * 0 for x == 0 or x > 2**31.
+ *
+ * x must be a u32 or an equivalent type such as limb. */
+#define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1)
+
+/* felem_reduce_carry adds a multiple of p in order to cancel |carry|,
+ * which is a term at 2**257.
+ *
+ * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28.
+ * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */
+static void felem_reduce_carry(felem inout, limb carry)
+{
+ const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry);
+
+ inout[0] += carry << 1;
+ inout[3] += 0x10000000 & carry_mask;
+ /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the
+ * previous line therefore this doesn't underflow. */
+ inout[3] -= carry << 11;
+ inout[4] += (0x20000000 - 1) & carry_mask;
+ inout[5] += (0x10000000 - 1) & carry_mask;
+ inout[6] += (0x20000000 - 1) & carry_mask;
+ inout[6] -= carry << 22;
+ /* This may underflow if carry is non-zero but, if so, we'll
+ * fix it in the next line. */
+ inout[7] -= 1 & carry_mask;
+ inout[7] += carry << 25;
+}
+
+/* felem_sum sets out = in+in2.
+ *
+ * On entry, in[i]+in2[i] must not overflow a 32-bit word.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
+static void felem_sum(felem out, const felem in, const felem in2)
+{
+ limb carry = 0;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ out[i] = in[i] + in2[i];
+ out[i] += carry;
+ carry = out[i] >> 29;
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ out[i] = in[i] + in2[i];
+ out[i] += carry;
+ carry = out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+#define two31m3 ((((limb)1) << 31) - (((limb)1) << 3))
+#define two30m2 ((((limb)1) << 30) - (((limb)1) << 2))
+#define two30p13m2 ((((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2))
+#define two31m2 ((((limb)1) << 31) - (((limb)1) << 2))
+#define two31p24m2 ((((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2))
+#define two30m27m2 ((((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2))
+
+/* zero31 is 0 mod p. */
+static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2,
+ two30m2, two31p24m2, two30m27m2, two31m2 };
+
+/* felem_diff sets out = in-in2.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
+ * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_diff(felem out, const felem in, const felem in2)
+{
+ limb carry = 0;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ out[i] = in[i] - in2[i];
+ out[i] += zero31[i];
+ out[i] += carry;
+ carry = out[i] >> 29;
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ out[i] = in[i] - in2[i];
+ out[i] += zero31[i];
+ out[i] += carry;
+ carry = out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words
+ * with the same 29,28,... bit positions as an felem.
+ *
+ * The values in felems are in Montgomery form: x*R mod p where R = 2**257.
+ * Since we just multiplied two Montgomery values together, the result is
+ * x*y*R*R mod p. We wish to divide by R in order for the result also to be
+ * in Montgomery form.
+ *
+ * On entry: tmp[i] < 2**64
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
+static void felem_reduce_degree(felem out, u64 tmp[17])
+{
+ /* The following table may be helpful when reading this code:
+ *
+ * Limb number: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10...
+ * Width (bits): 29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29
+ * Start bit: 0 | 29| 57| 86|114|143|171|200|228|257|285
+ * (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */
+ limb tmp2[18], carry, x, xMask;
+ unsigned i;
+
+ /* tmp contains 64-bit words with the same 29,28,29-bit positions as an
+ * felem. So the top of an element of tmp might overlap with another
+ * element two positions down. The following loop eliminates this
+ * overlap. */
+ tmp2[0] = (limb)(tmp[0] & kBottom29Bits);
+
+ /* In the following we use "(limb) tmp[x]" and "(limb)
+ * (tmp[x]>>32)" to try and hint to the compiler that it can
+ * do a single-word shift by selecting the right register
+ * rather than doing a double-word shift and truncating
+ * afterwards. */
+ tmp2[1] = ((limb) tmp[0]) >> 29;
+ tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits;
+ tmp2[1] += ((limb) tmp[1]) & kBottom28Bits;
+ carry = tmp2[1] >> 28;
+ tmp2[1] &= kBottom28Bits;
+
+ for (i = 2; i < 17; i++) {
+ tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
+ tmp2[i] += ((limb)(tmp[i - 1])) >> 28;
+ tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits;
+ tmp2[i] += ((limb) tmp[i]) & kBottom29Bits;
+ tmp2[i] += carry;
+ carry = tmp2[i] >> 29;
+ tmp2[i] &= kBottom29Bits;
+
+ i++;
+ if (i == 17)
+ break;
+ tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
+ tmp2[i] += ((limb)(tmp[i - 1])) >> 29;
+ tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits;
+ tmp2[i] += ((limb) tmp[i]) & kBottom28Bits;
+ tmp2[i] += carry;
+ carry = tmp2[i] >> 28;
+ tmp2[i] &= kBottom28Bits;
+ }
+
+ tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25;
+ tmp2[17] += ((limb)(tmp[16])) >> 29;
+ tmp2[17] += (((limb)(tmp[16] >> 32)) << 3);
+ tmp2[17] += carry;
+
+ /* Montgomery elimination of terms.
+ *
+ * Since R is 2**257, we can divide by R with a bitwise shift
+ * if we can ensure that the right-most 257 bits are all
+ * zero. We can make that true by adding multiplies of p
+ * without affecting the value.
+ *
+ * So we eliminate limbs from right to left. Since the bottom
+ * 29 bits of p are all ones, then by adding tmp2[0]*p to tmp2
+ * we'll make tmp2[0] == 0. We can do that for 8 further
+ * limbs and then right shift to eliminate the extra factor of
+ * R. */
+ for (i = 0;; i += 2) {
+ tmp2[i + 1] += tmp2[i] >> 29;
+ x = tmp2[i] & kBottom29Bits;
+ xMask = NON_ZERO_TO_ALL_ONES(x);
+ tmp2[i] = 0;
+
+ /* The bounds calculations for this loop are
+ * tricky. Each iteration of the loop eliminates two
+ * words by adding values to words to their right.
+ *
+ * The following table contains the amounts added to
+ * each word (as an offset from the value of i at the
+ * top of the loop). The amounts are accounted for
+ * from the first and second half of the loop
+ * separately and are written as, for example, 28 to
+ * mean a value < 2**28.
+ *
+ * Word: 3 4 5 6 7 8 9 10
+ * Added in top half: 28 11 29 21 29 28
+ * 28 29
+ * 29
+ * Added in bottom half: 29 10 28 21 28 28
+ * 29
+ *
+ * The value that is currently offset 7 will be offset
+ * 5 for the next iteration and then offset 3 for the
+ * iteration after that. Therefore the total value
+ * added will be the values added at 7, 5 and 3.
+ *
+ * The following table accumulates these values. The
+ * sums at the bottom are written as, for example,
+ * 29+28, to mean a value < 2**29+2**28.
+ *
+ * Word: 3 4 5 6 7 8 9 10 11 12 13
+ * 28 11 10 29 21 29 28 28 28 28 28
+ * 29 28 11 28 29 28 29 28 29 28
+ * 29 28 21 21 29 21 29 21
+ * 10 29 28 21 28 21 28
+ * 28 29 28 29 28 29 28
+ * 11 10 29 10 29 10
+ * 29 28 11 28 11
+ * 29 29
+ * --------------------------------------------
+ * 30+ 31+ 30+ 31+ 30+
+ * 28+ 29+ 28+ 29+ 21+
+ * 21+ 28+ 21+ 28+ 10
+ * 10 21+ 10 21+
+ * 11 11
+ *
+ * So the greatest amount is added to tmp2[10] and
+ * tmp2[12]. If tmp2[10/12] has an initial value of
+ * <2**29, then the maximum value will be < 2**31 +
+ * 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32, as
+ * required. */
+ tmp2[i + 3] += (x << 10) & kBottom28Bits;
+ tmp2[i + 4] += (x >> 18);
+
+ tmp2[i + 6] += (x << 21) & kBottom29Bits;
+ tmp2[i + 7] += x >> 8;
+
+ /* At position 200, which is the starting bit position
+ * for word 7, we have a factor of 0xf000000 = 2**28 -
+ * 2**24. */
+ tmp2[i + 7] += 0x10000000 & xMask;
+ /* Word 7 is 28 bits wide, so the 2**28 term exactly
+ * hits word 8. */
+ tmp2[i + 8] += (x - 1) & xMask;
+ tmp2[i + 7] -= (x << 24) & kBottom28Bits;
+ tmp2[i + 8] -= x >> 4;
+
+ tmp2[i + 8] += 0x20000000 & xMask;
+ tmp2[i + 8] -= x;
+ tmp2[i + 8] += (x << 28) & kBottom29Bits;
+ tmp2[i + 9] += ((x >> 1) - 1) & xMask;
+
+ if (i+1 == NLIMBS)
+ break;
+ tmp2[i + 2] += tmp2[i + 1] >> 28;
+ x = tmp2[i + 1] & kBottom28Bits;
+ xMask = NON_ZERO_TO_ALL_ONES(x);
+ tmp2[i + 1] = 0;
+
+ tmp2[i + 4] += (x << 11) & kBottom29Bits;
+ tmp2[i + 5] += (x >> 18);
+
+ tmp2[i + 7] += (x << 21) & kBottom28Bits;
+ tmp2[i + 8] += x >> 7;
+
+ /* At position 199, which is the starting bit of the
+ * 8th word when dealing with a context starting on an
+ * odd word, we have a factor of 0x1e000000 = 2**29 -
+ * 2**25. Since we have not updated i, the 8th word
+ * from i+1 is i+8. */
+ tmp2[i + 8] += 0x20000000 & xMask;
+ tmp2[i + 9] += (x - 1) & xMask;
+ tmp2[i + 8] -= (x << 25) & kBottom29Bits;
+ tmp2[i + 9] -= x >> 4;
+
+ tmp2[i + 9] += 0x10000000 & xMask;
+ tmp2[i + 9] -= x;
+ tmp2[i + 10] += (x - 1) & xMask;
+ }
+
+ /* We merge the right shift with a carry chain. The words
+ * above 2**257 have widths of 28,29,... which we need to
+ * correct when copying them down. */
+ carry = 0;
+ for (i = 0; i < 8; i++) {
+ /* The maximum value of tmp2[i + 9] occurs on the
+ * first iteration and is < 2**30+2**29+2**28. Adding
+ * 2**29 (from tmp2[i + 10]) is therefore safe. */
+ out[i] = tmp2[i + 9];
+ out[i] += carry;
+ out[i] += (tmp2[i + 10] << 28) & kBottom29Bits;
+ carry = out[i] >> 29;
+ out[i] &= kBottom29Bits;
+
+ i++;
+ out[i] = tmp2[i + 9] >> 1;
+ out[i] += carry;
+ carry = out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+
+ out[8] = tmp2[17];
+ out[8] += carry;
+ carry = out[8] >> 29;
+ out[8] &= kBottom29Bits;
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_square sets out=in*in.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_square(felem out, const felem in)
+{
+ u64 tmp[17];
+
+ tmp[0] = ((u64) in[0]) * in[0];
+ tmp[1] = ((u64) in[0]) * (in[1] << 1);
+ tmp[2] = ((u64) in[0]) * (in[2] << 1) +
+ ((u64) in[1]) * (in[1] << 1);
+ tmp[3] = ((u64) in[0]) * (in[3] << 1) +
+ ((u64) in[1]) * (in[2] << 1);
+ tmp[4] = ((u64) in[0]) * (in[4] << 1) +
+ ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2];
+ tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) *
+ (in[4] << 1) + ((u64) in[2]) * (in[3] << 1);
+ tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) *
+ (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) +
+ ((u64) in[3]) * (in[3] << 1);
+ tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) *
+ (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) +
+ ((u64) in[3]) * (in[4] << 1);
+ /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 +
+ * 2**60 + 2**60, which is < 2**64 as required. */
+ tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) *
+ (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) +
+ ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4];
+ tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) *
+ (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) +
+ ((u64) in[4]) * (in[5] << 1);
+ tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) *
+ (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) +
+ ((u64) in[5]) * (in[5] << 1);
+ tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) *
+ (in[7] << 1) + ((u64) in[5]) * (in[6] << 1);
+ tmp[12] = ((u64) in[4]) * (in[8] << 1) +
+ ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6];
+ tmp[13] = ((u64) in[5]) * (in[8] << 1) +
+ ((u64) in[6]) * (in[7] << 1);
+ tmp[14] = ((u64) in[6]) * (in[8] << 1) +
+ ((u64) in[7]) * (in[7] << 1);
+ tmp[15] = ((u64) in[7]) * (in[8] << 1);
+ tmp[16] = ((u64) in[8]) * in[8];
+
+ felem_reduce_degree(out, tmp);
+}
+
+/* felem_mul sets out=in*in2.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
+ * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_mul(felem out, const felem in, const felem in2)
+{
+ u64 tmp[17];
+
+ tmp[0] = ((u64) in[0]) * in2[0];
+ tmp[1] = ((u64) in[0]) * (in2[1] << 0) +
+ ((u64) in[1]) * (in2[0] << 0);
+ tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) *
+ (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0);
+ tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) *
+ (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) +
+ ((u64) in[3]) * (in2[0] << 0);
+ tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) *
+ (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) +
+ ((u64) in[3]) * (in2[1] << 1) +
+ ((u64) in[4]) * (in2[0] << 0);
+ tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) *
+ (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) +
+ ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) *
+ (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0);
+ tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) *
+ (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) +
+ ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) *
+ (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) +
+ ((u64) in[6]) * (in2[0] << 0);
+ tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) *
+ (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) +
+ ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) *
+ (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) +
+ ((u64) in[6]) * (in2[1] << 0) +
+ ((u64) in[7]) * (in2[0] << 0);
+ /* tmp[8] has the greatest value but doesn't overflow. See logic in
+ * felem_square. */
+ tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) *
+ (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) +
+ ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) *
+ (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) +
+ ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) *
+ (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0);
+ tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) *
+ (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) +
+ ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) *
+ (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) +
+ ((u64) in[7]) * (in2[2] << 0) +
+ ((u64) in[8]) * (in2[1] << 0);
+ tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) *
+ (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) +
+ ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) *
+ (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) +
+ ((u64) in[8]) * (in2[2] << 0);
+ tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) *
+ (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) +
+ ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) *
+ (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0);
+ tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) *
+ (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) +
+ ((u64) in[7]) * (in2[5] << 1) +
+ ((u64) in[8]) * (in2[4] << 0);
+ tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) *
+ (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) +
+ ((u64) in[8]) * (in2[5] << 0);
+ tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) *
+ (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0);
+ tmp[15] = ((u64) in[7]) * (in2[8] << 0) +
+ ((u64) in[8]) * (in2[7] << 0);
+ tmp[16] = ((u64) in[8]) * (in2[8] << 0);
+
+ felem_reduce_degree(out, tmp);
+}
+
+static void felem_assign(felem out, const felem in)
+{
+ memcpy(out, in, sizeof(felem));
+}
+
+/* felem_inv calculates |out| = |in|^{-1}
+ *
+ * Based on Fermat's Little Theorem:
+ * a^p = a (mod p)
+ * a^{p-1} = 1 (mod p)
+ * a^{p-2} = a^{-1} (mod p)
+ */
+static void felem_inv(felem out, const felem in)
+{
+ felem ftmp, ftmp2;
+ /* each e_I will hold |in|^{2^I - 1} */
+ felem e2, e4, e8, e16, e32, e64;
+ unsigned i;
+
+ felem_square(ftmp, in); /* 2^1 */
+ felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */
+ felem_assign(e2, ftmp);
+ felem_square(ftmp, ftmp); /* 2^3 - 2^1 */
+ felem_square(ftmp, ftmp); /* 2^4 - 2^2 */
+ felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */
+ felem_assign(e4, ftmp);
+ felem_square(ftmp, ftmp); /* 2^5 - 2^1 */
+ felem_square(ftmp, ftmp); /* 2^6 - 2^2 */
+ felem_square(ftmp, ftmp); /* 2^7 - 2^3 */
+ felem_square(ftmp, ftmp); /* 2^8 - 2^4 */
+ felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */
+ felem_assign(e8, ftmp);
+ for (i = 0; i < 8; i++)
+ felem_square(ftmp, ftmp);
+ /* 2^16 - 2^8 */
+ felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */
+ felem_assign(e16, ftmp);
+ for (i = 0; i < 16; i++)
+ felem_square(ftmp, ftmp);
+ /* 2^32 - 2^16 */
+ felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */
+ felem_assign(e32, ftmp);
+ for (i = 0; i < 32; i++)
+ felem_square(ftmp, ftmp);
+ /* 2^64 - 2^32 */
+ felem_assign(e64, ftmp);
+ felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */
+ for (i = 0; i < 192; i++)
+ felem_square(ftmp, ftmp);
+ /* 2^256 - 2^224 + 2^192 */
+
+ felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */
+ for (i = 0; i < 16; i++)
+ felem_square(ftmp2, ftmp2);
+ /* 2^80 - 2^16 */
+ felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */
+ for (i = 0; i < 8; i++)
+ felem_square(ftmp2, ftmp2);
+ /* 2^88 - 2^8 */
+ felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */
+ for (i = 0; i < 4; i++)
+ felem_square(ftmp2, ftmp2);
+ /* 2^92 - 2^4 */
+ felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */
+ felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */
+ felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */
+ felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */
+ felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */
+ felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */
+ felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */
+
+ felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
+}
+
+/* felem_scalar_3 sets out=3*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_3(felem out)
+{
+ limb carry = 0;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ out[i] *= 3;
+ out[i] += carry;
+ carry = out[i] >> 29;
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ out[i] *= 3;
+ out[i] += carry;
+ carry = out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_scalar_4 sets out=4*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_4(felem out)
+{
+ limb carry = 0, next_carry;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ next_carry = out[i] >> 27;
+ out[i] <<= 2;
+ out[i] &= kBottom29Bits;
+ out[i] += carry;
+ carry = next_carry + (out[i] >> 29);
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ next_carry = out[i] >> 26;
+ out[i] <<= 2;
+ out[i] &= kBottom28Bits;
+ out[i] += carry;
+ carry = next_carry + (out[i] >> 28);
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_scalar_8 sets out=8*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_8(felem out)
+{
+ limb carry = 0, next_carry;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ next_carry = out[i] >> 26;
+ out[i] <<= 3;
+ out[i] &= kBottom29Bits;
+ out[i] += carry;
+ carry = next_carry + (out[i] >> 29);
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ next_carry = out[i] >> 25;
+ out[i] <<= 3;
+ out[i] &= kBottom28Bits;
+ out[i] += carry;
+ carry = next_carry + (out[i] >> 28);
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of
+ * time depending on the value of |in|. */
+static char felem_is_zero_vartime(const felem in)
+{
+ limb carry;
+ int i;
+ limb tmp[NLIMBS];
+
+ felem_assign(tmp, in);
+
+ /* First, reduce tmp to a minimal form. */
+ do {
+ carry = 0;
+ for (i = 0;; i++) {
+ tmp[i] += carry;
+ carry = tmp[i] >> 29;
+ tmp[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ tmp[i] += carry;
+ carry = tmp[i] >> 28;
+ tmp[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(tmp, carry);
+ } while (carry);
+
+ /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */
+ return memcmp(tmp, kZero, sizeof(tmp)) == 0 ||
+ memcmp(tmp, kP, sizeof(tmp)) == 0 ||
+ memcmp(tmp, k2P, sizeof(tmp)) == 0;
+}
+
+/* Group operations:
+ *
+ * Elements of the elliptic curve group are represented in Jacobian
+ * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in
+ * Jacobian form. */
+
+/* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */
+static void point_double(felem x_out, felem y_out, felem z_out, const felem x,
+ const felem y, const felem z)
+{
+ felem delta, gamma, alpha, beta, tmp, tmp2;
+
+ felem_square(delta, z);
+ felem_square(gamma, y);
+ felem_mul(beta, x, gamma);
+
+ felem_sum(tmp, x, delta);
+ felem_diff(tmp2, x, delta);
+ felem_mul(alpha, tmp, tmp2);
+ felem_scalar_3(alpha);
+
+ felem_sum(tmp, y, z);
+ felem_square(tmp, tmp);
+ felem_diff(tmp, tmp, gamma);
+ felem_diff(z_out, tmp, delta);
+
+ felem_scalar_4(beta);
+ felem_square(x_out, alpha);
+ felem_diff(x_out, x_out, beta);
+ felem_diff(x_out, x_out, beta);
+
+ felem_diff(tmp, beta, x_out);
+ felem_mul(tmp, alpha, tmp);
+ felem_square(tmp2, gamma);
+ felem_scalar_8(tmp2);
+ felem_diff(y_out, tmp, tmp2);
+}
+
+/* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}.
+ * (i.e. the second point is affine.)
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * Note that this function does not handle P+P, infinity+P nor P+infinity
+ * correctly. */
+static void point_add_mixed(felem x_out, felem y_out, felem z_out,
+ const felem x1, const felem y1, const felem z1,
+ const felem x2, const felem y2)
+{
+ felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp;
+
+ felem_square(z1z1, z1);
+ felem_sum(tmp, z1, z1);
+
+ felem_mul(u2, x2, z1z1);
+ felem_mul(z1z1z1, z1, z1z1);
+ felem_mul(s2, y2, z1z1z1);
+ felem_diff(h, u2, x1);
+ felem_sum(i, h, h);
+ felem_square(i, i);
+ felem_mul(j, h, i);
+ felem_diff(r, s2, y1);
+ felem_sum(r, r, r);
+ felem_mul(v, x1, i);
+
+ felem_mul(z_out, tmp, h);
+ felem_square(rr, r);
+ felem_diff(x_out, rr, j);
+ felem_diff(x_out, x_out, v);
+ felem_diff(x_out, x_out, v);
+
+ felem_diff(tmp, v, x_out);
+ felem_mul(y_out, tmp, r);
+ felem_mul(tmp, y1, j);
+ felem_diff(y_out, y_out, tmp);
+ felem_diff(y_out, y_out, tmp);
+}
+
+/* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * Note that this function does not handle P+P, infinity+P nor P+infinity
+ * correctly. */
+static void point_add(felem x_out, felem y_out, felem z_out, const felem x1,
+ const felem y1, const felem z1, const felem x2,
+ const felem y2, const felem z2)
+{
+ felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr,
+ v, tmp;
+
+ felem_square(z1z1, z1);
+ felem_square(z2z2, z2);
+ felem_mul(u1, x1, z2z2);
+
+ felem_sum(tmp, z1, z2);
+ felem_square(tmp, tmp);
+ felem_diff(tmp, tmp, z1z1);
+ felem_diff(tmp, tmp, z2z2);
+
+ felem_mul(z2z2z2, z2, z2z2);
+ felem_mul(s1, y1, z2z2z2);
+
+ felem_mul(u2, x2, z1z1);
+ felem_mul(z1z1z1, z1, z1z1);
+ felem_mul(s2, y2, z1z1z1);
+ felem_diff(h, u2, u1);
+ felem_sum(i, h, h);
+ felem_square(i, i);
+ felem_mul(j, h, i);
+ felem_diff(r, s2, s1);
+ felem_sum(r, r, r);
+ felem_mul(v, u1, i);
+
+ felem_mul(z_out, tmp, h);
+ felem_square(rr, r);
+ felem_diff(x_out, rr, j);
+ felem_diff(x_out, x_out, v);
+ felem_diff(x_out, x_out, v);
+
+ felem_diff(tmp, v, x_out);
+ felem_mul(y_out, tmp, r);
+ felem_mul(tmp, s1, j);
+ felem_diff(y_out, y_out, tmp);
+ felem_diff(y_out, y_out, tmp);
+}
+
+/* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} +
+ * {x2,y2,z2}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */
+static void point_add_or_double_vartime(
+ felem x_out, felem y_out, felem z_out, const felem x1, const felem y1,
+ const felem z1, const felem x2, const felem y2, const felem z2)
+{
+ felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr,
+ v, tmp;
+ char x_equal, y_equal;
+
+ felem_square(z1z1, z1);
+ felem_square(z2z2, z2);
+ felem_mul(u1, x1, z2z2);
+
+ felem_sum(tmp, z1, z2);
+ felem_square(tmp, tmp);
+ felem_diff(tmp, tmp, z1z1);
+ felem_diff(tmp, tmp, z2z2);
+
+ felem_mul(z2z2z2, z2, z2z2);
+ felem_mul(s1, y1, z2z2z2);
+
+ felem_mul(u2, x2, z1z1);
+ felem_mul(z1z1z1, z1, z1z1);
+ felem_mul(s2, y2, z1z1z1);
+ felem_diff(h, u2, u1);
+ x_equal = felem_is_zero_vartime(h);
+ felem_sum(i, h, h);
+ felem_square(i, i);
+ felem_mul(j, h, i);
+ felem_diff(r, s2, s1);
+ y_equal = felem_is_zero_vartime(r);
+ if (x_equal && y_equal) {
+ point_double(x_out, y_out, z_out, x1, y1, z1);
+ return;
+ }
+ felem_sum(r, r, r);
+ felem_mul(v, u1, i);
+
+ felem_mul(z_out, tmp, h);
+ felem_square(rr, r);
+ felem_diff(x_out, rr, j);
+ felem_diff(x_out, x_out, v);
+ felem_diff(x_out, x_out, v);
+
+ felem_diff(tmp, v, x_out);
+ felem_mul(y_out, tmp, r);
+ felem_mul(tmp, s1, j);
+ felem_diff(y_out, y_out, tmp);
+ felem_diff(y_out, y_out, tmp);
+}
+
+/* copy_conditional sets out=in if mask = 0xffffffff in constant time.
+ *
+ * On entry: mask is either 0 or 0xffffffff. */
+static void copy_conditional(felem out, const felem in, limb mask)
+{
+ int i;
+
+ for (i = 0; i < NLIMBS; i++) {
+ const limb tmp = mask & (in[i] ^ out[i]);
+
+ out[i] ^= tmp;
+ }
+}
+
+/* select_affine_point sets {out_x,out_y} to the index'th entry of table.
+ * On entry: index < 16, table[0] must be zero. */
+static void select_affine_point(felem out_x, felem out_y, const limb *table,
+ limb index)
+{
+ limb i, j;
+
+ memset(out_x, 0, sizeof(felem));
+ memset(out_y, 0, sizeof(felem));
+
+ for (i = 1; i < 16; i++) {
+ limb mask = i ^ index;
+
+ mask |= mask >> 2;
+ mask |= mask >> 1;
+ mask &= 1;
+ mask--;
+ for (j = 0; j < NLIMBS; j++, table++)
+ out_x[j] |= *table & mask;
+ for (j = 0; j < NLIMBS; j++, table++)
+ out_y[j] |= *table & mask;
+ }
+}
+
+/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of
+ * table. On entry: index < 16, table[0] must be zero. */
+static void select_jacobian_point(felem out_x, felem out_y, felem out_z,
+ const limb *table, limb index)
+{
+ limb i, j;
+
+ memset(out_x, 0, sizeof(felem));
+ memset(out_y, 0, sizeof(felem));
+ memset(out_z, 0, sizeof(felem));
+
+ /* The implicit value at index 0 is all zero. We don't need to
+ * perform that iteration of the loop because we already set
+ * out_* to zero. */
+ table += 3 * NLIMBS;
+
+ /* Hit all entries to obscure cache profiling. */
+ for (i = 1; i < 16; i++) {
+ limb mask = i ^ index;
+
+ mask |= mask >> 2;
+ mask |= mask >> 1;
+ mask &= 1;
+ mask--;
+ for (j = 0; j < NLIMBS; j++, table++)
+ out_x[j] |= *table & mask;
+ for (j = 0; j < NLIMBS; j++, table++)
+ out_y[j] |= *table & mask;
+ for (j = 0; j < NLIMBS; j++, table++)
+ out_z[j] |= *table & mask;
+ }
+}
+
+/* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian
+ * number. Note that the value of scalar must be less than the order of the
+ * group. */
+static void scalar_base_mult(felem nx, felem ny, felem nz,
+ const p256_int *scalar)
+{
+ int i, j;
+ limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask;
+ u32 table_offset;
+
+ felem px, py;
+ felem tx, ty, tz;
+
+ memset(nx, 0, sizeof(felem));
+ memset(ny, 0, sizeof(felem));
+ memset(nz, 0, sizeof(felem));
+
+ /* The loop adds bits at positions 0, 64, 128 and 192, followed by
+ * positions 32,96,160 and 224 and does this 32 times. */
+ for (i = 0; i < 32; i++) {
+ if (i)
+ point_double(nx, ny, nz, nx, ny, nz);
+
+ table_offset = 0;
+ for (j = 0; j <= 32; j += 32) {
+ char bit0 = p256_get_bit(scalar, 31 - i + j);
+ char bit1 = p256_get_bit(scalar, 95 - i + j);
+ char bit2 = p256_get_bit(scalar, 159 - i + j);
+ char bit3 = p256_get_bit(scalar, 223 - i + j);
+ limb index =
+ bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3);
+
+ select_affine_point(px, py,
+ kPrecomputed + table_offset, index);
+ table_offset += 30 * NLIMBS;
+
+ /* Since scalar is less than the order of the
+ * group, we know that {nx,ny,nz} !=
+ * {px,py,1}, unless both are zero, which we
+ * handle below. */
+ point_add_mixed(tx, ty, tz, nx, ny, nz, px, py);
+ /* The result of point_add_mixed is incorrect
+ * if {nx,ny,nz} is zero (a.k.a. the point at
+ * infinity). We handle that situation by
+ * copying the point from the table. */
+ copy_conditional(nx, px, n_is_infinity_mask);
+ copy_conditional(ny, py, n_is_infinity_mask);
+ copy_conditional(nz, kOne, n_is_infinity_mask);
+
+ /* Equally, the result is also wrong if the
+ * point from the table is zero, which happens
+ * when the index is zero. We handle that by
+ * only copying from {tx,ty,tz} to {nx,ny,nz}
+ * if index != 0. */
+ p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
+ mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
+ copy_conditional(nx, tx, mask);
+ copy_conditional(ny, ty, mask);
+ copy_conditional(nz, tz, mask);
+ /* If p was not zero, then n is now non-zero. */
+ n_is_infinity_mask &= ~p_is_noninfinite_mask;
+ }
+ }
+}
+
+/* point_to_affine converts a Jacobian point to an affine point. If
+ * the input is the point at infinity then it returns (0, 0) in
+ * constant time. */
+static void point_to_affine(felem x_out, felem y_out, const felem nx,
+ const felem ny, const felem nz)
+{
+ felem z_inv, z_inv_sq;
+
+ felem_inv(z_inv, nz);
+ felem_square(z_inv_sq, z_inv);
+ felem_mul(x_out, nx, z_inv_sq);
+ felem_mul(z_inv, z_inv, z_inv_sq);
+ felem_mul(y_out, ny, z_inv);
+}
+
+/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */
+static void scalar_mult(felem nx, felem ny, felem nz, const felem x,
+ const felem y, const p256_int *scalar)
+{
+ int i;
+ felem px, py, pz, tx, ty, tz;
+ felem precomp[16][3];
+ limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask;
+
+ /* We precompute 0,1,2,... times {x,y}. */
+ memset(precomp, 0, sizeof(felem) * 3);
+ memcpy(&precomp[1][0], x, sizeof(felem));
+ memcpy(&precomp[1][1], y, sizeof(felem));
+ memcpy(&precomp[1][2], kOne, sizeof(felem));
+
+ for (i = 2; i < 16; i += 2) {
+ point_double(precomp[i][0], precomp[i][1], precomp[i][2],
+ precomp[i / 2][0], precomp[i / 2][1],
+ precomp[i / 2][2]);
+
+ point_add_mixed(
+ precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2],
+ precomp[i][0], precomp[i][1], precomp[i][2], x, y);
+ }
+
+ memset(nx, 0, sizeof(felem));
+ memset(ny, 0, sizeof(felem));
+ memset(nz, 0, sizeof(felem));
+ n_is_infinity_mask = -1;
+
+ /* We add in a window of four bits each iteration and do this
+ * 64 times. */
+ for (i = 0; i < 256; i += 4) {
+ if (i) {
+ point_double(nx, ny, nz, nx, ny, nz);
+ point_double(nx, ny, nz, nx, ny, nz);
+ point_double(nx, ny, nz, nx, ny, nz);
+ point_double(nx, ny, nz, nx, ny, nz);
+ }
+
+ index = (p256_get_bit(scalar, 255 - i - 0) << 3) |
+ (p256_get_bit(scalar, 255 - i - 1) << 2) |
+ (p256_get_bit(scalar, 255 - i - 2) << 1) |
+ p256_get_bit(scalar, 255 - i - 3);
+
+ /* See the comments in scalar_base_mult about handling
+ * infinities. */
+ select_jacobian_point(px, py, pz, precomp[0][0], index);
+ point_add(tx, ty, tz, nx, ny, nz, px, py, pz);
+ copy_conditional(nx, px, n_is_infinity_mask);
+ copy_conditional(ny, py, n_is_infinity_mask);
+ copy_conditional(nz, pz, n_is_infinity_mask);
+
+ p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
+ mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
+
+ copy_conditional(nx, tx, mask);
+ copy_conditional(ny, ty, mask);
+ copy_conditional(nz, tz, mask);
+ n_is_infinity_mask &= ~p_is_noninfinite_mask;
+ }
+}
+
+/* 2^257 mod p256.p */
+#define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1}
+/* 1 / 2^257 mod p256.p */
+#define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, \
+ 1, 0x7fffffff}
+
+static const p256_int kR = { kRDigits };
+static const p256_int kRInv = { kRInvDigits };
+
+/* to_montgomery sets out = R*in. */
+static void to_montgomery(felem out, const p256_int *in)
+{
+ p256_int in_shifted;
+ int i;
+
+ p256_init(&in_shifted);
+ p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted);
+
+ for (i = 0; i < NLIMBS; i++) {
+ if ((i & 1) == 0) {
+ out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits;
+ p256_shr(&in_shifted, 29, &in_shifted);
+ } else {
+ out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits;
+ p256_shr(&in_shifted, 28, &in_shifted);
+ }
+ }
+
+ p256_clear(&in_shifted);
+}
+
+/* from_montgomery sets out=in/R. */
+static void from_montgomery(p256_int *out, const felem in)
+{
+ p256_int result, tmp;
+ int i, top;
+
+ p256_init(&result);
+ p256_init(&tmp);
+
+ p256_add_d(&tmp, in[NLIMBS - 1], &result);
+ for (i = NLIMBS - 2; i >= 0; i--) {
+ if ((i & 1) == 0)
+ top = p256_shl(&result, 29, &tmp);
+ else
+ top = p256_shl(&result, 28, &tmp);
+
+ top |= p256_add_d(&tmp, in[i], &result);
+ }
+
+ p256_modmul(&SECP256r1_p, &kRInv, top, &result, out);
+
+ p256_clear(&result);
+ p256_clear(&tmp);
+}
+
+/* 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)
+{
+ felem x, y, z;
+
+ if (p256_is_zero(n) != 0) {
+ p256_clear(out_x);
+ p256_clear(out_y);
+ return 0;
+ }
+
+ scalar_base_mult(x, y, z, n);
+
+ {
+ felem x_affine, y_affine;
+
+ point_to_affine(x_affine, y_affine, x, y, z);
+ from_montgomery(out_x, x_affine);
+ from_montgomery(out_y, y_affine);
+ }
+
+ return 1;
+}
+
+/* p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is <
+ * the order of the group. */
+void p256_point_mul(const p256_int *n, const p256_int *in_x,
+ const p256_int *in_y, p256_int *out_x, p256_int *out_y)
+{
+ felem x, y, z, px, py;
+
+ to_montgomery(px, in_x);
+ to_montgomery(py, in_y);
+
+ scalar_mult(x, y, z, px, py, n);
+
+ point_to_affine(px, py, x, y, z);
+ from_montgomery(out_x, px);
+ from_montgomery(out_y, py);
+}
+
+/* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where
+ * n1 and n2 are < the order of the group.
+ *
+ * As indicated by the name, this function operates in variable time. This
+ * is safe because it's used for signature validation which doesn't deal
+ * with secrets. */
+void p256_points_mul_vartime(
+ const p256_int *n1, const p256_int *n2, const p256_int *in_x,
+ const p256_int *in_y, p256_int *out_x, p256_int *out_y)
+{
+ felem x1, y1, z1, x2, y2, z2, px, py;
+
+ /* If both scalars are zero, then the result is the point at
+ * infinity. */
+ if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) {
+ p256_clear(out_x);
+ p256_clear(out_y);
+ return;
+ }
+
+ to_montgomery(px, in_x);
+ to_montgomery(py, in_y);
+ scalar_base_mult(x1, y1, z1, n1);
+ scalar_mult(x2, y2, z2, px, py, n2);
+
+ if (p256_is_zero(n2) != 0) {
+ /* If n2 == 0, then {x2,y2,z2} is zero and the result is just
+ * {x1,y1,z1}. */
+ } else if (p256_is_zero(n1) != 0) {
+ /* If n1 == 0, then {x1,y1,z1} is zero and the result is just
+ * {x2,y2,z2}. */
+ memcpy(x1, x2, sizeof(x2));
+ memcpy(y1, y2, sizeof(y2));
+ memcpy(z1, z2, sizeof(z2));
+ } else {
+ /* This function handles the case where {x1,y1,z1} ==
+ * {x2,y2,z2}. */
+ point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2);
+ }
+
+ point_to_affine(px, py, x1, y1, z1);
+ from_montgomery(out_x, px);
+ from_montgomery(out_y, py);
+}
+
+/* p256_points_mul sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where
+ * n1 and n2 are < the order of the group.
+ *
+ * As indicated by the name, this function operates in variable time. This
+ * is safe because it's used for signature validation which doesn't deal
+ * with secrets. */
+int DCRYPTO_p256_points_mul(p256_int *out_x, p256_int *out_y,
+ const p256_int *n1, const p256_int *n2,
+ const p256_int *in_x, const p256_int *in_y)
+{
+ felem x1, y1, z1, x2, y2, z2, px, py;
+
+ /* If both scalars are zero, then the result is the point at
+ * infinity. */
+ if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) {
+ p256_clear(out_x);
+ p256_clear(out_y);
+ return 0;
+ }
+
+ to_montgomery(px, in_x);
+ to_montgomery(py, in_y);
+ scalar_base_mult(x1, y1, z1, n1);
+ scalar_mult(x2, y2, z2, px, py, n2);
+
+ if (p256_is_zero(n2) != 0) {
+ /* If n2 == 0, then {x2,y2,z2} is zero and the result is just
+ * {x1,y1,z1}. */
+ } else if (p256_is_zero(n1) != 0) {
+ /* If n1 == 0, then {x1,y1,z1} is zero and the result is just
+ * {x2,y2,z2}. */
+ memcpy(x1, x2, sizeof(x2));
+ memcpy(y1, y2, sizeof(y2));
+ memcpy(z1, z2, sizeof(z2));
+ } else {
+ /* This function handles the case where
+ * {x1,y1,z1} == {x2,y2,z2}. */
+ point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2);
+ }
+
+ point_to_affine(px, py, x1, y1, z1);
+ from_montgomery(out_x, px);
+ from_montgomery(out_y, py);
+ return 1;
+}
diff --git a/chip/g/dcrypto/p256_ecdsa.c b/chip/g/dcrypto/p256_ecdsa.c
new file mode 100644
index 0000000000..2385c58d62
--- /dev/null
+++ b/chip/g/dcrypto/p256_ecdsa.c
@@ -0,0 +1,103 @@
+/* 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 <stdint.h>
+
+#include "dcrypto.h"
+
+/* Compute k based on a given {key, digest} pair, 0 < k < n. */
+static void determine_k(const p256_int *key, const p256_int *digest,
+ char *tweak, p256_int *k)
+{
+ do {
+ p256_int p1, p2;
+ struct HMAC_CTX hmac;
+
+ /* NOTE: taking the p256_int in-memory representation
+ * is not endian neutral. Signatures with an
+ * identical key on identical digests will differ per
+ * host endianness. This however does not jeopardize
+ * the key bits. */
+ dcrypto_HMAC_SHA256_init(&hmac, key, P256_NBYTES);
+ dcrypto_HMAC_update(&hmac, tweak, 1);
+ dcrypto_HMAC_update(&hmac, (uint8_t *) digest, P256_NBYTES);
+ ++(*tweak);
+ p256_from_bin(dcrypto_HMAC_final(&hmac), &p1);
+
+ dcrypto_HMAC_SHA256_init(&hmac, key, P256_NBYTES);
+ dcrypto_HMAC_update(&hmac, tweak, 1);
+ dcrypto_HMAC_update(&hmac, (uint8_t *) digest, P256_NBYTES);
+ ++(*tweak);
+ p256_from_bin(dcrypto_HMAC_final(&hmac), &p2);
+
+ /* Combine p1 and p2 into well distributed k. */
+ p256_modmul(&SECP256r1_n, &p1, 0, &p2, k);
+
+ /* (Attempt to) clear stack state. */
+ p256_clear(&p1);
+ p256_clear(&p2);
+
+ } while (p256_is_zero(k));
+}
+
+void DCRYPTO_p256_ecdsa_sign(const p256_int *key, const p256_int *digest,
+ p256_int *r, p256_int *s)
+{
+ char tweak = 'A';
+ p256_digit top;
+
+ for (;;) {
+ p256_int k, kinv;
+
+ determine_k(key, digest, &tweak, &k);
+ DCRYPTO_p256_base_point_mul(r, s, &k);
+ p256_mod(&SECP256r1_n, r, r);
+
+ /* Make sure r != 0. */
+ if (p256_is_zero(r))
+ continue;
+
+ p256_modmul(&SECP256r1_n, r, 0, key, s);
+ top = p256_add(s, digest, s);
+ p256_modinv(&SECP256r1_n, &k, &kinv);
+ p256_modmul(&SECP256r1_n, &kinv, top, s, s);
+
+ /* (Attempt to) clear stack state. */
+ p256_clear(&k);
+ p256_clear(&kinv);
+
+ /* Make sure s != 0. */
+ if (p256_is_zero(s))
+ continue;
+
+ break;
+ }
+}
+
+int DCRYPTO_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
+ const p256_int *digest,
+ const p256_int *r, const p256_int *s)
+{
+ p256_int u, v;
+
+ /* Check public key. */
+ if (!DCRYPTO_p256_valid_point(key_x, key_y))
+ return 0;
+
+ /* Check r and s are != 0 % n. */
+ p256_mod(&SECP256r1_n, r, &u);
+ p256_mod(&SECP256r1_n, s, &v);
+ if (p256_is_zero(&u) || p256_is_zero(&v))
+ return 0;
+
+ p256_modinv_vartime(&SECP256r1_n, s, &v);
+ p256_modmul(&SECP256r1_n, digest, 0, &v, &u); /* digest / s % n */
+ p256_modmul(&SECP256r1_n, r, 0, &v, &v); /* r / s % n */
+
+ p256_points_mul_vartime(&u, &v, key_x, key_y, &u, &v);
+
+ p256_mod(&SECP256r1_n, &u, &u); /* (x coord % p) % n */
+ return p256_cmp(r, &u) == 0;
+}
diff --git a/include/extension.h b/include/extension.h
index c985640fa9..78b9d63f37 100644
--- a/include/extension.h
+++ b/include/extension.h
@@ -49,6 +49,7 @@ enum {
EXTENSION_AES = 0,
EXTENSION_HASH = 1,
EXTENSION_RSA = 2,
+ EXTENSION_EC = 3,
};
diff --git a/test/tpm_test/ecc_test.py b/test/tpm_test/ecc_test.py
new file mode 100644
index 0000000000..cd4bb0a261
--- /dev/null
+++ b/test/tpm_test/ecc_test.py
@@ -0,0 +1,169 @@
+#!/usr/bin/python
+# 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.
+
+"""Module for testing ecc functions using extended commands."""
+import binascii
+import hashlib
+import os
+import struct
+
+import subcmd
+import utils
+
+_EC_OPCODES = {
+ 'SIGN': 0x00,
+ 'VERIFY': 0x01,
+ 'KEYGEN': 0x02,
+ 'KEYDERIVE': 0x03,
+}
+
+_EC_CURVES = {
+ 'NIST-P256': 0x03,
+}
+
+# TPM2 signature codes.
+_SIGN_MODE = {
+ 'NONE': 0x00,
+ 'ECDSA': 0x18,
+ # TODO(ngm): add support for SCHNORR.
+ # 'SCHNORR': 0x1c
+}
+
+# TPM2 ALG codes.
+_HASH = {
+ 'NONE': 0x00,
+ 'SHA1': 0x04,
+ 'SHA256': 0x0B
+}
+
+_HASH_FUNC = {
+ 'NIST-P256': hashlib.sha256
+}
+
+# Command format.
+#
+# 0x00 OP
+# 0x00 CURVE_ID
+# 0x00 SIGN_MODE
+# 0x00 HASHING
+# 0x00 MSB IN LEN
+# 0x00 LSB IN LEN
+# .... IN
+# 0x00 MSB DIGEST LEN
+# 0x00 LSB DIGEST LEN
+# .... DIGEST
+#
+_EC_CMD_FORMAT = '{o:c}{c:c}{s:c}{h:c}{ml:s}{msg}{dl:s}{dig}'
+
+
+def _sign_cmd(curve_id, hash_func, sign_mode, msg):
+ op = _EC_OPCODES['SIGN']
+ digest = hash_func(msg).digest()
+ digest_len = len(digest)
+ return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=sign_mode, h=_HASH['NONE'],
+ ml=struct.pack('>H', 0), msg='',
+ dl=struct.pack('>H', digest_len), dig=digest)
+
+
+def _verify_cmd(curve_id, hash_func, sign_mode, msg, sig):
+ op = _EC_OPCODES['VERIFY']
+ sig_len = len(sig)
+ digest = hash_func(msg).digest()
+ digest_len = len(digest)
+ return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=sign_mode, h=_HASH['NONE'],
+ ml=struct.pack('>H', sig_len), msg=sig,
+ dl=struct.pack('>H', digest_len), dig=digest)
+
+
+def _keygen_cmd(curve_id):
+ op = _EC_OPCODES['KEYGEN']
+ return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=_SIGN_MODE['NONE'],
+ h=_HASH['NONE'], ml=struct.pack('>H', 0), msg='',
+ dl=struct.pack('>H', 0), dig='')
+
+
+def _keyderive_cmd(curve_id, seed):
+ op = _EC_OPCODES['KEYDERIVE']
+ seed_len = len(seed)
+ return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=_SIGN_MODE['NONE'],
+ h=_HASH['NONE'], ml=struct.pack('>H', seed_len),
+ msg=seed, dl=struct.pack('>H', 0), dig='')
+
+
+_SIGN_INPUTS = (
+ ('NIST-P256', 'ECDSA'),
+)
+
+
+_KEYGEN_INPUTS = (
+ ('NIST-P256',),
+)
+
+
+_KEYDERIVE_INPUTS = (
+ # Curve-id, random seed size.
+ ('NIST-P256', 32),
+)
+
+
+class ECError(Exception):
+ pass
+
+
+def _sign_test(tpm):
+ msg = 'Hello CR50'
+
+ for data in _SIGN_INPUTS:
+ curve_id, sign_mode = data
+ test_name = 'EC-SIGN:%s:%s' % data
+ cmd = _sign_cmd(_EC_CURVES[curve_id], _HASH_FUNC[curve_id],
+ _SIGN_MODE[sign_mode], msg)
+ wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd))
+ signature = tpm.unwrap_ext_response(subcmd.EC, wrapped_response)
+
+ cmd = _verify_cmd(_EC_CURVES[curve_id], _HASH_FUNC[curve_id],
+ _SIGN_MODE[sign_mode], msg, signature)
+ wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd))
+ verified = tpm.unwrap_ext_response(subcmd.EC, wrapped_response)
+ expected = '\x01'
+ if verified != expected:
+ raise ECError('%s error:%s:%s' % (
+ test_name, utils.hex_dump(verified), utils.hex_dump(expected)))
+ print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
+
+
+def _keygen_test(tpm):
+ for data in _KEYGEN_INPUTS:
+ curve_id, = data
+ test_name = 'EC-KEYGEN:%s' % data
+ cmd = _keygen_cmd(_EC_CURVES[curve_id])
+ wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd))
+ valid = tpm.unwrap_ext_response(subcmd.EC, wrapped_response)
+ expected = '\x01'
+ if valid != expected:
+ raise ECError('%s error:%s:%s' % (
+ test_name, utils.hex_dump(valid), utils.hex_dump(expected)))
+ print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
+
+
+def _keyderive_test(tpm):
+ for data in _KEYDERIVE_INPUTS:
+ curve_id, seed_bytes = data
+ seed = os.urandom(seed_bytes)
+ test_name = 'EC-KEYDERIVE:%s' % data[0]
+ cmd = _keyderive_cmd(_EC_CURVES[curve_id], seed)
+ wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd))
+ valid = tpm.unwrap_ext_response(subcmd.EC, wrapped_response)
+ expected = '\x01'
+ if valid != expected:
+ raise ECError('%s error:%s:%s' % (
+ test_name, utils.hex_dump(valid), utils.hex_dump(expected)))
+ print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
+
+
+def ecc_test(tpm):
+ _sign_test(tpm)
+ _keygen_test(tpm)
+ _keyderive_test(tpm)
diff --git a/test/tpm_test/subcmd.py b/test/tpm_test/subcmd.py
index f7bd8090a0..d14c2e9b9c 100644
--- a/test/tpm_test/subcmd.py
+++ b/test/tpm_test/subcmd.py
@@ -9,3 +9,4 @@
AES = 0
HASH = 1
RSA = 2
+EC = 3
diff --git a/test/tpm_test/tpmtest.py b/test/tpm_test/tpmtest.py
index 52d7205022..173f0ec693 100755
--- a/test/tpm_test/tpmtest.py
+++ b/test/tpm_test/tpmtest.py
@@ -19,6 +19,7 @@ root_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
sys.path.append(os.path.join(root_dir, '..', '..', 'build', 'tpm_test'))
import crypto_test
+import ecc_test
import ftdi_spi_tpm
import hash_test
import rsa_test
@@ -135,6 +136,7 @@ if __name__ == '__main__':
t = TPM(debug_mode=debug_needed)
crypto_test.crypto_tests(t, os.path.join(root_dir, 'crypto_test.xml'))
+ ecc_test.ecc_test(t)
hash_test.hash_test(t)
rsa_test.rsa_test(t)
except (TpmError, crypto_test.CryptoError, hash_test.HashError,