diff --git a/fhevm/tfhe.go b/fhevm/tfhe_ciphertext.go similarity index 88% rename from fhevm/tfhe.go rename to fhevm/tfhe_ciphertext.go index bc82781..5c8b485 100644 --- a/fhevm/tfhe.go +++ b/fhevm/tfhe_ciphertext.go @@ -1,175 +1,18 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - package fhevm /* -#cgo linux CFLAGS: -O3 -I../tfhe-rs/target/release -I../tfhe-rs/target/release/deps -#cgo linux LDFLAGS: -L../tfhe-rs/target/release -l:libtfhe.a -L../tfhe-rs/target/release/deps -l:libtfhe_c_api_dynamic_buffer.a -lm -#cgo darwin CFLAGS: -O3 -I../tfhe-rs/target/release -I../tfhe-rs/target/release/deps -#cgo darwin LDFLAGS: -framework Security -L../tfhe-rs/target/release -ltfhe -L../tfhe-rs/target/release/deps -ltfhe_c_api_dynamic_buffer -lm - #include "tfhe_wrappers.h" - */ import "C" - import ( - _ "embed" "errors" - "fmt" "math/big" - "os" - "path" "unsafe" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) -func toDynamicBufferView(in []byte) C.DynamicBufferView { - return C.DynamicBufferView{ - pointer: (*C.uint8_t)(unsafe.Pointer(&in[0])), - length: (C.size_t)(len(in)), - } -} - -// Expanded TFHE ciphertext sizes by type, in bytes. -var expandedFheCiphertextSize map[FheUintType]uint - -// Compact TFHE ciphertext sizes by type, in bytes. -var compactFheCiphertextSize map[FheUintType]uint - -// server key: evaluation key -var sks unsafe.Pointer - -// client key: secret key -var cks unsafe.Pointer - -// public key -var pks unsafe.Pointer -var pksHash common.Hash - -// Generate keys for the fhevm (sks, cks, psk) -func generateFhevmKeys() (unsafe.Pointer, unsafe.Pointer, unsafe.Pointer) { - var keys = C.generate_fhevm_keys() - return keys.sks, keys.cks, keys.pks -} - -func allGlobalKeysPresent() bool { - return sks != nil && cks != nil && pks != nil -} - -func initGlobalKeysWithNewKeys() { - sks, cks, pks = generateFhevmKeys() - initCiphertextSizes() -} - -func initCiphertextSizes() { - expandedFheCiphertextSize = make(map[FheUintType]uint) - compactFheCiphertextSize = make(map[FheUintType]uint) - - expandedFheCiphertextSize[FheUint8] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint8).serialize())) - expandedFheCiphertextSize[FheUint16] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint16).serialize())) - expandedFheCiphertextSize[FheUint32] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint32).serialize())) - expandedFheCiphertextSize[FheUint64] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint64).serialize())) - - compactFheCiphertextSize[FheUint8] = uint(len(encryptAndSerializeCompact(0, FheUint8))) - compactFheCiphertextSize[FheUint16] = uint(len(encryptAndSerializeCompact(0, FheUint16))) - compactFheCiphertextSize[FheUint32] = uint(len(encryptAndSerializeCompact(0, FheUint32))) - compactFheCiphertextSize[FheUint64] = uint(len(encryptAndSerializeCompact(0, FheUint64))) -} - -func InitGlobalKeysFromFiles(keysDir string) error { - if _, err := os.Stat(keysDir); os.IsNotExist(err) { - return fmt.Errorf("init_keys: global keys directory doesn't exist (FHEVM_GO_KEYS_DIR): %s", keysDir) - } - // read keys from files - var sksPath = path.Join(keysDir, "sks") - sksBytes, err := os.ReadFile(sksPath) - if err != nil { - return err - } - var pksPath = path.Join(keysDir, "pks") - pksBytes, err := os.ReadFile(pksPath) - if err != nil { - return err - } - - sks = C.deserialize_server_key(toDynamicBufferView(sksBytes)) - - pksHash = crypto.Keccak256Hash(pksBytes) - pks = C.deserialize_compact_public_key(toDynamicBufferView(pksBytes)) - - initCiphertextSizes() - - fmt.Println("INFO: global keys loaded from: " + keysDir) - - return nil -} - -// initialize keys automatically only if FHEVM_GO_KEYS_DIR is set -func init() { - var keysDirPath, present = os.LookupEnv("FHEVM_GO_KEYS_DIR") - if present { - err := InitGlobalKeysFromFiles(keysDirPath) - if err != nil { - panic(err) - } - fmt.Println("INFO: global keys are initialized automatically using FHEVM_GO_KEYS_DIR env variable") - } else { - fmt.Println("INFO: global keys aren't initialized automatically (FHEVM_GO_KEYS_DIR env variable not set)") - } -} - -func serialize(ptr unsafe.Pointer, t FheUintType) ([]byte, error) { - out := &C.DynamicBuffer{} - var ret C.int - switch t { - case FheUint8: - ret = C.serialize_fhe_uint8(ptr, out) - case FheUint16: - ret = C.serialize_fhe_uint16(ptr, out) - case FheUint32: - ret = C.serialize_fhe_uint32(ptr, out) - case FheUint64: - ret = C.serialize_fhe_uint64(ptr, out) - default: - panic("serialize: unexpected ciphertext type") - } - if ret != 0 { - return nil, errors.New("serialize: failed to serialize a ciphertext") - } - ser := C.GoBytes(unsafe.Pointer(out.pointer), C.int(out.length)) - C.destroy_dynamic_buffer(out) - return ser, nil -} - -func serializePublicKey(pks unsafe.Pointer) ([]byte, error) { - out := &C.DynamicBuffer{} - var ret C.int - ret = C.serialize_compact_public_key(pks, out) - if ret != 0 { - return nil, errors.New("serialize: failed to serialize public key") - } - ser := C.GoBytes(unsafe.Pointer(out.pointer), C.int(out.length)) - C.destroy_dynamic_buffer(out) - return ser, nil -} - // Represents a TFHE ciphertext type, i.e. its bit capacity. type FheUintType uint8 @@ -1622,28 +1465,3 @@ func (ct *tfheCiphertext) getHash() common.Hash { ct.computeHash() return *ct.hash } - -func isValidType(t byte) bool { - if uint8(t) < uint8(FheUint8) || uint8(t) > uint8(FheUint64) { - return false - } - return true -} - -func encryptAndSerializeCompact(value uint64, fheUintType FheUintType) []byte { - out := &C.DynamicBuffer{} - switch fheUintType { - case FheUint8: - C.public_key_encrypt_and_serialize_fhe_uint8_list(pks, C.uint8_t(value), out) - case FheUint16: - C.public_key_encrypt_and_serialize_fhe_uint16_list(pks, C.uint16_t(value), out) - case FheUint32: - C.public_key_encrypt_and_serialize_fhe_uint32_list(pks, C.uint32_t(value), out) - case FheUint64: - C.public_key_encrypt_and_serialize_fhe_uint64_list(pks, C.uint64_t(value), out) - } - - ser := C.GoBytes(unsafe.Pointer(out.pointer), C.int(out.length)) - C.destroy_dynamic_buffer(out) - return ser -} diff --git a/fhevm/tfhe_key_management.go b/fhevm/tfhe_key_management.go new file mode 100644 index 0000000..4dc2c68 --- /dev/null +++ b/fhevm/tfhe_key_management.go @@ -0,0 +1,105 @@ +package fhevm + +/* +#include "tfhe_wrappers.h" +*/ +import "C" + +import ( + "fmt" + "math/big" + "os" + "path" + "unsafe" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +// Expanded TFHE ciphertext sizes by type, in bytes. +var expandedFheCiphertextSize map[FheUintType]uint + +// Compact TFHE ciphertext sizes by type, in bytes. +var compactFheCiphertextSize map[FheUintType]uint + +// server key: evaluation key +var sks unsafe.Pointer + +// client key: secret key +var cks unsafe.Pointer + +// public key +var pks unsafe.Pointer +var pksHash common.Hash + +// Generate keys for the fhevm (sks, cks, psk) +func generateFhevmKeys() (unsafe.Pointer, unsafe.Pointer, unsafe.Pointer) { + var keys = C.generate_fhevm_keys() + return keys.sks, keys.cks, keys.pks +} + +func allGlobalKeysPresent() bool { + return sks != nil && cks != nil && pks != nil +} + +func initGlobalKeysWithNewKeys() { + sks, cks, pks = generateFhevmKeys() + initCiphertextSizes() +} + +func initCiphertextSizes() { + expandedFheCiphertextSize = make(map[FheUintType]uint) + compactFheCiphertextSize = make(map[FheUintType]uint) + + expandedFheCiphertextSize[FheUint8] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint8).serialize())) + expandedFheCiphertextSize[FheUint16] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint16).serialize())) + expandedFheCiphertextSize[FheUint32] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint32).serialize())) + expandedFheCiphertextSize[FheUint64] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint64).serialize())) + + compactFheCiphertextSize[FheUint8] = uint(len(encryptAndSerializeCompact(0, FheUint8))) + compactFheCiphertextSize[FheUint16] = uint(len(encryptAndSerializeCompact(0, FheUint16))) + compactFheCiphertextSize[FheUint32] = uint(len(encryptAndSerializeCompact(0, FheUint32))) + compactFheCiphertextSize[FheUint64] = uint(len(encryptAndSerializeCompact(0, FheUint64))) +} + +func InitGlobalKeysFromFiles(keysDir string) error { + if _, err := os.Stat(keysDir); os.IsNotExist(err) { + return fmt.Errorf("init_keys: global keys directory doesn't exist (FHEVM_GO_KEYS_DIR): %s", keysDir) + } + // read keys from files + var sksPath = path.Join(keysDir, "sks") + sksBytes, err := os.ReadFile(sksPath) + if err != nil { + return err + } + var pksPath = path.Join(keysDir, "pks") + pksBytes, err := os.ReadFile(pksPath) + if err != nil { + return err + } + + sks = C.deserialize_server_key(toDynamicBufferView(sksBytes)) + + pksHash = crypto.Keccak256Hash(pksBytes) + pks = C.deserialize_compact_public_key(toDynamicBufferView(pksBytes)) + + initCiphertextSizes() + + fmt.Println("INFO: global keys loaded from: " + keysDir) + + return nil +} + +// initialize keys automatically only if FHEVM_GO_KEYS_DIR is set +func init() { + var keysDirPath, present = os.LookupEnv("FHEVM_GO_KEYS_DIR") + if present { + err := InitGlobalKeysFromFiles(keysDirPath) + if err != nil { + panic(err) + } + fmt.Println("INFO: global keys are initialized automatically using FHEVM_GO_KEYS_DIR env variable") + } else { + fmt.Println("INFO: global keys aren't initialized automatically (FHEVM_GO_KEYS_DIR env variable not set)") + } +} diff --git a/fhevm/tfhe_wrappers.go b/fhevm/tfhe_wrappers.go new file mode 100644 index 0000000..2633684 --- /dev/null +++ b/fhevm/tfhe_wrappers.go @@ -0,0 +1,101 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package fhevm + +/* +#cgo linux CFLAGS: -O3 -I../tfhe-rs/target/release -I../tfhe-rs/target/release/deps +#cgo linux LDFLAGS: -L../tfhe-rs/target/release -l:libtfhe.a -L../tfhe-rs/target/release/deps -l:libtfhe_c_api_dynamic_buffer.a -lm +#cgo darwin CFLAGS: -O3 -I../tfhe-rs/target/release -I../tfhe-rs/target/release/deps +#cgo darwin LDFLAGS: -framework Security -L../tfhe-rs/target/release -ltfhe -L../tfhe-rs/target/release/deps -ltfhe_c_api_dynamic_buffer -lm + +#include "tfhe_wrappers.h" + +*/ +import "C" + +import ( + _ "embed" + "errors" + "unsafe" +) + +func toDynamicBufferView(in []byte) C.DynamicBufferView { + return C.DynamicBufferView{ + pointer: (*C.uint8_t)(unsafe.Pointer(&in[0])), + length: (C.size_t)(len(in)), + } +} + +func serialize(ptr unsafe.Pointer, t FheUintType) ([]byte, error) { + out := &C.DynamicBuffer{} + var ret C.int + switch t { + case FheUint8: + ret = C.serialize_fhe_uint8(ptr, out) + case FheUint16: + ret = C.serialize_fhe_uint16(ptr, out) + case FheUint32: + ret = C.serialize_fhe_uint32(ptr, out) + case FheUint64: + ret = C.serialize_fhe_uint64(ptr, out) + default: + panic("serialize: unexpected ciphertext type") + } + if ret != 0 { + return nil, errors.New("serialize: failed to serialize a ciphertext") + } + ser := C.GoBytes(unsafe.Pointer(out.pointer), C.int(out.length)) + C.destroy_dynamic_buffer(out) + return ser, nil +} + +func serializePublicKey(pks unsafe.Pointer) ([]byte, error) { + out := &C.DynamicBuffer{} + var ret C.int + ret = C.serialize_compact_public_key(pks, out) + if ret != 0 { + return nil, errors.New("serialize: failed to serialize public key") + } + ser := C.GoBytes(unsafe.Pointer(out.pointer), C.int(out.length)) + C.destroy_dynamic_buffer(out) + return ser, nil +} + +func isValidType(t byte) bool { + if uint8(t) < uint8(FheUint8) || uint8(t) > uint8(FheUint64) { + return false + } + return true +} + +func encryptAndSerializeCompact(value uint64, fheUintType FheUintType) []byte { + out := &C.DynamicBuffer{} + switch fheUintType { + case FheUint8: + C.public_key_encrypt_and_serialize_fhe_uint8_list(pks, C.uint8_t(value), out) + case FheUint16: + C.public_key_encrypt_and_serialize_fhe_uint16_list(pks, C.uint16_t(value), out) + case FheUint32: + C.public_key_encrypt_and_serialize_fhe_uint32_list(pks, C.uint32_t(value), out) + case FheUint64: + C.public_key_encrypt_and_serialize_fhe_uint64_list(pks, C.uint64_t(value), out) + } + + ser := C.GoBytes(unsafe.Pointer(out.pointer), C.int(out.length)) + C.destroy_dynamic_buffer(out) + return ser +}