ceremonyclient/bedlam/compiler/circuits/circ_index.go
Cassandra Heart e51992f3e8
OT
2025-03-23 21:11:16 -05:00

102 lines
1.9 KiB
Go

//
// Copyright (c) 2021-2023 Markku Rossi
//
// All rights reserved.
//
package circuits
import (
"fmt"
)
// NewIndex creates a new array element selection (index) circuit.
func NewIndex(cc *Compiler, size int, array, index, out []*Wire) error {
if len(array)%size != 0 {
return fmt.Errorf("array width %d must be multiple of element size %d",
len(array), size)
}
if len(out) < size {
return fmt.Errorf("out %d too small for element size %d",
len(out), size)
}
n := len(array) / size
if n == 0 {
for i := 0; i < len(out); i++ {
out[i] = cc.ZeroWire()
}
return nil
}
bits := 1
var length int
for length = 2; length < n; length *= 2 {
bits++
}
return newIndex(cc, bits-1, length, size, array, index, out)
}
func newIndex(cc *Compiler, bit, length, size int,
array, index, out []*Wire) error {
// Default "not found" value.
def := make([]*Wire, size)
for i := 0; i < size; i++ {
def[i] = cc.ZeroWire()
}
n := len(array) / size
if bit == 0 {
fVal := array[:size]
var tVal []*Wire
if n > 1 {
tVal = array[size : 2*size]
} else {
tVal = def
}
return NewMUX(cc, index[0:1], tVal, fVal, out)
}
length /= 2
fArray := array
if n > length {
fArray = fArray[:length*size]
}
if bit >= len(index) {
// Not enough bits to select upper half so just select from
// the lower half.
return newIndex(cc, bit-1, length, size, fArray, index, out)
}
fVal := make([]*Wire, size)
for i := 0; i < size; i++ {
fVal[i] = cc.Calloc.Wire()
}
err := newIndex(cc, bit-1, length, size, fArray, index, fVal)
if err != nil {
return err
}
var tVal []*Wire
if n > length {
tVal = make([]*Wire, size)
for i := 0; i < size; i++ {
tVal[i] = cc.Calloc.Wire()
}
err = newIndex(cc, bit-1, length, size,
array[length*size:], index, tVal)
if err != nil {
return err
}
} else {
tVal = def
}
return NewMUX(cc, index[bit:bit+1], tVal, fVal, out)
}