ceremonyclient/node/execution/intrinsics/compute/compute_intrinsic_code_deployment.go
2025-12-15 16:45:31 -06:00

194 lines
4.5 KiB
Go

package compute
import (
"bytes"
"math/big"
"slices"
"github.com/iden3/go-iden3-crypto/poseidon"
"github.com/pkg/errors"
hg "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph"
"source.quilibrium.com/quilibrium/monorepo/types/compiler"
"source.quilibrium.com/quilibrium/monorepo/types/execution/intrinsics"
"source.quilibrium.com/quilibrium/monorepo/types/execution/state"
qcrypto "source.quilibrium.com/quilibrium/monorepo/types/tries"
)
// CodeDeployment represents a code deployment operation
type CodeDeployment struct {
// The QCL circuit to deploy
Circuit []byte
// The QCL types/classes of the main arguments, 0 - garbler, 1 - evaluator
InputTypes [2]string
// The QCL types/classes of the output values
OutputTypes []string
// The app address
Domain [32]byte
inputQCLSource []byte
inputSizes [2][]int
compiler compiler.CircuitCompiler
}
// NewCodeDeployment creates a new code deployment
func NewCodeDeployment(
domain [32]byte,
sourceCode []byte,
inputTypes [2]string,
inputSizes [2][]int,
outputTypes []string,
compiler compiler.CircuitCompiler,
) (*CodeDeployment, error) {
return &CodeDeployment{
inputQCLSource: sourceCode, // buildutils:allow-slice-alias slice is static
Domain: domain,
InputTypes: inputTypes,
OutputTypes: outputTypes, // buildutils:allow-slice-alias slice is static
inputSizes: inputSizes,
compiler: compiler,
}, nil
}
// GetCost implements intrinsics.IntrinsicOperation
func (c *CodeDeployment) GetCost() (*big.Int, error) {
// Cost based on code size
return big.NewInt(int64(len(c.Circuit))), nil
}
// Prove implements intrinsics.IntrinsicOperation
func (c *CodeDeployment) Prove(frameNumber uint64) (err error) {
defer func() {
if r := recover(); r != nil {
err = errors.Wrap(
errors.New("panic encountered while proving code"),
"prove",
)
}
}()
compiledCircuit, err := c.compiler.Compile(
string(c.inputQCLSource),
c.inputSizes[:],
)
if err != nil {
return errors.Wrap(err, "verify")
}
buf := new(bytes.Buffer)
if err = compiledCircuit.Marshal(buf); err != nil {
return errors.Wrap(err, "verify")
}
out := buf.Bytes()
c.Circuit = out
return nil
}
func (c *CodeDeployment) GetReadAddresses(
frameNumber uint64,
) ([][]byte, error) {
return nil, nil
}
func (c *CodeDeployment) GetWriteAddresses(
frameNumber uint64,
) ([][]byte, error) {
// Get the domain from the hypergraph
domain := c.Domain
// Generate a unique address for this code file
codeAddressBI, err := poseidon.HashBytes(
slices.Concat(
domain[:],
c.Circuit,
),
)
if err != nil {
return nil, errors.Wrap(err, "get write addresses")
}
codeAddress := codeAddressBI.FillBytes(make([]byte, 32))
codeFullAddress := [64]byte{}
copy(codeFullAddress[:32], c.Domain[:])
copy(codeFullAddress[32:], codeAddress)
return [][]byte{codeFullAddress[:]}, nil
}
// Verify implements intrinsics.IntrinsicOperation
func (c *CodeDeployment) Verify(frameNumber uint64) (bool, error) {
buf := bytes.NewReader(c.Circuit)
err := c.compiler.ValidateCircuit(buf)
if err != nil {
return false, errors.Wrap(err, "verify")
}
return true, nil
}
// Materialize implements intrinsics.IntrinsicOperation
func (c *CodeDeployment) Materialize(
frameNumber uint64,
state state.State,
) (state.State, error) {
hypergraph, ok := state.(*hg.HypergraphState)
if !ok {
return nil, errors.Wrap(errors.New("invalid state type"), "materialize")
}
// Get the domain from the hypergraph
domain := c.Domain
// Generate a unique address for this code file
codeAddressBI, err := poseidon.HashBytes(
slices.Concat(
domain[:],
c.Circuit,
),
)
if err != nil {
return nil, errors.Wrap(err, "materialize")
}
codeAddress := codeAddressBI.FillBytes(make([]byte, 32))
// Create a tree to store the code
codeTree := &qcrypto.VectorCommitmentTree{}
// Store the code content
if err := codeTree.Insert(
[]byte{0 << 2}, // Index 0
c.Circuit,
nil,
big.NewInt(int64(len(c.Circuit))),
); err != nil {
return nil, errors.Wrap(err, "materialize")
}
// Create the materialized state
value := hypergraph.NewVertexAddMaterializedState(
[32]byte(domain),
[32]byte(codeAddress),
frameNumber,
nil,
codeTree,
)
// Set the state
err = hypergraph.Set(
domain[:],
codeAddress,
hg.VertexAddsDiscriminator,
frameNumber,
value,
)
if err != nil {
return nil, errors.Wrap(err, "materialize")
}
return hypergraph, nil
}
var _ intrinsics.IntrinsicOperation = (*CodeDeployment)(nil)