A lightweight C++ implementation of the CKKS (Cheon-Kim-Kim-Song) homomorphic encryption scheme, optimized for embedded systems and cross-platform deployment. Implemented with full-RNS. No bootstrapping. ~1.2k lines of code and quite readable.
This project is a fork of smkhe with the following modifications:
- Removed multi-key (MK) functionality for single-key use cases
- Removed protobuf serialization
- Optimized for benchmarking CKKS encryption on embedded boards
- Added cross-compilation support for ARM platforms
This library provides a clean, efficient implementation of CKKS homomorphic encryption, allowing you to perform computations on encrypted data. This implements the full RNS version of CKKS.
simple-ckks/
├── include/simple_ckks/ # Header files
│ ├── simple_ckks.h # Main include file
│ ├── parameters.h # CKKS parameters
│ ├── encoder.h # Encoding/decoding operations
│ ├── encryptor.h # Encryption/decryption
│ ├── evaluator.h # Homomorphic operations
│ ├── keygen.h # Key generation
│ └── math/ # Mathematical operations
├── src/ # Source files
├── test/ # Unit tests
├── demo/ # Demo application
│ └── ckks_demo.cpp # Example usage with timing
├── CMakeLists.txt # Build configuration
├── toolchain-aarch64.cmake # ARM cross-compilation settings
└── build scripts # Convenience scripts
- CMake 3.10 or higher
- C++17 compatible compiler
- (Optional) aarch64 cross-compiler for ARM builds
./build.shThis will create a build/ directory with:
libsimple_ckks.a- Static librarytests- Unit test executableckks_demo- Demo application
To cross-compile, you need a sysroot from your target board. Create it by:
-
SSH into your board and create a tar archive of the system libraries:
ssh root@your-board-ip tar czf /tmp/imx-sysroot.tar.gz /usr/include /usr/lib /lib
-
Copy the archive to your development machine:
scp root@your-board-ip:/tmp/imx-sysroot.tar.gz . -
Extract it to a directory on your development machine:
mkdir -p ~/imx-sysroot tar xzf imx-sysroot.tar.gz -C ~/imx-sysroot
-
Set the environment variable:
export IMX_SYSROOT=~/imx-sysroot
Once you have the sysroot set up:
./build-arm.shThis creates a build-arm/ directory with the NXP ARM64 Cortex A35 binary ckks_demo.
Alternatively, you can pass the sysroot path directly to CMake:
cmake -B build-arm -S . -DIMX_SYSROOT=/path/to/imx-sysroot -DCMAKE_TOOLCHAIN_FILE=toolchain-aarch64.cmake
make -C build-arm ckks_demo./build.sh- Full native build./build-arm.sh- Full ARM cross-compilation./quick-build-arm.sh- Fast NXP rebuild (source changes only)./clean.sh- Remove all build artifacts
#include "simple_ckks/simple_ckks.h"
using namespace simple_ckks;
// Set up parameters
vector<uint64_t> primes = {1152921504606748673, 576460752308273153, 576460752302473217};
vector<uint64_t> special_primes = {0x7fffffffe0001, 0x80000001c0001, 0x80000002c0001, 0x7ffffffd20001};
Parameters params(1ULL << 40, 8192, primes, special_primes);
// Generate keys
Keygen keygen(params);
SecretKey secret_key = keygen.generateSecretKey();
PublicKey public_key = keygen.generatePublicKey();
EvaluationKey eval_key = keygen.generateEvaluationKey();
// Encode and encrypt
Encoder encoder(params);
Encryptor encryptor(params);
vector<complex<double>> data = {3.14159, 2.71828, 1.41421, 1.61803};
Plaintext plaintext = encoder.encode(data);
Ciphertext ciphertext = encryptor.encrypt(plaintext, public_key);
// Perform homomorphic operations
Evaluator evaluator(params, eval_key);
vector<complex<double>> addend = {1.0, 1.0, 1.0, 1.0};
Plaintext add_plain = encoder.encode(addend);
evaluator.addPlainInPlace(ciphertext, add_plain);
// Decrypt and decode
Plaintext result_plain = encryptor.decrypt(ciphertext, secret_key);
vector<complex<double>> result = encoder.decode(result_plain);The included demo (demo/ckks_demo.cpp) demonstrates:
- Key generation
- Encoding/encryption
- Homomorphic addition
- Decryption/decoding
- Performance timing for each operation
Run it with:
./build/ckks_demo # Native
./build-arm/ckks_demo # On ARM boardTo deploy to an NXP or similar ARM64 board:
-
Build for ARM:
./build-arm.sh
-
Copy to your board:
scp build-arm/ckks_demo user@board-ip:/path/to/destination/
-
Run on the board:
ssh user@board-ip ./ckks_demo
The demo will output timing information for all operations, helping you optimize parameters for your specific hardware.
Key parameters that affect performance and security:
-
Polynomial degree (
poly_degree) -
Scale: Typically 2^40
- Affects precision of computations
-
Number of primes: Affects the multiplicative depth
- More primes = more multiplications possible
- Also affects performance
Run the unit tests:
./build/testsAvailable test suites:
- Encoder: Encoding/decoding operations
- NTTransformer: Number theoretic transforms
- Encryptor: Encryption/decryption
- Evaluator: Homomorphic operations
Typical performance on embedded ARM Cortex-A35 with secure parameters:
- Key generation: ~60s
- Encryption: ~60s
- Homomorphic addition: ~10s
- Decryption: ~1s
Performance varies based on polynomial degree and number of primes.