Documentation Index Fetch the complete documentation index at: https://mintlify.com/octra-labs/pvac_hfhe_cpp/llms.txt
Use this file to discover all available pages before exploring further.
This example demonstrates the core functionality of PVAC-HFHE, including key generation, encryption/decryption, homomorphic operations, and various algebraic properties.
Overview
The basic usage example showcases:
Key generation and parameter setup
Encryption and decryption of values
Homomorphic addition, multiplication, and subtraction
Algebraic properties (commutativity, associativity, distributivity)
Advanced operations (powers, polynomials, Fibonacci, factorial)
Text encryption and performance benchmarks
Key generation
Initialize parameters and keys
Start by setting up the cryptographic parameters and generating the public/secret key pair: #include <pvac/pvac.hpp>
using namespace pvac ;
Params prm;
PubKey pk;
SecKey sk;
keygen (prm, pk, sk);
This creates default parameters with:
m_bits: Field size parameter
n_bits: Security parameter
B: Budget parameter
Basic encryption and decryption
Encrypt and decrypt integer values:
uint64_t a = 42 , b = 17 ;
Cipher ca = enc_value (pk, sk, a);
Cipher cb = enc_value (pk, sk, b);
// Decrypt and verify
assert ( dec_value (pk, sk, ca). lo == 42 );
assert ( dec_value (pk, sk, cb). lo == 17 );
The .lo field extracts the lower 64 bits of the field element, which contains the encrypted integer value.
Homomorphic operations
Addition and subtraction
// Encrypt values
Cipher ca = enc_value (pk, sk, 42 );
Cipher cb = enc_value (pk, sk, 17 );
// Homomorphic addition
Cipher sum = ct_add (pk, ca, cb);
assert ( dec_value (pk, sk, sum). lo == 59 ); // 42 + 17
// Homomorphic subtraction
Cipher diff = ct_sub (pk, ca, cb);
assert ( dec_value (pk, sk, diff). lo == 25 ); // 42 - 17
Multiplication
// Homomorphic multiplication
Cipher prod = ct_mul (pk, ca, cb);
assert ( dec_value (pk, sk, prod). lo == 714 ); // 42 * 17
Algebraic properties
PVAC-HFHE preserves standard algebraic properties:
Commutativity
// Addition: a + b = b + a
Cipher c_ab = ct_add (pk, ca, cb);
Cipher c_ba = ct_add (pk, cb, ca);
assert ( dec_value (pk, sk, c_ab). lo == dec_value (pk, sk, c_ba). lo );
// Multiplication: a * b = b * a
assert ( dec_value (pk, sk, ct_mul (pk, ca, cb)). lo ==
dec_value (pk, sk, ct_mul (pk, cb, ca)). lo );
Associativity
uint64_t c = 7 ;
Cipher cc = enc_value (pk, sk, c);
// (a + b) + c = a + (b + c)
Cipher c_ab_c = ct_add (pk, ct_add (pk, ca, cb), cc);
Cipher c_a_bc = ct_add (pk, ca, ct_add (pk, cb, cc));
assert ( dec_value (pk, sk, c_ab_c). lo == dec_value (pk, sk, c_a_bc). lo );
// (a * b) * c = a * (b * c)
Cipher c_ab_c_mul = ct_mul (pk, ct_mul (pk, ca, cb), cc);
Cipher c_a_bc_mul = ct_mul (pk, ca, ct_mul (pk, cb, cc));
assert ( dec_value (pk, sk, c_ab_c_mul). lo == dec_value (pk, sk, c_a_bc_mul). lo );
Distributivity
// a * (b + c) = a*b + a*c
Cipher c_bpc = ct_add (pk, cb, cc);
Cipher c_a_bpc = ct_mul (pk, ca, c_bpc);
Cipher c_ab_ac = ct_add (pk, ct_mul (pk, ca, cb), ct_mul (pk, ca, cc));
assert ( dec_value (pk, sk, c_a_bpc). lo == dec_value (pk, sk, c_ab_ac). lo );
Advanced examples
Computing powers
Compute x^8 through repeated squaring:
Cipher cx_1 = enc_value (pk, sk, 2 );
Cipher cx_2 = ct_mul (pk, cx_1, cx_1); // 2^2 = 4
Cipher cx_4 = ct_mul (pk, cx_2, cx_2); // 4^2 = 16
Cipher cx_8 = ct_mul (pk, cx_4, cx_4); // 16^2 = 256
assert ( dec_value (pk, sk, cx_8). lo == 256 );
The circuit depth for x^8 is only 3 multiplications when using repeated squaring, making it very efficient.
Fibonacci sequence
Compute the 10th Fibonacci number:
Cipher fib_p = enc_value (pk, sk, 0 );
Cipher fib_c = enc_value (pk, sk, 1 );
for ( int i = 2 ; i <= 10 ; i ++ ) {
Cipher fib_n = ct_add (pk, fib_p, fib_c);
fib_p = fib_c;
fib_c = fib_n;
}
assert ( dec_value (pk, sk, fib_c). lo == 55 ); // fib(10) = 55
Factorial
Compute 6! homomorphically:
Cipher fact = enc_value (pk, sk, 1 );
for ( uint64_t i = 2 ; i <= 6 ; i ++ ) {
fact = ct_mul (pk, fact, enc_value (pk, sk, i));
}
assert ( dec_value (pk, sk, fact). lo == 720 ); // 6! = 720
Sum of squares
Compute 1² + 2² + 3² + 4² + 5²:
Cipher sum_sq = enc_value (pk, sk, 0 );
for ( uint64_t i = 1 ; i <= 5 ; i ++ ) {
Cipher ci = enc_value (pk, sk, i);
sum_sq = ct_add (pk, sum_sq, ct_mul (pk, ci, ci));
}
assert ( dec_value (pk, sk, sum_sq). lo == 55 ); // 1 + 4 + 9 + 16 + 25 = 55
Text encryption
PVAC-HFHE supports encrypting text strings:
// ASCII text
std ::string ascii = "Hello, World!" ;
std ::vector < Cipher > enc_ascii = enc_text (pk, sk, ascii);
std ::string dec_ascii = dec_text (pk, sk, enc_ascii);
assert (dec_ascii == ascii);
// Special characters
std ::string special = "!@#$%^&*()_+-=[]{}|;':" ,. /<>? ` ~ ";
assert(dec_text(pk, sk, enc_text(pk, sk, special)) == special);
// Empty string
std::string empty = "";
assert(dec_text(pk, sk, enc_text(pk, sk, empty)) == empty);
Ciphertext properties
Randomized encryption
The same plaintext encrypted twice produces different ciphertexts:
Cipher ca1 = enc_value (pk, sk, 100 );
Cipher ca2 = enc_value (pk, sk, 100 );
// Both decrypt to 100
assert ( dec_value (pk, sk, ca1). lo == 100 );
assert ( dec_value (pk, sk, ca2). lo == 100 );
// But have different randomness
assert ( ca1 . E [ 0 ]. w [ 0 ]. lo != ca2 . E [ 0 ]. w [ 0 ]. lo );
Commitments
Generate cryptographic commitments to ciphertexts:
auto cm1 = commit_ct (pk, ca1);
auto cm2 = commit_ct (pk, ca2);
// Different ciphertexts produce different commitments
assert (cm1 != cm2);
Commitments bind to specific ciphertexts and can be used for verifiable computation protocols.
Complete example
Here’s a complete working example:
#include <iostream>
#include <pvac/pvac.hpp>
using namespace pvac ;
int main () {
// Key generation
Params prm;
PubKey pk;
SecKey sk;
keygen (prm, pk, sk);
// Encrypt values
uint64_t a = 42 , b = 17 ;
Cipher ca = enc_value (pk, sk, a);
Cipher cb = enc_value (pk, sk, b);
// Homomorphic operations
Cipher sum = ct_add (pk, ca, cb);
Cipher prod = ct_mul (pk, ca, cb);
Cipher diff = ct_sub (pk, ca, cb);
// Decrypt results
std ::cout << "a + b = " << dec_value (pk, sk, sum). lo << std ::endl; // 59
std ::cout << "a * b = " << dec_value (pk, sk, prod). lo << std ::endl; // 714
std ::cout << "a - b = " << dec_value (pk, sk, diff). lo << std ::endl; // 25
return 0 ;
}
Source code
The complete basic usage example with all test cases is available at:
Next steps
Polynomial evaluation Learn how to evaluate polynomials homomorphically
ML credit scoring Build encrypted machine learning models