extrakeys: add secp256k1_pubkey_cmp

This commit is contained in:
Jonas Nick 2023-01-13 19:41:57 +00:00
parent 73d5b6654d
commit 98242fcdd9
No known key found for this signature in database
GPG Key ID: 4861DBF262123605
3 changed files with 82 additions and 0 deletions

View File

@ -256,6 +256,21 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compare two public keys using lexicographic order
*
* Returns: <0 if the first public key is less than the second
* >0 if the first public key is greater than the second
* 0 if the two public keys are equal
* Args: ctx: a secp256k1 context object.
* In: pubkey1: first public key to compare
* pubkey2: second public key to compare
*/
SECP256K1_API int secp256k1_pubkey_cmp(
const secp256k1_context* ctx,
const secp256k1_pubkey* pk1,
const secp256k1_pubkey* pk2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
#ifdef __cplusplus
}
#endif

View File

@ -304,4 +304,31 @@ int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_ke
return ret;
}
int secp256k1_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pk0, const secp256k1_pubkey* pk1) {
unsigned char out[2][33];
const secp256k1_pubkey* pk[2];
int i;
VERIFY_CHECK(ctx != NULL);
pk[0] = pk0; pk[1] = pk1;
for (i = 0; i < 2; i++) {
size_t outputlen = sizeof(out[i]);
/* If the public key is NULL or invalid, pubkey_serialize will
* call the illegal_callback and return 0. In that case we will
* serialize the key as all zeros which is less than any valid public
* key. This results in consistent comparisons even if NULL or invalid
* pubkeys are involved and prevents edge cases such as sorting
* algorithms that use this function and do not terminate as a
* result. */
if (!secp256k1_ec_pubkey_serialize(ctx, out[i], &outputlen, pk[i], SECP256K1_EC_COMPRESSED)) {
/* Note that pubkey_serialize should already set the output to
* zero in that case, but it's not guaranteed by the API, we can't
* test it and writing a VERIFY_CHECK is more complex than
* explicitly memsetting (again). */
memset(out[i], 0, sizeof(out[i]));
}
}
return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1]));
}
#endif

View File

@ -619,6 +619,45 @@ void test_hsort(void) {
}
#undef NUM
void test_pubkey_comparison(void) {
unsigned char pk1_ser[33] = {
0x02,
0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11,
0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23
};
const unsigned char pk2_ser[33] = {
0x03,
0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d,
0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c
};
secp256k1_pubkey pk1;
secp256k1_pubkey pk2;
int ecount = 0;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
CHECK(secp256k1_ec_pubkey_parse(none, &pk1, pk1_ser, sizeof(pk1_ser)) == 1);
CHECK(secp256k1_ec_pubkey_parse(none, &pk2, pk2_ser, sizeof(pk2_ser)) == 1);
CHECK(secp256k1_pubkey_cmp(none, NULL, &pk2) < 0);
CHECK(ecount == 1);
CHECK(secp256k1_pubkey_cmp(none, &pk1, NULL) > 0);
CHECK(ecount == 2);
CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk2) < 0);
CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk1) > 0);
CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk1) == 0);
CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk2) == 0);
CHECK(ecount == 2);
memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk2) < 0);
CHECK(ecount == 3);
CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk1) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk1) > 0);
CHECK(ecount == 6);
secp256k1_context_destroy(none);
}
void test_xonly_sort_helper(secp256k1_xonly_pubkey *pk, size_t *pk_order, size_t n_pk) {
size_t i;
const secp256k1_xonly_pubkey *pk_test[5];
@ -740,6 +779,7 @@ void run_extrakeys_tests(void) {
test_hsort();
test_xonly_sort_api();
test_xonly_sort();
test_pubkey_comparison();
}
#endif