arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/verifier/internal/gates/random_access_gate.go
verifier/internal/gates/random_access_gate.goRaw
  1package gates
  2
  3import (
  4	"fmt"
  5	"regexp"
  6	"strconv"
  7
  8	"github.com/consensys/gnark/frontend"
  9	"github.com/succinctlabs/gnark-plonky2-verifier/field"
 10)
 11
 12var randomAccessGateRegex = regexp.MustCompile("RandomAccessGate { bits: (?P<bits>[0-9]+), num_copies: (?P<numCopies>[0-9]+), num_extra_constants: (?P<numExtraConstants>[0-9]+), _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=(?P<base>[0-9]+)>")
 13
 14func deserializeRandomAccessGate(parameters map[string]string) Gate {
 15	// Has the format "RandomAccessGate { bits: 2, num_copies: 13, num_extra_constants: 2, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
 16	bits, hasBits := parameters["bits"]
 17	numCopies, hasNumCopies := parameters["numCopies"]
 18	numExtraConstants, hasNumExtraConstants := parameters["numExtraConstants"]
 19
 20	if !hasBits || !hasNumCopies || !hasNumExtraConstants {
 21		panic("missing bits, numCopies, numExtraConstants or base in RandomAccessGate")
 22	}
 23
 24	bitsInt, err := strconv.ParseUint(bits, 10, 64)
 25	if err != nil {
 26		panic("invalid bits in RandomAccessGate")
 27	}
 28
 29	numCopiesInt, err := strconv.ParseUint(numCopies, 10, 64)
 30	if err != nil {
 31		panic("invalid numCopies in RandomAccessGate")
 32	}
 33
 34	numExtraConstantsInt, err := strconv.ParseUint(numExtraConstants, 10, 64)
 35	if err != nil {
 36		panic("invalid numExtraConstants in RandomAccessGate")
 37	}
 38
 39	return NewRandomAccessGate(bitsInt, numCopiesInt, numExtraConstantsInt)
 40}
 41
 42type RandomAccessGate struct {
 43	bits              uint64
 44	numCopies         uint64
 45	numExtraConstants uint64
 46}
 47
 48func NewRandomAccessGate(bits uint64, numCopies uint64, numExtraConstants uint64) *RandomAccessGate {
 49	return &RandomAccessGate{
 50		bits:              bits,
 51		numCopies:         numCopies,
 52		numExtraConstants: numExtraConstants,
 53	}
 54}
 55
 56func (g *RandomAccessGate) Id() string {
 57	return fmt.Sprintf("RandomAccessGate { bits: %d, num_copies: %d, num_extra_constants: %d }", g.bits, g.numCopies, g.numExtraConstants)
 58}
 59
 60func (g *RandomAccessGate) vecSize() uint64 {
 61	return 1 << g.bits
 62}
 63
 64func (g *RandomAccessGate) WireAccessIndex(copy uint64) uint64 {
 65	if copy >= g.numCopies {
 66		panic("RandomAccessGate.WireAccessIndex called with copy >= num_copies")
 67	}
 68	return (2 + g.vecSize()) * copy
 69}
 70
 71func (g *RandomAccessGate) WireClaimedElement(copy uint64) uint64 {
 72	if copy >= g.numCopies {
 73		panic("RandomAccessGate.WireClaimedElement called with copy >= num_copies")
 74	}
 75
 76	return (2+g.vecSize())*copy + 1
 77}
 78
 79func (g *RandomAccessGate) WireListItem(i uint64, copy uint64) uint64 {
 80	if i >= g.vecSize() {
 81		panic("RandomAccessGate.WireListItem called with i >= vec_size")
 82	}
 83	if copy >= g.numCopies {
 84		panic("RandomAccessGate.WireListItem called with copy >= num_copies")
 85	}
 86
 87	return (2+g.vecSize())*copy + 2 + i
 88}
 89
 90func (g *RandomAccessGate) startExtraConstants() uint64 {
 91	return (2 + g.vecSize()) * g.numCopies
 92}
 93
 94func (g *RandomAccessGate) wireExtraConstant(i uint64) uint64 {
 95	if i >= g.numExtraConstants {
 96		panic("RandomAccessGate.wireExtraConstant called with i >= num_extra_constants")
 97	}
 98
 99	return g.startExtraConstants() + i
100}
101
102func (g *RandomAccessGate) NumRoutedWires() uint64 {
103	return g.startExtraConstants() + g.numExtraConstants
104}
105
106func (g *RandomAccessGate) WireBit(i uint64, copy uint64) uint64 {
107	if i >= g.bits {
108		panic("RandomAccessGate.WireBit called with i >= bits")
109	}
110	if copy >= g.numCopies {
111		panic("RandomAccessGate.WireBit called with copy >= num_copies")
112	}
113
114	return g.NumRoutedWires() + copy*g.bits + i
115}
116
117func (g *RandomAccessGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
118	two := field.QuadraticExtension{field.NewFieldElement(2), field.NewFieldElement(0)}
119	constraints := []field.QuadraticExtension{}
120
121	for copy := uint64(0); copy < g.numCopies; copy++ {
122		accessIndex := vars.localWires[g.WireAccessIndex(copy)]
123		listItems := []field.QuadraticExtension{}
124		for i := uint64(0); i < g.vecSize(); i++ {
125			listItems = append(listItems, vars.localWires[g.WireListItem(i, copy)])
126		}
127		claimedElement := vars.localWires[g.WireClaimedElement(copy)]
128		bits := []field.QuadraticExtension{}
129		for i := uint64(0); i < g.bits; i++ {
130			bits = append(bits, vars.localWires[g.WireBit(i, copy)])
131		}
132
133		// Assert that each bit wire value is indeed boolean.
134		for _, b := range bits {
135			bSquared := qeAPI.MulExtension(b, b)
136			constraints = append(constraints, qeAPI.SubExtension(bSquared, b))
137		}
138
139		// Assert that the binary decomposition was correct.
140		reconstructedIndex := qeAPI.ReduceWithPowers(bits, two)
141		constraints = append(constraints, qeAPI.SubExtension(reconstructedIndex, accessIndex))
142
143		for _, b := range bits {
144			listItemsTmp := []field.QuadraticExtension{}
145			for i := 0; i < len(listItems); i += 2 {
146				x := listItems[i]
147				y := listItems[i+1]
148
149				// This is computing `if b { x } else { y }`
150				// i.e. `bx - (by-y)`.
151				mul1 := qeAPI.MulExtension(b, x)
152				sub1 := qeAPI.SubExtension(mul1, x)
153
154				mul2 := qeAPI.MulExtension(b, y)
155				sub2 := qeAPI.SubExtension(mul2, sub1)
156
157				listItemsTmp = append(listItemsTmp, sub2)
158			}
159			listItems = listItemsTmp
160		}
161
162		if len(listItems) != 1 {
163			panic("listItems(len) != 1")
164		}
165
166		constraints = append(constraints, qeAPI.SubExtension(listItems[0], claimedElement))
167	}
168
169	for i := uint64(0); i < g.numExtraConstants; i++ {
170		constraints = append(constraints, qeAPI.SubExtension(vars.localConstants[i], vars.localWires[g.wireExtraConstant(i)]))
171	}
172
173	return constraints
174}