func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness bls12_377witness.Witness, opt backend.ProverOption) (*Proof, error) {
	hFunc := sha256.New()
	fs := fiatshamir.NewTranscript(hFunc, "gamma", "alpha", "zeta")
	proof := &Proof{}
	var solution []fr.Element
	var err error
	if solution, err = spr.Solve(fullWitness, opt); err != nil {
		if !opt.Force {
			return nil, err
		} else {
			var r fr.Element
			_, _ = r.SetRandom()
			for i := spr.NbPublicVariables + spr.NbSecretVariables; i < len(solution); i++ {
				solution[i] = r
				r.Double(&r)
			}
		}
	}
	ll, lr, lo := computeLRO(spr, pk, solution)
	bcl, bcr, bco, err := computeBlindedLRO(ll, lr, lo, &pk.DomainNum)
	if err != nil {
		return nil, err
	}
	if err := commitToLRO(bcl, bcr, bco, proof, pk.Vk.KZGSRS); err != nil {
		return nil, err
	}
	gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2])
	if err != nil {
		return nil, err
	}
	var bz polynomial.Polynomial
	chZ := make(chan error, 1)
	var alpha fr.Element
	go func() {
		var err error
		bz, err = computeBlindedZ(ll, lr, lo, pk, gamma)
		if err != nil {
			chZ <- err
			close(chZ)
			return
		}
		if proof.Z, err = kzg.Commit(bz, pk.Vk.KZGSRS, runtime.NumCPU()*2); err != nil {
			chZ <- err
			close(chZ)
			return
		}
		alpha, err = deriveRandomness(&fs, "alpha", &proof.Z)
		chZ <- err
		close(chZ)
	}()
	var evalBL, evalBR, evalBO, evalBZ polynomial.Polynomial
	chEvalBL := make(chan struct{}, 1)
	chEvalBR := make(chan struct{}, 1)
	chEvalBO := make(chan struct{}, 1)
	go func() {
		evalBL = evaluateHDomain(bcl, &pk.DomainH)
		close(chEvalBL)
	}()
	go func() {
		evalBR = evaluateHDomain(bcr, &pk.DomainH)
		close(chEvalBR)
	}()
	go func() {
		evalBO = evaluateHDomain(bco, &pk.DomainH)
		close(chEvalBO)
	}()
	var constraintsInd, constraintsOrdering polynomial.Polynomial
	chConstraintInd := make(chan struct{}, 1)
	go func() {
		qk := make(polynomial.Polynomial, pk.DomainNum.Cardinality)
		copy(qk, fullWitness[:spr.NbPublicVariables])
		copy(qk[spr.NbPublicVariables:], pk.LQk[spr.NbPublicVariables:])
		pk.DomainNum.FFTInverse(qk, fft.DIF, 0)
		fft.BitReverse(qk)
		<-chEvalBL
		<-chEvalBR
		<-chEvalBO
		constraintsInd = evalConstraints(pk, evalBL, evalBR, evalBO, qk)
		close(chConstraintInd)
	}()
	chConstraintOrdering := make(chan error, 1)
	go func() {
		if err := <-chZ; err != nil {
			chConstraintOrdering <- err
			return
		}
		evalBZ = evaluateHDomain(bz, &pk.DomainH)
		<-chEvalBL
		<-chEvalBR
		<-chEvalBO
		constraintsOrdering = evalConstraintOrdering(pk, evalBZ, evalBL, evalBR, evalBO, gamma)
		chConstraintOrdering <- nil
		close(chConstraintOrdering)
	}()
	if err := <-chConstraintOrdering; err != nil {
		return nil, err
	}
	<-chConstraintInd
	h1, h2, h3 := computeH(pk, constraintsInd, constraintsOrdering, evalBZ, alpha)
	if err := commitToH(h1, h2, h3, proof, pk.Vk.KZGSRS); err != nil {
		return nil, err
	}
	zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2])
	if err != nil {
		return nil, err
	}
	var blzeta, brzeta, bozeta fr.Element
	var wgZetaEvals sync.WaitGroup
	wgZetaEvals.Add(3)
	go func() {
		blzeta = bcl.Eval(&zeta)
		wgZetaEvals.Done()
	}()
	go func() {
		brzeta = bcr.Eval(&zeta)
		wgZetaEvals.Done()
	}()
	go func() {
		bozeta = bco.Eval(&zeta)
		wgZetaEvals.Done()
	}()
	var zetaShifted fr.Element
	zetaShifted.Mul(&zeta, &pk.Vk.Generator)
	proof.ZShiftedOpening, err = kzg.Open(
		bz,
		&zetaShifted,
		&pk.DomainH,
		pk.Vk.KZGSRS,
	)
	if err != nil {
		return nil, err
	}
	bzuzeta := proof.ZShiftedOpening.ClaimedValue
	var (
		linearizedPolynomial       polynomial.Polynomial
		linearizedPolynomialDigest curve.G1Affine
		errLPoly                   error
	)
	chLpoly := make(chan struct{}, 1)
	go func() {
		wgZetaEvals.Wait()
		linearizedPolynomial = computeLinearizedPolynomial(
			blzeta,
			brzeta,
			bozeta,
			alpha,
			gamma,
			zeta,
			bzuzeta,
			bz,
			pk,
		)
		linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomial, pk.Vk.KZGSRS)
		close(chLpoly)
	}()
	var bZetaPowerm, bSize big.Int
	bSize.SetUint64(pk.DomainNum.Cardinality + 2)  
	var zetaPowerm fr.Element
	zetaPowerm.Exp(zeta, &bSize)
	zetaPowerm.ToBigIntRegular(&bZetaPowerm)
	foldedHDigest := proof.H[2]
	foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm)
	foldedHDigest.Add(&foldedHDigest, &proof.H[1])                    
	foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm)  
	foldedHDigest.Add(&foldedHDigest, &proof.H[0])                    
	foldedH := h3
	utils.Parallelize(len(foldedH), func(start, end int) {
		for i := start; i < end; i++ {
			foldedH[i].Mul(&foldedH[i], &zetaPowerm)  
			foldedH[i].Add(&foldedH[i], &h2[i])       
			foldedH[i].Mul(&foldedH[i], &zetaPowerm)  
			foldedH[i].Add(&foldedH[i], &h1[i])       
		}
	})
	<-chLpoly
	if errLPoly != nil {
		return nil, errLPoly
	}
	proof.BatchedProof, err = kzg.BatchOpenSinglePoint(
		[]polynomial.Polynomial{
			foldedH,
			linearizedPolynomial,
			bcl,
			bcr,
			bco,
			pk.CS1,
			pk.CS2,
		},
		[]kzg.Digest{
			foldedHDigest,
			linearizedPolynomialDigest,
			proof.LRO[0],
			proof.LRO[1],
			proof.LRO[2],
			pk.Vk.S[0],
			pk.Vk.S[1],
		},
		&zeta,
		hFunc,
		&pk.DomainH,
		pk.Vk.KZGSRS,
	)
	if err != nil {
		return nil, err
	}
	return proof, nil
}
Prove from the public data
package plonk
import (
	"crypto/sha256"
	"math/big"
	"math/bits"
	"runtime"
	"sync"
	"github.com/consensys/gnark-crypto/ecc/bls12-377/fr"
	curve "github.com/consensys/gnark-crypto/ecc/bls12-377"
	"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/polynomial"
	"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg"
	"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
	bls12_377witness "github.com/consensys/gnark/internal/backend/bls12-377/witness"
	"github.com/consensys/gnark/internal/backend/bls12-377/cs"
	"github.com/consensys/gnark-crypto/fiat-shamir"
	"github.com/consensys/gnark/backend"
	"github.com/consensys/gnark/internal/utils"
)
type Proof struct {
	LRO [3]kzg.Digest
	Z kzg.Digest
	H [3]kzg.Digest
	BatchedProof kzg.BatchOpeningProof
	ZShiftedOpening kzg.OpeningProof
}