Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions heu/library/algorithms/ashe/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Copyright 2024 Ant Group Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

load("@yacl//bazel:yacl.bzl", "yacl_cc_library", "yacl_cc_test")

package(default_visibility = ["//visibility:public"])

test_suite(
name = "ashe_tests",
)

yacl_cc_library(
name = "ashe",
hdrs = [
"ashe.h",
],
deps = [
":decryptor",
":encryptor",
":evaluator",
":key_generator",
],
)

yacl_cc_library(
name = "ciphertext",
hdrs = ["ciphertext.h"],
deps = [
"//heu/library/algorithms/util",
"@msgpack-c//:msgpack",
],
)

yacl_cc_library(
name = "secret_key",
hdrs = ["secret_key.h"],
deps = [
"//heu/library/algorithms/util",
"@msgpack-c//:msgpack",
],
)

yacl_cc_library(
name = "public_parameters",
srcs = ["public_parameters.cc"],
hdrs = ["public_parameters.h"],
deps = [
"//heu/library/algorithms/util",
"@msgpack-c//:msgpack",
],
)

yacl_cc_library(
name = "key_generator",
srcs = ["key_generator.cc"],
hdrs = ["key_generator.h"],
deps = [
":encryptor",
":public_parameters",
":secret_key",
],
)

yacl_cc_library(
name = "encryptor",
srcs = ["encryptor.cc"],
hdrs = ["encryptor.h"],
deps = [
":ciphertext",
":public_parameters",
":secret_key",
],
)

yacl_cc_library(
name = "decryptor",
srcs = ["decryptor.cc"],
hdrs = ["decryptor.h"],
deps = [
":ciphertext",
":public_parameters",
":secret_key",
],
)

yacl_cc_library(
name = "evaluator",
srcs = ["evaluator.cc"],
hdrs = ["evaluator.h"],
deps = [
":ciphertext",
":public_parameters",
],
)

yacl_cc_test(
name = "ashe_test",
srcs = ["ashe_tests.cc"],
deps = [
":ashe",
],
)
33 changes: 33 additions & 0 deletions heu/library/algorithms/ashe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Implementation of a Variant of Improved Symmetric Homomorphic Encryption(iSHE)

KeyGen(key_size):

- Sample a $k_p$-bit (usually $k_p=1536$) prime $p$
- Sample a $k_q$-bit (usually $k_q=512$) primes $q$
- Set $k_{r1}, k_{r2}$, the length of random numbers
- Set the message space parameter $k_m=64$
- The private key is $(p, q)$ and the public parameter is all the parameters $(k_p, k_q, k_{r1}, k_{r2}, k_m)$ and
pre-computed ciphertext of $0$

Encryption(sk, pp, m):

- Sample $r_1 \gets \{0,1\}^{k_{r1}}, r_2 \gets \{0,1\}^{k_{r2}}$
- The ciphertext is $c = r_1 \cdot p + r_2 \cdot q + (m\ \text{mod}\ (2^{k_m-1}-1))$

Decryption(sk, c):

- Compute $m' = c\ (\text{mod}\ p\ (\text{mod}\ q\ (\ \text{mod}\ (2^{k_m-1}-1)))$
- If $m' \le 2^{k_m-1}-1$ return m' else return $m'- 2^{k_m-1}-1$

Additive homomorphisms:

- Add $(c_1, c_2) = c_1 + c_2$
- AddPlain $(c, m) = c + (m\ (\ \text{mod}\ 2^{k_m-1}-1))$
- Negate $\text{MulPlain}(a, 2^{k_m-1}-2)$

Multiplicative homomorphism:

- MulPlain $(c, m) = c \cdot m$

