-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[API CHANGE] Introduce pubkey and signature types #282
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
Conversation
An alternative to this is having a secp256k1_pubkey_t type that maintains the compressedness, and is just a serialized pubkey, but in a constant-size buffer. This has as advantages that it does not add any significant performance overhead, and does not risk extra problems when uninitialized secp256k1_pubkey_t's are passed in (though that would still be a risky bug for other reasons), but it also would not avoid the compress/decompress/verify API calls, not offer any performance advantages for repeated pubkey use, and be a bit unintuitive for having parsing of an invalid pubkey potentially succeed. |
@afk11 Any comments here? This significantly changes the way public keys are handled, and removes the need for the secp256k1_ec_pubkey_compress function which you added. |
Added extra documentation. |
secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); | ||
} | ||
|
||
int secp256k1_ec_pubkey_parse(const secp256k1_context_t* ctx, secp256k1_pubkey_t* pubkey, const unsigned char *input, int inputlen) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The indentation in this function is different from all the others.
It looks like
|
c2f173c
to
e71b1f4
Compare
@DavidEGrayson I thought I already answered, but can't see the post now @gmaxwell would be right to point that out, but then we should consistently change it throughout the codebase once, not introduce multiple coding standards. |
I've changed the implementation of secp256k1_pubkey_load/save now, using secp256k1_ge_storage where possible... and the result is around 0.15% faster now than before the pubkey_t introduction. |
I extended the scope of this patch, and introduced a secp256k1_ecdsa_signature_t for ECDSA signatures. |
* 0: incorrect signature | ||
* -1: invalid public key | ||
* -2: invalid signature | ||
* 0: incorrect or unparseable signature | ||
* In: ctx: a secp256k1 context object, initialized for verification. | ||
* msg32: the 32-byte message hash being verified (cannot be NULL) | ||
* sig: the signature being verified (cannot be NULL) | ||
* siglen: the length of the signature |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update comment for removal of siglen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
/** Compute the public key for a secret key. | ||
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL) | ||
* compressed: whether the computed public key should be compressed | ||
* seckey: pointer to a 32-byte private key (cannot be NULL) | ||
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) | ||
* Out: pubkey: pointer to the created public key (cannot be NULL) | ||
* area to store the public key (cannot be NULL) | ||
* pubkeylen: pointer to int that will be updated to contains the pubkey's | ||
* length (cannot be NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove second line under pubkey
, entry for pubkeylen
, entry for compressed
in this comment
@@ -54,11 +54,152 @@ void secp256k1_context_destroy(secp256k1_context_t* ctx) { | |||
free(ctx); | |||
} | |||
|
|||
int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { | |||
static void secp256k1_pubkey_load(secp256k1_ge_t* ge, const secp256k1_pubkey_t* pubkey) { | |||
if (sizeof(secp256k1_ge_storage_t) == 64) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under what circumstances is this not 64? You are depending on its exact format in the case that it is, so I'm confused about what you think could change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Who knows what a compiler can do with integer sizes and alignments. Maybe we want to add debug fields at some point, when VERIFY is enabled.
It's also not relying on its exact representation, only that it can be memcpy'd to and from a 64-byte array, which is faster than going through the b32 representation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, this probably requires some comments in the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I realized that you weren't depending on the representation down below when I saw you were doing the same thing with scalar_t. I think you should add a comment saying that (assuming the data fits) the API only allows the content of pubkey->data
to be a memcpy of a preexisting secp256k1_ge_storage_t
, so this is fine.
Added several comments about the representation of pubkey and signature types. |
I find it a little confusing to have two signature types, especially ones that are so similarly named. It's hard to remember which one is the public one and which is the internal. The internal one, I propose:
This would avoid having separate types and remove some double conversions (like calling I don't feel super strongly about this, it's up to you. |
I think that would be a layering violation. the toplevel module defines a data type for external use, and depends on the internal code for operations on it. The lowlevel module would end up depending on the toplevel module if it needed to be passed in the toplevel data type, resulting in a weak circular dependency. Furthermore, both datatypes have a different use case: one is obscurity and consistency (at least wrt its size), the other is efficiency. Moving the load and save to ecdsa feels wrong, as it makes the ecdsa module depend on external API peculiarities. One option is to drop the internal type, and just operate on scalar_t's inside ecdsa. The other is perhaps to rename the internal types to something more obvious (secp256k1_ecdsa_signature_internal_t ?), and maybe move the recid inside it. |
That's a good point. Between the two options you listed I'd prefer to just operate on |
@sipa concept ACK on this, the performance boost should affect me also since presently I have to serialize my PublicKey types whenever calling |
@apoelstra Added a commit which removes the internal secp256k1_ecdsa_sig_t. |
Thanks, I'm much happier with this. |
ACK |
This introduces a new data type secp256k1_pubkey_t, which is an abstract parsed public key, convertible to/from serialized variable-size public keys.
This avoids all API problems resulting from needing to pass pubkey sizes and pointers to pubkey sizes anywhere public keys are needed.
Advantages:
Disadvantages: