Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions frontend/cs/scs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,12 +701,14 @@ func (builder *builder) ToCanonicalVariable(v frontend.Variable) frontend.Canoni
func (builder *builder) GetWireConstraints(wires []frontend.Variable, addMissing bool) ([][2]int, error) {
// construct a lookup table table for later quick access when iterating over instructions
lookup := make(map[int]struct{})
for _, w := range wires {
wireTerms := make([]expr.Term, len(wires)) // stores the term of each wire.
for i, w := range wires {
ww, ok := w.(expr.Term)
if !ok {
panic("input wire is not a Term")
}
lookup[ww.WireID()] = struct{}{}
wireTerms[i] = ww
}
nbPub := builder.cs.GetNbPublicVariables()
res := make([][2]int, 0, len(wires))
Expand All @@ -731,7 +733,15 @@ func (builder *builder) GetWireConstraints(wires []frontend.Variable, addMissing
}
if addMissing {
nbWitnessWires := builder.cs.GetNbPublicVariables() + builder.cs.GetNbSecretVariables()
for k := range lookup {
// It is important to iterate over wireTerms here as doing it over [lookup]
// would result in a non-deterministic order of constraints.
for _, ww := range wireTerms {

if _, ok := lookup[ww.WireID()]; !ok {
continue
}

k := ww.WireID()
if k >= nbWitnessWires {
return nil, fmt.Errorf("addMissing is true, but wire %d is not a witness", k)
}
Expand All @@ -741,6 +751,7 @@ func (builder *builder) GetWireConstraints(wires []frontend.Variable, addMissing
QL: constraint.CoeffIdOne,
QO: constraint.CoeffIdMinusOne,
}, builder.genericGate)

res = append(res, [2]int{nbPub + constraintIdx, 0})
delete(lookup, k)
}
Expand Down Expand Up @@ -777,7 +788,7 @@ func (builder *builder) GetWireConstraints(wires []frontend.Variable, addMissing
//
// ```
//
// GetWiresConstraintsNoDuplicate([]frontend.Variable{a, a, b, a, c}) => wa, wb, wc
// GetWiresConstraints([]frontend.Variable{a, a, b, a, c}) => wa, wb, wc
//
// ```
func (builder *builder) GetWiresConstraintExact(wires []frontend.Variable, addMissing bool) ([][2]int, error) {
Expand All @@ -787,6 +798,9 @@ func (builder *builder) GetWiresConstraintExact(wires []frontend.Variable, addMi
// canonical variables: therefore not to constants and not too terms
// with a coeff different from 1. This may add constraints but has the
// benefit of making it simpler to read the LRO values.
//
// wireIDsSetOrdered stores the same values as wireIDsSet but in order
// of insertion. This is necessary to ensure
var (
wireIDsSet = make(map[int]struct{})
wireTerms = make([]expr.Term, len(wires))
Expand Down Expand Up @@ -854,15 +868,24 @@ func (builder *builder) GetWiresConstraintExact(wires []frontend.Variable, addMi
}

if addMissing {
for k := range wireIDsSet {
for _, ww := range wireTerms {

// The above loop removes the wireIDs from the set when they are
// found. This means that a wireID is missing if and only if it
// is still in [wireIDsSet].
if _, isIndeedMissing := wireIDsSet[ww.VID]; !isIndeedMissing {
continue
}

constraintIdx := builder.cs.AddSparseR1C(constraint.SparseR1C{
XA: uint32(k),
XC: uint32(k),
XA: uint32(ww.VID),
XC: uint32(ww.VID),
QL: constraint.CoeffIdOne,
QO: constraint.CoeffIdMinusOne,
}, builder.genericGate)
foundWireIDPosition[k] = [2]int{nbPub + constraintIdx, 0}
delete(wireIDsSet, k)

foundWireIDPosition[ww.VID] = [2]int{nbPub + constraintIdx, 0}
delete(wireIDsSet, ww.VID)
}
}

Expand Down