This implement focus on 2048bits key size and 112bit security. The argument keysize in key_generator is actually the
scale of dataset.
22 changes: 22 additions & 0 deletions heu/library/algorithms/ashe/ashe.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2022 Ant Group Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include "heu/library/algorithms/ashe/decryptor.h"
#include "heu/library/algorithms/ashe/encryptor.h"
#include "heu/library/algorithms/ashe/evaluator.h"
#include "heu/library/algorithms/ashe/key_generator.h"
#include "heu/library/algorithms/ashe/public_parameters.h"
#include "heu/library/algorithms/ashe/secret_key.h"
184 changes: 184 additions & 0 deletions heu/library/algorithms/ashe/ashe_tests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// Copyright 2022 Ant Group Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>

#include "gtest/gtest.h"

#include "heu/library/algorithms/ashe/ashe.h"

namespace heu::lib::algorithms::ashe::test {

class asheTest : public testing::Test {
protected:
static void SetUpTestSuite() { KeyGenerator::Generate(2048, &sk_, &pp_); }

static SecretKey sk_;
static PublicKey pp_;
};

SecretKey asheTest::sk_;
PublicKey asheTest::pp_;

TEST_F(asheTest, SerializeTest) {
auto pp_buffer = pp_.Serialize();
PublicKey pp2;
pp2.Deserialize(pp_buffer);
ASSERT_EQ(pp_.k_r1, pp2.k_r1);
ASSERT_EQ(pp_.k_r2, pp2.k_r2);
ASSERT_EQ(pp_.k_q, pp2.k_q);
ASSERT_EQ(pp_.k_p, pp2.k_p);
ASSERT_EQ(pp_.randomZeros, pp2.randomZeros);

auto sk_buffer = sk_.Serialize();
SecretKey sk2;
sk2.Deserialize(sk_buffer);
ASSERT_EQ(sk_.p_, sk2.p_);
ASSERT_EQ(sk_.q_, sk2.q_);

Encryptor encryptor(pp2, sk2);

Evaluator evaluator(pp2);

BigInt m0(-12345);
Ciphertext ct = encryptor.Encrypt(m0);

BigInt dc;
Decryptor decryptor(pp_, sk_);
decryptor.Decrypt(ct, &dc);
EXPECT_EQ(dc, m0);
}

TEST_F(asheTest, OperationEvaluate) {
Encryptor encryptor_(pp_, sk_);
Evaluator evaluator_(pp_);
Decryptor decryptor_(pp_, sk_);

Plaintext m0 = Plaintext(12345);
Plaintext m1 = Plaintext(-20000);
Plaintext m3 = Plaintext(0);
Ciphertext c0 = encryptor_.Encrypt(m0);
Ciphertext c1 = encryptor_.Encrypt(m1);
Ciphertext c2 = encryptor_.Encrypt(-m0);
Ciphertext c3 = encryptor_.Encrypt(m3);
EXPECT_EQ(m0, Plaintext(12345));

Plaintext plain;
Ciphertext res;

// evaluate add
res = evaluator_.Add(c0, c0);
decryptor_.Decrypt(res, &plain);
EXPECT_EQ(plain, Plaintext(12345 * 2));
res = evaluator_.Add(c1, c1);
decryptor_.Decrypt(res, &plain);
EXPECT_EQ(plain, Plaintext(-20000 * 2));
res = evaluator_.Add(c0, c1);
decryptor_.Decrypt(res, &plain);
EXPECT_EQ(plain, Plaintext(12345 - 20000));
res = evaluator_.Add(c1, m3);
decryptor_.Decrypt(res, &plain);
EXPECT_EQ(plain, Plaintext(-20000));
res = evaluator_.Add(c0, m1);
decryptor_.Decrypt(res, &plain);
EXPECT_EQ(plain, Plaintext(12345 - 20000));
res = evaluator_.Add(c1, m0);
decryptor_.Decrypt(res, &plain);
EXPECT_EQ(plain, Plaintext(12345 - 20000));
res = evaluator_.Add(c2, c0);
decryptor_.Decrypt(res, &plain);
EXPECT_EQ(plain, Plaintext(0));

res = evaluator_.Mul(c0, m0);
decryptor_.Decrypt(res, &plain);
EXPECT_EQ(plain, Plaintext(12345 * 12345));
res = evaluator_.Mul(c1, m0);
decryptor_.Decrypt(res, &plain);

Ciphertext Zero = encryptor_.EncryptZero();
decryptor_.Decrypt(Zero, &plain);
EXPECT_EQ(plain, BigInt(0));
decryptor_.Decrypt(c1, &plain);
EXPECT_EQ(plain, BigInt(-20000));

Plaintext pt0 = Plaintext(12345);
Plaintext pt1 = Plaintext(20000);
Ciphertext ct0 = encryptor_.Encrypt(pt0);
Ciphertext ct1 = encryptor_.Encrypt(pt1);
evaluator_.AddInplace(&ct0, pt1);
decryptor_.Decrypt(ct0, &plain);
EXPECT_EQ(plain, BigInt(20000 + 12345));
evaluator_.AddInplace(&ct0, ct1);
decryptor_.Decrypt(ct0, &plain);
EXPECT_EQ(plain, BigInt(20000 + 12345 + 20000));
evaluator_.Randomize(&ct0);
decryptor_.Decrypt(ct0, &plain);
EXPECT_EQ(plain, BigInt(20000 + 12345 + 20000));
Plaintext pt_min = Plaintext(pp_.MessageSpace().first);
Plaintext pt_max = Plaintext(pp_.MessageSpace().second - BigInt(1));
Ciphertext ct_max = encryptor_.Encrypt(pt_max);
Ciphertext ct_min = encryptor_.Encrypt(pt_min);
Plaintext tmp = decryptor_.Decrypt(ct_min);
EXPECT_EQ(tmp, pt_min);
tmp = decryptor_.Decrypt(ct_max);
EXPECT_EQ(tmp, pt_max);
}

TEST_F(asheTest, NegateEvalutate) {
Encryptor encryptor_(pp_, sk_);
Evaluator evaluator_(pp_);
Decryptor decryptor_(pp_, sk_);
Plaintext p1 = Plaintext(123456);
Plaintext p2 = Plaintext(23456);
Ciphertext c1 = encryptor_.Encrypt(p1);
Ciphertext c2 = encryptor_.Encrypt(p2);
Ciphertext c3 = evaluator_.Sub(c1, c2);
c2 = evaluator_.Negate(c2);
decryptor_.Decrypt(c2, &p1);
EXPECT_EQ(p1, -23456);
decryptor_.Decrypt(c3, &p1);
EXPECT_EQ(BigInt(123456 - 23456), p1);
}

TEST_F(asheTest, RuntimeEfficientTest) {
Encryptor encryptor_(pp_, sk_);
Evaluator evaluator_(pp_);
Decryptor decryptor_(pp_, sk_);
Ciphertext c1, c2;
std::chrono::time_point<std::chrono::high_resolution_clock> t1, t2;
c1 = encryptor_.Encrypt(pp_.MessageSpace().second);
c2 = encryptor_.Encrypt(pp_.MessageSpace().second);
t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 100000; i++) {
evaluator_.AddInplace(&c1, c2);
// Plaintext m = decryptor_.Decrypt(c2);
// std::cout << m << std::endl;
// EXPECT_EQ(m, BigInt(-1)*BigInt(i + 2));
}
t2 = std::chrono::high_resolution_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
std::cout << "add 1w times used " << duration.count() << std::endl;
auto p = decryptor_.Decrypt(c1);
std::cout << p << std::endl;
EXPECT_EQ(p, pp_.MessageSpace().second * 100001);
t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10000; i++) {
Plaintext m = decryptor_.Decrypt(c2);
}
t2 = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
std::cout << "decrypt 1w times used " << duration.count() << std::endl;
}
} // namespace heu::lib::algorithms::ashe::test
Loading
Loading