Skip to content

Commit

Permalink
Merge pull request #141 from FhenixProtocol/implement-rotate-left-and…
Browse files Browse the repository at this point in the history
…-right-fhe-operations-1625101289

[FEAT] Support rotate left and right operations
  • Loading branch information
roeezolantz authored Sep 19, 2024
2 parents 1382de7 + 0acd67f commit c0df312
Show file tree
Hide file tree
Showing 15 changed files with 841 additions and 17 deletions.
66 changes: 64 additions & 2 deletions chains/arbitrum/contractsgen/contractsgen.go

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package main

import (
"fmt"
"math/big"
"os"
"strconv"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/fhenixprotocol/fheos/precompiles"
fhedriver "github.com/fhenixprotocol/warp-drive/fhe-driver"
"github.com/spf13/cobra"
"math/big"
"os"
"strconv"
)

func removeDb() error {
Expand Down Expand Up @@ -249,8 +250,10 @@ func main() {
var max = setupOperationCommand("max", "max two numbers", precompiles.Max)
var shl = setupOperationCommand("shl", "shl two numbers", precompiles.Shl)
var shr = setupOperationCommand("shr", "shr two numbers", precompiles.Shr)
var rol = setupOperationCommand("rol", "ror two numbers", precompiles.Rol)
var ror = setupOperationCommand("ror", "rol two numbers", precompiles.Rol)

rootCmd.AddCommand(initDb, initState, add, sub, lte, sub, mul, lt, div, gt, gte, rem, and, or, xor, eq, ne, min, max, shl, shr)
rootCmd.AddCommand(initDb, initState, add, sub, lte, sub, mul, lt, div, gt, gte, rem, and, or, xor, eq, ne, min, max, shl, shr, rol, ror)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
Expand Down
72 changes: 72 additions & 0 deletions nitro-overrides/precompiles/FheOps.go
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,78 @@ func (con FheOps) Req(c ctx, evm mech, utype byte, input []byte) ([]byte, error)
return ret, err
}

func (con FheOps) Rol(c ctx, evm mech, utype byte, lhsHash []byte, rhsHash []byte) ([]byte, error) {
tp := fheos.TxParamsFromEVM(evm, c.caller)
if metrics.Enabled {
h := fmt.Sprintf("%s/%s/%s", "fheos", "Rol", fheos.UtypeToString(utype))
defer func(start time.Time) {
sampler := func() metrics.Sample {
return metrics.NewBoundedHistogramSample()
}
metrics.GetOrRegisterHistogramLazy(h, nil, sampler).Update(time.Since(start).Microseconds())
}(time.Now())
}

ret, gas, err := fheos.Rol(utype, lhsHash, rhsHash, &tp)

if err != nil {
if metrics.Enabled {
c := fmt.Sprintf("%s/%s/%s/%s", "fheos", "Rol", fheos.UtypeToString(utype), "error/fhe_failure")
metrics.GetOrRegisterCounter(c, nil).Inc(1)
}
return ret, err
}

err = c.Burn(gas)

if metrics.Enabled {
metricPath := fmt.Sprintf("%s/%s/%s/%s", "fheos", "Rol", fheos.UtypeToString(utype), "success/total")
if err != nil {
metricPath = fmt.Sprintf("%s/%s/%s/%s", "fheos", "Rol", fheos.UtypeToString(utype), "error/fhe_gas_failure")
}

metrics.GetOrRegisterCounter(metricPath, nil).Inc(1)
}

return ret, err
}

func (con FheOps) Ror(c ctx, evm mech, utype byte, lhsHash []byte, rhsHash []byte) ([]byte, error) {
tp := fheos.TxParamsFromEVM(evm, c.caller)
if metrics.Enabled {
h := fmt.Sprintf("%s/%s/%s", "fheos", "Ror", fheos.UtypeToString(utype))
defer func(start time.Time) {
sampler := func() metrics.Sample {
return metrics.NewBoundedHistogramSample()
}
metrics.GetOrRegisterHistogramLazy(h, nil, sampler).Update(time.Since(start).Microseconds())
}(time.Now())
}

ret, gas, err := fheos.Ror(utype, lhsHash, rhsHash, &tp)

if err != nil {
if metrics.Enabled {
c := fmt.Sprintf("%s/%s/%s/%s", "fheos", "Ror", fheos.UtypeToString(utype), "error/fhe_failure")
metrics.GetOrRegisterCounter(c, nil).Inc(1)
}
return ret, err
}

err = c.Burn(gas)

if metrics.Enabled {
metricPath := fmt.Sprintf("%s/%s/%s/%s", "fheos", "Ror", fheos.UtypeToString(utype), "success/total")
if err != nil {
metricPath = fmt.Sprintf("%s/%s/%s/%s", "fheos", "Ror", fheos.UtypeToString(utype), "error/fhe_gas_failure")
}

metrics.GetOrRegisterCounter(metricPath, nil).Inc(1)
}

return ret, err
}

func (con FheOps) SealOutput(c ctx, evm mech, utype byte, ctHash []byte, pk []byte) (string, error) {
tp := fheos.TxParamsFromEVM(evm, c.caller)
if metrics.Enabled {
Expand Down
105 changes: 102 additions & 3 deletions precompiles/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package precompiles
import (
"encoding/hex"
"fmt"
"math/big"
"os"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/fhenixprotocol/fheos/precompiles/types"
storage2 "github.com/fhenixprotocol/fheos/storage"
"github.com/fhenixprotocol/warp-drive/fhe-driver"
"math/big"
"os"
"strings"

"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log"
Expand Down Expand Up @@ -1359,6 +1360,104 @@ func Shr(utype byte, lhsHash []byte, rhsHash []byte, tp *TxParams) ([]byte, uint
return ctHash[:], gas, nil
}

func Rol(utype byte, lhsHash []byte, rhsHash []byte, tp *TxParams) ([]byte, uint64, error) {
functionName := types.Rol

storage := storage2.NewMultiStore(tp.CiphertextDb, &State.Storage)
uintType := fhe.EncryptionType(utype)
if !types.IsValidType(uintType) {
logger.Error("invalid ciphertext", "type", utype)
return nil, 0, vm.ErrExecutionReverted
}

gas := getGasForPrecompile(functionName, uintType)
if tp.GasEstimation {
randomHash := State.GetRandomForGasEstimation()
return randomHash[:], gas, nil
}

if shouldPrintPrecompileInfo(tp) {
logger.Info("Starting new precompiled contract function: " + functionName.String())
}

lhs, rhs, err := get2VerifiedOperands(storage, lhsHash, rhsHash, tp.ContractAddress)
if err != nil {
logger.Error(functionName.String()+" inputs not verified", "err", err)
return nil, 0, vm.ErrExecutionReverted
}

if lhs.UintType != rhs.UintType {
msg := functionName.String() + " operand type mismatch"
logger.Error(msg, "lhs", lhs.UintType, "rhs", rhs.UintType)
return nil, 0, vm.ErrExecutionReverted
}

result, err := lhs.Rol(rhs)
if err != nil {
logger.Error(functionName.String()+" failed", "err", err)
return nil, 0, vm.ErrExecutionReverted
}
err = storeCipherText(storage, result, tp.ContractAddress)
if err != nil {
logger.Error(functionName.String()+" failed", "err", err)
return nil, 0, vm.ErrExecutionReverted
}

ctHash := result.Hash()

logger.Debug(functionName.String()+" success", "contractAddress", tp.ContractAddress, "lhs", lhs.Hash().Hex(), "rhs", rhs.Hash().Hex(), "result", ctHash.Hex())
return ctHash[:], gas, nil
}

func Ror(utype byte, lhsHash []byte, rhsHash []byte, tp *TxParams) ([]byte, uint64, error) {
functionName := types.Ror

storage := storage2.NewMultiStore(tp.CiphertextDb, &State.Storage)
uintType := fhe.EncryptionType(utype)
if !types.IsValidType(uintType) {
logger.Error("invalid ciphertext", "type", utype)
return nil, 0, vm.ErrExecutionReverted
}

gas := getGasForPrecompile(functionName, uintType)
if tp.GasEstimation {
randomHash := State.GetRandomForGasEstimation()
return randomHash[:], gas, nil
}

if shouldPrintPrecompileInfo(tp) {
logger.Info("Starting new precompiled contract function: " + functionName.String())
}

lhs, rhs, err := get2VerifiedOperands(storage, lhsHash, rhsHash, tp.ContractAddress)
if err != nil {
logger.Error(functionName.String()+" inputs not verified", "err", err)
return nil, 0, vm.ErrExecutionReverted
}

if lhs.UintType != rhs.UintType {
msg := functionName.String() + " operand type mismatch"
logger.Error(msg, "lhs", lhs.UintType, "rhs", rhs.UintType)
return nil, 0, vm.ErrExecutionReverted
}

result, err := lhs.Ror(rhs)
if err != nil {
logger.Error(functionName.String()+" failed", "err", err)
return nil, 0, vm.ErrExecutionReverted
}
err = storeCipherText(storage, result, tp.ContractAddress)
if err != nil {
logger.Error(functionName.String()+" failed", "err", err)
return nil, 0, vm.ErrExecutionReverted
}

ctHash := result.Hash()

logger.Debug(functionName.String()+" success", "contractAddress", tp.ContractAddress, "lhs", lhs.Hash().Hex(), "rhs", rhs.Hash().Hex(), "result", ctHash.Hex())
return ctHash[:], gas, nil
}

func Not(utype byte, value []byte, tp *TxParams) ([]byte, uint64, error) {
functionName := types.Not

Expand Down
2 changes: 1 addition & 1 deletion precompiles/gas.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func getRawPrecompileGas(precompileName types.PrecompileName, uintType fhe.Encry
case fhe.Uint128:
return 250000
}
case types.Shl, types.Shr:
case types.Shl, types.Shr, types.Rol, types.Ror:
switch uintType {
case fhe.Uint8:
return 65000
Expand Down
12 changes: 6 additions & 6 deletions precompiles/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ const (
Ne
TrivialEncrypt
Random
// Rol // Commented out if not used
// Ror // Commented out if not used
Rol
Ror
)

var precompileNameToString = map[PrecompileName]string{
Expand Down Expand Up @@ -102,8 +102,8 @@ var precompileNameToString = map[PrecompileName]string{
Ne: "ne",
Random: "random",
TrivialEncrypt: "trivialEncrypt",
// Rol: "rol",
// Ror: "ror",
Rol: "rol",
Ror: "ror",
}

var stringToPrecompileName = map[string]PrecompileName{
Expand Down Expand Up @@ -135,8 +135,8 @@ var stringToPrecompileName = map[string]PrecompileName{
"ne": Ne,
"random": Random,
"trivialEncrypt": TrivialEncrypt,
// "rol": Rol,
// "ror": Ror,
"rol": Rol,
"ror": Ror,
}

func (pn PrecompileName) String() string {
Expand Down
16 changes: 15 additions & 1 deletion solgen/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const EInputType = [
// FYI: Operations ["sealoutput", "seal", "decrypt", "ne"] are the minimum required for
// non failing generated code.

const patternAllowedOperationsEbool = ["ne|eq|^and$|or|xor|sealoutput|select|seal|decrypt|not"];
const patternAllowedOperationsEbool = ["ne|eq|^and$|^or$|xor|sealoutput|select|seal|decrypt|not"];
const patternAllowedOperationsEuint8 = [".*"];
const patternAllowedOperationsEuint16 = [".*"];
const patternAllowedOperationsEuint32 = [".*"];
Expand Down Expand Up @@ -230,6 +230,18 @@ export const ShorthandOperations: OperatorMap[] = [
unary: false,
returnsBool: false,
},
{
func: "rol",
operator: null,
unary: false,
returnsBool: false,
},
{
func: "ror",
operator: null,
unary: false,
returnsBool: false,
},
];

export const BindMathOperators = [
Expand All @@ -251,6 +263,8 @@ export const BindMathOperators = [
"min",
"shl",
"shr",
"rol",
"ror"
];
export const bitwiseAndLogicalOperators = ["and", "or", "xor", "not"];

Expand Down
Loading

0 comments on commit c0df312

Please sign in to comment.