2023-05-19 19:49:14 -07:00
package gates
2023-05-16 17:11:01 -07:00
import (
"fmt"
2023-05-18 15:30:32 -07:00
"regexp"
"strconv"
2023-05-19 19:49:14 -07:00
"github.com/consensys/gnark/frontend"
2023-07-24 16:08:17 -07:00
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
2023-05-16 17:11:01 -07:00
)
2023-05-18 15:30:32 -07:00
var 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]+)>" )
2023-05-19 19:49:14 -07:00
func deserializeRandomAccessGate ( parameters map [ string ] string ) Gate {
2023-05-18 15:30:32 -07:00
// Has the format "RandomAccessGate { bits: 2, num_copies: 13, num_extra_constants: 2, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
bits , hasBits := parameters [ "bits" ]
numCopies , hasNumCopies := parameters [ "numCopies" ]
numExtraConstants , hasNumExtraConstants := parameters [ "numExtraConstants" ]
if ! hasBits || ! hasNumCopies || ! hasNumExtraConstants {
panic ( "missing bits, numCopies, numExtraConstants or base in RandomAccessGate" )
}
bitsInt , err := strconv . ParseUint ( bits , 10 , 64 )
if err != nil {
panic ( "invalid bits in RandomAccessGate" )
}
numCopiesInt , err := strconv . ParseUint ( numCopies , 10 , 64 )
if err != nil {
panic ( "invalid numCopies in RandomAccessGate" )
}
numExtraConstantsInt , err := strconv . ParseUint ( numExtraConstants , 10 , 64 )
if err != nil {
panic ( "invalid numExtraConstants in RandomAccessGate" )
}
2023-12-19 13:00:22 -08:00
base , hasBase := parameters [ "base" ]
if ! hasBase {
panic ( "Missing field base in RandomAccessGate" )
}
baseInt , err := strconv . Atoi ( base )
if err != nil {
panic ( "Invalid base field in RandomAccessGate" )
}
if baseInt != gl . D {
panic ( "Expected base field in RandomAccessGate to equal gl.D" )
}
2023-05-18 15:30:32 -07:00
return NewRandomAccessGate ( bitsInt , numCopiesInt , numExtraConstantsInt )
}
2023-05-16 17:11:01 -07:00
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
}
2023-07-24 16:08:17 -07:00
func ( g * RandomAccessGate ) EvalUnfiltered (
api frontend . API ,
glApi gl . Chip ,
vars EvaluationVars ,
) [ ] gl . QuadraticExtensionVariable {
two := gl . NewVariable ( 2 ) . ToQuadraticExtension ( )
constraints := [ ] gl . QuadraticExtensionVariable { }
2023-05-16 17:11:01 -07:00
for copy := uint64 ( 0 ) ; copy < g . numCopies ; copy ++ {
accessIndex := vars . localWires [ g . WireAccessIndex ( copy ) ]
2023-07-24 16:08:17 -07:00
listItems := [ ] gl . QuadraticExtensionVariable { }
2023-05-16 17:11:01 -07:00
for i := uint64 ( 0 ) ; i < g . vecSize ( ) ; i ++ {
listItems = append ( listItems , vars . localWires [ g . WireListItem ( i , copy ) ] )
}
claimedElement := vars . localWires [ g . WireClaimedElement ( copy ) ]
2023-07-24 16:08:17 -07:00
bits := [ ] gl . QuadraticExtensionVariable { }
2023-05-16 17:11:01 -07:00
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 {
2023-07-24 16:08:17 -07:00
bSquared := glApi . MulExtension ( b , b )
constraints = append ( constraints , glApi . SubExtension ( bSquared , b ) )
2023-05-16 17:11:01 -07:00
}
// Assert that the binary decomposition was correct.
2023-07-24 16:08:17 -07:00
reconstructedIndex := glApi . ReduceWithPowers ( bits , two )
constraints = append ( constraints , glApi . SubExtension ( reconstructedIndex , accessIndex ) )
2023-05-16 17:11:01 -07:00
for _ , b := range bits {
2023-07-24 16:08:17 -07:00
listItemsTmp := [ ] gl . QuadraticExtensionVariable { }
2023-05-16 17:11:01 -07:00
for i := 0 ; i < len ( listItems ) ; i += 2 {
x := listItems [ i ]
y := listItems [ i + 1 ]
// This is computing `if b { x } else { y }`
2023-12-19 12:22:19 -08:00
// i.e. `by - (bx - x)`.
2023-07-24 16:08:17 -07:00
mul1 := glApi . MulExtension ( b , x )
sub1 := glApi . SubExtension ( mul1 , x )
2023-05-16 17:11:01 -07:00
2023-07-24 16:08:17 -07:00
mul2 := glApi . MulExtension ( b , y )
sub2 := glApi . SubExtension ( mul2 , sub1 )
2023-05-16 17:11:01 -07:00
listItemsTmp = append ( listItemsTmp , sub2 )
}
listItems = listItemsTmp
}
if len ( listItems ) != 1 {
panic ( "listItems(len) != 1" )
}
2023-07-24 16:08:17 -07:00
constraints = append ( constraints , glApi . SubExtension ( listItems [ 0 ] , claimedElement ) )
2023-05-16 17:11:01 -07:00
}
for i := uint64 ( 0 ) ; i < g . numExtraConstants ; i ++ {
2023-07-24 16:08:17 -07:00
constraints = append ( constraints , glApi . SubExtension ( vars . localConstants [ i ] , vars . localWires [ g . wireExtraConstant ( i ) ] ) )
2023-05-16 17:11:01 -07:00
}
return constraints
}