github.com/consensys/gnark@v0.11.0/constraint/blueprint_r1cs.go (about)

     1  package constraint
     2  
     3  // BlueprintGenericR1C implements Blueprint and BlueprintR1C.
     4  // Encodes
     5  //
     6  //	L * R == 0
     7  type BlueprintGenericR1C struct{}
     8  
     9  func (b *BlueprintGenericR1C) CalldataSize() int {
    10  	// size of linear expressions are unknown.
    11  	return -1
    12  }
    13  func (b *BlueprintGenericR1C) NbConstraints() int {
    14  	return 1
    15  }
    16  func (b *BlueprintGenericR1C) NbOutputs(inst Instruction) int {
    17  	return 0
    18  }
    19  
    20  func (b *BlueprintGenericR1C) CompressR1C(c *R1C, to *[]uint32) {
    21  	// we store total nb inputs, len L, len R, len O, and then the "flatten" linear expressions
    22  	nbInputs := 4 + 2*(len(c.L)+len(c.R)+len(c.O))
    23  	(*to) = append((*to), uint32(nbInputs))
    24  	(*to) = append((*to), uint32(len(c.L)), uint32(len(c.R)), uint32(len(c.O)))
    25  	for _, t := range c.L {
    26  		(*to) = append((*to), uint32(t.CoeffID()), uint32(t.WireID()))
    27  	}
    28  	for _, t := range c.R {
    29  		(*to) = append((*to), uint32(t.CoeffID()), uint32(t.WireID()))
    30  	}
    31  	for _, t := range c.O {
    32  		(*to) = append((*to), uint32(t.CoeffID()), uint32(t.WireID()))
    33  	}
    34  }
    35  
    36  func (b *BlueprintGenericR1C) DecompressR1C(c *R1C, inst Instruction) {
    37  	copySlice := func(slice *LinearExpression, expectedLen, idx int) {
    38  		if cap(*slice) >= expectedLen {
    39  			(*slice) = (*slice)[:expectedLen]
    40  		} else {
    41  			(*slice) = make(LinearExpression, expectedLen, expectedLen*2)
    42  		}
    43  		for k := 0; k < expectedLen; k++ {
    44  			(*slice)[k].CID = inst.Calldata[idx]
    45  			idx++
    46  			(*slice)[k].VID = inst.Calldata[idx]
    47  			idx++
    48  		}
    49  	}
    50  
    51  	lenL := int(inst.Calldata[1])
    52  	lenR := int(inst.Calldata[2])
    53  	lenO := int(inst.Calldata[3])
    54  
    55  	const offset = 4
    56  	copySlice(&c.L, lenL, offset)
    57  	copySlice(&c.R, lenR, offset+2*lenL)
    58  	copySlice(&c.O, lenO, offset+2*(lenL+lenR))
    59  }
    60  
    61  func (b *BlueprintGenericR1C) UpdateInstructionTree(inst Instruction, tree InstructionTree) Level {
    62  	// a R1C doesn't know which wires are input and which are outputs
    63  	lenL := int(inst.Calldata[1])
    64  	lenR := int(inst.Calldata[2])
    65  	lenO := int(inst.Calldata[3])
    66  
    67  	outputWires := make([]uint32, 0)
    68  	maxLevel := LevelUnset
    69  	walkWires := func(n, idx int) {
    70  		for k := 0; k < n; k++ {
    71  			wireID := inst.Calldata[idx+1]
    72  			idx += 2 // advance the offset (coeffID + wireID)
    73  			if !tree.HasWire(wireID) {
    74  				continue
    75  			}
    76  			if level := tree.GetWireLevel(wireID); level == LevelUnset {
    77  				outputWires = append(outputWires, wireID)
    78  			} else if level > maxLevel {
    79  				maxLevel = level
    80  			}
    81  		}
    82  	}
    83  
    84  	const offset = 4
    85  	walkWires(lenL, offset)
    86  	walkWires(lenR, offset+2*lenL)
    87  	walkWires(lenO, offset+2*(lenL+lenR))
    88  
    89  	// insert the new wires.
    90  	maxLevel++
    91  	for _, wireID := range outputWires {
    92  		tree.InsertWire(wireID, maxLevel)
    93  	}
    94  
    95  	return maxLevel
    96  }