Skip to content

Commit b403666

Browse files
Initial commit: project setup
1 parent 34758bc commit b403666

File tree

5 files changed

+555
-0
lines changed

5 files changed

+555
-0
lines changed

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/collapsinghierarchy/ofhe-go
2+
3+
go 1.24.3

openfhe.go

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
//go:build openfhe && cgo
2+
3+
package main
4+
5+
/*
6+
#cgo CFLAGS: -I/usr/local/include -I/usr/local/include/openfhe/core -I/usr/local/include/openfhe/pke -I/usr/local/include/openfhe/ -I/usr/local/include/openfhe/binfhe
7+
#cgo CXXFLAGS: -I/usr/local/include -I/usr/local/include/openfhe/core -I/usr/local/include/openfhe/pke -I/usr/local/include/openfhe/ -I/usr/local/include/openfhe/binfhe -std=c++17
8+
#cgo LDFLAGS: -lOPENFHEcore -lOPENFHEpke -lstdc++ -lm -lpthread
9+
#include "openfhe_c.h" // header only – no .cpp here
10+
*/
11+
import "C"
12+
import (
13+
"errors"
14+
"unsafe"
15+
)
16+
17+
// Context wraps a BGVRNS CryptoContext
18+
type Context struct{ ptr unsafe.Pointer }
19+
20+
// NewBGVRNS creates a new BGVRNS context
21+
func NewBGVRNS(depth uint32, t uint64) *Context {
22+
return &Context{C.go_bgvrns_new(C.uint(depth), C.uint64_t(t))}
23+
}
24+
25+
// Free releases the underlying C++ CryptoContext
26+
func (c *Context) Free() {
27+
if c != nil && c.ptr != nil {
28+
C.go_bgvrns_free(c.ptr)
29+
c.ptr = nil
30+
}
31+
}
32+
33+
// Raw returns the underlying pointer for internal use
34+
func (c *Context) Raw() unsafe.Pointer {
35+
if c == nil {
36+
return nil
37+
}
38+
return c.ptr
39+
}
40+
41+
// PublicKey wraps an opaque PublicKey<DCRTPoly>*
42+
type PublicKey struct{ ptr unsafe.Pointer }
43+
44+
// Raw returns the underlying pointer
45+
func (pk *PublicKey) Raw() unsafe.Pointer {
46+
if pk == nil {
47+
return nil
48+
}
49+
return pk.ptr
50+
}
51+
52+
// Free releases the C++ PublicKey
53+
func (pk *PublicKey) Free() {
54+
if pk != nil && pk.ptr != nil {
55+
C.go_pk_free(pk.ptr)
56+
pk.ptr = nil
57+
}
58+
}
59+
60+
// Serialize returns the binary serialization of the public key
61+
func (pk *PublicKey) Serialize() ([]byte, error) {
62+
if pk == nil || pk.ptr == nil {
63+
return nil, errors.New("PublicKey is nil")
64+
}
65+
var buf *C.uint8_t
66+
var length C.size_t
67+
C.go_pk_serialize(pk.ptr, &buf, &length)
68+
defer C.go_buf_free(buf)
69+
return C.GoBytes(unsafe.Pointer(buf), C.int(length)), nil
70+
}
71+
72+
// DeserializePublicKey creates a PublicKey from serialized data
73+
func DeserializePublicKey(ctx *Context, data []byte) *PublicKey {
74+
ptr := C.go_pk_deserialize(ctx.ptr,
75+
(*C.uint8_t)(unsafe.Pointer(&data[0])),
76+
C.size_t(len(data)))
77+
return &PublicKey{ptr}
78+
}
79+
80+
// SecretKey wraps an opaque PrivateKey<DCRTPoly>*
81+
type SecretKey struct{ ptr unsafe.Pointer }
82+
83+
// Raw returns the underlying pointer
84+
func (sk *SecretKey) Raw() unsafe.Pointer {
85+
if sk == nil {
86+
return nil
87+
}
88+
return sk.ptr
89+
}
90+
91+
// Free releases the C++ SecretKey
92+
func (sk *SecretKey) Free() {
93+
if sk != nil && sk.ptr != nil {
94+
C.go_sk_free(sk.ptr)
95+
sk.ptr = nil
96+
}
97+
}
98+
99+
// Serialize returns binary serialization of the secret key
100+
func (sk *SecretKey) Serialize() ([]byte, error) {
101+
if sk == nil || sk.ptr == nil {
102+
return nil, errors.New("SecretKey is nil")
103+
}
104+
var buf *C.uint8_t
105+
var length C.size_t
106+
C.go_sk_serialize(sk.ptr, &buf, &length)
107+
defer C.go_buf_free(buf)
108+
return C.GoBytes(unsafe.Pointer(buf), C.int(length)), nil
109+
}
110+
111+
// DeserializeSecretKey creates a SecretKey from serialized data
112+
func DeserializeSecretKey(ctx *Context, data []byte) *SecretKey {
113+
ptr := C.go_sk_deserialize(ctx.ptr,
114+
(*C.uint8_t)(unsafe.Pointer(&data[0])),
115+
C.size_t(len(data)))
116+
return &SecretKey{ptr}
117+
}
118+
119+
// Ciphertext wraps an opaque Ciphertext<DCRTPoly>*
120+
type Ciphertext struct{ ptr unsafe.Pointer }
121+
122+
// Raw returns the underlying pointer
123+
func (ct *Ciphertext) Raw() unsafe.Pointer {
124+
if ct == nil {
125+
return nil
126+
}
127+
return ct.ptr
128+
}
129+
130+
// Free releases the C++ Ciphertext
131+
func (ct *Ciphertext) Free() {
132+
if ct != nil && ct.ptr != nil {
133+
C.go_ct_free(ct.ptr)
134+
ct.ptr = nil
135+
}
136+
}
137+
138+
// Serialize returns binary serialization of the ciphertext
139+
func (ct *Ciphertext) Serialize() ([]byte, error) {
140+
if ct == nil || ct.ptr == nil {
141+
return nil, errors.New("Ciphertext is nil")
142+
}
143+
var buf *C.uint8_t
144+
var length C.size_t
145+
C.go_ct_ser(ct.ptr, &buf, &length)
146+
defer C.go_buf_free(buf)
147+
return C.GoBytes(unsafe.Pointer(buf), C.int(length)), nil
148+
}
149+
150+
// DeserializeCiphertext creates a Ciphertext from serialized data
151+
func DeserializeCiphertext(ctx *Context, data []byte) *Ciphertext {
152+
ptr := C.go_ct_deser(ctx.ptr,
153+
(*C.uint8_t)(unsafe.Pointer(&data[0])),
154+
C.size_t(len(data)))
155+
return &Ciphertext{ptr}
156+
}
157+
158+
// KeyGenPtr generates a new key pair, returning opaque pointers
159+
func (c *Context) KeyGenPtr() (*PublicKey, *SecretKey, error) {
160+
var pkPtr, skPtr unsafe.Pointer
161+
C.go_keygen_ptr(c.ptr, &pkPtr, &skPtr)
162+
if pkPtr == nil || skPtr == nil {
163+
return nil, nil, errors.New("keygen failed")
164+
}
165+
return &PublicKey{pkPtr}, &SecretKey{skPtr}, nil
166+
}
167+
168+
// EncryptU64ToPtr encrypts a uint64 to an opaque Ciphertext pointer
169+
func (c *Context) EncryptU64ToPtr(pk *PublicKey, value uint64) (*Ciphertext, error) {
170+
if pk == nil || pk.ptr == nil {
171+
return nil, errors.New("PublicKey is nil")
172+
}
173+
ptr := C.go_encrypt_u64_ptr_out(c.ptr, pk.ptr, C.uint64_t(value))
174+
if ptr == nil {
175+
return nil, errors.New("encryption failed")
176+
}
177+
return &Ciphertext{ptr}, nil
178+
}
179+
180+
// DecryptU64FromPtr decrypts an opaque Ciphertext using a SecretKey pointer
181+
func (c *Context) DecryptU64FromPtr(sk *SecretKey, ct *Ciphertext) (uint64, error) {
182+
if sk == nil || sk.ptr == nil {
183+
return 0, errors.New("SecretKey is nil")
184+
}
185+
if ct == nil || ct.ptr == nil {
186+
return 0, errors.New("Ciphertext is nil")
187+
}
188+
result := C.go_decrypt_u64_ptr(c.ptr, sk.ptr, ct.ptr)
189+
return uint64(result), nil
190+
}
191+
192+
// EvalAdd homomorphically adds `other` into `acc` (acc = acc + other)
193+
func (c *Context) EvalAdd(acc, other *Ciphertext) error {
194+
if c == nil || c.ptr == nil {
195+
return errors.New("Context is nil")
196+
}
197+
if acc == nil || acc.ptr == nil {
198+
return errors.New("acc Ciphertext is nil")
199+
}
200+
if other == nil || other.ptr == nil {
201+
return errors.New("other Ciphertext is nil")
202+
}
203+
C.go_eval_add_inplace(c.ptr, acc.ptr, other.ptr)
204+
return nil
205+
}

