github.com/consensys/gnark@v0.11.0/constraint/r1cs.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 R1CS interface { 18 ConstraintSystem 19 20 // AddR1C adds a constraint to the system and returns its id 21 // This does not check for validity of the constraint. 22 AddR1C(r1c R1C, bID BlueprintID) int 23 24 // GetR1Cs return the list of R1C 25 // See StringBuilder for more info. 26 // ! this is an experimental API. 27 GetR1Cs() []R1C 28 29 // GetR1CIterator returns an R1CIterator to iterate on the R1C constraints of the system. 30 GetR1CIterator() R1CIterator 31 } 32 33 // R1CIterator facilitates iterating through R1C constraints. 34 type R1CIterator struct { 35 R1C 36 cs *System 37 n int 38 } 39 40 // Next returns the next R1C or nil if end. Caller must not store the result since the 41 // same memory space is re-used for subsequent calls to Next. 42 func (it *R1CIterator) Next() *R1C { 43 if it.n >= it.cs.GetNbInstructions() { 44 return nil 45 } 46 inst := it.cs.Instructions[it.n] 47 it.n++ 48 blueprint := it.cs.Blueprints[inst.BlueprintID] 49 if bc, ok := blueprint.(BlueprintR1C); ok { 50 bc.DecompressR1C(&it.R1C, inst.Unpack(it.cs)) 51 return &it.R1C 52 } 53 return it.Next() 54 } 55 56 // // IsValid perform post compilation checks on the Variables 57 // // 58 // // 1. checks that all user inputs are referenced in at least one constraint 59 // // 2. checks that all hints are constrained 60 // func (r1cs *R1CSCore) CheckUnconstrainedWires() error { 61 // return nil 62 63 // // TODO @gbotrel add unit test for that. 64 65 // inputConstrained := make([]bool, r1cs.GetNbSecretVariables()+r1cs.GetNbPublicVariables()) 66 // // one wire does not need to be constrained 67 // inputConstrained[0] = true 68 // cptInputs := len(inputConstrained) - 1 // marking 1 wire as already constrained // TODO @gbotrel check that 69 // if cptInputs == 0 { 70 // return errors.New("invalid constraint system: no input defined") 71 // } 72 73 // cptHints := len(r1cs.MHints) 74 // mHintsConstrained := make(map[int]bool) 75 76 // // for each constraint, we check the linear expressions and mark our inputs / hints as constrained 77 // processLinearExpression := func(l LinearExpression) { 78 // for _, t := range l { 79 // if t.CoeffID() == CoeffIdZero { 80 // // ignore zero coefficient, as it does not constraint the Variable 81 // // though, we may want to flag that IF the Variable doesn't appear else where 82 // continue 83 // } 84 // vID := t.WireID() 85 // if vID < len(inputConstrained) { 86 // if !inputConstrained[vID] { 87 // inputConstrained[vID] = true 88 // cptInputs-- 89 // } 90 // } else { 91 // // internal variable, let's check if it's a hint 92 // if _, ok := r1cs.MHints[vID]; ok { 93 // if !mHintsConstrained[vID] { 94 // mHintsConstrained[vID] = true 95 // cptHints-- 96 // } 97 // } 98 // } 99 100 // } 101 // } 102 // for _, r1c := range r1cs.Constraints { 103 // processLinearExpression(r1c.L) 104 // processLinearExpression(r1c.R) 105 // processLinearExpression(r1c.O) 106 107 // if cptHints|cptInputs == 0 { 108 // return nil // we can stop. 109 // } 110 111 // } 112 113 // // something is a miss, we build the error string 114 // var sbb strings.Builder 115 // if cptInputs != 0 { 116 // sbb.WriteString(strconv.Itoa(cptInputs)) 117 // sbb.WriteString(" unconstrained input(s):") 118 // sbb.WriteByte('\n') 119 // for i := 0; i < len(inputConstrained) && cptInputs != 0; i++ { 120 // if !inputConstrained[i] { 121 // if i < len(r1cs.Public) { 122 // sbb.WriteString(r1cs.Public[i]) 123 // } else { 124 // sbb.WriteString(r1cs.Secret[i-len(r1cs.Public)]) 125 // } 126 127 // sbb.WriteByte('\n') 128 // cptInputs-- 129 // } 130 // } 131 // sbb.WriteByte('\n') 132 // return errors.New(sbb.String()) 133 // } 134 135 // if cptHints != 0 { 136 // // TODO @gbotrel @ivokub investigate --> emulated hints seems to go in this path a lot. 137 // sbb.WriteString(strconv.Itoa(cptHints)) 138 // sbb.WriteString(" unconstrained hints; i.e. wire created through NewHint() but doesn't not appear in the constraint system") 139 // sbb.WriteByte('\n') 140 // log := logger.Logger() 141 // log.Warn().Err(errors.New(sbb.String())).Send() 142 // return nil 143 // // TODO we may add more debug info here ā idea, in NewHint, take the debug stack, and store in the hint map some 144 // // debugInfo to find where a hint was declared (and not constrained) 145 // } 146 // return errors.New(sbb.String()) 147 // } 148 149 // R1C used to compute the wires 150 type R1C struct { 151 L, R, O LinearExpression 152 } 153 154 // String formats a R1C as Lā R == O 155 func (r1c *R1C) String(r Resolver) string { 156 sbb := NewStringBuilder(r) 157 sbb.WriteLinearExpression(r1c.L) 158 sbb.WriteString(" ā ") 159 sbb.WriteLinearExpression(r1c.R) 160 sbb.WriteString(" == ") 161 sbb.WriteLinearExpression(r1c.O) 162 return sbb.String() 163 }