You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
4.0 KiB

package plonky2_verifier
import (
"fmt"
. "gnark-plonky2-verifier/field"
)
type RandomAccessGate struct {
bits uint64
numCopies uint64
numExtraConstants uint64
}
func NewRandomAccessGate(bits uint64, numCopies uint64, numExtraConstants uint64) *RandomAccessGate {
return &RandomAccessGate{
bits: bits,
numCopies: numCopies,
numExtraConstants: numExtraConstants,
}
}
func (g *RandomAccessGate) Id() string {
return fmt.Sprintf("RandomAccessGate { bits: %d, num_copies: %d, num_extra_constants: %d }", g.bits, g.numCopies, g.numExtraConstants)
}
func (g *RandomAccessGate) vecSize() uint64 {
return 1 << g.bits
}
func (g *RandomAccessGate) WireAccessIndex(copy uint64) uint64 {
if copy >= g.numCopies {
panic("RandomAccessGate.WireAccessIndex called with copy >= num_copies")
}
return (2 + g.vecSize()) * copy
}
func (g *RandomAccessGate) WireClaimedElement(copy uint64) uint64 {
if copy >= g.numCopies {
panic("RandomAccessGate.WireClaimedElement called with copy >= num_copies")
}
return (2+g.vecSize())*copy + 1
}
func (g *RandomAccessGate) WireListItem(i uint64, copy uint64) uint64 {
if i >= g.vecSize() {
panic("RandomAccessGate.WireListItem called with i >= vec_size")
}
if copy >= g.numCopies {
panic("RandomAccessGate.WireListItem called with copy >= num_copies")
}
return (2+g.vecSize())*copy + 2 + i
}
func (g *RandomAccessGate) startExtraConstants() uint64 {
return (2 + g.vecSize()) * g.numCopies
}
func (g *RandomAccessGate) wireExtraConstant(i uint64) uint64 {
if i >= g.numExtraConstants {
panic("RandomAccessGate.wireExtraConstant called with i >= num_extra_constants")
}
return g.startExtraConstants() + i
}
func (g *RandomAccessGate) NumRoutedWires() uint64 {
return g.startExtraConstants() + g.numExtraConstants
}
func (g *RandomAccessGate) WireBit(i uint64, copy uint64) uint64 {
if i >= g.bits {
panic("RandomAccessGate.WireBit called with i >= bits")
}
if copy >= g.numCopies {
panic("RandomAccessGate.WireBit called with copy >= num_copies")
}
return g.NumRoutedWires() + copy*g.bits + i
}
func (g *RandomAccessGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
two := QuadraticExtension{NewFieldElement(2), NewFieldElement(0)}
constraints := []QuadraticExtension{}
for copy := uint64(0); copy < g.numCopies; copy++ {
accessIndex := vars.localWires[g.WireAccessIndex(copy)]
listItems := []QuadraticExtension{}
for i := uint64(0); i < g.vecSize(); i++ {
listItems = append(listItems, vars.localWires[g.WireListItem(i, copy)])
}
claimedElement := vars.localWires[g.WireClaimedElement(copy)]
bits := []QuadraticExtension{}
for i := uint64(0); i < g.bits; i++ {
bits = append(bits, vars.localWires[g.WireBit(i, copy)])
}
// Assert that each bit wire value is indeed boolean.
for _, b := range bits {
bSquared := p.qeAPI.MulExtension(b, b)
constraints = append(constraints, p.qeAPI.SubExtension(bSquared, b))
}
// Assert that the binary decomposition was correct.
reconstructedIndex := p.qeAPI.ReduceWithPowers(bits, two)
constraints = append(constraints, p.qeAPI.SubExtension(reconstructedIndex, accessIndex))
for _, b := range bits {
listItemsTmp := []QuadraticExtension{}
for i := 0; i < len(listItems); i += 2 {
x := listItems[i]
y := listItems[i+1]
// This is computing `if b { x } else { y }`
// i.e. `bx - (by-y)`.
mul1 := p.qeAPI.MulExtension(b, x)
sub1 := p.qeAPI.SubExtension(mul1, x)
mul2 := p.qeAPI.MulExtension(b, y)
sub2 := p.qeAPI.SubExtension(mul2, sub1)
listItemsTmp = append(listItemsTmp, sub2)
}
listItems = listItemsTmp
}
if len(listItems) != 1 {
panic("listItems(len) != 1")
}
constraints = append(constraints, p.qeAPI.SubExtension(listItems[0], claimedElement))
}
for i := uint64(0); i < g.numExtraConstants; i++ {
constraints = append(constraints, p.qeAPI.SubExtension(vars.localConstants[i], vars.localWires[g.wireExtraConstant(i)]))
}
return constraints
}