Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add secp256k1_ec_pubkey_cmp method #850

Merged
merged 2 commits into from
May 13, 2021

Conversation

apoelstra
Copy link
Contributor

No description provided.

@real-or-random
Copy link
Contributor

Concept ACK

I would be easier to simply have a compare function which returns <0, ==0, or >0. Not sure which API is better. Did you think about this possibility?

Implementation is then just a call to memcmp.

@apoelstra
Copy link
Contributor Author

I did think about this possibility, and if secp256k1_memcmp_var exposed this API then I probably would've just done a thin wrapper around that. But given that I had to do some extra work anyway, I felt that this API was more consistent than the libc one.

@apoelstra
Copy link
Contributor Author

I don't feel strongly about it, I'm happy to implement the memcmp API if that's what people want.

@real-or-random
Copy link
Contributor

if secp256k1_memcmp_var exposed this API

Oh it does.

@elichai
Copy link
Contributor

elichai commented Nov 23, 2020

I also think that exposing a memcmp-like single API is somewhat nicer (but this is also ok)

@apoelstra
Copy link
Contributor Author

Oh, neat, I misread the memcmp_var code. Ok, I'll just expose a single function then.

@apoelstra apoelstra changed the title add secp256k1_ec_pubkey_equal and secp256k1_ec_pubkey_leq methods add secp256k1_ec_pubkey_cmp method Nov 23, 2020
@apoelstra
Copy link
Contributor Author

Replaced with a single _cmp method.

@jonasnick
Copy link
Contributor

@apoelstra may I ask what you intend to use this for?

@apoelstra
Copy link
Contributor Author

@jonasnick it's needed for the sortedmulti descriptor and to use publickeys as keys in ordered sets (e.g. for PSBTs which should round-trip deterministically)

@sipa
Copy link
Contributor

sipa commented Nov 23, 2020

