Closed readygo67 closed 8 months ago
Hmm, I think we could add a more descriptive error message, but I'm still not confident we should add such an edge case. For me it doesn't make sense to recursively verify a circuit without a public witness. Or is there any?
I hope to create a VDF function by applying hash several times (hash(hash(hash(x)))), so don't expose the immediate hash result。And because of non-exposure, I can not get the finial result.
But in this case wouldn't you have to prove inside SNARK that out=hash(hash(hash(x)))
is actually valid VDF output of x
? Wouldn't the circuit's inputs be out
and x
?
I see that if instead of the claim "out
is a valid VDF output of x
" you want to claim "I have performed VDF for some input" which indeed is a valid statement to prove. However, if you do not include anything in the public input, then it would be possible to copy the proof and the actual claim would actually be "someone has performed VDF for some input". Particularly, as some SNARKs are malleable (i.e. we can rerandomize the proof without proving), then it wouldn't even possible to perform some checking in database that no such has been provided.
So, I still think that you have to provide some public input.
Description
In plonk recursion, if the inner circuit has no public witness, when compile the outer circuit, the following error emitted.
which is caused by unreachable index=0 if witness is nil
Expected Behavior
outer circuit compile success.
Actual Behavior
panic happens
Steps to Reproduce
func (c InnerCircuitNative) Define(api frontend.API) error { // prove that PQ == N res := api.Mul(c.P, c.Q) api.AssertIsEqual(res, c.N) // we must also enforce that P != 1 and Q != 1 api.AssertIsDifferent(c.P, 1) api.AssertIsDifferent(c.Q, 1) return nil }
// computeInnerProof computes the proof for the inner circuit we want to verify // recursively. In this example the PLONK keys are generated on the fly, but // in practice should be genrated once and using MPC. func computeInnerProof(field, outer *big.Int) (constraint.ConstraintSystem, native_plonk.VerifyingKey, witness.Witness, native_plonk.Proof) { innerCcs, err := frontend.Compile(field, scs.NewBuilder, &InnerCircuitNative{}) if err != nil { panic(err) } // NB! UNSAFE! Use MPC. srs, srsLagrange, err := unsafekzg.NewSRS(innerCcs) if err != nil { panic(err) }
}
// OuterCircuit is the generic outer circuit which can verify PLONK proofs // using field emulation or 2-chains of curves. type OuterCircuit[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { Proof plonk.Proof[FR, G1El, G2El] VerifyingKey plonk.VerifyingKey[FR, G1El, G2El]
gnark:"-"
// constant verification key InnerWitness plonk.Witness[FR]gnark:",public"
}func (c *OuterCircuit[FR, G1El, G2El, GtEl]) Define(api frontend.API) error { verifier, err := plonk.NewVerifierFR, G1El, G2El, GtEl if err != nil { return fmt.Errorf("new verifier: %w", err) } err = verifier.AssertProof(c.VerifyingKey, c.Proof, c.InnerWitness) return err }
func TestPlonkRecursion_BW761_BN254(t *testing.T) { // compute the proof which we want to verify recursively innerCcs, innerVK, innerWitness, innerProof := computeInnerProof(ecc.BW6_761.ScalarField(), ecc.BN254.ScalarField())
}