diff --git a/.vscode/settings.json b/.vscode/settings.json index 08f7c2754eca28a6614fecd7bd407203456c8097..f33cd36653b3a3dbb38cc531d7ee070e3c0ea1fe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,50 @@ "files.associations": { "complex": "cpp", "dense": "cpp", - "ostream": "cpp" + "ostream": "cpp", + "cmath": "cpp", + "iostream": "cpp", + "array": "cpp", + "deque": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "string_view": "cpp", + "initializer_list": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp", + "bit": "cpp" } } \ No newline at end of file diff --git a/bin/ciphertext.o b/bin/ciphertext.o index 5830b00f6e69da3dc16db8d5894f13bd1c281a13..53e2c279b2ccdaff6da70a2d7f9352b09e9d4e99 100644 Binary files a/bin/ciphertext.o and b/bin/ciphertext.o differ diff --git a/bin/ckks.o b/bin/ckks.o index cae37b73ac92dd312ef0b12fc2b0e98c01ed2da0..f3e2ce74b322285685d2a403fc6cef174094f9c0 100644 Binary files a/bin/ckks.o and b/bin/ckks.o differ diff --git a/bin/encoder.o b/bin/encoder.o index b45cd2614cfd93450643ca4f93e3c386bed296ac..66bb08d71a4344b4bc6a95824fd5374cbded1496 100644 Binary files a/bin/encoder.o and b/bin/encoder.o differ diff --git a/bin/evalkey.o b/bin/evalkey.o new file mode 100644 index 0000000000000000000000000000000000000000..e6440f8b4c2062a013146f0e44ba409475399f18 Binary files /dev/null and b/bin/evalkey.o differ diff --git a/bin/polynomial.o b/bin/polynomial.o index c3e84466b6fd1deb930b972183851d4c40d09685..85c713ba9381c4b08f003d14563c751776a81b7d 100644 Binary files a/bin/polynomial.o and b/bin/polynomial.o differ diff --git a/bin/pubkey.o b/bin/pubkey.o index 79471ef1cb37f39f1a4bf905b34d853f55c72ad4..ed114a7969e2488aa3e90825a8f52ae3a0452ab3 100644 Binary files a/bin/pubkey.o and b/bin/pubkey.o differ diff --git a/bin/seckey.o b/bin/seckey.o index 7619d41e8e790f22564107fc44bc4aa425085484..a4cfdc38f9f44fbab072cae7adc4365fde3b5734 100644 Binary files a/bin/seckey.o and b/bin/seckey.o differ diff --git a/comptest.sh b/comptest.sh new file mode 100755 index 0000000000000000000000000000000000000000..a5908bd2734b83a8a9bc22118474b58a7b90f29a --- /dev/null +++ b/comptest.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +g++ -c -o test.o test.cpp +g++ -o run test.o ./bin/ciphertext.o ./bin/ckks.o ./bin/encoder.o ./bin/polynomial.o ./bin/pubkey.o ./bin/seckey.o ./bin/evalkey.o \ No newline at end of file diff --git a/run b/run index 1608ab344c472f4669b5cebd69158c93f52c7ba0..d630e8fb57da53d34b4b5ac06d8fe066fb4675c9 100755 Binary files a/run and b/run differ diff --git a/src/ciphertext.cpp b/src/ciphertext.cpp index 7598a47567efa0badba07dc361315c3cdc79c977..e1bf748641f2467193a3ea526409ee80c4b3ab5a 100644 --- a/src/ciphertext.cpp +++ b/src/ciphertext.cpp @@ -15,3 +15,4 @@ Ciphertext Ciphertext:: operator + (Ciphertext const &obj){ Ciphertext out(out1, out2); return out; } + diff --git a/src/ciphertext.h b/src/ciphertext.h index fe752a9ce9de7d360d273a33ccda6773cb73c80c..a65b2fc8d7a5d23fb95dede554ac849b3b221689 100644 --- a/src/ciphertext.h +++ b/src/ciphertext.h @@ -10,6 +10,7 @@ class Ciphertext { Ciphertext(Polynomial _c0, Polynomial _c1); Ciphertext operator + (Ciphertext const &obj); + }; #endif \ No newline at end of file diff --git a/src/ckks.cpp b/src/ckks.cpp index 7d862113aa0174514d83f5002cc1d0849ce5a229..12725cea556a7c4ff38a9e84537faee20bd8d200 100644 --- a/src/ckks.cpp +++ b/src/ckks.cpp @@ -7,10 +7,15 @@ using namespace std; -CKKS::CKKS(int N, PubKey _pk, SecKey _sk){ +CKKS::CKKS(int N, PubKey _pk, EvalKey _evk, SecKey _sk){ pk = _pk; sk = _sk; + evk = _evk; deg = N; + ql = q0; + for (int i=0; i<6; i++){ + ql *= pl[i]; + } } Polynomial CKKS::genE(int degree, double var){ @@ -45,15 +50,47 @@ Polynomial CKKS::genZO(){ Ciphertext CKKS::encrypt(Polynomial pt){ Polynomial e = genE(4, 1.0); - Polynomial c0 = (e + pt) + pk.b; + Polynomial c0 = (pt) + pk.b; Polynomial c1 = pk.a; - Ciphertext ct(c0, c1); + Ciphertext ct(c0.modCoeff(ql), c1.modCoeff(ql)); return ct; } Polynomial CKKS::decrypt(Ciphertext ct){ Polynomial pt = ct.c0 + (ct.c1 * sk.s); - return pt; + return pt.modCoeff(ql); +} + +Ciphertext CKKS::add(Ciphertext ct1, Ciphertext ct2){ + Ciphertext out = ct1 + ct2; + return out; } +Ciphertext CKKS::mult(Ciphertext ct1, Ciphertext ct2){ + // Multiplication + Polynomial d1 = (ct1.c0 * ct2.c0).modCoeff(ql); + Polynomial d2 = ((ct1.c0 * ct2.c1) + (ct2.c0 * ct1.c1)).modCoeff(ql); + Polynomial d3 = (ct1.c1 * ct2.c1).modCoeff(ql); + + // Relin + Polynomial d3_0 = (d3 * evk.b).scaleRoundCoeff(1.0/1000.0); + Polynomial d3_1 = (d3 * evk.a).scaleRoundCoeff(1.0/1000.0); + + Polynomial outC0 = d1.modCoeff(ql) + d3_0.modCoeff(ql); + Polynomial outC1 = d2.modCoeff(ql) + d3_1.modCoeff(ql); + + // Rescale + ql = (double)ql / (double)pl[level-1]; + + outC0.scaleRoundCoeff(1.0/(double)pl[level-1]); + outC0.modCoeff(ql); + + outC1.scaleRoundCoeff(1.0/(double)pl[level-1]); + outC1.modCoeff(ql); + + level -= 1; + + Ciphertext out(outC0, outC1); + return out; +} \ No newline at end of file diff --git a/src/ckks.h b/src/ckks.h index 47e87ff138e8b3d03ef8c647b4f26252a607674d..21657d47ca15885824d57117d5176cad6c0a3a8e 100644 --- a/src/ckks.h +++ b/src/ckks.h @@ -1,6 +1,7 @@ #include "polynomial.h" #include "pubkey.h" #include "seckey.h" +#include "evalkey.h" #include "ciphertext.h" @@ -10,15 +11,22 @@ class CKKS { public: int deg; + int level = 6; + int q0 = 67; + int pl[6] = {61, 67, 71, 73, 79, 59}; + int ql; PubKey pk; + EvalKey evk; SecKey sk; - CKKS(int N, PubKey _pk, SecKey _sk); + CKKS(int N, PubKey _pk, EvalKey _evk, SecKey _sk); Polynomial genE(int degree, double var); Polynomial genZO(); Ciphertext encrypt(Polynomial pt); Polynomial decrypt(Ciphertext ct); + Ciphertext add(Ciphertext ct1, Ciphertext ct2); + Ciphertext mult(Ciphertext ct1, Ciphertext ct2); }; #endif \ No newline at end of file diff --git a/src/compile.sh b/src/compile.sh new file mode 100755 index 0000000000000000000000000000000000000000..0bb493acf053a07abd5bd82ac9246398f42d056b --- /dev/null +++ b/src/compile.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +g++ -c -o ../bin/ciphertext.o ciphertext.cpp +g++ -c -o ../bin/ckks.o ckks.cpp +g++ -c -o ../bin/encoder.o encoder.cpp +g++ -c -o ../bin/polynomial.o polynomial.cpp +g++ -c -o ../bin/pubkey.o pubkey.cpp +g++ -c -o ../bin/seckey.o seckey.cpp +g++ -c -o ../bin/evalkey.o evalkey.cpp diff --git a/src/evalkey.cpp b/src/evalkey.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7715cf188d918b491829f427e384de11e0c31669 --- /dev/null +++ b/src/evalkey.cpp @@ -0,0 +1,41 @@ +#include<iostream> +#include <complex> +#include <cmath> +#include <random> +#include "evalkey.h" + +using namespace std; + +EvalKey::EvalKey(Polynomial _s, int q){ + a = Polynomial(4); + b = Polynomial(4); + p = 1000; + s = _s; + cout << q << endl; + generateA(4, q); + computeB(q); +} + +void EvalKey::generateA(int degree, int q){ + int half_q = (p*q)/2; + random_device rd; + mt19937 gen(rd()); + uniform_int_distribution<int> dis(-half_q, half_q); + double a_coeffs[degree]; + + for (int i=0; i<degree; i++){ + a_coeffs[i] = (double) dis(gen); + } + a.setCoeffs(a_coeffs); +} + +void EvalKey::computeB(int q){ + double e[4] = {0.0, 0.0, 0.0, 0.0}; + Polynomial err(4, e); + Polynomial ev = (s * s).scaleCoeff(p); + Polynomial temp = (a.scaleCoeff(-1.0)) * s + err + ev; + Polynomial res = temp.modCoeff(q * p); + + b.setDegree(res.degree); + b.setCoeffs(res.coeffs); +} \ No newline at end of file diff --git a/src/evalkey.h b/src/evalkey.h new file mode 100644 index 0000000000000000000000000000000000000000..a1fbcf303bb1699a73be563383373b0683a99c3d --- /dev/null +++ b/src/evalkey.h @@ -0,0 +1,19 @@ +#include "polynomial.h" + +#ifndef EVALKEY_H +#define EVALKEY_H + +class EvalKey{ + public: + Polynomial a; + Polynomial b; + Polynomial s; + int p; + + EvalKey() = default; + EvalKey(Polynomial _s, int q); + void generateA(int degree, int q); + void computeB(int q); +}; + +#endif \ No newline at end of file diff --git a/src/polynomial.cpp b/src/polynomial.cpp index 593d1e3c2ae0afb43696d94dbb99fb25c6d90602..9389ddb75288cc0da9c91610bb5e8b1484c2c0fa 100644 --- a/src/polynomial.cpp +++ b/src/polynomial.cpp @@ -1,17 +1,23 @@ #include <complex> #include <cmath> #include <random> +#include <algorithm> +#include <string.h> +#include <iostream> #include "polynomial.h" +using namespace std; Polynomial::Polynomial(int deg){ degree = deg; + memset(coeffs, 0, sizeof(coeffs)); } Polynomial::Polynomial(int deg, double coeff[]){ degree = deg; + memset(coeffs, 0, sizeof(coeffs)); for(int i=0; i<degree; i++){ - coeffs[i] = coeff[i]; + coeffs[i] = coeff[i]; } } @@ -21,49 +27,72 @@ void Polynomial::setDegree(int N){ void Polynomial::setCoeffs(double coeff[]){ for(int i=0; i<degree; i++){ - coeffs[i] = coeff[i]; + coeffs[i] = coeff[i]; } } Polynomial Polynomial::scaleCoeff(double scale){ Polynomial out(degree); for (int i=0; i<degree; i++){ - out.coeffs[i] = coeffs[i] * scale; + out.coeffs[i] = coeffs[i] * scale; + } + return out; +} + +Polynomial Polynomial::scaleRoundCoeff(double scale){ + Polynomial out(degree); + for (int i=0; i<degree; i++){ + out.coeffs[i] = (double) round(coeffs[i] * scale); + } + return out; +} + +Polynomial Polynomial::modCoeff(int q){ + Polynomial out(degree); + for (int i=0; i<degree; i++){ + int temp = ((int) coeffs[i])%q; + out.coeffs[i] = (double) temp; } return out; } Polynomial Polynomial::dot (Polynomial const &obj){ - double coeff[degree]; - for(int i=0; i<degree; i++){ + int deg = max(obj.degree, degree); + double coeff[deg]; + for(int i=0; i<deg; i++){ coeff[i] = coeffs[i] * obj.coeffs[i]; } - Polynomial out(degree, coeff); + Polynomial out(deg, coeff); return out; } Polynomial Polynomial::operator + (Polynomial const &obj){ - double coeff[degree]; - for(int i=0; i<degree; i++){ - coeff[i] = coeffs[i] + obj.coeffs[i]; + int deg = max(obj.degree, degree); + double coeff[deg]; + for(int i=0; i<deg; i++){ + coeff[i] = coeffs[i] + obj.coeffs[i]; } - Polynomial out(degree, coeff); + Polynomial out(deg, coeff); return out; } Polynomial Polynomial::operator * (Polynomial const &obj){ - int deg = degree + obj.degree - 1; - double coeff[deg] = {0.0}; - + int deg = degree + obj.degree -1; + double coeff[deg]; for(int i=0; i<degree; i++){ - for(int j=0; j<obj.degree; j++){ - coeff[i+j] += coeffs[i] * obj.coeffs[j]; - } + for(int j=0; j<obj.degree; j++){ + coeff[i+j] += coeffs[i] * obj.coeffs[j]; + } } Polynomial out(deg, coeff); return out; } - +void Polynomial::printPol(){ + for(int i=0; i<degree; i++){ + cout << coeffs[i] << "x^" << i << "+ "; + } + cout << endl; +} \ No newline at end of file diff --git a/src/polynomial.h b/src/polynomial.h index 35b3e40876751cf9b8d19854cf0a830130213161..a9101a20a4d57a5740c1445a2d2abc70c6223c03 100644 --- a/src/polynomial.h +++ b/src/polynomial.h @@ -4,7 +4,7 @@ class Polynomial { public: int degree; - double coeffs[10]; + double coeffs[100]; Polynomial() = default; Polynomial(int deg); @@ -13,9 +13,13 @@ class Polynomial { void setDegree(int N); void setCoeffs(double coeff[]); Polynomial scaleCoeff(double scale); + Polynomial scaleRoundCoeff(double scale); + Polynomial modCoeff(int q); Polynomial dot(Polynomial const &obj); Polynomial operator + (Polynomial const &obj); Polynomial operator * (Polynomial const &obj); + + void printPol(); }; diff --git a/src/pubkey.cpp b/src/pubkey.cpp index ac08347cec4d7facc43f959da553d6a99c36515c..8472f7c60b0a15c3f6b68b60963cfd9b4d0378e5 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -6,13 +6,13 @@ using namespace std; -PubKey::PubKey(Polynomial _s){ +PubKey::PubKey(Polynomial _s, int q){ a = Polynomial(4); b = Polynomial(4); s = _s; - generateA(4, 4); - computeB(); + generateA(4, q); + computeB(q); } void PubKey::generateA(int degree, int q){ @@ -23,15 +23,17 @@ void PubKey::generateA(int degree, int q){ double a_coeffs[degree]; for (int i=0; i<degree; i++){ - a_coeffs[i] = (double) dis(gen); + a_coeffs[i] = (double) dis(gen); } a.setCoeffs(a_coeffs); } -void PubKey::computeB(){ +void PubKey::computeB(int q){ double e[4] = {0.0, 0.0, 0.0, 0.0}; Polynomial err(4, e); - Polynomial temp = (a.scaleCoeff(-1.0)).dot(s) + err; + Polynomial temp = (a.scaleCoeff(-1.0)) * s + err; + Polynomial res = temp.modCoeff(q); - b.setCoeffs(temp.coeffs); + b.setDegree(res.degree); + b.setCoeffs(res.coeffs); } diff --git a/src/pubkey.h b/src/pubkey.h index 0ef05535b87e23963638b8a269e4fcd76a4bffa4..4ab3dfaf52a203182bc19cd3af3e0c248a70f97c 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -10,9 +10,9 @@ class PubKey{ Polynomial s; PubKey() = default; - PubKey(Polynomial _s); + PubKey(Polynomial _s, int q); void generateA(int degree, int q); - void computeB(); + void computeB(int q); }; #endif \ No newline at end of file diff --git a/src/seckey.cpp b/src/seckey.cpp index 1d95c5e8714722c5225f3b47f1d9015404b9daaf..6eb3b518767677876478f50e680197a0da810d35 100644 --- a/src/seckey.cpp +++ b/src/seckey.cpp @@ -1,10 +1,25 @@ -#include <complex> -#include <cmath> #include <random> +#include <string> #include "seckey.h" +#include "encoder.h" + +using namespace std; SecKey::SecKey(){ s = Polynomial(4); - double test[4] = {1.0,-1.0,1.0,0.0}; - s.setCoeffs(test); + double coeff[4]; + + int h = 2; + string ones(h, '1'); + string zeros(2, '0'); + + string key = ones + zeros; + random_shuffle(key.begin(), key.end()); + + for(int i=0; i<4; i++){ + char temp = key.at(i); + coeff[i] = (double) (atoi(&temp)); + } + + s.setCoeffs(coeff); } diff --git a/src/seckey.h b/src/seckey.h index b7285285223476f1e51b37dcfa5e11841a1f2a51..8671f2908adaf07c1920b56aa0bd256a1161237d 100644 --- a/src/seckey.h +++ b/src/seckey.h @@ -1,4 +1,5 @@ #include "polynomial.h" +#include <string> #ifndef SECKEY_H #define SECKEY_H diff --git a/test.cpp b/test.cpp index baf0d9201fdf46576bd10ec10bd3b611d2ccd709..0e2dcafe35ad877272b266bbb5d0e5709126ee3f 100644 --- a/test.cpp +++ b/test.cpp @@ -2,13 +2,14 @@ #include "src/encoder.h" #include "src/polynomial.h" #include "src/ckks.h" +#include <string> using namespace std; int main(){ - Encoder enc(8, 128.0); - dcomplex a1 = 3.0 + 4.0 *J; + Encoder enc(8, 64.0); + dcomplex a1 = 3.0 + 4.0 *J; dcomplex a2 = 2.0 - 1.0 *J; dcomparr input = {a1, a2}; Polynomial pt = enc.encode(input); @@ -18,41 +19,48 @@ int main(){ } cout << endl; - SecKey sk = SecKey(); - PubKey pk(sk.s); - for(int i=0; i<4; i++){ - cout << pk.a.coeffs[i] << " "; - } - cout << endl; + int q0 = 67; + int pl[6] = {61, 67, 71, 73, 79, 59}; + int ql = q0; - for(int i=0; i<4; i++){ - cout << pk.b.coeffs[i] << " "; + for (int i=0; i<5; i++){ + ql *= pl[i]; } - cout << endl; - CKKS ckks(4, pk, sk); + SecKey sk = SecKey(); + PubKey pk(sk.s, ql); + EvalKey evk(sk.s, ql); + + CKKS ckks(4, pk, evk, sk); Ciphertext ct = ckks.encrypt(pt); - for(int i=0; i<4; i++){ - cout << ct.c0.coeffs[i] << " "; - } - cout << endl; + Ciphertext ctadd = ckks.mult(ct, ct); + // for(int i=0; i<8; i++){ + // cout << ctadd.c0.coeffs[i] << " "; + // } + // cout << endl; + Polynomial ptOut = ckks.decrypt(ctadd); + dcomparr output = enc.decode(ptOut); for(int i=0; i<4; i++){ - cout << ct.c1.coeffs[i] << " "; + cout << output.arr[i]/64.0 << " "; } cout << endl; - - Polynomial ptOut = ckks.decrypt(ct); + + Polynomial pt2 = pt * pt; + pt2.printPol(); + dcomparr out = enc.decode(pt2); for(int i=0; i<4; i++){ - cout << ptOut.coeffs[i] << " "; + cout << out.arr[i]/64.0 << " "; } cout << endl; - dcomparr output = enc.decode(pt); - for(int i=0; i<2; i++){ - cout << output.arr[i] << " "; - } - cout << endl; + // double test[] = {25600.0, 28800.0, 59300.0, 43200.0, 33700.0, 14400.0, 2025.0}; + // Polynomial mult(8, test); + // dcomparr out = enc.decode(mult); + // for(int i=0; i<4; i++){ + // cout << out.arr[i]/64.0 << " "; + // } + // cout << endl; return 0; } \ No newline at end of file diff --git a/test.o b/test.o index 1d39d18e28b05242fb33bb2902ed2650aebda916..af375def8b45afb52458808a0dac5ec9c9cb6c85 100644 Binary files a/test.o and b/test.o differ diff --git a/test.sh b/test.sh new file mode 100755 index 0000000000000000000000000000000000000000..f7f76f20516f84ff580f1f713c68a56cadc3dcf8 --- /dev/null +++ b/test.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +cd src +chmod +x compile.sh +./compile.sh +cd .. +chmod +x comptest.sh +./comptest.sh +./run \ No newline at end of file