openfhe_c.cpp

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#include "openfhe_c.h"
2+
3+
#include <openfhe/core/openfhecore.h> // v1.3 header root
4+
#include <openfhe/pke/openfhe.h>
5+
#include <openfhe/core/utils/serial.h>
6+
#include <openfhe/pke/ciphertext-ser.h>
7+
#include <openfhe/pke/key/key-ser.h>
8+
#include <openfhe/pke/scheme/bgvrns/bgvrns-ser.h>
9+
10+
using namespace lbcrypto;
11+
12+
// ────────── Serialization Helpers ───────────────────────────────────────
13+
#include <vector>
14+
#include <sstream>
15+
#include <cstring>
16+
#include <cstdlib>
17+
18+
template <typename T>
19+
void serialize_to_vec(const T& obj, std::vector<uint8_t>& out) {
20+
std::stringstream ss;
21+
Serial::Serialize(obj, ss, SerType::BINARY);
22+
auto s = ss.str();
23+
out.assign(s.begin(), s.end());
24+
}
25+
26+
template <typename T>
27+
bool deserialize_from_buf(T& obj, const uint8_t* buf, size_t len) {
28+
std::stringstream ss;
29+
ss.write(reinterpret_cast<const char*>(buf), len);
30+
ss.seekg(0);
31+
try {
32+
Serial::Deserialize(obj, ss, SerType::BINARY);
33+
return true;
34+
} catch (...) {
35+
return false;
36+
}
37+
}
38+
39+
// ────────── Context ────────────────────────────────────────────────────
40+
void* go_bgvrns_new(uint32_t depth, uint64_t t) {
41+
CCParams<CryptoContextBGVRNS> params;
42+
params.SetMultiplicativeDepth(depth);
43+
params.SetPlaintextModulus(t);
44+
auto cc = GenCryptoContext(params);
45+
cc->Enable(PKE);
46+
cc->Enable(LEVELEDSHE);
47+
return new CryptoContext<DCRTPoly>(cc);
48+
}
49+
50+
void go_bgvrns_free(void* ctx) {
51+
delete static_cast<CryptoContext<DCRTPoly>*>(ctx);
52+
}
53+
54+
// ────────── Key Generation ──────────────────────────────────────────────
55+
void go_keygen_ptr(void* ctx, void** pk_ptr, void** sk_ptr) {
56+
auto cc = *static_cast<CryptoContext<DCRTPoly>*>(ctx);
57+
auto kp = cc->KeyGen();
58+
*pk_ptr = new PublicKey<DCRTPoly>(kp.publicKey);
59+
*sk_ptr = new PrivateKey<DCRTPoly>(kp.secretKey);
60+
}
61+
62+
// ────────── PublicKey ───────────────────────────────────────────────────
63+
void go_pk_serialize(void* pk_ptr, uint8_t** buf, size_t* len) {
64+
auto& pk = *static_cast<PublicKey<DCRTPoly>*>(pk_ptr);
65+
std::vector<uint8_t> tmp;
66+
serialize_to_vec(pk, tmp);
67+
*len = tmp.size();
68+
*buf = static_cast<uint8_t*>(malloc(*len));
69+
memcpy(*buf, tmp.data(), *len);
70+
}
71+
72+
void* go_pk_deserialize(void* ctx, const uint8_t* buf, size_t len) {
73+
auto pk = new PublicKey<DCRTPoly>();
74+
deserialize_from_buf(*pk, buf, len);
75+
return pk;
76+
}
77+
78+
void go_pk_free(void* pk_ptr) {
79+
delete static_cast<PublicKey<DCRTPoly>*>(pk_ptr);
80+
}
81+
82+
// ────────── SecretKey ───────────────────────────────────────────────────
83+
void go_sk_serialize(void* sk_ptr, uint8_t** buf, size_t* len) {
84+
auto& sk = *static_cast<PrivateKey<DCRTPoly>*>(sk_ptr);
85+
std::vector<uint8_t> tmp;
86+
serialize_to_vec(sk, tmp);
87+
*len = tmp.size();
88+
*buf = static_cast<uint8_t*>(malloc(*len));
89+
memcpy(*buf, tmp.data(), *len);
90+
}
91+
92+
void* go_sk_deserialize(void* ctx, const uint8_t* buf, size_t len) {
93+
auto sk = new PrivateKey<DCRTPoly>();
94+
deserialize_from_buf(*sk, buf, len);
95+
return sk;
96+
}
97+
98+
void go_sk_free(void* sk_ptr) {
99+
delete static_cast<PrivateKey<DCRTPoly>*>(sk_ptr);
100+
}
101+
102+
// ────────── Encryption/Decryption ──────────────────────────────────────
103+
void* go_encrypt_u64_ptr_out(void* ctx, void* pk_ptr, uint64_t value) {
104+
auto cc = *static_cast<CryptoContext<DCRTPoly>*>(ctx);
105+
auto& pk = *static_cast<PublicKey<DCRTPoly>*>(pk_ptr);
106+
Plaintext pt = cc->MakePackedPlaintext({static_cast<int64_t>(value)});
107+
auto ct = cc->Encrypt(pk, pt);
108+
return new Ciphertext<DCRTPoly>(ct);
109+
}
110+
111+
uint64_t go_decrypt_u64_ptr(void* ctx, void* sk_ptr, void* ct_ptr) {
112+
if (!ctx || !sk_ptr || !ct_ptr) return 0;
113+
auto cc = *static_cast<CryptoContext<DCRTPoly>*>(ctx);
114+
auto& sk = *static_cast<PrivateKey<DCRTPoly>*>(sk_ptr);
115+
auto& ct = *static_cast<Ciphertext<DCRTPoly>*>(ct_ptr);
116+
Plaintext pt;
117+
cc->Decrypt(sk, ct, &pt);
118+
pt->SetLength(1);
119+
return static_cast<uint64_t>(pt->GetPackedValue()[0]);
120+
}
121+
122+
// ────────── Ciphertext Serialization ───────────────────────────────────
123+
void go_ct_ser(void* ct_ptr, uint8_t** buf, size_t* len) {
124+
auto& ct = *static_cast<Ciphertext<DCRTPoly>*>(ct_ptr);
125+
std::vector<uint8_t> tmp;
126+
serialize_to_vec(ct, tmp);
127+
*len = tmp.size();
128+
*buf = static_cast<uint8_t*>(malloc(*len));
129+
memcpy(*buf, tmp.data(), *len);
130+
}
131+
132+
void* go_ct_deser(void* ctx, const uint8_t* buf, size_t len) {
133+
auto ct = new Ciphertext<DCRTPoly>();
134+
deserialize_from_buf(*ct, buf, len);
135+
return ct;
136+
}
137+
138+
void go_ct_free(void* ct_ptr) {
139+
delete static_cast<Ciphertext<DCRTPoly>*>(ct_ptr);
140+
}
141+
142+
// ────────── Evaluation ─────────────────────────────────────────────────
143+
void go_eval_add_inplace(void* ctx, void* acc_ptr, void* other_ptr) {
144+
auto cc = *static_cast<CryptoContext<DCRTPoly>*>(ctx);
145+
auto& acc = *static_cast<Ciphertext<DCRTPoly>*>(acc_ptr);
146+
auto& other = *static_cast<Ciphertext<DCRTPoly>*>(other_ptr);
147+
acc = cc->EvalAdd(acc, other);
148+
}
149+
150+
// ────────── Misc ───────────────────────────────────────────────────────
151+
void go_buf_free(uint8_t* p) {
152+
free(p);
153+
}

0 commit comments

Comments
 (0)