github.com/consensys/gnark@v0.11.0/constraint/r1cs_sparse.go (about) 1 // Copyright 2020 ConsenSys AG 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package constraint 16 17 type SparseR1CS interface { 18 ConstraintSystem 19 20 // AddSparseR1C adds a constraint to the constraint system. 21 AddSparseR1C(c SparseR1C, bID BlueprintID) int 22 23 // GetSparseR1Cs return the list of SparseR1C 24 // See StringBuilder for more info. 25 // ! this is an experimental API. 26 GetSparseR1Cs() []SparseR1C 27 28 // GetSparseR1CIterator returns an SparseR1CIterator to iterate on the SparseR1C constraints of the system. 29 GetSparseR1CIterator() SparseR1CIterator 30 } 31 32 // SparseR1CIterator facilitates iterating through SparseR1C constraints. 33 type SparseR1CIterator struct { 34 SparseR1C 35 cs *System 36 n int 37 } 38 39 // Next returns the next SparseR1C or nil if end. Caller must not store the result since the 40 // same memory space is re-used for subsequent calls to Next. 41 func (it *SparseR1CIterator) Next() *SparseR1C { 42 if it.n >= it.cs.GetNbInstructions() { 43 return nil 44 } 45 inst := it.cs.Instructions[it.n] 46 it.n++ 47 blueprint := it.cs.Blueprints[inst.BlueprintID] 48 if bc, ok := blueprint.(BlueprintSparseR1C); ok { 49 bc.DecompressSparseR1C(&it.SparseR1C, inst.Unpack(it.cs)) 50 return &it.SparseR1C 51 } 52 return it.Next() 53 } 54 55 // func (system *SparseR1CSCore) CheckUnconstrainedWires() error { 56 // // TODO @gbotrel add unit test for that. 57 // return nil 58 // inputConstrained := make([]bool, system.GetNbSecretVariables()+system.GetNbPublicVariables()) 59 // cptInputs := len(inputConstrained) 60 // if cptInputs == 0 { 61 // return errors.New("invalid constraint system: no input defined") 62 // } 63 64 // cptHints := len(system.MHints) 65 // mHintsConstrained := make(map[int]bool) 66 67 // // for each constraint, we check the terms and mark our inputs / hints as constrained 68 // processTerm := func(t Term) { 69 70 // // L and M[0] handles the same wire but with a different coeff 71 // vID := t.WireID() 72 // if t.CoeffID() != CoeffIdZero { 73 // if vID < len(inputConstrained) { 74 // if !inputConstrained[vID] { 75 // inputConstrained[vID] = true 76 // cptInputs-- 77 // } 78 // } else { 79 // // internal variable, let's check if it's a hint 80 // if _, ok := system.MHints[vID]; ok { 81 // vID -= (system.GetNbPublicVariables() + system.GetNbSecretVariables()) 82 // if !mHintsConstrained[vID] { 83 // mHintsConstrained[vID] = true 84 // cptHints-- 85 // } 86 // } 87 // } 88 // } 89 90 // } 91 // for _, c := range system.Constraints { 92 // processTerm(c.L) 93 // processTerm(c.R) 94 // processTerm(c.M[0]) 95 // processTerm(c.M[1]) 96 // processTerm(c.O) 97 // if cptHints|cptInputs == 0 { 98 // return nil // we can stop. 99 // } 100 101 // } 102 103 // // something is a miss, we build the error string 104 // var sbb strings.Builder 105 // if cptInputs != 0 { 106 // sbb.WriteString(strconv.Itoa(cptInputs)) 107 // sbb.WriteString(" unconstrained input(s):") 108 // sbb.WriteByte('\n') 109 // for i := 0; i < len(inputConstrained) && cptInputs != 0; i++ { 110 // if !inputConstrained[i] { 111 // if i < len(system.Public) { 112 // sbb.WriteString(system.Public[i]) 113 // } else { 114 // sbb.WriteString(system.Secret[i-len(system.Public)]) 115 // } 116 // sbb.WriteByte('\n') 117 // cptInputs-- 118 // } 119 // } 120 // sbb.WriteByte('\n') 121 // } 122 123 // if cptHints != 0 { 124 // sbb.WriteString(strconv.Itoa(cptHints)) 125 // sbb.WriteString(" unconstrained hints") 126 // sbb.WriteByte('\n') 127 // // TODO we may add more debug info here → idea, in NewHint, take the debug stack, and store in the hint map some 128 // // debugInfo to find where a hint was declared (and not constrained) 129 // } 130 // return errors.New(sbb.String()) 131 // } 132 133 type CommitmentConstraint uint32 134 135 const ( 136 NOT CommitmentConstraint = 0 137 COMMITTED CommitmentConstraint = 1 138 COMMITMENT CommitmentConstraint = 2 139 ) 140 141 // SparseR1C represent a PlonK-ish constraint 142 // qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC -committed?*Bsb22Commitments-commitment?*commitmentValue == 0 143 type SparseR1C struct { 144 XA, XB, XC uint32 145 QL, QR, QO, QM, QC uint32 146 Commitment CommitmentConstraint 147 } 148 149 func (c *SparseR1C) Clear() { 150 *c = SparseR1C{} 151 } 152 153 // String formats the constraint as qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 154 func (c *SparseR1C) String(r Resolver) string { 155 sbb := NewStringBuilder(r) 156 sbb.WriteTerm(Term{CID: c.QL, VID: c.XA}) 157 sbb.WriteString(" + ") 158 sbb.WriteTerm(Term{CID: c.QR, VID: c.XB}) 159 sbb.WriteString(" + ") 160 sbb.WriteTerm(Term{CID: c.QO, VID: c.XC}) 161 if qM := sbb.CoeffToString(int(c.QM)); qM != "0" { 162 xa := sbb.VariableToString(int(c.XA)) 163 xb := sbb.VariableToString(int(c.XB)) 164 sbb.WriteString(" + ") 165 sbb.WriteString(qM) 166 sbb.WriteString("⋅(") 167 sbb.WriteString(xa) 168 sbb.WriteString("×") 169 sbb.WriteString(xb) 170 sbb.WriteByte(')') 171 } 172 sbb.WriteString(" + ") 173 sbb.WriteString(r.CoeffToString(int(c.QC))) 174 sbb.WriteString(" == 0") 175 return sbb.String() 176 }