arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/plonky2_verifier/random_access_gate.go
plonky2_verifier/random_access_gate.goRaw
  1package plonky2_verifier
  2
  3import (
  4	"fmt"
  5	. "gnark-plonky2-verifier/field"
  6)
  7
  8type RandomAccessGate struct {
  9	bits              uint64
 10	numCopies         uint64
 11	numExtraConstants uint64
 12}
 13
 14func NewRandomAccessGate(bits uint64, numCopies uint64, numExtraConstants uint64) *RandomAccessGate {
 15	return &RandomAccessGate{
 16		bits:              bits,
 17		numCopies:         numCopies,
 18		numExtraConstants: numExtraConstants,
 19	}
 20}
 21
 22func (g *RandomAccessGate) Id() string {
 23	return fmt.Sprintf("RandomAccessGate { bits: %d, num_copies: %d, num_extra_constants: %d }", g.bits, g.numCopies, g.numExtraConstants)
 24}
 25
 26func (g *RandomAccessGate) vecSize() uint64 {
 27	return 1 << g.bits
 28}
 29
 30func (g *RandomAccessGate) WireAccessIndex(copy uint64) uint64 {
 31	if copy >= g.numCopies {
 32		panic("RandomAccessGate.WireAccessIndex called with copy >= num_copies")
 33	}
 34	return (2 + g.vecSize()) * copy
 35}
 36
 37func (g *RandomAccessGate) WireClaimedElement(copy uint64) uint64 {
 38	if copy >= g.numCopies {
 39		panic("RandomAccessGate.WireClaimedElement called with copy >= num_copies")
 40	}
 41
 42	return (2+g.vecSize())*copy + 1
 43}
 44
 45func (g *RandomAccessGate) WireListItem(i uint64, copy uint64) uint64 {
 46	if i >= g.vecSize() {
 47		panic("RandomAccessGate.WireListItem called with i >= vec_size")
 48	}
 49	if copy >= g.numCopies {
 50		panic("RandomAccessGate.WireListItem called with copy >= num_copies")
 51	}
 52
 53	return (2+g.vecSize())*copy + 2 + i
 54}
 55
 56func (g *RandomAccessGate) startExtraConstants() uint64 {
 57	return (2 + g.vecSize()) * g.numCopies
 58}
 59
 60func (g *RandomAccessGate) wireExtraConstant(i uint64) uint64 {
 61	if i >= g.numExtraConstants {
 62		panic("RandomAccessGate.wireExtraConstant called with i >= num_extra_constants")
 63	}
 64
 65	return g.startExtraConstants() + i
 66}
 67
 68func (g *RandomAccessGate) NumRoutedWires() uint64 {
 69	return g.startExtraConstants() + g.numExtraConstants
 70}
 71
 72func (g *RandomAccessGate) WireBit(i uint64, copy uint64) uint64 {
 73	if i >= g.bits {
 74		panic("RandomAccessGate.WireBit called with i >= bits")
 75	}
 76	if copy >= g.numCopies {
 77		panic("RandomAccessGate.WireBit called with copy >= num_copies")
 78	}
 79
 80	return g.NumRoutedWires() + copy*g.bits + i
 81}
 82
 83func (g *RandomAccessGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
 84	two := QuadraticExtension{NewFieldElement(2), NewFieldElement(0)}
 85	constraints := []QuadraticExtension{}
 86
 87	for copy := uint64(0); copy < g.numCopies; copy++ {
 88		accessIndex := vars.localWires[g.WireAccessIndex(copy)]
 89		listItems := []QuadraticExtension{}
 90		for i := uint64(0); i < g.vecSize(); i++ {
 91			listItems = append(listItems, vars.localWires[g.WireListItem(i, copy)])
 92		}
 93		claimedElement := vars.localWires[g.WireClaimedElement(copy)]
 94		bits := []QuadraticExtension{}
 95		for i := uint64(0); i < g.bits; i++ {
 96			bits = append(bits, vars.localWires[g.WireBit(i, copy)])
 97		}
 98
 99		// Assert that each bit wire value is indeed boolean.
100		for _, b := range bits {
101			bSquared := p.qeAPI.MulExtension(b, b)
102			constraints = append(constraints, p.qeAPI.SubExtension(bSquared, b))
103		}
104
105		// Assert that the binary decomposition was correct.
106		reconstructedIndex := p.qeAPI.ReduceWithPowers(bits, two)
107		constraints = append(constraints, p.qeAPI.SubExtension(reconstructedIndex, accessIndex))
108
109		for _, b := range bits {
110			listItemsTmp := []QuadraticExtension{}
111			for i := 0; i < len(listItems); i += 2 {
112				x := listItems[i]
113				y := listItems[i+1]
114
115				// This is computing `if b { x } else { y }`
116				// i.e. `bx - (by-y)`.
117				mul1 := p.qeAPI.MulExtension(b, x)
118				sub1 := p.qeAPI.SubExtension(mul1, x)
119
120				mul2 := p.qeAPI.MulExtension(b, y)
121				sub2 := p.qeAPI.SubExtension(mul2, sub1)
122
123				listItemsTmp = append(listItemsTmp, sub2)
124			}
125			listItems = listItemsTmp
126		}
127
128		if len(listItems) != 1 {
129			panic("listItems(len) != 1")
130		}
131
132		constraints = append(constraints, p.qeAPI.SubExtension(listItems[0], claimedElement))
133	}
134
135	for i := uint64(0); i < g.numExtraConstants; i++ {
136		constraints = append(constraints, p.qeAPI.SubExtension(vars.localConstants[i], vars.localWires[g.wireExtraConstant(i)]))
137	}
138
139	return constraints
140}