Skip to content

Commit 7ec673b

Browse files
ivokubCopilot
andauthored
refactor: PLONK commitment input and output registration (#1642)
Co-authored-by: Copilot <[email protected]>
1 parent 7e6ad4d commit 7ec673b

File tree

3 files changed

+59
-19
lines changed

3 files changed

+59
-19
lines changed

constraint/commitment.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type Groth16Commitment struct {
1616
type PlonkCommitment struct {
1717
Committed []int // sorted list of id's of committed variables in groth16. in plonk, list of indexes of constraints defining committed values
1818
CommitmentIndex int // CommitmentIndex index of the constraint defining the commitment
19+
Width int // width of the commitment (number of field elements). Should be 1 in case of large field, but can be larger in case of small field.
1920
}
2021

2122
type Commitment interface{}

frontend/api.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ type BatchInverter interface {
150150
BatchInvert(i1 []Variable) []Variable
151151
}
152152

153+
// PlonkAPI represents specific methods implemented by PLONK (sparse-R1CS)
154+
// constraint system builders. These methods are not part of the generic [API]
155+
// and [Builder] interfaces to ensure circuit compatibility with different
156+
// frontends (R1CS etc.). Any user using this interface should have a fallback
157+
// if the underlying builder does not implement it.
153158
type PlonkAPI interface {
154159
// EvaluatePlonkExpression returns res = qL.a + qR.b + qM.ab + qC
155160
EvaluatePlonkExpression(a, b Variable, qL, qR, qM, qC int) Variable

frontend/cs/scs/api.go

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,56 @@ func (builder *builder[E]) Compiler() frontend.Compiler {
580580
return builder
581581
}
582582

583+
// AddPlonkCommitmentInputs registers variables to be committed to. The method
584+
// iterates over the variables and adds constraints to indicate they are to be
585+
// committed to. The method returns the list of constraint indexes corresponding
586+
// to each input variable. Does not perform any deduplication or constant
587+
// filtering.
588+
//
589+
// NB! This method does not create the commitment itself. The user must call the
590+
// hint for computing the commitment value, registering the commitment output
591+
// using [AddPlonkCommitmentOutputs]. Note: [AddPlonkCommitmentOutputs] already
592+
// handles adding the commitment to the constraint system, so the user does not
593+
// need to call [constraint.System.AddCommitment] separately.
594+
//
595+
// This method is not exposed in standard APIs - it is meant to be used
596+
// externally for implementing wide commitments. We also use it internally in
597+
// the [Commit] method.
598+
func (builder *builder[E]) AddPlonkCommitmentInputs(inputs []frontend.Variable) []int {
599+
committed := make([]int, len(inputs))
600+
for i, vI := range inputs { // TODO @Tabaie Perf; If public, just hash it
601+
vINeg := builder.Neg(vI).(expr.Term[E])
602+
committed[i] = builder.cs.GetNbConstraints()
603+
// a constraint to enforce consistency between the commitment and committed value
604+
// - v + comm(n) = 0
605+
builder.addPlonkConstraint(sparseR1C[E]{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED})
606+
}
607+
return committed
608+
}
609+
610+
// AddPlonkCommitmentOutputs registers the outputs of a commitment. The method
611+
// adds constraints to the constraint system to indicate that the outputs of a
612+
// commitment will be provided at proof time. The method takes as input the list
613+
// of constraint indexes corresponding to the committed variables and the list
614+
// of output variables.
615+
//
616+
// This method is not exposed in standard APIs - it is meant to be used
617+
// externally for implementing wide commitments. We also use it internally in
618+
// the [Commit] method.
619+
func (builder *builder[E]) AddPlonkCommitmentOutputs(committed []int, outs []frontend.Variable) error {
620+
commitmentConstraintIndex := builder.cs.GetNbConstraints()
621+
for _, out := range outs {
622+
outNeg := builder.Neg(out).(expr.Term[E])
623+
// RHS will be provided by both prover and verifier independently, as for a public wire
624+
builder.addPlonkConstraint(sparseR1C[E]{xa: outNeg.VID, qL: outNeg.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later
625+
}
626+
return builder.cs.AddCommitment(constraint.PlonkCommitment{
627+
CommitmentIndex: commitmentConstraintIndex,
628+
Committed: committed,
629+
Width: len(outs),
630+
})
631+
}
632+
583633
func (builder *builder[E]) Commit(v ...frontend.Variable) (frontend.Variable, error) {
584634
if smallfields.IsSmallField(builder.Field()) {
585635
return nil, fmt.Errorf("commitment not supported for small field %s", builder.Field())
@@ -588,15 +638,7 @@ func (builder *builder[E]) Commit(v ...frontend.Variable) (frontend.Variable, er
588638
commitments := builder.cs.GetCommitments().(constraint.PlonkCommitments)
589639
v = filterConstants[E](v) // TODO: @Tabaie Settle on a way to represent even constants; conventional hash?
590640

591-
committed := make([]int, len(v))
592-
593-
for i, vI := range v { // TODO @Tabaie Perf; If public, just hash it
594-
vINeg := builder.Neg(vI).(expr.Term[E])
595-
committed[i] = builder.cs.GetNbConstraints()
596-
// a constraint to enforce consistency between the commitment and committed value
597-
// - v + comm(n) = 0
598-
builder.addPlonkConstraint(sparseR1C[E]{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED})
599-
}
641+
committed := builder.AddPlonkCommitmentInputs(v)
600642

601643
inputs := make([]frontend.Variable, len(v)+1)
602644
inputs[0] = len(commitments) // commitment depth
@@ -605,16 +647,8 @@ func (builder *builder[E]) Commit(v ...frontend.Variable) (frontend.Variable, er
605647
if err != nil {
606648
return nil, err
607649
}
608-
609-
commitmentVar := builder.Neg(outs[0]).(expr.Term[E])
610-
commitmentConstraintIndex := builder.cs.GetNbConstraints()
611-
// RHS will be provided by both prover and verifier independently, as for a public wire
612-
builder.addPlonkConstraint(sparseR1C[E]{xa: commitmentVar.VID, qL: commitmentVar.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later
613-
614-
return outs[0], builder.cs.AddCommitment(constraint.PlonkCommitment{
615-
CommitmentIndex: commitmentConstraintIndex,
616-
Committed: committed,
617-
})
650+
outs = outs[:1]
651+
return outs[0], builder.AddPlonkCommitmentOutputs(committed, outs)
618652
}
619653

620654
// EvaluatePlonkExpression in the form of res = qL.a + qR.b + qM.ab + qC

0 commit comments

Comments
 (0)