-
Notifications
You must be signed in to change notification settings - Fork 266
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
feat: Honk recursive verifier Pt. 1 #1488
Conversation
bd0057b
to
8e07148
Compare
@@ -186,136 +186,7 @@ ProverOutput<Curve> GeminiProver_<Curve>::compute_fold_polynomial_evaluations(st | |||
return { fold_poly_opening_pairs, std::move(fold_polynomials) }; | |||
}; | |||
|
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've moved the definitions of the the GeminiVerifier methods back to the header. This avoids a lot of pain, at least while we need to instantiate it with both native and stdlib Curve
s. It should be easy to revert once this is no longer the case (see bberg issue no. 673)
@@ -250,25 +250,6 @@ template <class FF, typename Tuple, std::size_t Index = 0> static constexpr auto | |||
} | |||
} | |||
|
|||
/** |
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 unrelated to this work but was unused and should have been removed previously.
779f3c2
to
af0eae8
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, only had some comments for things that were a bit unclear
* @tparam T | ||
* @tparam LENGTH (used only for containers which specify a length, e.g. array/Univariate) | ||
*/ | ||
template <typename T, size_t LENGTH = 0> struct CorrespondingNativeType { |
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.
Looking at how this is used in the codem shortening the name to NativeType
would still make sense, so it's not that verbose.
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
} | ||
|
||
/** | ||
* @brief This function verifies an Ultra Honk proof for given program settings. |
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.
not related to this PR but program setting is from an older version of the proof system and should be replaced by flavor, right? (same for the UltraVerifier
)
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.
Updated, thanks
const auto pub_inputs_offset = transcript.template receive_from_prover<uint32_t>("pub_inputs_offset"); | ||
|
||
// Extract native integer types for these basic quantities for use in subsequent operations | ||
auto circuit_size_native = static_cast<size_t>(circuit_size.get_value()); |
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 was a bit confusing to look at. I presume subsequent operations expect size_t
and you get uint32_t
from the transcript which is why this is needed but I would rather just cast on circuit_size
and avoid creating a circuit_size_native
(same for the other things).
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 agree this is ugly. Its a bit more complicated than what you described because when we extract these quantities from the transcript in the recursive setting they are field_t's representing simple quantities (circuit size, public input size, etc.). However, in certain places we need to use them as simple (native) integers (e.g. in the loop below for extracting the public inputs from the transcript). So we could avoid naming these things and just use static_cast<size_t>(stdlib_type.get_value()) if you think that's more clear. Maybe just a better name than "..._native" would be best?
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.
Went ahead and just ditched these in favor of using the static cast in place. Don't love that either but it might be more clear than defining these additional variables
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 it took me a bit to understand the point of native
variables and I think the in-place cast (and maybe comments why they're there) might be better
info("Batched eval: num gates = ", builder->get_num_gates() - prev_num_gates); | ||
prev_num_gates = builder->get_num_gates(); | ||
|
||
// Construct vectors of scalars for batched unshifted and to-be-shifted commitments |
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 you add some more detailed comments here why this diverges from the native implementation?
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.
Comment added
|
||
// Confirm that the native and stdlib transcripts have generated the same manifest | ||
// Confirm that the native and stdlib verifier transcripts have generated the same manifest | ||
EXPECT_EQ(transcript.get_manifest(), native_transcript.get_manifest()); | ||
|
||
// TODO(luke): This doesn't check much of anything until hashing is constrained in the stdlib transcript |
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.
what does this mean?
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.
When I implemented the stdlib Transcript for Honk, I "stubbed out" the hashing portion, i.e. it does not currently lay down contraints to emulate hashing. I did this at Codys suggestion for expediency since it was a big pain to get the result to agree with the native hash (pedersen + blake3) and we are going to be changing the hash very soon anyway.
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.
Added the issue number and a clearer comment
@@ -3,6 +3,12 @@ | |||
#include <algorithm> | |||
#include <array> | |||
|
|||
// TODO(#674): We need the functionality of BarycentricData for both field and field_t. The former is "literal" i.e. is |
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.
// TODO(#674): We need the functionality of BarycentricData for both field and field_t. The former is "literal" i.e. is | |
// TODO(#674): We need the functionality of BarycentricData for both field and field_ct. The former is "literal" i.e. is |
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.
field and field_t are the names of class templates (native and stdlib, respectively), field_ct is an alias for the specialization of field_t with a particular builder. So I think field and field_t are the correct terms here
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.
ah, I see, misunderstood all of this, thanks for clarifying
@@ -3,6 +3,12 @@ | |||
#include <algorithm> | |||
#include <array> | |||
|
|||
// TODO(#674): We need the functionality of BarycentricData for both field and field_t. The former is "literal" i.e. is | |||
// compatible with constexpr operations, and the former is not. The functions for computing the pre-computable arrays in |
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.
hm literal is a confusing term - i think native (which, at least for me, means non-circuit stuff) is more appropriate
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.
Literal is a c++ term/concept which roughly means "compatible with constexpr expressions". Apparently the concept is being deprecated since this is actually quite difficult to define. Anyway, for our purposes, native vs stdlib is really the important distinction so I've gotten rid of the term "literal"
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.
ah! the more you know about c++. Are concepts all together being deprecated?
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.
No definitely not. There used to be a std::is_literal_type
method that when called on our field
would return true (indicating that it's 'constexpr' in some sense). But this particular concept is apparently quite tricky to define so the recommendation is to define your own concept that more specifically qualifies the stuff you need. For example, does it have a constexpr constructor and assignment operator, etc.
@@ -14,6 +14,19 @@ TYPED_TEST_SUITE(BarycentricDataTests, FieldTypes); | |||
|
|||
#define BARYCENTIC_DATA_TESTS_TYPE_ALIASES using FF = TypeParam; | |||
|
|||
/** | |||
* @brief Ensure auxilliary arrays (e.g. big_domain) are computed at compile time if possible (i.e. if FF is literal) |
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.
first, I noticed literal here and was confused what you are refering to
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.
changed language to native
inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge); | ||
vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge); | ||
} | ||
// If recursion, invert elements individually, otherwise batch invert |
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.
add a comment explaining that inversion is quite cheap in circuits and there's no need for batching
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.
added
|
||
namespace proof_system::honk::flavor { | ||
|
||
class UltraRecursive { |
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 you add a comment that this class is mostly similar to the Ultra
flavor class except the curve is intantiated with the stdlib types and you have removed stuff that is only relevant for the prover (since only a verifier is instantiated with UltraRecursive
)? and other differences that maybe I haven't spotted.
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.
thanks, done
af0eae8
to
6a22879
Compare
Early-stage UltraHonk recursive verifier.
The idea is to have a single
UltraVerifier
class that is instantiated with a genuine builder for recursive verification and a simulated builder for native verification. (This is as opposed to Plonk which has two separate implementations). Some notes:UltraRecursiveVerifier_
in the stdlib. It is essentially a duplicate of the existingUltraVerifier_
with some very minor changes. Once aSimulator
is in place, this will become the one and only verifier and the original will be deleted.UltraRecursiveVerifier_
itself is duplicated fromUltraVerifier_
, the bulk of the actual verification logic takes place in theSumcheckVerifier
,GeminiVerifier
, andShplonkVerifier
, which are not duplicated; they are the same classes used by the native verifier. The only addition is a handful of constexpr if's to facilitate differences between native and stdlib behavior, e.g. performing a batch mul (stdlib) vs doing naive accumulation (native).Checklist:
Remove the checklist to signal you've completed it. Enable auto-merge if the PR is ready to merge.