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

Sapling proving and verifying API #30

Merged
merged 5 commits into from
Jan 6, 2019
Merged

Conversation

str4d
Copy link
Contributor

@str4d str4d commented Aug 14, 2018

This PR defines a Rust API (with no unsafe) for creating and verifying the Sapling components of a Zcash transaction.

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) {
Copy link
Contributor

@Eirik0 Eirik0 Aug 22, 2018

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.

Copy link
Contributor Author

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) {
Copy link
Contributor

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.

Copy link
Contributor Author

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());
Copy link
Contributor

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(
Copy link
Contributor

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;
Copy link
Contributor

@Eirik0 Eirik0 Aug 23, 2018

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.

str4d pushed a commit to str4d/librustzcash that referenced this pull request Aug 28, 2018
@str4d
Copy link
Contributor Author

str4d commented Sep 11, 2018

Rebased on master to fix merge conflicts, and addressed @Eirik0's serialisation comment.

@str4d
Copy link
Contributor Author

str4d commented Sep 11, 2018

Edited the proving and binding sig refactor to target the zcash_proofs crate, so that it is accessible by other crates (like zcash_wallet).

@str4d
Copy link
Contributor Author

str4d commented Oct 16, 2018

Rebased on master to fix merge conflicts.

@str4d
Copy link
Contributor Author

str4d commented Oct 16, 2018

Rebased to fix a build error I missed during the previous rebase.

Copy link
Contributor

@Eirik0 Eirik0 left a 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.

return false;
}

// Accumulate the value commitment in the context
Copy link
Contributor

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)

let nullifier = multipack::bytes_to_bits_le(nullifier);
let nullifier = multipack::compute_multipacking::<Bls12>(&nullifier);

assert_eq!(nullifier.len(), 2);
Copy link
Contributor

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?

Copy link
Contributor Author

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.

spend_auth_sig: Signature,
zkproof: Proof<Bls12>,
verifying_key: &PreparedVerifyingKey<Bls12>,
params: &JubjubBls12,
Copy link
Contributor

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?

Copy link
Contributor Author

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.

};

// This function computes `value` in the exponent of the value commitment base
fn compute_value_balance(
Copy link
Contributor

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.

edwards::Point<Bls12, Unknown>,
PublicKey<Bls12>,
),
(),
Copy link
Contributor

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.

Copy link
Contributor Author

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.

// Verify the proof
match verify_proof(verifying_key, &proof, &public_input[..]) {
// No error, and proof verification successful
Ok(true) => {}
Copy link
Contributor

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<(), ...>).

Copy link
Contributor Author

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).

@str4d
Copy link
Contributor Author

str4d commented Nov 8, 2018

Rebased on master to fix merge conflict.

@str4d
Copy link
Contributor Author

str4d commented Nov 8, 2018

I'm going to adjust this PR to move the verifier into zcash_proofs alongside the prover, in line with @ebfull's plan outlined in #41.

@str4d str4d changed the title Sapling API cleanup Sapling proving and verifying API Nov 9, 2018
@str4d
Copy link
Contributor Author

str4d commented Nov 9, 2018

Force-pushed to rework the PR. It now only contains the proving and verifying API refactor; the spendAuthSig refactor will be in a subsequent PR (once #39 is merged).

@daira
Copy link
Contributor

daira commented Nov 30, 2018

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?

@str4d
Copy link
Contributor Author

str4d commented Nov 30, 2018

@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...

@Eirik0
Copy link
Contributor

Eirik0 commented Nov 30, 2018

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.

@str4d
Copy link
Contributor Author

str4d commented Dec 1, 2018

@daira @Eirik0 I've added some refactoring commits which I think will help. LMK if I should try and break things down further.

@str4d
Copy link
Contributor Author

str4d commented Jan 3, 2019

Force-pushed to update the cargo fmt commit in order to trigger a Travis CI build.

@ebfull
Copy link
Collaborator

ebfull commented Jan 3, 2019

ACK

Copy link
Contributor

@Eirik0 Eirik0 left a 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.

@ebfull ebfull merged commit f65c37e into zcash:master Jan 6, 2019
@str4d str4d deleted the sapling-api-cleanup branch January 6, 2019 10:08
@Eirik0 Eirik0 mentioned this pull request Jan 7, 2019
19 tasks
str4d added a commit to str4d/librustzcash that referenced this pull request Aug 22, 2020
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants