From 1ff04d10c6ddf891d36671c976a1a9191242d25b Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 26 May 2025 10:28:27 +0200 Subject: [PATCH] feat(crypto): Add ECDSA private key masking functions. --- crypto/ecdsa.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++ crypto/ecdsa.h | 22 +++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c index a02d4f78ac..8c0133788b 100644 --- a/crypto/ecdsa.c +++ b/crypto/ecdsa.c @@ -1377,3 +1377,84 @@ ecdsa_tweak_pubkey_result ecdsa_tweak_pubkey(const ecdsa_curve *curve, #endif return tc_ecdsa_tweak_pubkey(curve, pub_key, tweak, tweaked_pub_key); } + +int ecdsa_mask_scalar(const ecdsa_curve *curve, + const uint8_t masking_key[ECDSA_PRIVATE_KEY_SIZE], + const uint8_t scalar[ECDSA_PRIVATE_KEY_SIZE], + uint8_t masked_scalar[ECDSA_PRIVATE_KEY_SIZE]) { + bignum256 k = {0}; + bn_read_be(masking_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid masking key. + memzero(&k, sizeof(k)); + return 1; + } + + bignum256 s = {0}; + bn_read_be(scalar, &s); + bn_multiply(&k, &s, &curve->order); // s = s * k + bn_mod(&s, &curve->order); + bn_write_be(&s, masked_scalar); + memzero(&k, sizeof(k)); + memzero(&s, sizeof(s)); + return 0; +} + +int ecdsa_unmask_scalar(const ecdsa_curve *curve, + const uint8_t masking_key[ECDSA_PRIVATE_KEY_SIZE], + const uint8_t masked_scalar[ECDSA_PRIVATE_KEY_SIZE], + uint8_t scalar[ECDSA_PRIVATE_KEY_SIZE]) { + bignum256 k = {0}; + bn_read_be(masking_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid masking key. + memzero(&k, sizeof(k)); + return 1; + } + + bignum256 s = {0}; + bn_read_be(masked_scalar, &s); + bn_inverse(&k, &curve->order); // k = k^-1 + bn_multiply(&k, &s, &curve->order); // s = s * k + bn_mod(&s, &curve->order); + bn_write_be(&s, scalar); + memzero(&k, sizeof(k)); + memzero(&s, sizeof(s)); + return 0; +} + +// masked_pub_key may be compressed or uncompressed +int ecdsa_unmask_public_key(const ecdsa_curve *curve, + const uint8_t masking_key[ECDSA_PRIVATE_KEY_SIZE], + const uint8_t *masked_pub_key, + uint8_t pub_key[ECDSA_PUBLIC_KEY_SIZE]) { + int ret = 0; + + curve_point point = {0}; + if (!ecdsa_read_pubkey(curve, masked_pub_key, &point)) { + // Invalid public key. + ret = 1; + goto cleanup; + } + + bignum256 k = {0}; + bn_read_be(masking_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid masking key. + ret = 2; + goto cleanup; + } + + bn_inverse(&k, &curve->order); + bn_mod(&k, &curve->order); + point_multiply(curve, &k, &point, &point); + + pub_key[0] = 0x04; + bn_write_be(&point.x, pub_key + 1); + bn_write_be(&point.y, pub_key + 33); + +cleanup: + memzero(&point, sizeof(point)); + memzero(&k, sizeof(k)); + return ret; +} diff --git a/crypto/ecdsa.h b/crypto/ecdsa.h index 5f042238df..f3d7698f65 100644 --- a/crypto/ecdsa.h +++ b/crypto/ecdsa.h @@ -61,7 +61,15 @@ typedef struct { // (4 + 32 + 1 + 4 [checksum]) * 8 / log2(58) plus NUL. #define MAX_WIF_SIZE (57) -#define ECDSA_PRIVATE_KEY_SIZE 32 +// Maximum length of a DER-encoded secp256k1 or secp256p1 signature. +#define MAX_DER_SIGNATURE_SIZE 72 + +#define ECDSA_SCALAR_SIZE 32 +#define ECDSA_COORDINATE_SIZE 32 +#define ECDSA_PRIVATE_KEY_SIZE ECDSA_SCALAR_SIZE +#define ECDSA_PUBLIC_KEY_SIZE (1 + 2 * ECDSA_COORDINATE_SIZE) +#define ECDSA_PUBLIC_KEY_COMPRESSED_SIZE (1 + ECDSA_COORDINATE_SIZE) +#define ECDSA_RAW_SIGNATURE_SIZE (2 * ECDSA_SCALAR_SIZE) void point_copy(const curve_point *cp1, curve_point *cp2); void point_add(const ecdsa_curve *curve, const curve_point *cp1, @@ -126,6 +134,18 @@ int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, int recid); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); int ecdsa_sig_from_der(const uint8_t *der, size_t der_len, uint8_t sig[64]); +int ecdsa_mask_scalar(const ecdsa_curve *curve, + const uint8_t masking_key[ECDSA_PRIVATE_KEY_SIZE], + const uint8_t scalar[ECDSA_SCALAR_SIZE], + uint8_t masked_scalar[ECDSA_SCALAR_SIZE]); +int ecdsa_unmask_scalar(const ecdsa_curve *curve, + const uint8_t masking_key[ECDSA_PRIVATE_KEY_SIZE], + const uint8_t masked_scalar[ECDSA_SCALAR_SIZE], + uint8_t scalar[ECDSA_SCALAR_SIZE]); +int ecdsa_unmask_public_key(const ecdsa_curve *curve, + const uint8_t masking_key[ECDSA_PRIVATE_KEY_SIZE], + const uint8_t *masked_pub_key, + uint8_t pub_key[ECDSA_PUBLIC_KEY_SIZE]); typedef enum { ECDSA_TWEAK_PUBKEY_SUCCESS = 0,