@apoelstra The sortedmulti descriptor sorts lexicographically by the pubkey serialization, which means that uncompressed keys will sort after compressed ones (BIP67 doesn't support uncompressed keys whatsoever, but sortedmulti extends the definition to all keys).

@apoelstra
Copy link
Contributor Author

sigh, ok, I guess we cannot support comparisons in this library

@real-or-random
Copy link
Contributor

sigh, ok, I guess we cannot support comparisons in this library

I'm not sure that sortedmulti stops us from exporting a comparison function that is compatible with compressed keys. This can be helpful for new applications which won't use the uncompressed serialization anyway, e.g., sorting keys in multisig. Moreover, orderings are in general helpful for some data structures, e.g., if you want to binary searches in a large set of keys.

A sad thing is that this ordering won't be compatible with the lexicographical ordering on x-only keys...

@apoelstra
Copy link
Contributor Author

Ironically, sorting by uncompressed encoding would be compatible with x-only keys.

@elichai
Copy link
Contributor

elichai commented Nov 30, 2020

actually, what about adding these to xonly_pubkey too?

@apoelstra
Copy link
Contributor Author

sure

@real-or-random
Copy link
Contributor

A week ago I argued that this is helpful but I'm not so sure anymore.

If these functions are just serializing and memcmp'ing, they're not essential, so we could leave this to the user.

Pro: The user has to make a deliberate choice on an ordering, which may be good a thing here as things are complicated.
Con: We may end up with many different orderings in the wild.

@apoelstra
Copy link
Contributor Author

As a user I find it extremely irritating to need to serialize in order to compare keys for equality, so I think we should expose that....and then it's only epsilon more work to expose a total order.

@real-or-random
Copy link
Contributor

real-or-random commented Dec 3, 2020

As a user I find it extremely irritating to need to serialize in order to compare keys for equality, so I think we should expose that....

Agreed, equality is a no-brainer.

and then it's only epsilon more work to expose a total order.

Indeed. But I think in common cases when you want an order, you need it because you're going to serialize anyway, so the user probably won't be extremely irritated in that case.

@sipa @jonasnick @elichai What do you think? Should we expose a total order? (And if yes, which one? :P)

@sipa
Copy link
Contributor

sipa commented Dec 18, 2020

@apoelstra Would it be useful to just have an equality test function? That avoids the rathole of trying to predict what ordering the user needs.

@apoelstra
Copy link
Contributor Author

Is there any actual opposition to merging this? Or just uncertainty about what ordering hypothetical users might want?

We could definitely use the xonly stuff (which is unambiguous) downstream now for MuSig so it would be cool to merge this.

@apoelstra
Copy link
Contributor Author

If it would be easier, I can remove the legacy stuff and only add the xonly comparison?

@sipa
Copy link
Contributor

sipa commented Mar 29, 2021

utACK 48ac53b

This ordering is sufficiently natural that we can just merge it, I think.


VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pk1 != NULL);
ARG_CHECK(pk2 != NULL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ARG_CHECK returns 0 for failure here, which isn't an appropriate return condition for a cmp function. You can use ARG_CHECK_NO_RETURN, but you won't have a post-condition that the pointer is non-NULL, and you will still need to handle that case. This can be done by zeroing the out1 and out2 buffers and only calling secp256k1_xonly_pubkey_serialize when pk is non NULL.

ARG_CHECK(pk1 != NULL);
ARG_CHECK(pk2 != NULL);

CHECK(secp256k1_xonly_pubkey_serialize(ctx, out1, pk1));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why these are CHECK instead of VERIFY_CHECK.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CHECK and VERIFY_CHECK are both not right here because they abort if the check fails, making it impossible to test the function with illegal keys. I'd suggest to remove the CHECK and instead make sure that out1 is all 0 if pubkey_serialize fails.

@jonasnick
Copy link
Contributor

@apoelstra I wrote a fixup for this PR that makes the cmp functions define a consistent order even when dealing with NULL or illegal pubkeys by treating them as 0. It's used in libsecp-zkp's musig aggregation PR to add a sorting function for public keys.

@real-or-random
Copy link
Contributor

Oh CI fails again because this PR is too old and we switched to Cirrus CI.

@apoelstra Can you quickly rebase this? This should solve it.

Copy link
Contributor

@jonasnick jonasnick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK mod nit

include/secp256k1.h Outdated Show resolved Hide resolved
@bitcoin-core bitcoin-core deleted a comment from ramsemune Apr 22, 2021
Comment on lines +379 to +381
* Args: ctx: a secp256k1 context object.
* In: pubkey1: first public key to compare
* pubkey2: second public key to compare
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add "(cannot be NULL)" here (and nit: full stops), same below

Suggested change
* Args: ctx: a secp256k1 context object.
* In: pubkey1: first public key to compare
* pubkey2: second public key to compare
* Args: ctx: a secp256k1 context object (cannot be NULL).
* In: pubkey1: first public key to compare (cannot be NULL).
* pubkey2: second public key to compare (cannot be NULL).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is implicit as per the discussion in #783 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, yes. Strictly speaking, we first need to add the line Unless explicitly stated all pointer arguments must not be NULL. in the header file (as done in #783) because currently we promise that the illegal_callback is only called for violations explicitly mentioned in the header.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added that line in #926

include/secp256k1.h Outdated Show resolved Hide resolved
src/secp256k1.c Outdated Show resolved Hide resolved
@jonasnick
Copy link
Contributor

Tim and I noticed that the comparison functions can be simplified because pubkey_serialize already ARG_CHECKs pk != NULL. We can rely on that because we check it in the API tests. I pushed fixups that also add comments on the rationale and fix the nits mentioned in this thread. @apoelstra if you think that makes sense, feel free to cherry-pick and squash.
https://github.com/jonasnick/secp256k1/tree/2020-11--pubkey-comparisons-jn

@real-or-random
Copy link
Contributor

@jonasnick Your branch looks good to me, I suggest we merge that one.

@apoelstra apoelstra force-pushed the 2020-11--pubkey-comparisons branch from f86f026 to 6eceec6 Compare May 6, 2021 18:52
@apoelstra
Copy link
Contributor Author

Squashed in jonas' commits.

Copy link
Contributor

@jonasnick jonasnick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 6eceec6

@elichai
Copy link
Contributor

elichai commented May 7, 2021

Code review ACK 6eceec6

Copy link
Contributor

@real-or-random real-or-random left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 6eceec6

* 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-null comments here too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary if #926 gets merged (needs more ACKs :] )

@jonasnick jonasnick merged commit 202a030 into bitcoin-core:master May 13, 2021
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Oct 22, 2024
…_cmp`

Summary:
Allows comparing `secp256k1_pubkey` and `secp256k1_xonly_pubkey` respectively, to establish an order between them.

This is a backport of [[ bitcoin-core/secp256k1#850 | secp256k1#850 ]] and [[ bitcoin-core/secp256k1#926 | secp256k1#926 ]].

We need this for porting `rust-secp256k1` to the secp256k1 library of this repo.

Test Plan: `ninja check-secp256k1`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D16957
Fabcien pushed a commit to Bitcoin-ABC/secp256k1 that referenced this pull request Oct 23, 2024
…_cmp`

Summary:
Allows comparing `secp256k1_pubkey` and `secp256k1_xonly_pubkey` respectively, to establish an order between them.

This is a backport of [[ bitcoin-core/secp256k1#850 | secp256k1#850 ]] and [[ bitcoin-core/secp256k1#926 | secp256k1#926 ]].

We need this for porting `rust-secp256k1` to the secp256k1 library of this repo.

Test Plan: `ninja check-secp256k1`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D16957
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants