Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Recursive proof of signature on ".../std/recursion/groth16".VerifyingKey #1215

Closed
aayux opened this issue Jul 19, 2024 · 3 comments
Closed

Comments

@aayux
Copy link

aayux commented Jul 19, 2024

Starting from the recursion/groth16 example on pkg.go.dev I am trying to build a recursive 2-chain where the outer circuit verifies a signature on the inner proof system's VerifyingKey (among other things).

type OuterCircuit[
	FR emulated.FieldParams,
	G1El algebra.G1ElementT,
	G2El algebra.G2ElementT,
	GtEl algebra.GtElementT,
] struct {
	InnerProof   rec_groth16.Proof[G1El, G2El] // rec_groth16 ".../std/recursion/groth16"
	InnerVerKey  rec_groth16.VerifyingKey[G1El, G2El, GtEl]
	InnerWitness rec_groth16.Witness[FR]
	SigVerKey    eddsa.PublicKey
	Signature    eddsa.Signature
}

I have two questions on this:

  1. How can I obtain the byte string (for each element of) vk of type rec_groth16.VerifyingKey[G1El, G2El, GtEl] to sign over in the actual signing function?
  2. More importantly, how would Define method manipulate InnerVerKey to get a message of valid type for eddsa.Verify?
@aayux aayux changed the title Recirsive proof of signature on ".../std/recursion/groth16".VerifyingKey Recursive proof of signature on ".../std/recursion/groth16".VerifyingKey Jul 19, 2024
@readygo67
Copy link
Contributor

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
}

@ivokub
Copy link
Collaborator

ivokub commented Jul 24, 2024

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/[email protected]/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.

@ivokub
Copy link
Collaborator

ivokub commented Jul 24, 2024

Converted to discussion as seems to be question about gnark usage, not an issue.

@Consensys Consensys locked and limited conversation to collaborators Jul 24, 2024
@ivokub ivokub converted this issue into discussion #1223 Jul 24, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants