ceremonyclient/bedlam/result.go

176 lines
3.9 KiB
Go

//
// Copyright (c) 2019-2024 Markku Rossi
//
// All rights reserved.
//
package bedlam
import (
"fmt"
"math/big"
"reflect"
"unicode"
"source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
"source.quilibrium.com/quilibrium/monorepo/bedlam/types"
)
// PrintResults prints the result values.
func PrintResults(results []*big.Int, outputs circuit.IO) {
for idx, value := range Results(results, outputs) {
fmt.Printf("Result[%d]: ", idx)
switch v := value.(type) {
case []byte:
fmt.Printf("%x\n", v)
default:
fmt.Printf("%v\n", v)
}
}
}
// Results return the result values as an array of Go values.
func Results(results []*big.Int, outputs circuit.IO) []interface{} {
var ret []interface{}
for idx, result := range results {
var r interface{}
if outputs == nil {
r = Result(result, circuit.IOArg{
Type: types.Info{
Type: types.TUint,
IsConcrete: true,
Bits: 1024, // Anything >64 returns big.Int
},
})
} else {
r = Result(result, outputs[idx])
}
ret = append(ret, r)
}
return ret
}
// Result converts the result to Go value.
func Result(result *big.Int, output circuit.IOArg) interface{} {
switch output.Type.Type {
case types.TString:
mask := big.NewInt(0xff)
var str string
for i := 0; i < int(output.Type.Bits)/8; i++ {
tmp := new(big.Int).Rsh(result, uint(i*8))
r := rune(tmp.And(tmp, mask).Uint64())
if unicode.IsPrint(r) {
str += string(r)
} else {
str += fmt.Sprintf("\\u%04x", r)
}
}
return str
case types.TUint:
if output.Type.Bits <= 8 {
return uint8(result.Uint64())
} else if output.Type.Bits <= 16 {
return uint16(result.Uint64())
} else if output.Type.Bits <= 32 {
return uint32(result.Uint64())
} else if output.Type.Bits <= 64 {
return result.Uint64()
} else {
return result
}
case types.TInt:
bits := int(output.Type.Bits)
if result.Bit(bits-1) == 1 {
// Negative number.
tmp := new(big.Int)
tmp.SetBit(tmp, bits, 1)
result.Sub(tmp, result)
result.Neg(result)
}
if output.Type.Bits <= 8 {
return int8(result.Int64())
} else if output.Type.Bits <= 16 {
return int16(result.Int64())
} else if output.Type.Bits <= 32 {
return int32(result.Int64())
} else if output.Type.Bits <= 64 {
return result.Int64()
} else {
return result
}
case types.TBool:
return result.Uint64() != 0
case types.TArray, types.TSlice:
count := int(output.Type.ArraySize)
elSize := int(output.Type.ElementType.Bits)
mask := new(big.Int)
for i := 0; i < elSize; i++ {
mask.SetBit(mask, i, 1)
}
var slice reflect.Value
var elementType reflect.Type
switch output.Type.ElementType.Type {
case types.TString:
elementType = reflect.TypeOf("")
case types.TUint:
if elSize <= 8 {
elementType = reflect.TypeOf(uint8(0))
} else if elSize <= 16 {
elementType = reflect.TypeOf(uint16(0))
} else if elSize <= 32 {
elementType = reflect.TypeOf(uint32(0))
} else if elSize <= 64 {
elementType = reflect.TypeOf(uint64(0))
} else {
elementType = reflect.TypeOf((*big.Int)(nil))
}
case types.TInt:
if elSize <= 8 {
elementType = reflect.TypeOf(int8(0))
} else if elSize <= 16 {
elementType = reflect.TypeOf(int16(0))
} else if elSize <= 32 {
elementType = reflect.TypeOf(int32(0))
} else if elSize <= 64 {
elementType = reflect.TypeOf(int64(0))
} else {
elementType = reflect.TypeOf((*big.Int)(nil))
}
case types.TBool:
elementType = reflect.TypeOf(true)
default:
elementType = reflect.TypeOf(nil)
}
slice = reflect.MakeSlice(reflect.SliceOf(elementType), 0, count)
for i := 0; i < count; i++ {
r := new(big.Int).Rsh(result, uint(i*elSize))
r = r.And(r, mask)
v := reflect.ValueOf(Result(r, circuit.IOArg{
Type: *output.Type.ElementType,
}))
slice = reflect.Append(slice, v)
}
return slice.Interface()
default:
return fmt.Sprintf("%v (%s)", result, output.Type)
}
}