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  }