├── .gitignore ├── CMakeLists.txt ├── Datasets ├── t10k-images-idx3-ubyte ├── t10k-labels-idx1-ubyte ├── train-images-idx3-ubyte └── train-labels-idx1-ubyte ├── README.md └── src ├── defines.hpp ├── ideal_functionality.cpp ├── linear_regression.cpp ├── linear_regression.hpp ├── online_phase.cpp ├── online_phase.hpp ├── read_MNIST.hpp ├── secure_ML.cpp ├── setup_phase.cpp ├── setup_phase.hpp ├── util.cpp └── util.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Executables 2 | *.exe 3 | *.out 4 | *.app 5 | 6 | # Build Directory 7 | build/ 8 | 9 | # C tags 10 | tags 11 | 12 | # Vim 13 | # Swap 14 | [._]*.s[a-v][a-z] 15 | [._]*.sw[a-p] 16 | [._]s[a-rt-v][a-z] 17 | [._]ss[a-gi-z] 18 | [._]sw[a-p] 19 | 20 | # Persistent undo 21 | [._]*.un~ 22 | 23 | # MacOS 24 | # General 25 | .DS_Store 26 | .AppleDouble 27 | .LSOverride 28 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | project (Secure-ML) 3 | set(NAME "Secure-ML") 4 | set (CMAKE_CXX_STANDARD 11) 5 | find_path(CMAKE_FOLDER NAMES cmake/emp-tool-config.cmake) 6 | include(${CMAKE_FOLDER}/cmake/common.cmake) 7 | include(${CMAKE_FOLDER}/cmake/source_of_randomness.cmake) 8 | include(${CMAKE_FOLDER}/cmake/threading.cmake) 9 | find_package(emp-ot REQUIRED) 10 | find_package(Eigen3 REQUIRED NO_MODULE) 11 | INCLUDE_DIRECTORIES(${EMP-OT_INCLUDE_DIRS}) 12 | 13 | add_executable(ideal_functionality 14 | src/ideal_functionality.cpp 15 | src/util.cpp 16 | ) 17 | add_executable(secure_ML 18 | src/secure_ML.cpp 19 | src/linear_regression.cpp 20 | src/online_phase.cpp 21 | src/setup_phase.cpp 22 | src/util.cpp 23 | ) 24 | 25 | target_link_libraries(ideal_functionality ${EMP-OT_LIBRARIES} Eigen3::Eigen) 26 | target_link_libraries(secure_ML ${EMP-OT_LIBRARIES} Eigen3::Eigen) 27 | -------------------------------------------------------------------------------- /Datasets/t10k-images-idx3-ubyte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shreya-28/Secure-ML/025ac3dde646bec826f0538b19b427d020507177/Datasets/t10k-images-idx3-ubyte -------------------------------------------------------------------------------- /Datasets/t10k-labels-idx1-ubyte: -------------------------------------------------------------------------------- 1 | '                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             -------------------------------------------------------------------------------- /Datasets/train-images-idx3-ubyte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shreya-28/Secure-ML/025ac3dde646bec826f0538b19b427d020507177/Datasets/train-images-idx3-ubyte -------------------------------------------------------------------------------- /Datasets/train-labels-idx1-ubyte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shreya-28/Secure-ML/025ac3dde646bec826f0538b19b427d020507177/Datasets/train-labels-idx1-ubyte -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Secure Machine Learning 2 | 3 | Secure Linear Regression in the Semi-Honest Two-Party Setting. More details on the protocol can be found in the [SecureML paper](https://eprint.iacr.org/2017/396.pdf). 4 | 5 | ### Prerequisites 6 | 1. [emp-ot](https://github.com/emp-toolkit/emp-ot/tree/15fb731e528974bcfe5aa09c18bb16376e949283). 7 | 2. [Eigen 3.3.7](http://eigen.tuxfamily.org/index.php?title=Main_Page#Download). 8 | 9 | ### Building Secure-ML 10 | ``` 11 | git clone https://github.com/shreya-28/Secure-ML.git 12 | cd Secure-ML 13 | mkdir build 14 | cd build 15 | cmake .. 16 | make 17 | ``` 18 | 19 | ### Running Secure-ML 20 | The build system creates two binaries, namely, `ideal_functionality` and `secure_ML`. The former represents the functionality that the latter implements securely. 21 | The binaries can be executed as follows: 22 | * `ideal_functionality` 23 | - `./build/bin/ideal_functionality [num_iter]` 24 | - `secure_ML` 25 | - On local machine 26 | - `./build/bin/secure_ML 1 8000 [num_iter] & ./build/bin/secure_ML 2 8000 [num_iter]` 27 | - On two different machines 28 | - `./build/bin/secure_ML 1 8000 [num_iter]` on Machine 1 29 | - `./build/bin/secure_ML 2 8000 [num_iter] [addr_of_machine_1]` on Machine 2 30 | -------------------------------------------------------------------------------- /src/defines.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SECML_DEFINES_HPP 2 | #define SECML_DEFINES_HPP 3 | #include 4 | 5 | #define BATCH_SIZE 128 6 | #define BITLEN 64 7 | #define LEARNING_RATE_INV 128 // 1/LEARNING_RATE 8 | #define DEBUG 1 9 | 10 | #define SCALING_FACTOR 8192 // Precision of 13 bits 11 | 12 | extern int PARTY; 13 | 14 | typedef Eigen::Matrix RowMatrixXi64; 15 | typedef Eigen::Matrix ColMatrixXi64; 16 | typedef Eigen::Matrix RowVectorXi64; 17 | typedef Eigen::Matrix ColVectorXi64; 18 | typedef Eigen::Matrix SignedRowMatrixXi64; 19 | typedef Eigen::Matrix SignedColMatrixXi64; 20 | typedef Eigen::Matrix RowMatrixXd; 21 | typedef Eigen::Matrix ColMatrixXd; 22 | typedef Eigen::Matrix RowVectorXd; 23 | typedef Eigen::Matrix ColVectorXd; 24 | 25 | struct SetupTriples{ 26 | RowMatrixXi64 Ai; 27 | ColMatrixXi64 Bi; 28 | ColMatrixXi64 Ci; 29 | ColMatrixXi64 Bi_; 30 | ColMatrixXi64 Ci_; 31 | }; 32 | 33 | #endif // SECML_DEFINES_HPP 34 | -------------------------------------------------------------------------------- /src/ideal_functionality.cpp: -------------------------------------------------------------------------------- 1 | #include "read_MNIST.hpp" 2 | #include "util.hpp" 3 | #include 4 | 5 | using namespace Eigen; 6 | using Eigen::Matrix; 7 | using namespace std; 8 | 9 | Eigen::IOFormat CommaInitFmt(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", " << ", ";"); 10 | 11 | int NUM_IMAGES = BATCH_SIZE; 12 | 13 | struct TrainingParams{ 14 | int n, d; 15 | double alpha = 1.0/LEARNING_RATE_INV; 16 | }; 17 | 18 | class LinearRegression{ 19 | public: 20 | double alpha; 21 | int n, d, t; 22 | RowMatrixXd X; 23 | ColVectorXd Y; 24 | ColVectorXd w; 25 | LinearRegression(RowMatrixXd& training_data, ColVectorXd& training_labels, 26 | TrainingParams params){ 27 | this->n = params.n; 28 | this->d = params.d; 29 | this->t = (params.n)/BATCH_SIZE; 30 | this->alpha = params.alpha; 31 | X = training_data; 32 | Y = training_labels; 33 | w.resize(d); 34 | for(int i = 0; i < d; i++) 35 | w[i] = 0; 36 | train_model(); 37 | } 38 | 39 | void train_batch(int iter, int indexLo){ 40 | RowMatrixXd Xb = X.block(indexLo, 0, BATCH_SIZE, d); 41 | ColVectorXd Yb = Y.segment(indexLo, BATCH_SIZE); 42 | 43 | ColVectorXd Y_(BATCH_SIZE); 44 | ColVectorXd D(BATCH_SIZE); 45 | ColVectorXd delta(d); 46 | 47 | Y_ = Xb * w; 48 | 49 | D = Y_ - Yb; 50 | 51 | delta = Xb.transpose() * D; 52 | 53 | delta = (delta * alpha)/BATCH_SIZE; 54 | 55 | w -= delta; 56 | 57 | /* 58 | ColVectorXd cost = X*w - Y; 59 | cost *= cost; 60 | double cost_ = cost.mean(); 61 | cout << "Cost: " << cost_ << endl; 62 | */ 63 | } 64 | 65 | void train_model(){ 66 | for (int i = 0; i < t; i++){ 67 | int indexLo = (i * BATCH_SIZE) % n; 68 | train_batch(i, indexLo); 69 | } 70 | } 71 | 72 | void test_model(RowMatrixXd& testing_data, ColVectorXd& testing_labels){ 73 | ColVectorXd prediction; 74 | prediction = testing_data * w; 75 | prediction *= 10; 76 | int n_ = testing_labels.rows(); 77 | 78 | ColVectorXd error; 79 | prediction = round(prediction.array()); 80 | 81 | int num_correct = 0; 82 | for (int i = 0; i < n_; i++){ 83 | if(prediction[i] == testing_labels[i]) 84 | num_correct++; 85 | } 86 | double accuracy = num_correct/((double) n_); 87 | cout << "Accuracy on testing the trained model is " << accuracy * 100 << endl; 88 | } 89 | }; 90 | 91 | int main(int argc, char** argv){ 92 | 93 | int num_iters = atoi(argv[1]); 94 | NUM_IMAGES *= num_iters; 95 | 96 | TrainingParams params; 97 | 98 | cout << "========" << endl; 99 | cout << "Training" << endl; 100 | cout << "========" << endl; 101 | 102 | vector> training_data; 103 | vector training_labels; 104 | 105 | read_MNIST_data(true, training_data, params.n, params.d); 106 | RowMatrixXd X(params.n, params.d); 107 | vector2d_to_RowMatrixXd(training_data, X); 108 | X /= 255.0; 109 | 110 | read_MNIST_labels(true, training_labels); 111 | ColVectorXd Y(params.n); 112 | vector_to_ColVectorXd(training_labels, Y); 113 | Y /= 10.0; 114 | 115 | LinearRegression linear_regression(X, Y, params); 116 | 117 | cout << "=======" << endl; 118 | cout << "Testing" << endl; 119 | cout << "=======" << endl; 120 | 121 | vector testing_labels; 122 | int n_; 123 | 124 | vector> testing_data; 125 | read_MNIST_data(false, testing_data, n_, params.d); 126 | 127 | RowMatrixXd testX(n_, params.d); 128 | vector2d_to_RowMatrixXd(testing_data, testX); 129 | testX /= 255.0; 130 | read_MNIST_labels(false, testing_labels); 131 | 132 | ColVectorXd testY(n_); 133 | vector_to_ColVectorXd(testing_labels, testY); 134 | linear_regression.test_model(testX, testY); 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /src/linear_regression.cpp: -------------------------------------------------------------------------------- 1 | #include "linear_regression.hpp" 2 | 3 | using namespace Eigen; 4 | using Eigen::Matrix; 5 | using namespace emp; 6 | using namespace std; 7 | 8 | void LinearRegression::train_model(){ 9 | for (int i = 0; i < t; i++){ 10 | int indexLo = (i * BATCH_SIZE) % n; 11 | online->train_batch(i, indexLo); 12 | } 13 | 14 | if (party == BOB){ 15 | send(io, online->wi); 16 | } 17 | else 18 | recv(io, w); 19 | 20 | if (party == ALICE){ 21 | send(io, online->wi); 22 | } 23 | else 24 | recv(io, w); 25 | 26 | w += online->wi; 27 | 28 | descale(w, w_d); 29 | } 30 | 31 | void LinearRegression::test_model(RowMatrixXd& testing_data, ColVectorXd& testing_labels){ 32 | ColVectorXd prediction; 33 | prediction = testing_data * w_d; 34 | prediction *= 10; 35 | int n_ = testing_labels.rows(); 36 | 37 | ColVectorXd error; 38 | prediction = round(prediction.array()); 39 | 40 | int num_correct = 0; 41 | for (int i = 0; i < n_; i++){ 42 | if(prediction[i] == testing_labels[i]) 43 | num_correct++; 44 | } 45 | double accuracy = num_correct/((double) n_); 46 | cout << "Accuracy on testing the trained model is " << accuracy * 100 << endl; 47 | } 48 | -------------------------------------------------------------------------------- /src/linear_regression.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SECML_LR_HPP 2 | #define SECML_LR_HPP 3 | #include "setup_phase.hpp" 4 | #include "online_phase.hpp" 5 | 6 | class LinearRegression{ 7 | public: 8 | emp::NetIO* io; 9 | int party; 10 | int n, d, t; 11 | RowMatrixXi64 X; 12 | ColVectorXi64 Y; 13 | ColVectorXi64 w; 14 | ColVectorXd w_d; 15 | SetupPhase* setup; 16 | OnlinePhase* online; 17 | LinearRegression(RowMatrixXi64& training_data, ColVectorXi64& training_labels, 18 | TrainingParams params, emp::NetIO* io){ 19 | this->n = params.n; 20 | this->d = params.d; 21 | this->t = (params.n)/BATCH_SIZE; 22 | this->X = training_data; 23 | this->Y = training_labels; 24 | this->io = io; 25 | this->party = PARTY; 26 | this->w.resize(d); 27 | this->w_d.resize(d); 28 | 29 | this->setup = new SetupPhase(n, d, t, io); 30 | setup->generateMTs(); 31 | std::cout << "Setup done" << std::endl; 32 | SetupTriples triples; 33 | setup->getMTs(&triples); 34 | 35 | RowMatrixXi64 Xi(X.rows(), X.cols()); 36 | ColVectorXi64 Yi(Y.rows(), Y.cols()); 37 | if (party == emp::ALICE) { 38 | emp::PRG prg; 39 | RowMatrixXi64 rX(X.rows(), X.cols()); 40 | ColVectorXi64 rY(Y.rows(), Y.cols()); 41 | prg.random_data(rX.data(), X.rows() * X.cols() * sizeof(uint64_t)); 42 | prg.random_data(rY.data(), Y.rows() * Y.cols() * sizeof(uint64_t)); 43 | Xi = X + rX; 44 | Yi = Y + rY; 45 | rX *= -1; 46 | rY *= -1; 47 | send(io, rX); 48 | send(io, rY); 49 | } else { 50 | recv(io, Xi); 51 | recv(io, Yi); 52 | } 53 | 54 | this->online = new OnlinePhase(params, io, &triples); 55 | online->initialize(Xi, Yi); 56 | 57 | train_model(); 58 | } 59 | 60 | void train_model(); 61 | void test_model(RowMatrixXd& testing_data, ColVectorXd& testing_labels); 62 | }; 63 | #endif //SECML_LR_HPP 64 | -------------------------------------------------------------------------------- /src/online_phase.cpp: -------------------------------------------------------------------------------- 1 | #include "online_phase.hpp" 2 | 3 | using namespace Eigen; 4 | using Eigen::Matrix; 5 | using namespace emp; 6 | using namespace std; 7 | 8 | void OnlinePhase::initialize(RowMatrixXi64& Xi, ColVectorXi64& Yi){ 9 | this->Xi = Xi; 10 | this->Yi = Yi; 11 | 12 | for (int i = 0; i < d; i++){ 13 | wi(i) = 0; 14 | } 15 | 16 | Ui = triples->Ai; 17 | 18 | Ei = Xi - Ui; 19 | 20 | Vi = triples->Bi; 21 | Vi_ = triples->Bi_; 22 | Zi = triples->Ci; 23 | Zi_ = triples->Ci_; 24 | 25 | if (party == ALICE) 26 | send(io, Ei); 27 | else 28 | recv(io, E); 29 | if (party == BOB) 30 | send(io, Ei); 31 | else 32 | recv(io, E); 33 | 34 | E += Ei; 35 | } 36 | 37 | void OnlinePhase::train_batch(int iter, int indexLo){ 38 | RowMatrixXi64 X = Xi.block(indexLo, 0, BATCH_SIZE, d); 39 | ColVectorXi64 Y = Yi.segment(indexLo, BATCH_SIZE); 40 | RowMatrixXi64 Eb = E.block(indexLo, 0, BATCH_SIZE, d); 41 | ColVectorXi64 V = Vi.col(iter); 42 | ColVectorXi64 V_ = Vi_.col(iter); 43 | ColVectorXi64 Z = Zi.col(iter); 44 | ColVectorXi64 Z_ = Zi_.col(iter); 45 | 46 | Fi = wi - V; 47 | 48 | ColVectorXi64 D(BATCH_SIZE); 49 | ColVectorXi64 Y_(BATCH_SIZE); 50 | ColVectorXi64 Fi_(BATCH_SIZE); 51 | ColVectorXi64 F_(BATCH_SIZE); 52 | ColVectorXi64 delta(d); 53 | 54 | if (party == ALICE) 55 | send(io, Fi); 56 | else 57 | recv(io, F); 58 | 59 | if (party == BOB) 60 | send(io, Fi); 61 | else 62 | recv(io, F); 63 | 64 | F += Fi; 65 | 66 | Y_ = -i*(Eb * F) + X * F + Eb * wi + Z; 67 | 68 | truncate(i, SCALING_FACTOR, Y_); 69 | 70 | D = Y_ - Y; 71 | 72 | Fi_ = D - V_; 73 | 74 | if (party == ALICE) 75 | send(io, Fi_); 76 | else 77 | recv(io, F_); 78 | 79 | if (party == BOB) 80 | send(io, Fi_); 81 | else 82 | recv(io, F_); 83 | 84 | F_ += Fi_; 85 | 86 | RowMatrixXi64 Et= Eb.transpose(); 87 | RowMatrixXi64 Xt= X.transpose(); 88 | 89 | delta = -i*(Et * F_) + Xt * F_ + Et * D + Z_; 90 | 91 | truncate(i, SCALING_FACTOR, delta); 92 | truncate(i, alpha_inv * BATCH_SIZE, delta); 93 | 94 | wi -= delta; 95 | } 96 | -------------------------------------------------------------------------------- /src/online_phase.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SECML_ONLINE_HPP 2 | #define SECML_ONLINE_HPP 3 | #include 4 | #include "util.hpp" 5 | 6 | template 7 | void scale(Eigen::PlainObjectBase& X, Eigen::PlainObjectBase& x){ 8 | Derived scaled_X = X * SCALING_FACTOR; 9 | x = scaled_X.template cast(); 10 | return; 11 | } 12 | 13 | template 14 | void descale(Eigen::PlainObjectBase& X, Eigen::PlainObjectBase& x){ 15 | Derived signed_X = X * SCALING_FACTOR; 16 | x = (X.template cast()).template cast(); 17 | x /= SCALING_FACTOR; 18 | return; 19 | } 20 | 21 | template 22 | void truncate(int i, uint64_t scaling_factor, Eigen::PlainObjectBase& X){ 23 | if (i == 1) 24 | X = -1 * X; 25 | X /= scaling_factor; 26 | if (i == 1) 27 | X = -1 * X; 28 | return; 29 | } 30 | 31 | struct TrainingParams{ 32 | int n, d; 33 | int alpha_inv = LEARNING_RATE_INV; 34 | }; 35 | 36 | class OnlinePhase{ 37 | public: 38 | int party, port; 39 | int n, d, t, i, alpha_inv; 40 | SetupTriples* triples; 41 | emp::NetIO* io; 42 | emp::PRG prg; 43 | RowMatrixXi64 Xi, Ui, E, Ei; 44 | ColVectorXi64 Yi, F, Fi, wi; 45 | ColMatrixXi64 Vi, Zi, Vi_, Zi_; 46 | 47 | OnlinePhase(TrainingParams params, emp::NetIO* io, SetupTriples* triples){ 48 | this->n = params.n; 49 | this->d = params.d; 50 | this->t = (params.n)/BATCH_SIZE; 51 | this->party = PARTY; 52 | this->alpha_inv = params.alpha_inv; 53 | this->io = io; 54 | this->triples = triples; 55 | 56 | if (party == emp::ALICE) 57 | i = 0; 58 | else 59 | i = 1; 60 | 61 | Xi.resize(n, d); 62 | Ui.resize(n, d); 63 | E.resize(n, d); 64 | Ei.resize(n, d); 65 | Yi.resize(n); 66 | Fi.resize(d); 67 | F.resize(d); 68 | wi.resize(d); 69 | Vi.resize(d, t); 70 | Zi.resize(BATCH_SIZE, t); 71 | Vi_.resize(BATCH_SIZE, t); 72 | Zi_.resize(d, t); 73 | } 74 | 75 | void initialize(RowMatrixXi64& Xi, ColVectorXi64& Yi); 76 | void train_batch(int iter, int indexLo); 77 | }; 78 | #endif // SECML_ONLINE_HPP 79 | -------------------------------------------------------------------------------- /src/read_MNIST.hpp: -------------------------------------------------------------------------------- 1 | #ifndef READ_MNIST_HPP 2 | #define READ_MNIST_HPP 3 | #include 4 | #include 5 | #include 6 | 7 | extern int NUM_IMAGES; 8 | 9 | int reverse_int(int i){ 10 | unsigned char ch1, ch2, ch3, ch4; 11 | ch1 = i & 255; 12 | ch2 = (i >> 8) & 255; 13 | ch3 = (i >> 16) & 255; 14 | ch4 = (i >> 24) & 255; 15 | return ((int) ch1 << 24) + ((int) ch2 << 16) + ((int) ch3 << 8) + ch4; 16 | } 17 | 18 | template 19 | void read_MNIST_data(bool train, std::vector> &vec, int& number_of_images, int& number_of_features){ 20 | std::ifstream file; 21 | if (train == true) 22 | file.open("../../Datasets/train-images-idx3-ubyte",std::ios::binary); 23 | else 24 | file.open("../../Datasets/t10k-images-idx3-ubyte",std::ios::binary); 25 | 26 | if(!file){ 27 | std::cout<<"Unable to open file"; 28 | return; 29 | } 30 | if (file.is_open()){ 31 | int magic_number = 0; 32 | int n_rows = 0; 33 | int n_cols = 0; 34 | file.read((char*) &magic_number, sizeof(magic_number)); 35 | magic_number = reverse_int(magic_number); 36 | file.read((char*) &number_of_images, sizeof(number_of_images)); 37 | number_of_images = reverse_int(number_of_images); 38 | if(train == true) 39 | number_of_images = NUM_IMAGES; 40 | file.read((char*) &n_rows, sizeof(n_rows)); 41 | n_rows = reverse_int(n_rows); 42 | file.read((char*) &n_cols, sizeof(n_cols)); 43 | n_cols = reverse_int(n_cols); 44 | number_of_features = n_rows * n_cols; 45 | std::cout << "Number of Images: " << number_of_images << std::endl; 46 | std::cout << "Number of Features: " << number_of_features << std::endl; 47 | for(int i = 0; i < number_of_images; ++i){ 48 | std::vector tp; 49 | for(int r = 0; r < n_rows; ++r) 50 | for(int c = 0; c < n_cols; ++c){ 51 | unsigned char temp = 0; 52 | file.read((char*) &temp, sizeof(temp)); 53 | tp.push_back(((T) temp)); 54 | } 55 | vec.push_back(tp); 56 | } 57 | } 58 | } 59 | 60 | 61 | template 62 | void read_MNIST_labels(bool train, std::vector &vec){ 63 | std::ifstream file; 64 | if (train == true) 65 | file.open("../../Datasets/train-labels-idx1-ubyte",std::ios::binary); 66 | else 67 | file.open("../../Datasets/t10k-labels-idx1-ubyte", std::ios::binary); 68 | if(!file){ 69 | std::cout << "Unable to open file"; 70 | return; 71 | } 72 | if (file.is_open()){ 73 | int magic_number = 0; 74 | int number_of_images = 0; 75 | file.read((char*) &magic_number, sizeof(magic_number)); 76 | magic_number = reverse_int(magic_number); 77 | file.read((char*) &number_of_images, sizeof(number_of_images)); 78 | number_of_images = reverse_int(number_of_images); 79 | if(train == true) 80 | number_of_images = NUM_IMAGES; 81 | for(int i = 0; i < number_of_images; ++i){ 82 | unsigned char temp = 0; 83 | file.read((char*) &temp, sizeof(temp)); 84 | if((T) temp == 0) 85 | vec.push_back((T) 0); 86 | else 87 | vec.push_back((T) 1); 88 | } 89 | } 90 | } 91 | #endif // READ_MNIST_HPP 92 | -------------------------------------------------------------------------------- /src/secure_ML.cpp: -------------------------------------------------------------------------------- 1 | #include "read_MNIST.hpp" 2 | #include "linear_regression.hpp" 3 | 4 | using namespace Eigen; 5 | using Eigen::Matrix; 6 | using namespace emp; 7 | using namespace std; 8 | 9 | IOFormat CommaInitFmt(StreamPrecision, DontAlignCols, ", ", ", ", "", "", " << ", ";"); 10 | 11 | int NUM_IMAGES = BATCH_SIZE; 12 | int PARTY; 13 | 14 | int main(int argc, char** argv){ 15 | int port, num_iters; 16 | string address; 17 | 18 | PARTY = atoi(argv[1]); 19 | port = atoi(argv[2]); 20 | num_iters = atoi(argv[3]); 21 | 22 | try{ 23 | int x = -1; 24 | if(argc <= 4) 25 | throw x; 26 | address = argv[4]; 27 | } catch(int x) { 28 | address = "127.0.0.1"; 29 | } 30 | 31 | NUM_IMAGES *= num_iters; 32 | 33 | NetIO* io = new NetIO(PARTY == ALICE ? nullptr : address.c_str(), port); 34 | 35 | TrainingParams params; 36 | 37 | cout << "========" << endl; 38 | cout << "Training" << endl; 39 | cout << "========" << endl; 40 | 41 | vector > training_data; 42 | vector training_labels; 43 | 44 | read_MNIST_data(true, training_data, params.n, params.d); 45 | RowMatrixXi64 X(params.n, params.d); 46 | vector2d_to_RowMatrixXi64(training_data, X); 47 | X *= SCALING_FACTOR; 48 | X /= 255; 49 | 50 | read_MNIST_labels(true, training_labels); 51 | ColVectorXi64 Y(params.n); 52 | vector_to_ColVectorXi64(training_labels, Y); 53 | Y *= SCALING_FACTOR; 54 | Y /= 10; 55 | 56 | LinearRegression linear_regression(X, Y, params, io); 57 | 58 | cout << "=======" << endl; 59 | cout << "Testing" << endl; 60 | cout << "=======" << endl; 61 | 62 | vector testing_labels; 63 | int n_; 64 | 65 | vector> testing_data; 66 | read_MNIST_data(false, testing_data, n_, params.d); 67 | 68 | RowMatrixXd testX(n_, params.d); 69 | vector2d_to_RowMatrixXd(testing_data, testX); 70 | testX /= 255.0; 71 | read_MNIST_labels(false, testing_labels); 72 | 73 | ColVectorXd testY(n_); 74 | vector_to_ColVectorXd(testing_labels, testY); 75 | linear_regression.test_model(testX, testY); 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/setup_phase.cpp: -------------------------------------------------------------------------------- 1 | #include "setup_phase.hpp" 2 | 3 | using namespace Eigen; 4 | using Eigen::Matrix; 5 | using namespace emp; 6 | using namespace std; 7 | 8 | void SetupPhase::initialize_matrices(){ 9 | prg.random_data(Ai.data(), n * d * 8); 10 | prg.random_data(Bi.data(), d * t * 8); 11 | prg.random_data(Bi_.data(), BATCH_SIZE * t * 8); 12 | } 13 | 14 | void SetupPhase::generateMTs(){ 15 | vector> ci(t, vector(BATCH_SIZE)); 16 | vector> ci_(t, vector(d)); 17 | for(int i = 0; i < t; i++){ 18 | RowMatrixXi64 Ai_b = Ai.block(i * BATCH_SIZE, 0, BATCH_SIZE, d); 19 | vector> ai(BATCH_SIZE, vector(d)); 20 | RowMatrixXi64_to_vector2d(Ai_b, ai); 21 | RowMatrixXi64 Ai_bt = Ai_b.transpose(); 22 | vector> ai_t(d, vector(BATCH_SIZE)); 23 | RowMatrixXi64_to_vector2d(Ai_bt, ai_t); 24 | vector bi = ColVectorXi64_to_vector(Bi.col(i)); 25 | vector bi_ = ColVectorXi64_to_vector(Bi_.col(i)); 26 | secure_mult(BATCH_SIZE, d, ai, bi, ci[i]); 27 | secure_mult(d, BATCH_SIZE, ai_t, bi_, ci_[i]); 28 | } 29 | vector2d_to_ColMatrixXi64(ci, Ci); 30 | vector2d_to_ColMatrixXi64(ci_, Ci_); 31 | cout << "Triples Generated" << endl; 32 | #if DEBUG 33 | verify(); 34 | #endif 35 | } 36 | 37 | void SetupPhase::secure_mult(int N, int D, vector>& a, 38 | vector& b, vector &c){ 39 | int NUM_OT[BITLEN]; 40 | int total_ot = 0, num_ot; 41 | 42 | // Calculate total number of OT 43 | for (int p = 0; p < 64; p++){ 44 | int temp = 128/(64-p); 45 | NUM_OT[p] = N/temp; 46 | if (N % temp) 47 | NUM_OT[p]++; 48 | total_ot += NUM_OT[p]; 49 | } 50 | total_ot *= D; 51 | 52 | block *x0, *x1, *rec; 53 | x0 = new block[total_ot]; 54 | x1 = new block[total_ot]; 55 | rec = new block[total_ot]; 56 | 57 | int indexX0 = 0; 58 | int indexX1 = 0; 59 | 60 | bool bits_B[64]; 61 | bool* sigma; 62 | sigma = new bool[total_ot]; 63 | int index_sigma = 0; 64 | 65 | uint64_t ***X0; 66 | X0 = new uint64_t**[N]; 67 | for(int p = 0; p < N; p++) { 68 | X0[p] = new uint64_t*[BITLEN]; 69 | for(int e = 0; e < BITLEN; e++){ 70 | X0[p][e] = new uint64_t[D]; 71 | prg.random_data(X0[p][e], D * 8); 72 | } 73 | } 74 | 75 | for(int j = 0; j < D; j++){ 76 | int_to_bool(bits_B, b[j]); 77 | 78 | for (int z = 0; z < 64; z++){ 79 | num_ot = NUM_OT[z]; 80 | uint64_t randomA[N]; 81 | 82 | for (int p = 0; p < N; p++){ 83 | randomA[p] = X0[p][z][j] + a[p][j]; 84 | } 85 | 86 | int elements_in_block = 128/(64-z); 87 | int indexA = 0; 88 | 89 | for (int y = 0; y < num_ot; y++){ 90 | sigma[index_sigma++] = bits_B[z]; 91 | } 92 | 93 | for(int y = 0; y < num_ot; y++){ 94 | int flag = elements_in_block; 95 | uint64_t temp_lo=0, temp_hi=0; 96 | uint64_t r_temp_lo=0, r_temp_hi=0; 97 | int elements_in_temp = 64/(64-z); 98 | int left_bitsLo = (64 % ((64-z)*elements_in_temp)); 99 | 100 | r_temp_lo = (X0[indexA][z][j] << z); 101 | r_temp_lo >>= z; 102 | temp_lo = (randomA[indexA++] << z); 103 | temp_lo >>= z; 104 | flag--; 105 | for (int p=1; p>= z; 109 | r_next_element <<= ((64-z) * p); 110 | r_temp_lo ^= r_next_element; 111 | uint64_t next_element = (randomA[indexA++] << z); 112 | next_element >>= z; 113 | next_element <<= ((64-z) * p); 114 | temp_lo ^= next_element; 115 | flag--; 116 | } 117 | else 118 | break; 119 | } 120 | 121 | if (left_bitsLo){ 122 | if (indexA <= N-1 && flag){ 123 | uint64_t r_split_element = (X0[indexA][z][j] << z); 124 | r_split_element >>= z; 125 | r_temp_lo ^= (r_split_element << (64-left_bitsLo)); 126 | r_temp_hi ^= (r_split_element >> left_bitsLo); 127 | uint64_t split_element = (randomA[indexA++] << z); 128 | split_element >>= z; 129 | temp_lo ^= (split_element << (64-left_bitsLo)); 130 | temp_hi ^= (split_element >> left_bitsLo); 131 | flag--; 132 | } 133 | } 134 | 135 | for (int p=0; p>= z; 139 | if (left_bitsLo) 140 | r_next_element <<= (((64-z)*p)+(64-z-left_bitsLo)); 141 | else 142 | r_next_element <<= ((64-z)*p); 143 | r_temp_hi ^= r_next_element; 144 | uint64_t next_element = (randomA[indexA++] << z); 145 | next_element >>= z; 146 | if (left_bitsLo) 147 | next_element <<= (((64-z)*p)+(64-z-left_bitsLo)); 148 | else 149 | next_element <<= ((64-z)*p); 150 | temp_hi ^= next_element; 151 | flag--; 152 | } 153 | else 154 | break; 155 | } 156 | 157 | x0[indexX0++] = makeBlock(r_temp_hi, r_temp_lo); 158 | x1[indexX1++] = makeBlock(temp_hi, temp_lo); 159 | 160 | } 161 | } 162 | } 163 | if (party == ALICE){ 164 | send_ot->send(x0, x1, total_ot); 165 | } 166 | else if (party == BOB){ 167 | recv_ot->recv(rec, sigma, total_ot); 168 | } 169 | 170 | if (party == BOB){ 171 | send_ot->send(x0, x1, total_ot); 172 | } 173 | else if (party == ALICE){ 174 | recv_ot->recv(rec, sigma, total_ot); 175 | } 176 | 177 | int indexRec = 0; 178 | for (int j = 0; j < D; j++){ 179 | for (int z = 0; z < 64; z++){ 180 | int indexA = 0; 181 | num_ot = NUM_OT[z]; 182 | int elements_in_block = 128/(64-z); 183 | 184 | for (int y = 0; y < num_ot; y++){ 185 | int flag = elements_in_block; 186 | uint64_t temp_lo = extract_lo64(rec[indexRec]); 187 | uint64_t temp_hi = extract_hi64(rec[indexRec++]); 188 | 189 | int elements_in_temp = 64/(64-z); 190 | int left_bitsLo = (64 % ((64-z) * elements_in_temp)); 191 | uint64_t mask; 192 | if((64 - z) < 64) 193 | mask = ((1ULL << (64-z)) - 1); 194 | else 195 | mask = -1; 196 | 197 | for(int p = 0; p < elements_in_temp; p++){ 198 | if (indexA <= N-1 && flag) { 199 | uint64_t next_element = (temp_lo & mask); 200 | next_element <<= z; 201 | c[indexA++] += next_element; 202 | temp_lo >>= 64-z; 203 | flag--; 204 | 205 | } 206 | else 207 | break; 208 | } 209 | if (left_bitsLo){ 210 | if (indexA <= N-1 && flag){ 211 | uint64_t split_mask; 212 | if((64-z-left_bitsLo) < 64) 213 | split_mask = ((1ULL << (64-z-left_bitsLo)) -1); 214 | else 215 | split_mask = -1; 216 | uint64_t next_element = temp_hi & split_mask; 217 | next_element <<= left_bitsLo; 218 | next_element ^= temp_lo; 219 | next_element <<= z; 220 | c[indexA++] += next_element; 221 | temp_hi >>= (64-z-left_bitsLo); 222 | flag--; 223 | } 224 | } 225 | for(int p = 0; p < elements_in_temp; p++){ 226 | if (indexA <= N-1 && flag) { 227 | uint64_t next_element = (temp_hi & mask); 228 | next_element <<= z; 229 | c[indexA++] += next_element; 230 | temp_hi >>= 64-z; 231 | 232 | flag--; 233 | } 234 | else 235 | break; 236 | } 237 | } 238 | for (int p = 0; p < N; p++){ 239 | c[p] -= (X0[p][z][j] << z); 240 | } 241 | } 242 | } 243 | 244 | for(int p = 0; p < N; p++) { 245 | for(int e = 0; e < BITLEN; e++){ 246 | delete X0[p][e]; 247 | } 248 | delete X0[p]; 249 | } 250 | delete X0; 251 | 252 | for(int i = 0; i < N; i++){ 253 | for(int k = 0; k < D; k++){ 254 | c[i] += (a[i][k] * b[k]); 255 | } 256 | } 257 | } 258 | 259 | void SetupPhase::getMTs(SetupTriples *triples){ 260 | triples->Ai = this->Ai; 261 | triples->Bi = this->Bi; 262 | triples->Ci = this->Ci; 263 | triples->Bi_ = this->Bi_; 264 | triples->Ci_ = this->Ci_; 265 | } 266 | 267 | void SetupPhase::verify(){ 268 | if (party == ALICE) { 269 | RowMatrixXi64 Ai_b(BATCH_SIZE, d); 270 | ColMatrixXi64 Bi_b(d, 1); 271 | ColMatrixXi64 Ci_b(BATCH_SIZE, 1); 272 | ColMatrixXi64 Bi_b_(BATCH_SIZE, 1); 273 | ColMatrixXi64 Ci_b_(d, 1); 274 | for(int i = 0; i < t; i++) { 275 | Ai_b = Ai.block((i * BATCH_SIZE) % n, 0, BATCH_SIZE, d); 276 | Bi_b = Bi.col(i); 277 | Ci_b = Ci.col(i); 278 | Bi_b_ = Bi_.col(i); 279 | Ci_b_ = Ci_.col(i); 280 | send(io, Ai_b); 281 | send(io, Bi_b); 282 | send(io, Ci_b); 283 | send(io, Bi_b_); 284 | send(io, Ci_b_); 285 | } 286 | } 287 | 288 | else { 289 | bool flag = true; 290 | bool flag_ = true; 291 | RowMatrixXi64 A(BATCH_SIZE, d); 292 | ColMatrixXi64 B(d, 1); 293 | ColMatrixXi64 C(BATCH_SIZE, 1); 294 | ColMatrixXi64 AB(BATCH_SIZE, 1); 295 | RowMatrixXi64 A_t(d, BATCH_SIZE); 296 | ColMatrixXi64 B_(BATCH_SIZE, 1); 297 | ColMatrixXi64 C_(d, 1); 298 | ColMatrixXi64 AB_(d, 1); 299 | for(int i = 0; i < t; i++) { 300 | RowMatrixXi64 Ai_b = Ai.block((i * BATCH_SIZE) % n, 0, BATCH_SIZE, d); 301 | ColMatrixXi64 Bi_b = Bi.col(i); 302 | ColMatrixXi64 Ci_b = Ci.col(i); 303 | ColMatrixXi64 Bi_b_ = Bi_.col(i); 304 | ColMatrixXi64 Ci_b_ = Ci_.col(i); 305 | 306 | recv(io, A); 307 | recv(io, B); 308 | recv(io, C); 309 | recv(io, B_); 310 | recv(io, C_); 311 | 312 | A += Ai_b; 313 | A_t = A.transpose(); 314 | B += Bi_b; 315 | C += Ci_b; 316 | B_ += Bi_b_; 317 | C_ += Ci_b_; 318 | 319 | AB = A * B; 320 | AB_ = A_t * B_; 321 | 322 | if (C != AB) { 323 | flag_ = false; 324 | break; 325 | } 326 | 327 | if (C_ != AB_) { 328 | flag_ = false; 329 | break; 330 | } 331 | } 332 | 333 | if(flag == true) { 334 | cout << "Verification Successful" << endl; 335 | } else { 336 | cout << "Verification Failed" << endl; 337 | } 338 | 339 | if(flag_ == true) { 340 | cout << "Verification Successful" << endl; 341 | } else { 342 | cout << "Verification Failed" << endl; 343 | } 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /src/setup_phase.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SECML_SETUP_HPP 2 | #define SECML_SETUP_HPP 3 | #include "util.hpp" 4 | #include 5 | 6 | class SetupPhase{ 7 | public: 8 | int n, d, t; 9 | int party; 10 | RowMatrixXi64 Ai; 11 | ColMatrixXi64 Bi; 12 | ColMatrixXi64 Ci; 13 | ColMatrixXi64 Bi_; 14 | ColMatrixXi64 Ci_; 15 | 16 | emp::NetIO* io; 17 | emp::SHOTExtension* send_ot; 18 | emp::SHOTExtension* recv_ot; 19 | emp::PRG prg; 20 | 21 | SetupPhase(int n, int d, int t, emp::NetIO* io){ 22 | this->n = n; 23 | this->d = d; 24 | this->t = t; 25 | this->io = io; 26 | this->send_ot = new emp::SHOTExtension(io); 27 | this->recv_ot = new emp::SHOTExtension(io); 28 | this->party = PARTY; 29 | 30 | Ai.resize(n, d); 31 | Bi.resize(d, t); 32 | Ci.resize(BATCH_SIZE, t); 33 | Bi_.resize(BATCH_SIZE, t); 34 | Ci_.resize(d, t); 35 | 36 | initialize_matrices(); 37 | std::cout << "Matrices Initialized" << std::endl; 38 | } 39 | 40 | void initialize_matrices(); 41 | void generateMTs(); 42 | void secure_mult(int N, int D, vector>& a, 43 | vector& b, vector &c); 44 | void getMTs(SetupTriples* triples); 45 | void verify(); 46 | }; 47 | #endif // SECML_SETUP_HPP 48 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.hpp" 2 | 3 | using namespace std; 4 | using namespace Eigen; 5 | using namespace emp; 6 | using Eigen::Matrix; 7 | 8 | void vector2d_to_RowMatrixXd(vector>& x, RowMatrixXd& X){ 9 | for(int i = 0; i < x.size(); i++){ 10 | X.row(i) << Map(x[i].data(), x[i].size()); 11 | } 12 | return; 13 | } 14 | 15 | void vector_to_ColVectorXd(vector& x, ColVectorXd& X){ 16 | X << Map(x.data(), x.size()); 17 | return; 18 | } 19 | 20 | void vector_to_RowVectorXi64(vector& x, RowVectorXi64& X){ 21 | X << Map(x.data(), x.size()); 22 | return; 23 | } 24 | 25 | void vector2d_to_RowMatrixXi64(std::vector>& x, RowMatrixXi64& X){ 26 | for(int i = 0; i < x.size(); i++){ 27 | X.row(i) << Map(x[i].data(), x[i].size()); 28 | } 29 | return; 30 | } 31 | 32 | void vector2d_to_ColMatrixXi64(vector>& x, ColMatrixXi64& X){ 33 | for(int i = 0; i < x.size(); i++){ 34 | X.col(i) << Map(x[i].data(), x[i].size()); 35 | } 36 | return; 37 | } 38 | 39 | void vector_to_ColVectorXi64(vector& x, ColVectorXi64& X){ 40 | X << Map(x.data(), x.size()); 41 | } 42 | 43 | void RowMatrixXi64_to_vector2d(RowMatrixXi64 X, vector>& x){ 44 | for(int i = 0; i < X.rows(); i++){ 45 | for(int j = 0; j < X.cols(); j++){ 46 | x[i][j] = X(i, j); 47 | } 48 | } 49 | return; 50 | } 51 | 52 | vector ColVectorXi64_to_vector(ColVectorXi64 X){ 53 | vector x(X.data(), X.data() + X.rows()); 54 | return x; 55 | } 56 | 57 | void print128_num(emp::block var){ 58 | uint64_t *v64val = (uint64_t*) &var; 59 | printf("%016llX %016llX", v64val[1], v64val[0]); 60 | } 61 | 62 | void print_binary(uint64_t int_) { 63 | for (int i = 0; i < 64; i++){ 64 | cout << (int_ & 1); 65 | int_ >>= 1; 66 | } 67 | } 68 | 69 | void int_to_bool(bool* bool_, uint64_t int_) { 70 | for (int i = 0; i < 64; i++){ 71 | bool_[i] = (int_ & 1); 72 | int_ >>= 1; 73 | } 74 | } 75 | 76 | uint64_t extract_lo64(__m128i x){ // extract lower 64 bits of a block 77 | return (uint64_t) _mm_cvtsi128_si64(x); 78 | } 79 | 80 | uint64_t extract_hi64(__m128i x){ // extract higher 64 bits of a block 81 | uint64_t *v64val = (uint64_t*) &x; 82 | return (uint64_t) v64val[1]; 83 | } 84 | -------------------------------------------------------------------------------- /src/util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SECML_UTIL_HPP 2 | #define SECML_UTIL_HPP 3 | #include "defines.hpp" 4 | #include 5 | #include 6 | #include 7 | 8 | void vector2d_to_RowMatrixXd(std::vector>& x, RowMatrixXd& X); 9 | void vector_to_ColVectorXd(std::vector& x, ColVectorXd& X); 10 | void vector_to_RowVectorXi64(std::vector& x, RowVectorXi64& X); 11 | void vector2d_to_RowMatrixXi64(std::vector>& x, RowMatrixXi64& X); 12 | void vector2d_to_ColMatrixXi64(std::vector>& x, ColMatrixXi64& X); 13 | void vector_to_ColVectorXi64(std::vector& x, ColVectorXi64& X); 14 | void RowMatrixXi64_to_vector2d(RowMatrixXi64 X, std::vector>& x); 15 | std::vector ColVectorXi64_to_vector(ColVectorXi64 X); 16 | 17 | void print128_num(emp::block var); 18 | void print_binary(uint64_t int_); 19 | void int_to_bool(bool* bool_, uint64_t int_); 20 | 21 | uint64_t extract_lo64(__m128i x); 22 | uint64_t extract_hi64(__m128i x); 23 | 24 | template 25 | void send(emp::NetIO* io, Eigen::PlainObjectBase& X){ 26 | io->send_data(X.data(), X.rows() * X.cols() * sizeof(uint64_t)); 27 | return; 28 | } 29 | 30 | template 31 | void recv(emp::NetIO* io, Eigen::PlainObjectBase& X){ 32 | io->recv_data(X.data(), X.rows() * X.cols() * sizeof(uint64_t)); 33 | return; 34 | } 35 | 36 | #endif // SECML_UTIL_HPP 37 | --------------------------------------------------------------------------------