func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error {
	return pk.Vk.InitKZG(srs)
}
InitKZG inits pk.Vk.KZG using pk.DomainNum cardinality and provided SRS

This should be used after deserializing a ProvingKey
as pk.Vk.KZG is NOT serialized
package plonk
import (
	"errors"
	"github.com/consensys/gnark-crypto/ecc/bn254/fr"
	"github.com/consensys/gnark-crypto/ecc/bn254/fr/fft"
	"github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg"
	"github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial"
	"github.com/consensys/gnark/internal/backend/bn254/cs"
	kzgg "github.com/consensys/gnark-crypto/kzg"
)
type ProvingKey struct {
	Vk *VerifyingKey
	Ql, Qr, Qm, Qo polynomial.Polynomial
	CQk, LQk polynomial.Polynomial
	DomainNum, DomainH fft.Domain
	LS1, LS2, LS3 polynomial.Polynomial
	CS1, CS2, CS3 polynomial.Polynomial
	Permutation []int64
}
type VerifyingKey struct {
	Size              uint64
	SizeInv           fr.Element
	Generator         fr.Element
	NbPublicVariables uint64
	Shifter [2]fr.Element
	KZGSRS *kzg.SRS
	S [3]kzg.Digest
	Ql, Qr, Qm, Qo, Qk kzg.Digest
}
func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) {
	var pk ProvingKey
	var vk VerifyingKey
	pk.Vk = &vk
	nbConstraints := len(spr.Constraints)
	sizeSystem := uint64(nbConstraints + spr.NbPublicVariables)  
	pk.DomainNum = *fft.NewDomain(sizeSystem, 0, false)
	if sizeSystem < 6 {
		pk.DomainH = *fft.NewDomain(8*sizeSystem, 1, false)
	} else {
		pk.DomainH = *fft.NewDomain(4*sizeSystem, 1, false)
	}
	vk.Size = pk.DomainNum.Cardinality
	vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv)
	vk.Generator.Set(&pk.DomainNum.Generator)
	vk.NbPublicVariables = uint64(spr.NbPublicVariables)
	vk.Shifter[0].Set(&pk.DomainNum.FinerGenerator)
	vk.Shifter[1].Square(&pk.DomainNum.FinerGenerator)
	if err := pk.InitKZG(srs); err != nil {
		return nil, nil, err
	}
	pk.Ql = make([]fr.Element, pk.DomainNum.Cardinality)
	pk.Qr = make([]fr.Element, pk.DomainNum.Cardinality)
	pk.Qm = make([]fr.Element, pk.DomainNum.Cardinality)
	pk.Qo = make([]fr.Element, pk.DomainNum.Cardinality)
	pk.CQk = make([]fr.Element, pk.DomainNum.Cardinality)
	pk.LQk = make([]fr.Element, pk.DomainNum.Cardinality)
	for i := 0; i < spr.NbPublicVariables; i++ {  
		pk.Ql[i].SetOne().Neg(&pk.Ql[i])
		pk.Qr[i].SetZero()
		pk.Qm[i].SetZero()
		pk.Qo[i].SetZero()
		pk.CQk[i].SetZero()
		pk.LQk[i].SetZero()  
	}
	offset := spr.NbPublicVariables
	for i := 0; i < nbConstraints; i++ {  
		pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()])
		pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()])
		pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]).
			Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()])
		pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()])
		pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K])
		pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K])
	}
	pk.DomainNum.FFTInverse(pk.Ql, fft.DIF, 0)
	pk.DomainNum.FFTInverse(pk.Qr, fft.DIF, 0)
	pk.DomainNum.FFTInverse(pk.Qm, fft.DIF, 0)
	pk.DomainNum.FFTInverse(pk.Qo, fft.DIF, 0)
	pk.DomainNum.FFTInverse(pk.CQk, fft.DIF, 0)
	fft.BitReverse(pk.Ql)
	fft.BitReverse(pk.Qr)
	fft.BitReverse(pk.Qm)
	fft.BitReverse(pk.Qo)
	fft.BitReverse(pk.CQk)
	buildPermutation(spr, &pk)
	computeLDE(&pk)
	var err error
	if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil {
		return nil, nil, err
	}
	if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil {
		return nil, nil, err
	}
	if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil {
		return nil, nil, err
	}
	if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil {
		return nil, nil, err
	}
	if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil {
		return nil, nil, err
	}
	if vk.S[0], err = kzg.Commit(pk.CS1, vk.KZGSRS); err != nil {
		return nil, nil, err
	}
	if vk.S[1], err = kzg.Commit(pk.CS2, vk.KZGSRS); err != nil {
		return nil, nil, err
	}
	if vk.S[2], err = kzg.Commit(pk.CS3, vk.KZGSRS); err != nil {
		return nil, nil, err
	}
	return &pk, &vk, nil
}
func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) {
	sizeSolution := int(pk.DomainNum.Cardinality)
	lro := make([]int, 3*sizeSolution)
	pk.Permutation = make([]int64, 3*sizeSolution)
	for i := 0; i < spr.NbPublicVariables; i++ {  
		lro[i] = i
		lro[sizeSolution+i] = 0
		lro[2*sizeSolution+i] = 0
		pk.Permutation[i] = -1
		pk.Permutation[sizeSolution+i] = -1
		pk.Permutation[2*sizeSolution+i] = -1
	}
	offset := spr.NbPublicVariables
	for i := 0; i < len(spr.Constraints); i++ {  
		lro[offset+i] = spr.Constraints[i].L.VariableID()
		lro[sizeSolution+offset+i] = spr.Constraints[i].R.VariableID()
		lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.VariableID()
		pk.Permutation[i+offset] = -1
		pk.Permutation[sizeSolution+i+offset] = -1
		pk.Permutation[2*sizeSolution+i+offset] = -1
	}
	offset += len(spr.Constraints)
	for i := 0; i < sizeSolution-offset; i++ {
		pk.Permutation[offset+i] = -1
		pk.Permutation[offset+sizeSolution+i] = -1
		pk.Permutation[offset+2*sizeSolution+i] = -1
	}
	nbVariables := spr.NbInternalVariables + spr.NbPublicVariables + spr.NbSecretVariables
	cycle := make([]int64, nbVariables)
	for i := 0; i < len(cycle); i++ {
		cycle[i] = -1
	}
	for i := 0; i < 3*sizeSolution; i++ {
		if cycle[lro[i]] != -1 {
			pk.Permutation[i] = cycle[lro[i]]
		}
		cycle[lro[i]] = int64(i)
	}
	counter := nbVariables
	for iter := 0; counter > 0; iter++ {
		if pk.Permutation[iter] == -1 {
			pk.Permutation[iter] = cycle[lro[iter]]
			counter--
		}
	}
}
func computeLDE(pk *ProvingKey) {
	nbElmt := int(pk.DomainNum.Cardinality)
	sID := make([]fr.Element, 3*nbElmt)
	sID[0].SetOne()
	sID[nbElmt].Set(&pk.DomainNum.FinerGenerator)
	sID[2*nbElmt].Square(&pk.DomainNum.FinerGenerator)
	for i := 1; i < nbElmt; i++ {
		sID[i].Mul(&sID[i-1], &pk.DomainNum.Generator)                    
		sID[i+nbElmt].Mul(&sID[nbElmt+i-1], &pk.DomainNum.Generator)      
		sID[i+2*nbElmt].Mul(&sID[2*nbElmt+i-1], &pk.DomainNum.Generator)  
	}
	pk.LS1 = make(polynomial.Polynomial, nbElmt)
	pk.LS2 = make(polynomial.Polynomial, nbElmt)
	pk.LS3 = make(polynomial.Polynomial, nbElmt)
	for i := 0; i < nbElmt; i++ {
		pk.LS1[i].Set(&sID[pk.Permutation[i]])
		pk.LS2[i].Set(&sID[pk.Permutation[nbElmt+i]])
		pk.LS3[i].Set(&sID[pk.Permutation[2*nbElmt+i]])
	}
	pk.CS1 = make(polynomial.Polynomial, nbElmt)
	pk.CS2 = make(polynomial.Polynomial, nbElmt)
	pk.CS3 = make(polynomial.Polynomial, nbElmt)
	copy(pk.CS1, pk.LS1)
	copy(pk.CS2, pk.LS2)
	copy(pk.CS3, pk.LS3)
	pk.DomainNum.FFTInverse(pk.CS1, fft.DIF, 0)
	pk.DomainNum.FFTInverse(pk.CS2, fft.DIF, 0)
	pk.DomainNum.FFTInverse(pk.CS3, fft.DIF, 0)
	fft.BitReverse(pk.CS1)
	fft.BitReverse(pk.CS2)
	fft.BitReverse(pk.CS3)
}