File syn_p256.c¶
File List > crypto > syn_p256.c
Go to the documentation of this file
#include "syn_p256.h"
#if !defined(SYN_USE_HMAC_DRBG) || SYN_USE_HMAC_DRBG
#include "syn_hmac_drbg.h"
#endif
#include <string.h>
/* NIST P-256 Curve Constants (Little-Endian 32-bit Words: limbs[0] is least significant) */
static const uint32_t P256_P[8] = {0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U,
0x00000000U, 0x00000000U, 0x00000001U, 0xFFFFFFFFU};
static const uint32_t P256_N[8] = {0xFC632551U, 0xF3B9CAC2U, 0xA7179E84U, 0xBCE6FAADU,
0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0xFFFFFFFFU};
static const uint32_t P256_B[8] = {0x27D2604BU, 0x3BCE3C3EU, 0xCC53B0F6U, 0x651D06B0U,
0x769886BCU, 0xB3EBBD55U, 0xAA3A93E7U, 0x5AC635D8U};
static const uint32_t P256_GX[8] = {0xD898C296U, 0xF4A13945U, 0x2DEB33A0U, 0x77037D81U,
0x63A440F2U, 0xF8BCE6E5U, 0xE12C4247U, 0x6B17D1F2U};
static const uint32_t P256_GY[8] = {0x37BF51F5U, 0xCBB64068U, 0x6B315ECEU, 0x2BCE3357U,
0x7C0F9E16U, 0x8EE7EB4AU, 0xFE1A7F9BU, 0x4FE342E2U};
static const uint32_t BN_ONE[8] = {1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U};
/* ── 256-bit Big-Number Utilities ────────────────────────────────────────── */
typedef uint32_t bignum256[8];
static void bn_from_bytes(bignum256 r, const uint8_t bytes[32])
{
for (int i = 0; i < 8; i++) {
int idx = (7 - i) * 4;
r[i] = ((uint32_t)bytes[idx + 0] << 24U) | ((uint32_t)bytes[idx + 1] << 16U) |
((uint32_t)bytes[idx + 2] << 8U) | ((uint32_t)bytes[idx + 3]);
}
}
static void bn_to_bytes(uint8_t bytes[32], const bignum256 a)
{
for (int i = 0; i < 8; i++) {
int idx = (7 - i) * 4;
bytes[idx + 0] = (uint8_t)(a[i] >> 24U);
bytes[idx + 1] = (uint8_t)(a[i] >> 16U);
bytes[idx + 2] = (uint8_t)(a[i] >> 8U);
bytes[idx + 3] = (uint8_t)(a[i]);
}
}
static int bn_cmp(const bignum256 a, const bignum256 b)
{
for (int i = 7; i >= 0; i--) {
if (a[i] > b[i])
return 1;
if (a[i] < b[i])
return -1;
}
return 0;
}
static bool bn_is_zero(const bignum256 a)
{
for (int i = 0; i < 8; i++) {
if (a[i] != 0U)
return false;
}
return true;
}
static void bn_copy(bignum256 r, const bignum256 a)
{
memcpy(r, a, sizeof(bignum256));
}
/* ── Field Arithmetic Modulo p ─────────────────────────────────────────── */
static uint32_t bn_add_raw(bignum256 r, const bignum256 a, const bignum256 b)
{
uint64_t carry = 0;
for (int i = 0; i < 8; i++) {
uint64_t sum = (uint64_t)a[i] + (uint64_t)b[i] + carry;
r[i] = (uint32_t)sum;
carry = sum >> 32U;
}
return (uint32_t)carry;
}
static uint32_t bn_sub_raw(bignum256 r, const bignum256 a, const bignum256 b)
{
int64_t borrow = 0;
for (int i = 0; i < 8; i++) {
int64_t diff = (int64_t)a[i] - (int64_t)b[i] + borrow;
r[i] = (uint32_t)diff;
borrow = diff >> 32U;
}
return (uint32_t)(borrow != 0);
}
static void p256_mod_p_add(bignum256 r, const bignum256 a, const bignum256 b)
{
uint32_t carry = bn_add_raw(r, a, b);
if (carry || bn_cmp(r, P256_P) >= 0) {
bn_sub_raw(r, r, P256_P);
}
}
static void p256_mod_p_sub(bignum256 r, const bignum256 a, const bignum256 b)
{
uint32_t borrow = bn_sub_raw(r, a, b);
if (borrow) {
bn_add_raw(r, r, P256_P);
}
}
static void bn_mul_raw(uint32_t t[16], const bignum256 a, const bignum256 b)
{
memset(t, 0, 16 * sizeof(uint32_t));
for (int i = 0; i < 8; i++) {
uint64_t carry = 0;
for (int j = 0; j < 8; j++) {
uint64_t prod = (uint64_t)a[i] * (uint64_t)b[j] + (uint64_t)t[i + j] + carry;
t[i + j] = (uint32_t)prod;
carry = prod >> 32U;
}
int k = i + 8;
while (carry > 0 && k < 16) {
uint64_t sum = (uint64_t)t[k] + carry;
t[k] = (uint32_t)sum;
carry = sum >> 32U;
k++;
}
}
}
static void p256_mod_p_reduce(bignum256 r, const uint32_t c[16])
{
int64_t diff[8];
diff[0] = (int64_t)c[0] + c[8] + c[9] - c[11] - c[12] - c[13] - c[14];
diff[1] = (int64_t)c[1] + c[9] + c[10] - c[12] - c[13] - c[14] - c[15];
diff[2] = (int64_t)c[2] + c[10] + c[11] - c[13] - c[14] - c[15];
diff[3] = (int64_t)c[3] - c[8] - c[9] + 2LL * c[11] + 2LL * c[12] + c[13] - c[15];
diff[4] = (int64_t)c[4] - c[9] - c[10] + 2LL * c[12] + 2LL * c[13] + c[14];
diff[5] = (int64_t)c[5] - c[10] - c[11] + 2LL * c[13] + 2LL * c[14] + c[15];
diff[6] = (int64_t)c[6] - c[8] - c[9] + c[13] + 3LL * c[14] + 2LL * c[15];
diff[7] = (int64_t)c[7] + c[8] - c[10] - c[11] - c[12] - c[13] + 3LL * c[15];
int64_t carry = 0;
for (int i = 0; i < 8; i++) {
int64_t val = diff[i] + carry;
r[i] = (uint32_t)val;
carry = val >> 32U;
}
while (carry > 0 || bn_cmp(r, P256_P) >= 0) {
bn_sub_raw(r, r, P256_P);
carry--;
}
while (carry < 0) {
bn_add_raw(r, r, P256_P);
carry++;
}
}
static void p256_mod_p_mul(bignum256 r, const bignum256 a, const bignum256 b)
{
uint32_t t[16];
bn_mul_raw(t, a, b);
p256_mod_p_reduce(r, t);
}
static void p256_mod_p_sqr(bignum256 r, const bignum256 a)
{
p256_mod_p_mul(r, a, a);
}
static void p256_mod_p_inv(bignum256 r, const bignum256 a)
{
/* LCOV_EXCL_START: Identity shortcut */
if (bn_cmp(a, BN_ONE) == 0) {
bn_copy(r, BN_ONE);
return;
}
/* LCOV_EXCL_STOP */
bignum256 res;
memset(res, 0, sizeof(res));
res[0] = 1U;
bignum256 base;
bn_copy(base, a);
/* p - 2 exponent */
bignum256 exp;
bn_copy(exp, P256_P);
exp[0] -= 2U;
for (int i = 0; i < 8; i++) {
uint32_t w = exp[i];
for (int b = 0; b < 32; b++) {
if (w & 1U) {
p256_mod_p_mul(res, res, base);
}
p256_mod_p_sqr(base, base);
w >>= 1U;
}
}
bn_copy(r, res);
}
/* ── Group Order Arithmetic Modulo n ────────────────────────────────────── */
static void p256_mod_n_mul(bignum256 r, const bignum256 a, const bignum256 b)
{
uint32_t t[16];
bn_mul_raw(t, a, b);
bignum256 rem = {0};
for (int bit = 511; bit >= 0; bit--) {
uint32_t carry_bit = (t[bit / 32] >> (bit % 32)) & 1U;
for (int i = 0; i < 8; i++) {
uint32_t next_carry = rem[i] >> 31U;
rem[i] = (rem[i] << 1U) | carry_bit;
carry_bit = next_carry;
}
if (carry_bit || bn_cmp(rem, P256_N) >= 0) {
bn_sub_raw(rem, rem, P256_N);
}
}
bn_copy(r, rem);
}
static void p256_mod_n_sub(bignum256 r, const bignum256 a, const bignum256 b)
{
uint32_t borrow = bn_sub_raw(r, a, b);
if (borrow != 0U) {
bn_add_raw(r, r, P256_N);
}
}
static void bn_rshift1(bignum256 r, const bignum256 a)
{
uint32_t carry = 0U;
for (int i = 7; i >= 0; i--) {
uint32_t next_carry = a[i] & 1U;
r[i] = (a[i] >> 1U) | (carry << 31U);
carry = next_carry;
}
}
static void bn_div2_mod_n(bignum256 r, const bignum256 a)
{
if ((a[0] & 1U) != 0U) {
bignum256 sum;
uint32_t carry = bn_add_raw(sum, a, P256_N);
for (int i = 7; i >= 0; i--) {
uint32_t next_carry = sum[i] & 1U;
r[i] = (sum[i] >> 1U) | (carry << 31U);
carry = next_carry;
}
} else {
bn_rshift1(r, a);
}
}
static void p256_mod_n_inv(bignum256 r, const bignum256 a)
{
/* LCOV_EXCL_START: Identity and zero shortcuts */
if (bn_is_zero(a)) {
memset(r, 0, sizeof(bignum256));
return;
}
if (bn_cmp(a, BN_ONE) == 0) {
bn_copy(r, BN_ONE);
return;
}
/* LCOV_EXCL_STOP */
bignum256 u, v, x1, x2;
bn_copy(u, a);
bn_copy(v, P256_N);
memset(x1, 0, sizeof(x1));
x1[0] = 1U;
memset(x2, 0, sizeof(x2));
while (!bn_is_zero(u)) {
while ((u[0] & 1U) == 0U) {
bn_rshift1(u, u);
bn_div2_mod_n(x1, x1);
}
while ((v[0] & 1U) == 0U) {
bn_rshift1(v, v);
bn_div2_mod_n(x2, x2);
}
if (bn_cmp(u, v) >= 0) {
bn_sub_raw(u, u, v);
p256_mod_n_sub(x1, x1, x2);
} else {
bn_sub_raw(v, v, u);
p256_mod_n_sub(x2, x2, x1);
}
}
bn_copy(r, x2);
}
/* ── Jacobian Point Operations ───────────────────────────────────────────── */
typedef struct {
bignum256 x;
bignum256 y;
bignum256 z;
bool infinity;
} P256_Point;
static void point_set_infinity(P256_Point *p)
{
memset(p, 0, sizeof(P256_Point));
p->infinity = true;
}
static void point_to_affine(const P256_Point *p, bignum256 x_out, bignum256 y_out)
{
/* LCOV_EXCL_START: Point at infinity / zero guard */
if (p->infinity || bn_is_zero(p->z)) {
memset(x_out, 0, sizeof(bignum256));
memset(y_out, 0, sizeof(bignum256));
return;
}
/* LCOV_EXCL_STOP */
if (bn_cmp(p->z, BN_ONE) == 0) {
bn_copy(x_out, p->x);
bn_copy(y_out, p->y);
return;
}
bignum256 z_inv, z_inv2, z_inv3;
p256_mod_p_inv(z_inv, p->z);
p256_mod_p_sqr(z_inv2, z_inv);
p256_mod_p_mul(z_inv3, z_inv2, z_inv);
p256_mod_p_mul(x_out, p->x, z_inv2);
p256_mod_p_mul(y_out, p->y, z_inv3);
}
static void point_double(P256_Point *r, const P256_Point *p)
{
/* LCOV_EXCL_START: Point at infinity guard */
if (p->infinity || bn_is_zero(p->y)) {
point_set_infinity(r);
return;
}
/* LCOV_EXCL_STOP */
P256_Point out;
bignum256 s, m, t, y_sqr;
p256_mod_p_sqr(y_sqr, p->y);
/* S = 4 * X * Y^2 */
p256_mod_p_mul(s, p->x, y_sqr);
p256_mod_p_add(s, s, s);
p256_mod_p_add(s, s, s);
/* M = 3 * (X^2 - Z^4) = 3 * (X - Z^2) * (X + Z^2) (since a = -3) */
bignum256 z_sqr, delta, sum;
p256_mod_p_sqr(z_sqr, p->z);
p256_mod_p_sub(delta, p->x, z_sqr);
p256_mod_p_add(sum, p->x, z_sqr);
p256_mod_p_mul(m, delta, sum);
bignum256 m_tmp;
p256_mod_p_add(m_tmp, m, m);
p256_mod_p_add(m, m_tmp, m);
/* X' = M^2 - 2S */
p256_mod_p_sqr(out.x, m);
p256_mod_p_sub(out.x, out.x, s);
p256_mod_p_sub(out.x, out.x, s);
/* Z' = 2 * Y * Z */
p256_mod_p_mul(out.z, p->y, p->z);
p256_mod_p_add(out.z, out.z, out.z);
/* Y' = M * (S - X') - 8 * Y^4 */
p256_mod_p_sub(t, s, out.x);
p256_mod_p_mul(out.y, m, t);
bignum256 y4;
p256_mod_p_sqr(y4, y_sqr);
for (int i = 0; i < 3; i++) {
p256_mod_p_add(y4, y4, y4);
}
p256_mod_p_sub(out.y, out.y, y4);
out.infinity = false;
*r = out;
}
static void point_add_mixed(P256_Point *r, const P256_Point *p, const bignum256 qx,
const bignum256 qy)
{
bignum256 z1_sqr, u2, z1_cube, s2, h, rr;
p256_mod_p_sqr(z1_sqr, p->z);
p256_mod_p_mul(u2, qx, z1_sqr);
p256_mod_p_mul(z1_cube, z1_sqr, p->z);
p256_mod_p_mul(s2, qy, z1_cube);
p256_mod_p_sub(h, u2, p->x);
p256_mod_p_sub(rr, s2, p->y);
/* LCOV_EXCL_START: Coincident / Inverse point handling */
if (bn_is_zero(h)) {
if (bn_is_zero(rr)) {
point_double(r, p);
} else {
point_set_infinity(r);
}
return;
}
/* LCOV_EXCL_STOP */
P256_Point out;
bignum256 h2, h3, u1_h2;
p256_mod_p_sqr(h2, h);
p256_mod_p_mul(h3, h2, h);
p256_mod_p_mul(u1_h2, p->x, h2);
/* X' = R^2 - H^3 - 2 * U1 * H^2 */
p256_mod_p_sqr(out.x, rr);
p256_mod_p_sub(out.x, out.x, h3);
p256_mod_p_sub(out.x, out.x, u1_h2);
p256_mod_p_sub(out.x, out.x, u1_h2);
/* Y' = R * (U1 * H^2 - X') - S1 * H^3 */
bignum256 t, s1_h3;
p256_mod_p_sub(t, u1_h2, out.x);
p256_mod_p_mul(out.y, rr, t);
p256_mod_p_mul(s1_h3, p->y, h3);
p256_mod_p_sub(out.y, out.y, s1_h3);
/* Z' = Z1 * H */
p256_mod_p_mul(out.z, p->z, h);
out.infinity = false;
*r = out;
}
static void point_add(P256_Point *r, const P256_Point *p, const P256_Point *q)
{
if (p->infinity) {
*r = *q;
return;
}
if (q->infinity) {
*r = *p;
return;
}
bignum256 z1_sqr, z2_sqr, u1, u2, s1, s2;
p256_mod_p_sqr(z1_sqr, p->z);
p256_mod_p_sqr(z2_sqr, q->z);
p256_mod_p_mul(u1, p->x, z2_sqr);
p256_mod_p_mul(u2, q->x, z1_sqr);
bignum256 z1_cube, z2_cube;
p256_mod_p_mul(z1_cube, z1_sqr, p->z);
p256_mod_p_mul(z2_cube, z2_sqr, q->z);
p256_mod_p_mul(s1, p->y, z2_cube);
p256_mod_p_mul(s2, q->y, z1_cube);
bignum256 h, rr;
p256_mod_p_sub(h, u2, u1);
p256_mod_p_sub(rr, s2, s1);
/* LCOV_EXCL_START: Coincident / Inverse point handling */
if (bn_is_zero(h)) {
if (bn_is_zero(rr)) {
point_double(r, p);
} else {
point_set_infinity(r);
}
return;
}
/* LCOV_EXCL_STOP */
P256_Point out;
bignum256 h2, h3, u1_h2;
p256_mod_p_sqr(h2, h);
p256_mod_p_mul(h3, h2, h);
p256_mod_p_mul(u1_h2, u1, h2);
/* X' = R^2 - H^3 - 2 * U1 * H^2 */
p256_mod_p_sqr(out.x, rr);
p256_mod_p_sub(out.x, out.x, h3);
p256_mod_p_sub(out.x, out.x, u1_h2);
p256_mod_p_sub(out.x, out.x, u1_h2);
/* Y' = R * (U1 * H^2 - X') - S1 * H^3 */
bignum256 t, s1_h3;
p256_mod_p_sub(t, u1_h2, out.x);
p256_mod_p_mul(out.y, rr, t);
p256_mod_p_mul(s1_h3, s1, h3);
p256_mod_p_sub(out.y, out.y, s1_h3);
/* Z' = Z1 * Z2 * H */
bignum256 z1_z2;
p256_mod_p_mul(z1_z2, p->z, q->z);
p256_mod_p_mul(out.z, z1_z2, h);
out.infinity = false;
*r = out;
}
static void point_cmov(P256_Point *dst, const P256_Point *src, uint32_t mask)
{
for (int i = 0; i < 8; i++) {
dst->x[i] = (dst->x[i] & ~mask) | (src->x[i] & mask);
dst->y[i] = (dst->y[i] & ~mask) | (src->y[i] & mask);
dst->z[i] = (dst->z[i] & ~mask) | (src->z[i] & mask);
}
dst->infinity = (((uint32_t)dst->infinity & ~mask) | ((uint32_t)src->infinity & mask)) != 0;
}
static void point_scalar_mul_affine(P256_Point *r, const bignum256 k, const bignum256 px,
const bignum256 py)
{
point_set_infinity(r);
/* Precompute table: table[0] = Infinity, table[1] = 1*P, ..., table[15] = 15*P */
P256_Point table[16];
point_set_infinity(&table[0]);
bn_copy(table[1].x, px);
bn_copy(table[1].y, py);
memset(table[1].z, 0, sizeof(table[1].z));
table[1].z[0] = 1U;
table[1].infinity = false;
for (int i = 2; i < 16; i++) {
point_add_mixed(&table[i], &table[i - 1], px, py);
}
/* Process all 64 4-bit nibbles in constant time without secret-dependent branching */
for (int n = 63; n >= 0; n--) {
point_double(r, r);
point_double(r, r);
point_double(r, r);
point_double(r, r);
uint32_t nibble = (k[n / 8] >> ((n % 8) * 4)) & 0x0FU;
/* Constant-time select from table[0..15] based on nibble */
P256_Point term;
point_set_infinity(&term);
for (uint32_t v = 0; v < 16; v++) {
uint32_t match = (uint32_t)(nibble == v);
uint32_t mask = 0U - match;
point_cmov(&term, &table[v], mask);
}
point_add(r, r, &term);
}
}
/* ── Public API Implementation ───────────────────────────────────────────── */
bool syn_p256_is_on_curve(const uint8_t px[SYN_P256_BYTE_LEN], const uint8_t py[SYN_P256_BYTE_LEN])
{
if (px == NULL || py == NULL) {
return false;
}
bignum256 x, y;
bn_from_bytes(x, px);
bn_from_bytes(y, py);
if (bn_cmp(x, P256_P) >= 0 || bn_cmp(y, P256_P) >= 0) {
return false;
}
/* Left hand side: y^2 mod p */
bignum256 lhs;
p256_mod_p_sqr(lhs, y);
/* Right hand side: x^3 - 3x + b mod p */
bignum256 rhs, x3, three_x;
p256_mod_p_sqr(x3, x);
p256_mod_p_mul(x3, x3, x);
p256_mod_p_add(three_x, x, x);
p256_mod_p_add(three_x, three_x, x);
p256_mod_p_sub(rhs, x3, three_x);
p256_mod_p_add(rhs, rhs, P256_B);
return (bn_cmp(lhs, rhs) == 0);
}
bool syn_p256_base_mul(const uint8_t scalar[SYN_P256_BYTE_LEN], uint8_t pub_x[SYN_P256_BYTE_LEN],
uint8_t pub_y[SYN_P256_BYTE_LEN])
{
if (scalar == NULL || pub_x == NULL || pub_y == NULL) {
return false;
}
bignum256 k;
bn_from_bytes(k, scalar);
if (bn_is_zero(k) || bn_cmp(k, P256_N) >= 0) {
return false;
}
P256_Point res;
point_scalar_mul_affine(&res, k, P256_GX, P256_GY);
bignum256 rx, ry;
point_to_affine(&res, rx, ry);
bn_to_bytes(pub_x, rx);
bn_to_bytes(pub_y, ry);
return true;
}
bool syn_p256_point_mul(const uint8_t scalar[SYN_P256_BYTE_LEN],
const uint8_t px[SYN_P256_BYTE_LEN], const uint8_t py[SYN_P256_BYTE_LEN],
uint8_t rx[SYN_P256_BYTE_LEN], uint8_t ry[SYN_P256_BYTE_LEN])
{
if (scalar == NULL || px == NULL || py == NULL || rx == NULL || ry == NULL) {
return false;
}
if (!syn_p256_is_on_curve(px, py)) {
return false;
}
bignum256 k;
bn_from_bytes(k, scalar);
if (bn_is_zero(k) || bn_cmp(k, P256_N) >= 0) {
return false;
}
bignum256 ax, ay;
bn_from_bytes(ax, px);
bn_from_bytes(ay, py);
P256_Point res;
point_scalar_mul_affine(&res, k, ax, ay);
bignum256 out_x, out_y;
point_to_affine(&res, out_x, out_y);
bn_to_bytes(rx, out_x);
bn_to_bytes(ry, out_y);
return true;
}
bool syn_p256_ecdh(const uint8_t priv_key[SYN_P256_BYTE_LEN],
const uint8_t peer_pub_x[SYN_P256_BYTE_LEN],
const uint8_t peer_pub_y[SYN_P256_BYTE_LEN],
uint8_t shared_secret[SYN_P256_BYTE_LEN])
{
uint8_t dummy_y[SYN_P256_BYTE_LEN];
return syn_p256_point_mul(priv_key, peer_pub_x, peer_pub_y, shared_secret, dummy_y);
}
bool syn_p256_sign_ecdsa(const uint8_t priv_key[SYN_P256_BYTE_LEN],
const uint8_t nonce_k[SYN_P256_BYTE_LEN],
const uint8_t hash[SYN_P256_BYTE_LEN], uint8_t r_out[SYN_P256_BYTE_LEN],
uint8_t s_out[SYN_P256_BYTE_LEN])
{
if (priv_key == NULL || nonce_k == NULL || hash == NULL || r_out == NULL || s_out == NULL) {
return false;
}
/* 1. R = k * G */
uint8_t rx[SYN_P256_BYTE_LEN], ry[SYN_P256_BYTE_LEN];
if (!syn_p256_base_mul(nonce_k, rx, ry)) {
return false;
}
bignum256 bn_r;
bn_from_bytes(bn_r, rx);
/* 2. s = k^-1 * (e + d * r) mod n */
bignum256 k, k_inv, d, e, xr, num, s;
bn_from_bytes(k, nonce_k);
p256_mod_n_inv(k_inv, k);
bn_from_bytes(d, priv_key);
bn_from_bytes(e, hash);
while (bn_cmp(e, P256_N) >= 0) {
bn_sub_raw(e, e, P256_N);
}
p256_mod_n_mul(xr, d, bn_r);
/* num = e + d*r mod n */
uint32_t carry = bn_add_raw(num, e, xr);
if (carry || bn_cmp(num, P256_N) >= 0) {
bn_sub_raw(num, num, P256_N);
}
p256_mod_n_mul(s, k_inv, num);
if (bn_is_zero(s)) {
return false;
}
bn_to_bytes(r_out, bn_r);
bn_to_bytes(s_out, s);
return true;
}
bool syn_p256_sign_ecdsa_deterministic(const uint8_t priv_key[SYN_P256_BYTE_LEN],
const uint8_t hash[SYN_P256_BYTE_LEN],
uint8_t r_out[SYN_P256_BYTE_LEN],
uint8_t s_out[SYN_P256_BYTE_LEN])
{
#if !defined(SYN_USE_HMAC_DRBG) || SYN_USE_HMAC_DRBG
if (priv_key == NULL || hash == NULL || r_out == NULL || s_out == NULL) {
return false;
}
SYN_HMAC_DRBG drbg;
(void)syn_hmac_drbg_init(&drbg, priv_key, SYN_P256_BYTE_LEN, hash, SYN_P256_BYTE_LEN, NULL, 0U);
uint8_t nonce_k[SYN_P256_BYTE_LEN];
bool success = false;
for (uint32_t attempts = 0U; attempts < 100U; attempts++) {
(void)syn_hmac_drbg_generate(&drbg, nonce_k, sizeof(nonce_k), NULL, 0U);
if (syn_p256_sign_ecdsa(priv_key, nonce_k, hash, r_out, s_out)) {
success = true;
break;
}
}
syn_hmac_drbg_wipe(&drbg);
volatile uint8_t *vp = (volatile uint8_t *)nonce_k;
for (size_t i = 0U; i < sizeof(nonce_k); i++) {
vp[i] = 0U;
}
return success;
#else
(void)priv_key;
(void)hash;
(void)r_out;
(void)s_out;
return false;
#endif
}
bool syn_p256_verify_ecdsa(const uint8_t hash[SYN_P256_BYTE_LEN],
const uint8_t r[SYN_P256_BYTE_LEN], const uint8_t s[SYN_P256_BYTE_LEN],
const uint8_t pub_x[SYN_P256_BYTE_LEN],
const uint8_t pub_y[SYN_P256_BYTE_LEN])
{
if (hash == NULL || r == NULL || s == NULL || pub_x == NULL || pub_y == NULL) {
return false;
}
if (!syn_p256_is_on_curve(pub_x, pub_y)) {
return false;
}
bignum256 bn_r, bn_s;
bn_from_bytes(bn_r, r);
bn_from_bytes(bn_s, s);
/* FIPS 186-4: Verify that r and s are in [1, n-1] */
if (bn_is_zero(bn_r) || bn_cmp(bn_r, P256_N) >= 0 || bn_is_zero(bn_s) ||
bn_cmp(bn_s, P256_N) >= 0) {
return false;
}
bignum256 e;
bn_from_bytes(e, hash);
while (bn_cmp(e, P256_N) >= 0) {
bn_sub_raw(e, e, P256_N);
}
/* w = s^-1 mod n */
bignum256 w;
p256_mod_n_inv(w, bn_s);
/* u1 = e * w mod n */
bignum256 u1;
p256_mod_n_mul(u1, e, w);
/* u2 = r * w mod n */
bignum256 u2;
p256_mod_n_mul(u2, bn_r, w);
/* Compute R = u1 * G + u2 * Q */
bignum256 qx, qy;
bn_from_bytes(qx, pub_x);
bn_from_bytes(qy, pub_y);
P256_Point p1, p2, res_pt;
point_scalar_mul_affine(&p1, u1, P256_GX, P256_GY);
point_scalar_mul_affine(&p2, u2, qx, qy);
point_add(&res_pt, &p1, &p2);
if (res_pt.infinity) {
return false;
}
bignum256 rx, ry;
point_to_affine(&res_pt, rx, ry);
return (bn_cmp(rx, bn_r) == 0);
}