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
Re-implementing public key ordering using underlying FFI functions #309
Conversation
cea9f79
to
8c741de
Compare
Not sure I understand why fuzzification destroys comparison operation in tests. Should I move |
Can you write up a benchmark for this in some context (eg inserting public keys into a BtreeMap)? I'm somewhat worried the lack of ability to inline here may hurt some common use-cases. |
8c741de
to
3f063c7
Compare
Added tests in commit 76cfe2b before the rest of commits so benchmarking with previous ordering version can be measured by checking it out. Before (with autoderived cmp):
After (with libsecp256k1 backed cmp):
So with C function it is actually faster :) |
@TheBlueMatt any ideas on this? #309 (comment) |
Huh. That sounds like a rather significant bug in LLVM or at least rustc, then, actually. As for fuzz, I think best to re-implement it as a extern C function in |
Oh, so this means that we the current derived implementation of Concept ACK then ;) But this is an API change then. |
fda53a6
to
e001be2
Compare
e001be2
to
7476c6a
Compare
7476c6a
to
84aa321
Compare
@TheBlueMatt I was finally able to make this PR to pass CI :) Pls review |
Since there is no way to access a "real" representation of the keys without going through the C API, there is no way we can get the kind of inlining behavior that Matt wants. (Ok, we could make assumptions about the internal/opaque representation of the pubkey types, which we could get away with since we vendor specific versions of the library, but this representation is not supposed to be user-visible so we should really not do this.) I am also very surprised by @dr-orlovsky benchmark results. They do not replicate for me. With auto-derive I get
and with the FFI version I get
But anyway, there is no non-FFI way to implement this so I think we are stuck. |
With @dr-orlovsky can you implement some sort of ordering for fuzzable public keys? You can even just auto-derive one. |
My understanding of the libsecp API is that it *does* guarantee that the public key is a byte array of a certain number of bytes. Given we’re not seeking any specific order, but only *some* order, I don’t see why we’re not allowed to simply memcmp? It seems that would be API guaranteed to not be defined, though the specific order may vary between versions or be random.
… On Sep 8, 2021, at 11:46, Andrew Poelstra ***@***.***> wrote:
Since there is no way to access a "real" representation of the keys without going through the C API, there is no way we can get the kind of inlining behavior that Matt wants. (Ok, we could make assumptions about the internal/opaque representation of the pubkey types, which we could get away with since we vendor specific versions of the library, but this representation is not supposed to be user-visible so we should really not do this.)
I am also very surprised by @dr-orlovsky benchmark results. They do not replicate for me. With auto-derive I get
test key::benches::bench_pk_ordering ... bench: 3,344 ns/iter (+/- 38)
and with the FFI version I get
test key::benches::bench_pk_ordering ... bench: 5,057 ns/iter (+/- 284)
But anyway, there is no non-FFI way to implement this so I think we are stuck.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
Hmm, yeah, that makes sense to me. cc @real-or-random what do you think? If we're comparing public keys from exactly the same build of libsecp, and we know that they are fixed-size byte arrays, and we don't care about the specific order, surely we can just use |
I remember we had a discussion around that on IRC, can we even assume that equal public keys have the same byte representation? because even for "some order" that should be important |
I don't understand, maybe I lack context. Why aren't we seeking any specific order? I think we do. Wouldn't it be strange to expose different order on every platform? We're doing this currently but I think it's a bug. If performance is really an issue (I can believe it is), wouldn't it be possible to offer a verbose wrapper type with a fast But assuming we think And yeah, I think @elichai is right. The secp256k1 API does nowhere state the guarantee that equal keys have an equal byte representation. Although we may extend secp256k1 to guarantee this, or simply rely on it: If you look at the implementation, those 64 bytes will (of course) hold the x-coordinate and the y-coordinate. This is not guaranteed either but if we make this assumption, then this already enough to deduce that there are no padding bytes in the FFI type (since both values are 32-byte integers), and this implies it's safe to use |
@real-or-random we cannot fix the performance issues by using wrapper types. The problem is that to get from the platform-dependent representation to any other representation, we have to go through the C layer, which makes inlining impossible. |
Hmm, why is this a bug? I don't see why a user would ever materially care, unless they're trying to be very specific, in which case you probably want to do it manually (Eg lightning cares about the order, serialized as 33 bytes, but we're not gonna get that from libsecp). |
Because it may make it hard to send sorted data structures, e.g. binary search trees, across the wire. |
Hmm, so that would be a bug for any platform-specific behavior but not for a specific ordering? I suppose we're kinda screwed either way there, though. Of course the real bug here is that rust encourages rustup so heavily instead of encouraging distro packages, where cross-language LTO is a totally reasonable thing to expect, and then we wouldn't care. This is somewhat annoying either way - for reference, rust-lightning does have a large |
What I meant is this: We can have a It's certainly not elegant but it does the job. A more elegant option would be comparators but nothing like this is in
It's simply what (I personally) would expect from an order as I expect |
We could also have a |
That's also reasonable. When you store the keys in a collection, you probably want to compare each key at least once, so you anyway want to serialize. |
If somebody implements, say, a BST which is serialized as a flat vector, then sends it across the wire to a machine with a different ordering, the receiving machine will get mysteriously incorrect behavior when trying to use the BST. I'm not sure how to parse
Yes, any platform-specific behavior would result in these sorts of bugs ... but AFAIK the pubkey ordering is the only such behavior in the library right now. |
Can we summarize somehow to which specific conclusion we have arrived on this matter, such that I can update the PR? |
I don't think we have arrived at a conclusion yet. The three proposals are:
|
Is the option "let's make ordering consistent and not produce extra types" off the table? |
I added that one to the list. |
How we can move forward with making a decision of which way to follow? |
I don't think I'm in the position to take a decision but (unsurprisingly) I still favor my own solution. @apoelstra Do you want to have a look and take a decision? |
My decision for now is to punt for the next major release (which implicitly means "don't care that |
Following up on this - we moved to a |
I think we should implement (my) slow solution, and try to document somewhere that if you need fast sorting and searching of keys then you should pre-serialize them like this. |
I think that focusing on correctness (cross-platform, stable ordering) is better for Bitcoin stuff. :) To avoid too many types, we could add a method Is there a chance to get this in the next release? From what I understand the only difference between @apoelstra and @real-or-random opinions is that @real-or-random wants to provide the unstable wrappers while @apoelstra doesn't want the burden with providing them (LMK if I misunderstood). Maybe my suggestion is an acceptable middle ground? I personally don't care which of the three options is chosen as long as the default ordering is the stable one. Regarding cross-language LTO, unless we're making it cumbersome, it should be the responsibility of the application developers to setup their environment to allow it if their code is performance-sensitive. |
Yeah, I think if this were rebased I'd be happy to take it. |
To my knowledge Maxim is busy at least until June 24. If someone has the time to rebase and open a new PR I think it'd be great. I may be able to do it in upcoming days too but not sure. |
…ctions 13af519 Make key comparison non-fuzzable (Dr Maxim Orlovsky) 7396604 Implement PublicKey ordering using FFI (Dr Maxim Orlovsky) 0faf404 Benchmark for key ordering (Dr Maxim Orlovsky) 999d165 FFI for pubkey comparison ops (Dr Maxim Orlovsky) Pull request description: Re-base #309 for @dr-orlovsky on request by @Kixunil. To do the rebase I just had to change instances of cfg_attr to use `v0_5_0` instead of `v0_4_1` e.g., ``` #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_5_0_xonly_pubkey_cmp")] ``` And drop the changes to `src/schnorrsig.rs`, all these changes are covered by the changes in `key.rs` I believe. ACKs for top commit: Kixunil: ACK 13af519 apoelstra: ACK 13af519 Tree-SHA512: 3054fcbc1707679f54466cdc91162c286394ad691e4f5c8ee18635a22b0854a4e60f1186ef3ca1532aacd8a637d0a153601ec203947e9e58dfcebf1bcb619955
Superceded by #449 |
No description provided.