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 }