-
Notifications
You must be signed in to change notification settings - Fork 44
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 crypto jets for secp256k1 operations. #34
Conversation
8804eaa
to
f76406a
Compare
@ysangkok You may want to follow this PR. We will have Schnorr jets in master when this is merged. |
072801b
to
db16b46
Compare
db16b46
to
ccd93b3
Compare
ccd93b3
to
b2fe26d
Compare
Updated to recent libsecp256k1, which includes the latest BIP-0340 schnorr signature standard. |
b2fe26d
to
5d7a997
Compare
5d7a997
to
6419a43
Compare
6419a43
to
8765456
Compare
23f0b5a
to
403e49c
Compare
403e49c
to
1790810
Compare
1790810
to
f89cc92
Compare
@apoelstra This PR is ready for your review. You need only review the C code. Please have a look at C/secp256k1/README.md first. |
71040b9
to
07bd9ae
Compare
static inline void write_gej(frameItem* dst, secp256k1_gej* r) { | ||
write_fe(dst, &r->x); | ||
write_fe(dst, &r->y); | ||
write_fe(dst, &r->z); |
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.
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.
if you grep infinity =
across the codebase and ignore all the = 0
cases, you will find a short list of places that the infinity flag might be set. Most are ok. One that jumps out at me though is secp256k1_gej_set_ge
which sets the output infintiy flag equal to the input infinity flag, but uncontditionally sets the output z
coordinate to 1.
Similar code exists in secp256k1_gej_add_zinv_var
In fact, I think are the only two offending lines, and that they should be fixed inline. In addition to breaking write_gej
, they violate the claim in your second commit (19d3074) message that "Our specification has no infinity flag, and treats the infinity flag as a cache of a z=0 test."
Given this analysis I think you can probably remove the r->infinity
check from write_ge
as well.
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.
I also checked every instance of secp256k1_fe_add
to see if they might change the coordinates of an infinite point away from zero, and none of them do. Meanwhile secp256k1_fe_mul
and secp256k1_fe_neg
cannot change a 0 value to a nonzero one and secp256k1_fe_inv_var
I assume is guarded against being passed zero.
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.
Since bitcoin-core/secp256k1@dd6c3de it does seem that the r->infinity
check is no longer needed since secp256k1_ge_set_gej_var
now explicitly calls secp256k1_ge_set_infinity
.
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.
I believe a very detailed analysis would show that secp256k1_gej_set_ge
and especially secp256k1_gej_add_zinv_var
are never called in such a way to set the infinity flag in this way.
But, for the same reason, there is very little reason not to amend the code to make the z-coordinate match the flag even in these cases. The diff will be small.
I will make that ammendment.
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.
I believe these concerns have now been addressed.
This should be ready again. |
5c8fb3b
to
bdc0ce1
Compare
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.
ACK bdc0ce1
Did not review the Haskell code; did not review the Simplicity bytecode; did not attempt to regenerate the autogenerated C code. But I did read the rest of the code (or at least used range-diff
to confirm that it was substantially similar to what I had reviewed before) and checked the encoding-infinity changes, which I believe are ok now.
cc @sanket1729 this PR changes the jet encoding, you may want to check it out.
I could give a go at reviewing the Haskell code. So far what I gather is that the Haskell code is doing C source generation for test cases. But it also looks like there are jets that are being called from the Haskell code. Is the purpose for the Haskell code to be an entire test runner for the C tests (generation, running, and eval) or am I missing the broader purpose here? |
The Haskell code has an bunch of aspects to it.
The testing code uses a "fast-evaluation" which ends up runs the C code for evaluation of any (proper!) sub-expressions matching that matches jets. The testing therefore, in a sense, operates in layers, where the testing of the field operations implies the reliability of using those field operation's C implementation for testing the group operations, and so forth. This keeps the test time manageable, because running the whole Schnorr signature verification directly in Simplicity is exhausting. Somewhat separately we have in I hope that this is a helpful guide. FWIW, review of the Haskell code is not blocking for this PR. The Haskell code is technically informative at not normative. Only the C code will form the consensus rules when incorporated into Elements or Bitcoin. Thus I may merge this PR prior to any Haskell review. That said, even post-merge reviews are helpful and appreciated if you are willing to perform them. P.S. You may stumble over |
bdc0ce1
to
c84e74e
Compare
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.
I need more time to review this. The reasoning about infinity is confusing
|
||
unsigned char buf[64]; | ||
secp256k1_xonly_pubkey pubkey; | ||
unsigned char msg[32]; |
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.
If and when we support variable len messages, how would it work?
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.
One has to use some combination of secp256k1-pubkey-unpack
, bip0340-challenge-midstate
, and secp256k1-linear-verify
. These have been sketched out in the Tech Report, but not all of them have made it into this PR.
c84e74e
to
f4b709e
Compare
We need our own copy of libsecp256k1 because we are breaking the API by directly creating Simplicity bindings for low-level elliptic curve operations.
Fixups of secp256k1 to make it compatible with our prefered specifications. (1) Our specification has no infinity flag, and treats the infinity flag as a cache of a z=0 test. This view holds everywhere except when doubling a point of order 2. We fix this instance. We also adjust secp256k1_gej_set_ge and secp256k1_gej_add_zinv_var to ensure that the z-value is set to zero when infinity is returned. (2) gej_add_ge leaves the rzr value uninitialized when the a input is infinity. This can occur when ecmult builds a scalar table for very low order points, i.e. odd order points of order less than 15 or so. While this uninitialized value is read and then eventually multiplied by 0, this is techincally unspecified behaviour. Thus we prefer to explicity clear the rzr in this case. (3) Our specification of GE cannot include points at infinity. However secp256k1_ge_globalz_set_table_gej may produce GE points at the infinity when ecmult builds a scalar table for very low order points, i.e. odd order points of order less than 15 or so. For compatability with our specification, we clear the infinity flag, yeilding the cusp point of (0,0).
With secp256k1 jets available the compile-test cycle seems faster without optimizations than with optimizations.
Now that tests use jets for evaluation, they are not as long running, (though obviously now assume that the jet implementations are faithful).
f4b709e
to
424411b
Compare
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.
Looks good to me. I would want to cross-test this with rust-simplicity, but it is far behind in implementation. I think we can go ahead with this for now.
I checked that jets do the correct thing for points on secp256k1
, but still am not sure if operations on out of curve points can never produce a point that is on curve
I have little doubt that running "addition" on points that are off curve, especially on inputs that are not even on the same curve, can result in points on the secp256k1 curve. (in particular all the curves share the same representation for points at infinity.) But there is nothing wrong with that. |
A set of crypto jets cloned from secp256k1.