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

Add ParamsVerifierKZG #301

Closed
wants to merge 4 commits into from
Closed

Add ParamsVerifierKZG #301

wants to merge 4 commits into from

Conversation

davidnevadoc
Copy link

@davidnevadoc davidnevadoc commented Mar 20, 2024

Description

The aim of this PR is to allow the verification of a KZG proof without having to deal with the complete KZG parameters.
ParamsKZG contains 2 G2 elements and 2 vectors of n-sized vectors of G1 elements, where n is the size of the circuit.
The verifier only needs the 2 G2 elements, and as many G1 elements as public inputs in the circuit.

Changes

  • Add the struct ParamsVerifierKZG.
    This struct contains the bare minimum info needed to verify a proof.
  • Remove get_g from ParamsProver.
  • Modify verifier_params -> into_verifier_params.
    I'm not 100% convinced how this ended up, so any suggestion is greatly appreciated.
  • Adjust to function calls to use verifier parameters when needed, instead of the full parameters.

Closes #280

 - remove `get_g` from ParamsProver
 - modify `verifier_params` -> `into_verifier_params`
 - Adjust to function calls to use verifier parameters
 when needed, instead of the full parameters.
@davidnevadoc davidnevadoc marked this pull request as ready for review March 20, 2024 18:13
Copy link
Member

@CPerezz CPerezz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where's all this read/write impls comming from??

Comment on lines 94 to 91
fn verifier_params(&'params self) -> &'params Self::ParamsVerifier;
fn into_verifier_params(self) -> Self::ParamsVerifier;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why removimg the return of the ref? You can always clone later if you need to own the data.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for bringing this up! This is the change I'm the least happy with.

Before this PR, the verfier params and the prover params where the same struct. As a result, this function could just return self without issue.
The problem is that now, the verifier and prover params are different. Moreover, the prover parameters do not contain the verifier parameters directly. As a result, the ParamsVerifier struct must be created here, and we cannot return a reference.

I reasoned that in most cases, when you create the verifier params you are done with all the proving, so it is acceptable to consume the prover parameters. ( I removed an unnecessary clone in the From implementation 3b5b8a5). So in most cases, the user can generate the verifier parameters without cloning.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we at least get &self as input?
I say it as usually, when we test, we do both prove and verify within the same scope. And this will force a clone of a quite big struct most likely.

In any case, not strongly against this change though. Just wanted to explore the options.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also would have liked to keep the &self as input, but it run into a big issue: A lot of cloning.
For example, in IPA, where the verifier parameters are the same as the input parameters, this forced to clone the whole struct (with its n sized vectors and all...).
I found that by getting self, the user could decide to clone in advance to keep the parameters, or just consume them to create the verifier params, which is the most usual case.

Copy link
Author

@davidnevadoc davidnevadoc Apr 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is an attempt to go back to the original function: 4e2f44e

The g and g_lagrange fields of ParmamsIPA have been changed from Vec<C> to Arc<[C]> ( as suggested by @ed255). As a result, the clone that that would happen in verifier_params is very cheap.

Despite this, I'm not sure if this is the right choice. There are a couple of points where I've been forced to initialize a vector first, and then convert it to Arc. I'd like to avoid these re-allocations, but I'm not sure if it is possible.

@davidnevadoc
Copy link
Author

Where's all this read/write impls comming from??

These are adaptations from the implementations of ParamsKZG, they are equal just with different fields in the struct.

@CPerezz
Copy link
Member

CPerezz commented Mar 21, 2024

Where's all this read/write impls comming from??

These are adaptations from the implementations of ParamsKZG, they are equal just with different fields in the struct.

We should consider this as related to #176

// Domain size.
pub(crate) n: u64,
// This is the maximum size of PI supported.
pub(crate) trimed_size: u32,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of storing trimed_size here if AFIS it's just g_lagrange.len()?
Makes sense to store it serialized, but maybe it's not necessary to be kept in memory.

@@ -186,6 +204,8 @@ where
where
E::G2Affine: SerdeCurveAffine,
{
// TODO: 4 bytes is too much for k, this is the log-size of the params.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's just enough with the check you added later.

        // This is a generous bound on the size of the domain.
        debug_assert!(k < 32);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that check is definitely necessary, even with just 1 byte for storing k. This check was already added in the verifier keys, as it could lead to the attempt of allocating a 2 ^ (2 ^ 32) len vector. ( #244 ). In this PR, we also reduced the number of bytes from 4 to 1, so I think it would be good to reduce it here to keep things coherent. WDYT?

}

/// Reads verifier parameters from a buffer.
pub fn read_custom<R: io::Read>(reader: &mut R, format: SerdeFormat) -> io::Result<Self>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some code that is repeated in ParamsKZG::read_custom, maybe it can be reused via shared functions.

Go back to `verifier_params` method in `ParamsProver`.
To avoid duplciating the IPA parameters when calling this function,
`g`, `g_lagrange` has been change from `Vec<C>` to `Arc<[C]>`.
@davidnevadoc davidnevadoc marked this pull request as draft April 10, 2024 18:22
@davidnevadoc
Copy link
Author

Overridden by #318

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.

ParamsVerifierKZG is ParamsKZG even though it could be smaller
3 participants