Closed aayux closed 2 months ago
I think you can finish the above 2 task at once, please check https://github.com/lightec-xyz/gnark/blob/feat/vkey_fp/std/recursion/plonk/verifier.go.
FingerPrint write vk's element into a mimc buffer , then sum them. this function is for recursion plonk, but I think you can adopt it for groth16.
// FingerPrint() returns the MiMc hash of the VerifyingKey. It could be used to identify a VerifyingKey
// during recursive verification.
func (vk *VerifyingKey[FR, G1El, G2El]) FingerPrint(api frontend.API) (frontend.Variable, error) {
var ret frontend.Variable
mimc, err := mimc.NewMiMC(api)
if err != nil {
return ret, err
}
mimc.Write(vk.BaseVerifyingKey.NbPublicVariables)
mimc.Write(vk.CircuitVerifyingKey.Size)
mimc.Write(vk.CircuitVerifyingKey.Generator.Limbs[:]...)
comms := make([]kzg.Commitment[G1El], 0)
comms = append(comms, vk.CircuitVerifyingKey.S[:]...)
comms = append(comms, vk.CircuitVerifyingKey.Ql)
comms = append(comms, vk.CircuitVerifyingKey.Qr)
comms = append(comms, vk.CircuitVerifyingKey.Qm)
comms = append(comms, vk.CircuitVerifyingKey.Qo)
comms = append(comms, vk.CircuitVerifyingKey.Qk)
comms = append(comms, vk.CircuitVerifyingKey.Qcp[:]...)
for _, comm := range comms {
el := comm.G1El
switch r := any(&el).(type) {
case *sw_bls12377.G1Affine:
mimc.Write(r.X)
mimc.Write(r.Y)
case *sw_bls12381.G1Affine:
mimc.Write(r.X.Limbs[:]...)
mimc.Write(r.Y.Limbs[:]...)
case *sw_bls24315.G1Affine:
mimc.Write(r.X)
mimc.Write(r.Y)
case *sw_bw6761.G1Affine:
mimc.Write(r.X.Limbs[:]...)
mimc.Write(r.Y.Limbs[:]...)
case *sw_bn254.G1Affine:
mimc.Write(r.X.Limbs[:]...)
mimc.Write(r.Y.Limbs[:]...)
default:
return ret, fmt.Errorf("unknown parametric type")
}
}
mimc.Write(vk.CircuitVerifyingKey.CommitmentConstraintIndexes[:]...)
result := mimc.Sum()
return result, nil
}
In principle the above approach works - you just have to keep in mind that when computing the witness that you use the same representation for hashing, i.e. you have to split the coordinates at 64-bit intervals.
We have some helper tools which do this automatically, see https://pkg.go.dev/github.com/consensys/gnark@v0.10.0/std/recursion and the corresponding test file https://github.com/Consensys/gnark/blob/master/std/recursion/wrapped_hash_test.go. This wrapper is not very efficient though - we work with binary decomposition of non-native elements to map into native field for hashing and binary decomposition is slow. We're planning to migrate to the approach where we hash the limbs directly, but this requires also changes in gnark-crypto.
Converted to discussion as seems to be question about gnark usage, not an issue.
Starting from the
recursion/groth16
example onpkg.go.dev
I am trying to build a recursive 2-chain where the outer circuit verifies a signature on the inner proof system'sVerifyingKey
(among other things).I have two questions on this:
vk
of typerec_groth16.VerifyingKey[G1El, G2El, GtEl]
to sign over in the actual signing function?Define
method manipulateInnerVerKey
to get a message of valid type foreddsa.Verify
?