-
Notifications
You must be signed in to change notification settings - Fork 250
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
Sapling proving and verifying API #30
Conversation
src/rustzcash.rs
Outdated
(&mut data_to_be_signed[32..64]).copy_from_slice(&(unsafe { &*sighash_value })[..]); | ||
|
||
// Deserialize rk | ||
let rk = match redjubjub::PublicKey::<Bls12>::read(&(unsafe { &*rk })[..], &JUBJUB) { |
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.
We have moved this deserialization in to the implementation of the context but not the deserialization of cv, anchor, spend_auth_sig, etc. I think I would prefer either moving all the desializations or none, unless this is necessary.
Edit: after looking through the rest of the commits, I think this would make sense not to move this read.
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 organised it like this because the serialized form is used in the signature, and I was trying to minimise serialization operations. But you are right that it would be semantically simpler to just treat the Rust API as having Rust types, and serialize on either side as required. I'll adjust.
src/sapling.rs
Outdated
return false; | ||
} | ||
|
||
if is_small_order(&epk) { |
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.
We used to accumulate the value commitment before we checked if epk was of small order. I think this makes more sense, but just wanted to confirm that we want to change this.
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 figured it made sense to do the necessary checks before any data processing.
src/sapling.rs
Outdated
params: &JubjubBls12, | ||
) -> bool { | ||
// Obtain current bvk from the context | ||
let mut bvk = PublicKey(self.bvk.clone()); |
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.
Below we refer to bvk.0 more than we refer to bvk. It doesn't matter because of the "zero-cost abstractions", but I like saying let mut bvk = self.bvk.clone();
here and PublicKey(bvk).verify(
below
src/sapling.rs
Outdated
(&mut data_to_be_signed[32..64]).copy_from_slice(&sighash_value[..]); | ||
|
||
// Verify the binding_sig | ||
bvk.verify( |
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 like that we changed this to return the result of verify rather than having the conditional.
src/sapling.rs
Outdated
tmp.add_assign(&self.bsk); | ||
|
||
// Update the context | ||
self.bsk = tmp; |
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 are a few places where we are doing this or similar accumulate logic. Now that this is not unsafe it could be more easily done in one line. self.bsk.add_assign(&rcv)
or something similar. The same goes for when we are de-accumulating. I'm not sure the best way to abstract this logic across the two contexts perhaps a struct ContextualPoint
with the accumulate and de-accumulate methods? This can be done later.
Optimise Boolean::enforce_equal.
83aa9b6
to
527d698
Compare
Rebased on master to fix merge conflicts, and addressed @Eirik0's serialisation comment. |
527d698
to
a6b3d14
Compare
Edited the proving and binding sig refactor to target the |
a6b3d14
to
a492956
Compare
Rebased on master to fix merge conflicts. |
a492956
to
0944cee
Compare
Rebased to fix a build error I missed during the previous rebase. |
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.
utACK. There were a couple things I had questions on, and a couple things which could potentially be simplified, but those are beyond the scope of this refactoring.
librustzcash/src/sapling.rs
Outdated
return false; | ||
} | ||
|
||
// Accumulate the value commitment in the context |
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 block below this comment could be simplified, but that is beyond the scope of this refactor. See: #30 (comment)
librustzcash/src/sapling.rs
Outdated
let nullifier = multipack::bytes_to_bits_le(nullifier); | ||
let nullifier = multipack::compute_multipacking::<Bls12>(&nullifier); | ||
|
||
assert_eq!(nullifier.len(), 2); |
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.
It feels odd to have asserts in production code, but this has not changed in the move. I wonder if we should be explicitly panicking here with a better error message.
Edit: Actually, why are we not returning None
/Err(())
/false
in the places that we are asserting?
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.
This is an internal consistency check. We know (via the function's type signature) that nullifier
is 32 bytes, and we "know" that when packed this should result in two field elements. The assertion here upgrades the "know" to a know, by catching any bugs that might result in a different-length packing.
librustzcash/src/sapling.rs
Outdated
spend_auth_sig: Signature, | ||
zkproof: Proof<Bls12>, | ||
verifying_key: &PreparedVerifyingKey<Bls12>, | ||
params: &JubjubBls12, |
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.
Will params every be anything other than &JUBJUB
? Why pass this in rather than use the constant?
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.
That's something we should address across the entire codebase: which parts will only ever need JUBJUB
, and which should be agnostic.
librustzcash/src/sapling.rs
Outdated
}; | ||
|
||
// This function computes `value` in the exponent of the value commitment base | ||
fn compute_value_balance( |
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.
It's a little hard to follow what happens with this function, but the total number of additions/removals across all commits adds up. The change are that the parameter value: i64_t
becomes value: i64
(which makes sense), and we now pass in params
rather than refer to &JUBJUB
directly.
zcash_proofs/src/sapling.rs
Outdated
edwards::Point<Bls12, Unknown>, | ||
PublicKey<Bls12>, | ||
), | ||
(), |
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 general comment is that it feels odd to return a Result with an empty error (we do this in a few places in this file). I would think that either we would return an Option<...>
if we don't care what the error is. Alternatively we could return a Result <...>
with an error type that encapsulates the error types that could result from the functions that we are calling - this would allow us to take advantage of the ?
operator if nothing else.
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 benefit to returning a Result
instead of an Option
is that the standard rustc linters will generate a warning if a Result
is unused (either via matching or an explicit unwrap()
). As for improved error-handling (which is definitely a good idea), this should be tackled as part of a wider refactor.
zcash_proofs/src/sapling.rs
Outdated
// Verify the proof | ||
match verify_proof(verifying_key, &proof, &public_input[..]) { | ||
// No error, and proof verification successful | ||
Ok(true) => {} |
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.
Ok(true)
feels odd because it makes one wonder what Ok(false)
means. It doesn't look like we ever use the Err
from verify_proof
. IMO it would make more sense if verify_proof
just returned a bool
, or if the error type it returned encapsulated the situation where this could be false (Result<(), ...>
).
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 would also prefer to use Result<(), SomeErrorType>
; this is something we should think about when doing an error-handling refactor (and which will require changes to bellman in this case).
0944cee
to
9139ec4
Compare
Rebased on master to fix merge conflict. |
9139ec4
to
2de6301
Compare
Force-pushed to rework the PR. It now only contains the proving and verifying API refactor; the |
This is difficult to review (specifically, to check that the code movement is just movement). Can it be split into commits that move smaller pieces at a time? |
@daira I'm not sure it can, at least while ensuring that the code compiles. I can go back and try it out, but no guarantee that I can simplify it in that way. I could also try doing some refactoring in-place before moving code, and see if that improves the diffs... |
If it isn't too much trouble I like the idea of refactoring in place and then moving. I also had wondered about making the new structs and then pulling in the functions one commit at a time. Not necessarily simpler but less to look at all at once. |
2de6301
to
b83234a
Compare
b83234a
to
1a1c775
Compare
Force-pushed to update the |
ACK |
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. The refactoring looks good. Some of my previous comments still stand, but those can be addressed later.
38d38af3 Merge pull request zcash#32 from kevaundray/patch-1 af5598da Merge pull request zcash#33 from ZcashFoundation/scalar 109ec40d Add public Scalar type alias for Fr 8e9c5fe6 typo in Fr.rs 8e9337ee Merge pull request zcash#30 from rex4539/typos 5f4374c8 Fix typo git-subtree-dir: jubjub git-subtree-split: 38d38af3b792d2c55d815d214a7cd157dc8f71ad
This PR defines a Rust API (with no
unsafe
) for creating and verifying the Sapling components of a Zcash transaction.