-
Notifications
You must be signed in to change notification settings - Fork 120
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
Use batch optimizations, load params in groth16::Verifier, verify Spend & Output descriptions #1713
Conversation
aaabbac
to
e9202da
Compare
Rebased onto #1704 while in progress |
c133db7
to
a2315fb
Compare
@yaahc I'm running into conflicts between bellman's rand/rand_core traits, and redjubjub's rand/rand_core traits, which I thought I had resolved to the same, but rustc still mad at me, maybe you can take a look? |
eabe599
to
a3ab377
Compare
Supports the bellman batch math optimizations, and creates 3 static instances, one for Spend, Output, and JoinSplit, per their different VerifyingKeys
Commit a143434 (merge 0a0d11b) synced within 3 hours on testnet, and 5 hours on mainnet. That's pretty typical for me, I'm network-limited, and my local peers are a much larger proportion of testnet. (Also testnet data is much smaller.) Didn't notice much CPU load, but I do have a lot of cores. I've restarted with the latest version of this PR 525a6f6 (merge 611b335), and I'll let it run overnight. Feel free to ping me if I forget to update this ticket. |
#redjubjub = "0.2" | ||
redjubjub = {git = "https://github.com/ZcashFoundation/redjubjub", rev = "8101eaff1cb2fca45334f77a65caa4c46e3d545b"} |
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 should probably stick with using the [patch.crates-io]
section in the top level toml for specifying git deps
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.
Let's also open a follow-up ticket that describes when we can un-patch the crates.
The existing ticket is #1086, but we should probably start a new one for crypto crates.
pub fn primary_inputs(&self) -> Vec<jubjub::Fq> { | ||
let mut inputs = vec![]; | ||
|
||
let cv_affine = jubjub::AffinePoint::from_bytes(self.cv.into()).unwrap(); |
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.
can we replace these unwrap
s with expect
s that describe why this should never fail
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.
Bah unfortunately this is CtOption
but I'll make it better anyway
https://docs.rs/subtle/2.2.2/subtle/struct.CtOption.html
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.
wow I can't believe CtOption
doesn't have an expect call...
You could use an extension trait here to add the expect
method and have it just internally call unwrap_or_else(|| panic!(...))
#bellman = "0.8" | ||
bellman = { git = "https://github.com/zkcrypto/bellman", rev = "bd4af09f50a4d020a3672aff37c4f3f2da2bb36b" } |
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.
should also be specified via patch
section
/// Note that making a `Service` call requires mutable access to the service, so | ||
/// you should call `.clone()` on the global handle to create a local, mutable | ||
/// handle. | ||
pub static SPEND_VERIFIER: Lazy< | ||
Fallback<Batch<Verifier, Item>, ServiceFn<fn(Item) -> Ready<Result<(), VerificationError>>>>, | ||
> = Lazy::new(|| { |
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 should not make this handle public if we want to enforce cloning, and instead expose a pub method that calls clone and returns that handle.
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 should make a similar change to our other batch verifiers, but that can be done in a follow-up ticket.
Let's make sure we open that follow-up ticket :-)
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 we now have 4, going to be 5 batch verifier services that are currently clone()'d inside transaction::Verifier::call()
, script_verifier
is assigned to the Verifier instance on construction and later clone'd, the others are referenced and clone'd only within call
. I think all are currently static
besides script::Verifier
. Are we doing this right?
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 think consistency is important, but we were always going to have a lot of batch verifiers, so having 5 doesn't worry me.
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.
To be specific: let's access, store, and clone them all the same way. Clones should be cheap.
batch_flushes_on_max_items().await | ||
} | ||
|
||
#[spandoc::spandoc] |
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 you have a #[spandoc]
attribute here, it might be a cool idea to add a /// SPANDOC:
comment before the main line in the test where it can potentially fail, so we get a nice description of what it was doing in the error message. Otherwise we should probably remove the attribute since it's not doing anything.
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.
Oh man, this got committed when it was not updated away from redjubjub yet, but I should include the better SPANDOC:
comment either way
let spend_rsp = spend_verifier | ||
.ready_and() | ||
.await? | ||
.call(primitives::groth16::ItemWrapper::from(spend).into()); |
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.
minor: we can probably change the spend_verifier
so its request type is Into<Item>
so that this into call happens automatically inside the service
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.
ooo neat
rand_core = "0.5.1" | ||
rand_core = "0.6" |
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.
Does this add a dependency on multiple versions of rand_core
?
Maybe we should check which forks of ed25519-zebra use rand_core = "0.6"
now. But this isn't a high priority.
@@ -27,6 +27,30 @@ pub struct Output { | |||
pub zkproof: Groth16Proof, | |||
} | |||
|
|||
impl Output { | |||
/// Encodes the primary inputs for the proof statement as 5 Bls12_381 base |
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.
Should we have an assertion that checks the returned Vec
's length?
@@ -31,6 +31,35 @@ pub struct Spend { | |||
pub spend_auth_sig: redjubjub::Signature<SpendAuth>, | |||
} | |||
|
|||
impl Spend { | |||
/// Encodes the primary inputs for the proof statement as 7 Bls12_381 base |
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.
Should we have an assertion that checks the returned Vec
's length?
@@ -30,11 +33,10 @@ tower-batch = { path = "../tower-batch/" } | |||
zebra-chain = { path = "../zebra-chain" } | |||
zebra-state = { path = "../zebra-state" } | |||
zebra-script = { path = "../zebra-script" } | |||
pairing = "0.18.0" | |||
wagyu-zcash-parameters = "0.2.0" |
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.
Do we need to pull in all 7 wagyu sub-crates? They're pretty large.
Does the redundant data get optimised away in release builds?
/// Note that making a `Service` call requires mutable access to the service, so | ||
/// you should call `.clone()` on the global handle to create a local, mutable | ||
/// handle. | ||
pub static OUTPUT_VERIFIER: Lazy< |
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.
Similar to the above comment, let's have a public method that returns a clone.
|
||
use blake2b_simd::State; | ||
|
||
/// Abstraction over a reader which hashes the data being 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.
Don't we already have an impl of HashReader
somewhere?
If not, this seems like generic utility code, rather than groth16-specific code, so it belongs somewhere else in the module tree.
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 think an equivalent is https://github.com/ZcashFoundation/zebra/blob/main/zebra-chain/src/serialization/sha256d.rs, but that's for SHA256d, this one is for Blake2b; we can more it to a top level module still in zebra-consensus
, or zebra-chain
.
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, I just have a few questions and task dependencies
Including over mainnet test vectors and a forced appropriate failure.
Motivation
Tie together the existing async groth16::Verifier to the bellman batch optimizations and the required loading in of the different VerifyingKeys and Params for each statement type.
Solution
Supports the bellman batch math optimizations, and creates 3 static instances,
one for Spend and Output per their different VerifyingKeys.
Depends on #1704, and zkcrypto/bellman#59
The code in this pull request has:
Review
@yaahc @teor2345 @oxarbitrage
Related Issues
#1645, #406
Follow Up Work
#1835