HE-API提供一个统一的接口,屏蔽了底层使用的SHE library
的细节,使对加密不是很了解的人也可以轻松掌握(代码在这里)。HE-API
目前只支持HElib,通过使用不同的编译选项(FXPT
,BINARY
)来生成支持不同数据类型的库:helib.a.fxpt
,helib.a.binary
和helib.a.ulong
。下面以testInteger
函数为例,来分析如何使用:
template <unsigned long nb_tests>
int testInteger() {
// Determine if the test should run
#ifdef BINARY
unsigned long run = HE::supports_bit_encryption;
#else
unsigned long run = HE::supports_unsigned_encryption;
#endif
if (!run) {
return 0;
}
timing t;
gmp_randclass prng(gmp_randinit_default);
// prng.seed(0);
prng.seed(time(NULL)); // To set different seeds
void* parameters = nullptr;
void* sk = nullptr;
void* pk = nullptr;
void* evk = nullptr;
// Init
t.start();
HE::init(¶meters);
t.stop("Init");
// Keygen
t.start();
HE::keygen(parameters, &sk, &pk, &evk);
t.stop("Keygen");
// HE::serialize_sk("sk.bin", sk);
// std::cout << "serialized?" << std::endl;
// Random messages
unsigned long* messages1 = new unsigned long[nb_tests];
unsigned long* messages2 = new unsigned long[nb_tests];
for (unsigned long i = 0; i < nb_tests; i++) {
messages1[i] =
mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();
messages2[i] =
mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();
}
// Encrypt
void** ciphertexts1 = new void* [nb_tests];
void** ciphertexts2 = new void* [nb_tests];
t.start();
for (unsigned long i = 0; i < nb_tests; i++) {
HE::encryptInteger(pk, &(ciphertexts1[i]), messages1[i]);
HE::encryptInteger(pk, &(ciphertexts2[i]), messages2[i]);
}
t.stop("Encrypt Integer", nb_tests * 2);
// Decrypt
unsigned long* messages1_decrypted = new unsigned long[nb_tests];
unsigned long* messages2_decrypted = new unsigned long[nb_tests];
t.start();
for (unsigned long i = 0; i < nb_tests; i++) {
HE::decryptInteger(sk, pk, ciphertexts1[i], &(messages1_decrypted[i]));
HE::decryptInteger(sk, pk, ciphertexts2[i], &(messages2_decrypted[i]));
}
t.stop("Decrypt Integer", nb_tests * 2);
// Correctness of decryption
for (unsigned long i = 0; i < nb_tests; i++) {
assert(messages1[i] == messages1_decrypted[i]);
assert(messages2[i] == messages2_decrypted[i]);
}
// Homomorphic additions
unsigned long* messages_added = new unsigned long[nb_tests];
for (unsigned long i = 0; i < nb_tests; i++) {
messages_added[i] = (messages1[i] + messages2[i]) % HE::plaintext_modulus;
}
void** ciphertexts_added = new void* [nb_tests];
t.start();
for (unsigned long i = 0; i < nb_tests; i++) {
HE::add(pk, evk, &(ciphertexts_added[i]), ciphertexts1[i], ciphertexts2[i]);
}
t.stop("Homomorphic Addition", nb_tests);
// Correctness of addition
unsigned long* messages_added_decrypted = new unsigned long[nb_tests];
for (unsigned long i = 0; i < nb_tests; i++) {
HE::decryptInteger(sk, pk, ciphertexts_added[i],
&(messages_added_decrypted[i]));
assert(messages_added_decrypted[i] == messages_added[i]);
}
// Homomorphic multiplications
unsigned long* messages_multiplied = new unsigned long[nb_tests];
for (unsigned long i = 0; i < nb_tests; i++) {
messages_multiplied[i] = (messages1[i] * messages2[i]) % HE::plaintext_modulus;
}
void** ciphertexts_multiplied = new void* [nb_tests];
t.start();
for (unsigned long i = 0; i < nb_tests; i++) {
HE::mul(pk, evk, &(ciphertexts_multiplied[i]), ciphertexts1[i],
ciphertexts2[i]);
}
t.stop("Homomorphic Multiplication", nb_tests);
// Correctness of multiplication
unsigned long* messages_multiplied_decrypted = new unsigned long[nb_tests];
for (unsigned long i = 0; i < nb_tests; i++) {
HE::decryptInteger(sk, pk, ciphertexts_multiplied[i],
&(messages_multiplied_decrypted[i]));
assert(messages_multiplied_decrypted[i] == messages_multiplied[i]);
}
delete[] messages1;
delete[] messages2;
delete[] messages_added;
delete[] messages_added_decrypted;
delete[] messages_multiplied;
delete[] messages_multiplied_decrypted;
for(long i=0; i< nb_tests; i++)
{
HE::freeup_ciphertext(pk,ciphertexts1[i]);
HE::freeup_ciphertext(pk,ciphertexts2[i]);
HE::freeup_ciphertext(pk,ciphertexts_added[i]);
HE::freeup_ciphertext(pk,ciphertexts_multiplied[i]);
}
delete[] ciphertexts1;
delete[] ciphertexts2;
delete[] ciphertexts_added;
delete[] ciphertexts_multiplied;
HE::freeup_keys(parameters,sk,pk,evk);
return 0;
}
(1)HE-API
使用了gmp项目:
a)gmp_randclass
类用来生成随机数:
......
gmp_randclass prng(gmp_randinit_default);
// prng.seed(0);
prng.seed(time(NULL)); // To set different seeds
......
messages1[i] =
mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();
messages2[i] =
mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();
b)mpz_class
用来表示整数。get_ui()
返回mpz_class
的最低位的unsigned long
。以Binary
为例,mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();
随机返回0
和1
。
(2)另外就是需要注意加法和乘法时的取模运算:
......
messages_added[i] = (messages1[i] + messages2[i]) % HE::plaintext_modulus;
......
messages_multiplied[i] = (messages1[i] * messages2[i]) % HE::plaintext_modulus;
仍以Binary
为例,此时PLAINTEXT_MODULUS
的值为2
,即要对2
取模。操作数是1
个bit
,取值为0
或1
,加密结果对应的也是0
或1
。
P.S.,在编译HEAT
使用HElib
时可能会遇到错误,具体参考这个issue。