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

libsecp256k1 bindings: also use secp256k1 for point addition #1621

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

cculianu
Copy link
Collaborator

I saw this commit recently in Electrum: 65d896b

It was an easy port, but I have no idea if this helps or what. Is it worth doing? @markblundeberg help!

Note I ported it over by copy-pasting the code and adapting it without really understanding. I am weak at ECC crypto operations, sadly. I could use some help here.

All tox tests pass.. so that's a good sign.. I think. EC also runs and signs and verifies sigs ok both with and without schnorr.

No idea what I am doing though. :)

Should we merge this commit? Is it worth it? Help!

@cculianu cculianu added Do Not Merge (Yet!) Pull requests that we intend to merge in the future but that should not yet be merged. performance / optimization Issues related to speeding up the performance of the app labels Sep 16, 2019
@cculianu cculianu self-assigned this Sep 16, 2019
@cculianu
Copy link
Collaborator Author

Also Mark if you do end up helping here -- help me write tests for this? Or are the tests we already have sufficient?

(I couldn't easily port over the Electrum tests as they massively refactored bitcoin.py and so their tests wouldn't work for us unless somebody who understood crypto adapted them to our codebase a little bit...).

@markblundeberg
Copy link
Collaborator

markblundeberg commented Sep 17, 2019

Yeah this is a decent idea. Point addition isn't the slowest operation in EC math but it will definitely help if it's accelerated. I expect this would get used in the BIP32 key derivations.

The code looks exactly right too, no problems there. :) (If it runs, then it seems to be right!)

@cculianu
Copy link
Collaborator Author

cculianu commented Sep 17, 2019

Note that in the diff I modified the signature for secp256k1_ec_pubkey_combine on argument 3 to take instead of a POINTER(c_void_p) it now takes c_void_p.

This change affects your code here in schnorr.py:

res = seclib.secp256k1_ec_pubkey_combine(ctx, Rnew_buf, publist, 3)

The reason for my changing it to c_void_p is because the Electrum guys, in their commit, gave this function's arg their own signature POINTER(POINTER(c_char_p)), and they use it as such when calling it in add. c_void_p was the only type that basically allowed both codepaths to work (your schnorr code in schnorr.py and the stuff in ecc_fast.py) .

My reading of this situation is that it would work 100%. Can you sanity check me on that? :)

@markblundeberg
Copy link
Collaborator

Hmm the correct argument type should void **arg or perhaps char **arg, so that seems like too many pointers in their call signature (which I would read as char ***arg). Indeed just void *arg as you've done would be the most general approach and I can't see why ctypes wouldn't like it. 👍

@markblundeberg
Copy link
Collaborator

markblundeberg commented Sep 17, 2019

Hmm yeah actually those cast(pubkey1, POINTER(c_char_p)) in this commit should really be cast(pubkey1, c_char_p), and the line ptr_to_array_of_pubkey_ptrs = (POINTER(c_char_p) * 2)... should be array_of_pubkey_ptrs = (c_char_p * 2)... ! Man, casts let you get away with anything...

@markblundeberg
Copy link
Collaborator

For reference the C call signature:

SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
    const secp256k1_context* ctx,
    secp256k1_pubkey *out,
    const secp256k1_pubkey * const * ins,
    size_t n
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

where secp256k1_pubkey is a 64-byte struct.

@cculianu
Copy link
Collaborator Author

Hmm yeah actually those cast(pubkey1, POINTER(c_char_p)) in this commit should really be cast(pubkey1, c_char_p), and the line ptr_to_array_of_pubkey_ptrs = (POINTER(c_char_p) * 2)... should be array_of_pubkey_ptrs = (c_char_p * 2)... ! Man, casts let you get away with anything...

This makes my brain melt. I know C really well. I know Python well as well. But thinking about how ctypes tries to think about how C thinks about things makes my brain melt. You clearly are more of a ctypes master than me.

I'll leave it as-is for fear of touching it. After this is merged -- feel free to correct what they did.

I am pushing a commit now that adds some tests for this (I had to import a whole bunch of code from Electrum to do it -- but it's a good thing: they refactored that EC_KEY class in bitcoin.py into two more useful classes -- and having those classes going forward is a good thing.. I think).

Now bitcoin.py is full of so much redundant code.. ha!

This involved pulling in 2 classes refactored from EC_KEY: EC_Pubkey
and EC_Privkey.  They work a lot like the original EC_KEY class. Note
that now all 3 classes are present in the codebase (perhaps some day we
will transition to using the new classes).
@cculianu
Copy link
Collaborator Author

cculianu commented Sep 17, 2019

@markblundeberg Can you review this again? I pushed some changes that adds some stuff from Electrum (I actually wanted their tests for these operations -- but I ended up pulling in a bunch of stuff into bitcoin.py).

Can you review the changes in terms of relevancy? I am pretty sure the code is correct and the port is ok (although if your eyeballs catch something, that's good!).

All tests pass.

In particular I don't know what that signature65 business is and a bunch of utility functions added to bitcoin.py for this change also are enigmatic to me (there is some der_low_S stuff idk .. you know more than me!!).

Can you tell me if any of them need to be deleted? Maybe they are BTC-only things?

Also I realize bitcoin.py only grows more confusing now.. but my hope is we can slowly transition over to the Electrum refactor (they broke up the EC_KEY class into 2 more useful subclasses).

Thanks!

Copy link
Collaborator

@markblundeberg markblundeberg left a comment

Choose a reason for hiding this comment

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

I looked over the code and it seems generally reasonable, though for now it's just bloating the file I guess. :-)

Signature65 is the thing used in signed messages (65 byte signatures that allow unambiguous pubkey recovery).

lib/bitcoin.py Outdated Show resolved Hide resolved
lib/bitcoin.py Outdated Show resolved Hide resolved
SomberNight added a commit to spesmilo/electrum that referenced this pull request Sep 17, 2019
@markblundeberg
Copy link
Collaborator

@SomberNight well that's one way to answer the question. Thanks :-)

@cculianu
Copy link
Collaborator Author

cculianu commented Sep 18, 2019

Ha ha — that works, @SomberNight.

Thanks Mark a ton for your review. I will update this PR soon to reflect discussion and ghost43’s changes.

I am thinking about the bloat issue — I may try and simplify the file by either re-using this code or some other approach.

@cculianu cculianu changed the title libseck256k1 bindings: also use secp256k1 for point addition libsecp256k1 bindings: also use secp256k1 for point addition Sep 18, 2019
@cculianu
Copy link
Collaborator Author

@markblundeberg Ok, I incorporated your changes but I want to let it sit some more. I am travelling but maybe I can find time to refactor what we have in bitcoin.py like I said to either use this code or .. something. Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Do Not Merge (Yet!) Pull requests that we intend to merge in the future but that should not yet be merged. performance / optimization Issues related to speeding up the performance of the app
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants