ceremonyclient/bedlam/circuit/ioarg.go
Cassandra Heart dbd95bd9e9
v2.1.0 (#439)
* v2.1.0 [omit consensus and adjacent] - this commit will be amended with the full release after the file copy is complete

* 2.1.0 main node rollup
2025-09-30 02:48:15 -05:00

214 lines
4.3 KiB
Go

//
// Copyright (c) 2019-2024 Markku Rossi
//
// All rights reserved.
//
package circuit
import (
"fmt"
"math/big"
"strings"
"source.quilibrium.com/quilibrium/monorepo/bedlam/types"
)
// IO specifies circuit input and output arguments.
type IO []IOArg
// Size computes the size of the circuit input and output arguments in
// bits.
func (io IO) Size() int {
var sum int
for _, a := range io {
sum += int(a.Type.Bits)
}
return sum
}
func (io IO) String() string {
var str = ""
for i, a := range io {
if i > 0 {
str += ", "
}
if len(a.Name) > 0 {
str += a.Name + ":"
}
str += a.Type.String()
}
return str
}
// Split splits the value into separate I/O arguments.
func (io IO) Split(in *big.Int) []*big.Int {
var result []*big.Int
var bit int
for _, arg := range io {
r := big.NewInt(0)
for i := 0; i < int(arg.Type.Bits); i++ {
if in.Bit(bit) == 1 {
r = big.NewInt(0).SetBit(r, i, 1)
}
bit++
}
result = append(result, r)
}
return result
}
// IOArg describes circuit input argument.
type IOArg struct {
Name string
Type types.Info
Compound IO
}
func (io IOArg) String() string {
if len(io.Compound) > 0 {
return io.Compound.String()
}
if len(io.Name) > 0 {
return io.Name + ":" + io.Type.String()
}
return io.Type.String()
}
// Parse parses the I/O argument from the input string values.
func (io IOArg) Parse(inputs []string) (*big.Int, error) {
result := new(big.Int)
if len(io.Compound) == 0 {
if len(inputs) != 1 {
return nil,
fmt.Errorf("invalid amount of arguments, got %d, expected 1",
len(inputs))
}
switch io.Type.Type {
case types.TInt, types.TUint:
_, ok := result.SetString(inputs[0], 0)
if !ok {
return nil, fmt.Errorf("invalid input '%s' for %s",
inputs[0], io.Type)
}
case types.TBool:
switch inputs[0] {
case "0", "f", "false":
case "1", "t", "true":
result.SetInt64(1)
default:
return nil, fmt.Errorf("invalid bool constant: %s", inputs[0])
}
case types.TArray, types.TSlice:
count := int(io.Type.ArraySize)
elSize := int(io.Type.ElementType.Bits)
if io.Type.Type == types.TArray && count == 0 {
// Handle empty types.TArray arguments.
break
}
val := new(big.Int)
_, ok := val.SetString(inputs[0], 0)
if !ok {
return nil, fmt.Errorf("invalid input '%s' for %s",
inputs[0], io.Type)
}
var bitLen int
if strings.HasPrefix(inputs[0], "0x") {
bitLen = (len(inputs[0]) - 2) * 4
} else {
bitLen = val.BitLen()
}
valElCount := bitLen / elSize
if bitLen%elSize != 0 {
valElCount++
}
if io.Type.Type == types.TSlice {
// Set the count=valElCount for types.TSlice arguments.
count = valElCount
}
if valElCount > count {
return nil, fmt.Errorf("too many values for input: %s",
inputs[0])
}
pad := count - valElCount
val.Lsh(val, uint(pad*elSize))
mask := new(big.Int)
for i := 0; i < elSize; i++ {
mask.SetBit(mask, i, 1)
}
for i := 0; i < count; i++ {
next := new(big.Int).Rsh(val, uint((count-i-1)*elSize))
next = next.And(next, mask)
next.Lsh(next, uint(i*elSize))
result.Or(result, next)
}
default:
return nil, fmt.Errorf("unsupported input type: %s", io.Type)
}
return result, nil
}
if len(inputs) != len(io.Compound) {
return nil,
fmt.Errorf("invalid amount of arguments, got %d, expected %d",
len(inputs), len(io.Compound))
}
var offset int
for idx, arg := range io.Compound {
input, err := arg.Parse(inputs[idx : idx+1])
if err != nil {
return nil, err
}
input.Lsh(input, uint(offset))
result.Or(result, input)
offset += int(arg.Type.Bits)
}
return result, nil
}
// InputSizes computes the bit sizes of the input arguments. This is
// used for parametrized main() when the program is instantiated based
// on input sizes.
func InputSizes(inputs []string) ([]int, error) {
var result []int
for _, input := range inputs {
switch input {
case "_":
result = append(result, 0)
case "0", "f", "false", "1", "t", "true":
result = append(result, 1)
default:
if strings.HasPrefix(input, "0x") {
result = append(result, (len(input)-2)*4)
} else {
val := new(big.Int)
_, ok := val.SetString(input, 0)
if !ok {
return nil, fmt.Errorf("invalid input: %s", input)
}
result = append(result, val.BitLen())
}
}
}
return result, nil
}