├── README.md ├── library.properties ├── sdkconfig.h ├── sketches ├── evaluator │ └── evaluator.ino └── garbler │ └── garbler.ino └── src ├── ecc_helper.cpp ├── ecc_helper.h ├── garbled_circuit.cpp ├── garbled_circuit.h ├── oblivious_transfer.cpp └── oblivious_transfer.h /README.md: -------------------------------------------------------------------------------- 1 | # esp32-mpc 2 | 3 | MPC with ESP32 hardware devices, using Arduino C++ 4 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESP32MPC 2 | version=1.0.0 3 | author=Vivek Bhupatiraju 4 | maintainer=Vivek Bhupatiraju 5 | sentence=A library for secure multi-party computation (MPC) on ESP32 6 | paragraph=This library provides functionality for implementing secure two-party computation using garbled circuits on ESP32 devices. 7 | category=Communication 8 | url=https://github.com/RiverRuby/esp32-mpc 9 | architectures=esp32 10 | depends=mbedtls -------------------------------------------------------------------------------- /sdkconfig.h: -------------------------------------------------------------------------------- 1 | #define CONFIG_MBEDTLS_HARDWARE_AES 1 2 | #define CONFIG_MBEDTLS_HARDWARE_MPI 1 3 | #define CONFIG_MBEDTLS_HARDWARE_SHA 1 4 | #define CONFIG_MBEDTLS_HARDWARE_ECC 1 5 | #define CONFIG_MBEDTLS_ECP_RESTARTABLE 1 6 | #define CONFIG_MBEDTLS_HAVE_TIME 1 7 | #define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1 -------------------------------------------------------------------------------- /sketches/evaluator/evaluator.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "garbled_circuit.h" 3 | #include "oblivious_transfer.h" 4 | 5 | // Network configuration 6 | const char* ssid = "ESP32_Network"; 7 | const char* password = "testpassword"; 8 | const int TCP_PORT = 5555; 9 | 10 | // Button/lights config 11 | const int BUTTON_PIN_ON = 16; 12 | const int BUTTON_PIN_OFF = 14; 13 | const int LED_PIN = 17; 14 | 15 | WiFiClient client; 16 | GarbledCircuit::Circuit circuit; 17 | 18 | void setup() { 19 | Serial.begin(115200); 20 | pinMode(LED_PIN, OUTPUT); 21 | pinMode(BUTTON_PIN_ON, INPUT_PULLUP); 22 | pinMode(BUTTON_PIN_OFF, INPUT_PULLUP); 23 | digitalWrite(LED_PIN, LOW); 24 | 25 | // Initialize garbled circuit 26 | circuit.begin(); 27 | 28 | Serial.println("Connecting to AP..."); 29 | WiFi.begin(ssid, password); 30 | while (WiFi.status() != WL_CONNECTED) { 31 | delay(500); 32 | Serial.print("."); 33 | } 34 | Serial.println("\nConnected to AP"); 35 | 36 | // Single quick blink to show readiness 37 | digitalWrite(LED_PIN, HIGH); 38 | delay(200); 39 | digitalWrite(LED_PIN, LOW); 40 | } 41 | 42 | void loop() { 43 | static bool buttonHandled = false; 44 | 45 | if (!client.connected()) { 46 | if (client.connect(WiFi.gatewayIP(), TCP_PORT)) { 47 | if (!buttonHandled) { 48 | // Wait for button press 49 | bool b = false; 50 | bool inputReceived = false; 51 | 52 | while (!inputReceived) { 53 | if (digitalRead(BUTTON_PIN_ON) == LOW) { 54 | b = true; 55 | inputReceived = true; 56 | delay(50); 57 | } 58 | else if (digitalRead(BUTTON_PIN_OFF) == LOW) { 59 | b = false; 60 | inputReceived = true; 61 | delay(50); 62 | } 63 | delay(10); 64 | } 65 | 66 | digitalWrite(LED_PIN, HIGH); 67 | buttonHandled = true; 68 | 69 | // Receive sender's wire label 70 | GarbledCircuit::WireLabel senderLabel; 71 | while (client.available() < GarbledCircuit::KEY_SIZE) delay(10); 72 | client.readBytes(senderLabel.key, GarbledCircuit::KEY_SIZE); 73 | 74 | // Select my wire label based on my input using OT 75 | GarbledCircuit::WireLabel myLabel = ObliviousTransfer::receiveWireLabel(client, b); 76 | 77 | // Receive garbled table 78 | GarbledCircuit::TableEntry table[GarbledCircuit::TABLE_SIZE]; 79 | for(int i = 0; i < GarbledCircuit::TABLE_SIZE; i++) { 80 | while (client.available() < GarbledCircuit::ENCRYPTED_SIZE) delay(10); 81 | client.readBytes(table[i].encrypted, GarbledCircuit::ENCRYPTED_SIZE); 82 | } 83 | 84 | // Try to decrypt each table entry 85 | bool result = false; 86 | bool decrypted = false; 87 | 88 | Serial.println("Evaluator attempting to decrypt table entries"); 89 | 90 | for(int i = 0; i < GarbledCircuit::TABLE_SIZE; i++) { 91 | if(circuit.decryptEntry(senderLabel, myLabel, table[i], result)) { 92 | decrypted = true; 93 | break; 94 | } 95 | } 96 | 97 | if (decrypted) { 98 | Serial.println("Evaluator successfully decrypted result"); 99 | Serial.println(result ? "It's a match!\n" : "No match.\n"); 100 | client.write(result ? 1 : 0); 101 | 102 | if (result) { 103 | // Blink for 5 seconds then stay on 104 | for(int i = 0; i < 25; i++) { 105 | digitalWrite(LED_PIN, HIGH); 106 | delay(100); 107 | digitalWrite(LED_PIN, LOW); 108 | delay(100); 109 | } 110 | } else { 111 | // Single quick blink 112 | digitalWrite(LED_PIN, HIGH); 113 | delay(200); 114 | digitalWrite(LED_PIN, LOW); 115 | } 116 | } else { 117 | Serial.println("Evaluator failed to decrypt any table entries"); 118 | client.write((uint8_t)0); 119 | // Error pattern - three quick blinks 120 | for(int i = 0; i < 3; i++) { 121 | digitalWrite(LED_PIN, HIGH); 122 | delay(100); 123 | digitalWrite(LED_PIN, LOW); 124 | delay(100); 125 | } 126 | } 127 | } 128 | buttonHandled = false; 129 | } 130 | delay(1000); 131 | } 132 | } -------------------------------------------------------------------------------- /sketches/garbler/garbler.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "garbled_circuit.h" 3 | #include "oblivious_transfer.h" 4 | 5 | // Network configuration 6 | const char* ssid = "ESP32_Network"; 7 | const char* password = "testpassword"; 8 | const int TCP_PORT = 5555; 9 | 10 | // Button/lights config 11 | const int BUTTON_PIN_ON = 16; 12 | const int BUTTON_PIN_OFF = 14; 13 | const int LED_PIN = 17; 14 | 15 | WiFiServer tcpServer(TCP_PORT); 16 | GarbledCircuit::Circuit circuit; 17 | 18 | void setup() { 19 | Serial.begin(115200); 20 | pinMode(LED_PIN, OUTPUT); 21 | pinMode(BUTTON_PIN_ON, INPUT_PULLUP); 22 | pinMode(BUTTON_PIN_OFF, INPUT_PULLUP); 23 | digitalWrite(LED_PIN, LOW); 24 | 25 | // Initialize garbled circuit 26 | circuit.begin(); 27 | 28 | // Create Access Point 29 | WiFi.softAP(ssid, password); 30 | Serial.print("AP IP address: "); 31 | Serial.println(WiFi.softAPIP()); 32 | 33 | tcpServer.begin(); 34 | Serial.println("Server started"); 35 | 36 | // Single quick blink to show readiness 37 | digitalWrite(LED_PIN, HIGH); 38 | delay(200); 39 | digitalWrite(LED_PIN, LOW); 40 | } 41 | 42 | void loop() { 43 | WiFiClient client = tcpServer.available(); 44 | static bool buttonHandled = false; 45 | 46 | if (client) { 47 | if (!buttonHandled) { 48 | // Wait for button press 49 | bool a = false; 50 | bool inputReceived = false; 51 | 52 | while (!inputReceived) { 53 | if (digitalRead(BUTTON_PIN_ON) == LOW) { 54 | a = true; 55 | inputReceived = true; 56 | delay(50); 57 | } 58 | else if (digitalRead(BUTTON_PIN_OFF) == LOW) { 59 | a = false; 60 | inputReceived = true; 61 | delay(50); 62 | } 63 | delay(10); 64 | } 65 | 66 | digitalWrite(LED_PIN, HIGH); 67 | buttonHandled = true; 68 | 69 | // Generate wire labels 70 | GarbledCircuit::WireLabel a0, a1, b0, b1; 71 | circuit.generateWireLabel(a0, false); 72 | circuit.generateWireLabel(a1, true); 73 | circuit.generateWireLabel(b0, false); 74 | circuit.generateWireLabel(b1, true); 75 | 76 | // Create garbled AND table 77 | GarbledCircuit::TableEntry table[GarbledCircuit::TABLE_SIZE]; 78 | circuit.createGarbledANDTable(a0, a1, b0, b1, table); 79 | 80 | // Send my input's wire label 81 | const GarbledCircuit::WireLabel& myWireLabel = a ? a1 : a0; 82 | client.write(myWireLabel.key, GarbledCircuit::KEY_SIZE); 83 | 84 | // Send both wire labels for receiver's input using OT 85 | ObliviousTransfer::sendWireLabels(client, b0, b1); 86 | 87 | // Send garbled table 88 | for(int i = 0; i < GarbledCircuit::TABLE_SIZE; i++) { 89 | client.write(table[i].encrypted, GarbledCircuit::ENCRYPTED_SIZE); 90 | } 91 | } 92 | 93 | while (!client.available()) { 94 | delay(100); 95 | } 96 | 97 | bool result = client.read() == 1; 98 | Serial.println(result ? "It's a match!" : "No match"); 99 | 100 | if (result) { 101 | // Blink for 5 seconds then stay on 102 | for(int i = 0; i < 25; i++) { 103 | digitalWrite(LED_PIN, HIGH); 104 | delay(100); 105 | digitalWrite(LED_PIN, LOW); 106 | delay(100); 107 | } 108 | } else { 109 | // Single quick blink 110 | digitalWrite(LED_PIN, HIGH); 111 | delay(200); 112 | digitalWrite(LED_PIN, LOW); 113 | } 114 | 115 | client.stop(); 116 | buttonHandled = false; 117 | } 118 | } -------------------------------------------------------------------------------- /src/ecc_helper.cpp: -------------------------------------------------------------------------------- 1 | #include "ecc_helper.h" 2 | 3 | ECCHelper::ECCHelper() { 4 | mbedtls_entropy_init(&entropy); 5 | mbedtls_ctr_drbg_init(&ctr_drbg); 6 | mbedtls_ecp_group_init(&group); 7 | 8 | // Initialize RNG 9 | mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); 10 | 11 | // Load P-256 curve with hardware acceleration 12 | mbedtls_ecp_group_load(&group, MBEDTLS_ECP_DP_SECP256R1); 13 | } 14 | 15 | ECCHelper::~ECCHelper() { 16 | mbedtls_ecp_group_free(&group); 17 | mbedtls_ctr_drbg_free(&ctr_drbg); 18 | mbedtls_entropy_free(&entropy); 19 | } 20 | 21 | void ECCHelper::generateRandomScalar(mbedtls_mpi& scalar) { 22 | mbedtls_mpi_lset(&scalar, 0); 23 | unsigned char buf[32]; 24 | mbedtls_ctr_drbg_random(&ctr_drbg, buf, sizeof(buf)); 25 | mbedtls_mpi_read_binary(&scalar, buf, sizeof(buf)); 26 | mbedtls_mpi_mod_mpi(&scalar, &scalar, &group.N); 27 | } 28 | 29 | void ECCHelper::pointMultiply(mbedtls_ecp_point& result, const mbedtls_mpi& scalar, 30 | const mbedtls_ecp_point& point) { 31 | mbedtls_ecp_mul(&group, &result, &scalar, &point, 32 | mbedtls_ctr_drbg_random, &ctr_drbg); 33 | } -------------------------------------------------------------------------------- /src/ecc_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef ECC_HELPER_H 2 | #define ECC_HELPER_H 3 | 4 | #include "mbedtls/ecdh.h" 5 | #include "mbedtls/entropy.h" 6 | #include "mbedtls/ctr_drbg.h" 7 | 8 | class ECCHelper { 9 | private: 10 | mbedtls_entropy_context entropy; 11 | mbedtls_ctr_drbg_context ctr_drbg; 12 | mbedtls_ecp_group group; 13 | 14 | public: 15 | ECCHelper(); 16 | ~ECCHelper(); 17 | 18 | void generateRandomScalar(mbedtls_mpi& scalar); 19 | void pointMultiply(mbedtls_ecp_point& result, const mbedtls_mpi& scalar, 20 | const mbedtls_ecp_point& point); 21 | 22 | mbedtls_ecp_group* getGroup() { return &group; } 23 | mbedtls_ctr_drbg_context* getRNG() { return &ctr_drbg; } 24 | }; 25 | 26 | #endif -------------------------------------------------------------------------------- /src/garbled_circuit.cpp: -------------------------------------------------------------------------------- 1 | #include "garbled_circuit.h" 2 | 3 | namespace GarbledCircuit { 4 | 5 | Circuit::Circuit() : initialized(false) {} 6 | 7 | Circuit::~Circuit() { 8 | if (initialized) { 9 | mbedtls_entropy_free(&entropy); 10 | mbedtls_ctr_drbg_free(&ctr_drbg); 11 | } 12 | } 13 | 14 | void Circuit::begin() { 15 | if (!initialized) { 16 | mbedtls_entropy_init(&entropy); 17 | mbedtls_ctr_drbg_init(&ctr_drbg); 18 | mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); 19 | initialized = true; 20 | } 21 | } 22 | 23 | void Circuit::generateWireLabel(WireLabel& label, bool permute) { 24 | mbedtls_ctr_drbg_random(&ctr_drbg, label.key, KEY_SIZE); 25 | label.permute_bit = permute; 26 | } 27 | 28 | void Circuit::encryptEntry(const WireLabel& wa, const WireLabel& wb, TableEntry& entry, bool result) { 29 | mbedtls_aes_context aes; 30 | uint8_t iv1[16], iv2[16]; 31 | uint8_t plaintext[ENTRY_SIZE] = {0}; // Initialize all to zero 32 | uint8_t temp[ENTRY_SIZE]; 33 | uint8_t final_cipher[ENTRY_SIZE]; 34 | 35 | // Generate random IVs 36 | mbedtls_ctr_drbg_random(&ctr_drbg, iv1, 16); 37 | mbedtls_ctr_drbg_random(&ctr_drbg, iv2, 16); 38 | memcpy(entry.encrypted, iv1, 16); 39 | memcpy(entry.encrypted + 16, iv2, 16); 40 | 41 | // Set result in plaintext 42 | plaintext[0] = result ? 1 : 0; 43 | 44 | mbedtls_aes_init(&aes); 45 | 46 | // First encryption with wa's key 47 | if(mbedtls_aes_setkey_enc(&aes, wa.key, 128) != 0) { 48 | Serial.println("Failed to set encryption key A"); 49 | return; 50 | } 51 | 52 | if(mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, ENTRY_SIZE, iv1, plaintext, temp) != 0) { 53 | Serial.println("First encryption failed"); 54 | return; 55 | } 56 | 57 | // Second encryption with wb's key 58 | if(mbedtls_aes_setkey_enc(&aes, wb.key, 128) != 0) { 59 | Serial.println("Failed to set encryption key B"); 60 | return; 61 | } 62 | 63 | if(mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, ENTRY_SIZE, iv2, temp, final_cipher) != 0) { 64 | Serial.println("Second encryption failed"); 65 | return; 66 | } 67 | 68 | // Store ciphertext 69 | memcpy(entry.encrypted + 32, final_cipher, ENTRY_SIZE); 70 | 71 | mbedtls_aes_free(&aes); 72 | } 73 | 74 | void Circuit::createGarbledANDTable(const WireLabel& a0, const WireLabel& a1, 75 | const WireLabel& b0, const WireLabel& b1, 76 | TableEntry* table) { 77 | for(int i = 0; i < 2; i++) { 78 | for(int j = 0; j < 2; j++) { 79 | const WireLabel& wa = (i == 0) ? a0 : a1; 80 | const WireLabel& wb = (j == 0) ? b0 : b1; 81 | bool result = i && j; // AND truth table 82 | encryptEntry(wa, wb, table[2*i + j], result); 83 | } 84 | } 85 | } 86 | 87 | bool Circuit::decryptEntry(const WireLabel& wa, const WireLabel& wb, 88 | const TableEntry& entry, bool& result) { 89 | mbedtls_aes_context aes; 90 | uint8_t iv1[16], iv2[16]; 91 | uint8_t temp[ENTRY_SIZE]; 92 | uint8_t plaintext[ENTRY_SIZE]; 93 | uint8_t encrypted[ENTRY_SIZE]; 94 | 95 | memcpy(iv1, entry.encrypted, 16); 96 | memcpy(iv2, entry.encrypted + 16, 16); 97 | memcpy(encrypted, entry.encrypted + 32, ENTRY_SIZE); 98 | 99 | mbedtls_aes_init(&aes); 100 | 101 | // First decryption with wb's key 102 | if(mbedtls_aes_setkey_dec(&aes, wb.key, 128) != 0) { 103 | mbedtls_aes_free(&aes); 104 | return false; 105 | } 106 | 107 | if(mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, ENTRY_SIZE, iv2, encrypted, temp) != 0) { 108 | mbedtls_aes_free(&aes); 109 | return false; 110 | } 111 | 112 | // Second decryption with wa's key 113 | if(mbedtls_aes_setkey_dec(&aes, wa.key, 128) != 0) { 114 | mbedtls_aes_free(&aes); 115 | return false; 116 | } 117 | 118 | if(mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, ENTRY_SIZE, iv1, temp, plaintext) != 0) { 119 | mbedtls_aes_free(&aes); 120 | return false; 121 | } 122 | 123 | mbedtls_aes_free(&aes); 124 | 125 | // Check if all bytes after the first are zero 126 | for (int i = 1; i < ENTRY_SIZE; i++) { 127 | if (plaintext[i] != 0) { 128 | return false; 129 | } 130 | } 131 | 132 | result = (plaintext[0] == 1); 133 | return true; 134 | } 135 | 136 | void Circuit::printWireLabel(const char* prefix, const WireLabel& label) { 137 | Serial.print(prefix); 138 | Serial.print(" Key: "); 139 | for(int i = 0; i < KEY_SIZE; i++) { 140 | Serial.printf("%02X ", label.key[i]); 141 | } 142 | Serial.println(); 143 | } 144 | 145 | void Circuit::printTableEntry(const char* prefix, const TableEntry& entry) { 146 | Serial.print(prefix); 147 | Serial.print(" Entry: "); 148 | for(int i = 0; i < ENCRYPTED_SIZE; i++) { 149 | Serial.printf("%02X ", entry.encrypted[i]); 150 | if (i == 15 || i == 31) Serial.print("- "); 151 | } 152 | Serial.println(); 153 | } 154 | 155 | } // namespace GarbledCircuit -------------------------------------------------------------------------------- /src/garbled_circuit.h: -------------------------------------------------------------------------------- 1 | #ifndef GARBLED_CIRCUIT_H 2 | #define GARBLED_CIRCUIT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace GarbledCircuit { 12 | 13 | // Crypto constants 14 | const int KEY_SIZE = 16; // 128-bit keys 15 | const int TABLE_SIZE = 4; // 2^2 entries for AND gate 16 | const int ENTRY_SIZE = 32; // Two AES blocks 17 | const int ENCRYPTED_SIZE = ENTRY_SIZE + 32; // Add space for two IVs 18 | 19 | struct TableEntry { 20 | uint8_t encrypted[ENCRYPTED_SIZE]; // Space for two IVs plus encrypted data 21 | }; 22 | 23 | struct WireLabel { 24 | uint8_t key[KEY_SIZE]; 25 | bool permute_bit; 26 | }; 27 | 28 | class Circuit { 29 | public: 30 | Circuit(); 31 | ~Circuit(); 32 | 33 | // Initialize the circuit with entropy for random number generation 34 | void begin(); 35 | 36 | // Sender-side functions 37 | void generateWireLabel(WireLabel& label, bool permute); 38 | void encryptEntry(const WireLabel& wa, const WireLabel& wb, TableEntry& entry, bool result); 39 | void createGarbledANDTable(const WireLabel& a0, const WireLabel& a1, 40 | const WireLabel& b0, const WireLabel& b1, 41 | TableEntry* table); 42 | 43 | // Receiver-side functions 44 | bool decryptEntry(const WireLabel& wa, const WireLabel& wb, 45 | const TableEntry& entry, bool& result); 46 | 47 | // Utility functions 48 | void printWireLabel(const char* prefix, const WireLabel& label); 49 | void printTableEntry(const char* prefix, const TableEntry& entry); 50 | 51 | private: 52 | mbedtls_entropy_context entropy; 53 | mbedtls_ctr_drbg_context ctr_drbg; 54 | bool initialized; 55 | }; 56 | 57 | } // namespace GarbledCircuit 58 | 59 | #endif // GARBLED_CIRCUIT_H -------------------------------------------------------------------------------- /src/oblivious_transfer.cpp: -------------------------------------------------------------------------------- 1 | #include "oblivious_transfer.h" 2 | #include "mbedtls/sha256.h" 3 | 4 | void ObliviousTransfer::sendWireLabels(WiFiClient& client, 5 | const GarbledCircuit::WireLabel& label0, 6 | const GarbledCircuit::WireLabel& label1) { 7 | ECCHelper ecc; 8 | 9 | mbedtls_ecp_point A, B; 10 | mbedtls_mpi a; 11 | mbedtls_ecp_point_init(&A); 12 | mbedtls_ecp_point_init(&B); 13 | mbedtls_mpi_init(&a); 14 | 15 | Serial.println("Garbler ECP variables initialized"); 16 | 17 | // Generate random a and compute A = aG 18 | ecc.generateRandomScalar(a); 19 | mbedtls_ecp_mul(ecc.getGroup(), &A, &a, &ecc.getGroup()->G, 20 | mbedtls_ctr_drbg_random, ecc.getRNG()); 21 | 22 | // Debug output for 'a' 23 | Serial.print("Garbler scalar a: "); 24 | uint8_t a_bytes[32]; 25 | mbedtls_mpi_write_binary(&a, (unsigned char*)a_bytes, sizeof(a_bytes)); 26 | for(int i = 0; i < 32; i++) { 27 | Serial.printf("%02X ", a_bytes[i]); 28 | } 29 | Serial.println(); 30 | 31 | // Send A to receiver and debug output 32 | uint8_t A_buf[ECC_POINT_SIZE]; 33 | size_t olen; 34 | mbedtls_ecp_point_write_binary(ecc.getGroup(), &A, 35 | MBEDTLS_ECP_PF_UNCOMPRESSED, 36 | &olen, A_buf, sizeof(A_buf)); 37 | Serial.print("Garbler sending A point: "); 38 | for(size_t i = 0; i < olen; i++) { 39 | Serial.printf("%02X ", A_buf[i]); 40 | } 41 | Serial.println(); 42 | 43 | client.write(A_buf, ECC_POINT_SIZE); 44 | 45 | // Receive and debug output B 46 | uint8_t B_buf[ECC_POINT_SIZE]; 47 | while (client.available() < ECC_POINT_SIZE) delay(10); 48 | client.readBytes(B_buf, ECC_POINT_SIZE); 49 | Serial.print("Garbler received B point: "); 50 | for(int i = 0; i < ECC_POINT_SIZE; i++) { 51 | Serial.printf("%02X ", B_buf[i]); 52 | } 53 | Serial.println(); 54 | 55 | mbedtls_ecp_point_read_binary(ecc.getGroup(), &B, B_buf, ECC_POINT_SIZE); 56 | 57 | // Compute k0 = B^a 58 | uint8_t k0_buf[ECC_POINT_SIZE]; 59 | mbedtls_ecp_point k0_point; 60 | mbedtls_ecp_point_init(&k0_point); 61 | ecc.pointMultiply(k0_point, a, B); 62 | mbedtls_ecp_point_write_binary(ecc.getGroup(), &k0_point, 63 | MBEDTLS_ECP_PF_UNCOMPRESSED, 64 | &olen, k0_buf, sizeof(k0_buf)); 65 | 66 | Serial.print("Garbler k0 point (B^a): "); 67 | for(size_t i = 0; i < olen; i++) { 68 | Serial.printf("%02X ", k0_buf[i]); 69 | } 70 | Serial.println(); 71 | 72 | // Hash k0 73 | uint8_t k0_key[32]; 74 | mbedtls_sha256(k0_buf, olen, k0_key, 0); 75 | Serial.print("Garbler k0 key: "); 76 | for(int i = 0; i < 32; i++) { 77 | Serial.printf("%02X ", k0_key[i]); 78 | } 79 | Serial.println(); 80 | 81 | // Compute k1 = (B-A)^a 82 | mbedtls_ecp_point k1_point, temp_point; 83 | mbedtls_ecp_point_init(&k1_point); 84 | mbedtls_ecp_point_init(&temp_point); 85 | 86 | mbedtls_mpi one, neg_one; 87 | mbedtls_mpi_init(&one); 88 | mbedtls_mpi_init(&neg_one); 89 | mbedtls_mpi_lset(&one, 1); 90 | mbedtls_mpi_copy(&neg_one, &one); 91 | mbedtls_mpi_sub_mpi(&neg_one, &ecc.getGroup()->N, &neg_one); // neg_one = N - 1 92 | 93 | // Compute B - A 94 | mbedtls_ecp_muladd(ecc.getGroup(), &temp_point, &one, &B, &neg_one, &A); 95 | 96 | // Compute a * (B - A) 97 | ecc.pointMultiply(k1_point, a, temp_point); 98 | 99 | uint8_t k1_buf[ECC_POINT_SIZE]; 100 | mbedtls_ecp_point_write_binary(ecc.getGroup(), &k1_point, 101 | MBEDTLS_ECP_PF_UNCOMPRESSED, 102 | &olen, k1_buf, sizeof(k1_buf)); 103 | 104 | Serial.print("Garbler k1 point (B-A)*a: "); 105 | for(size_t i = 0; i < olen; i++) { 106 | Serial.printf("%02X ", k1_buf[i]); 107 | } 108 | Serial.println(); 109 | 110 | // Hash k1 111 | uint8_t k1_key[32]; 112 | mbedtls_sha256(k1_buf, olen, k1_key, 0); 113 | Serial.print("Garbler k1 key: "); 114 | for(int i = 0; i < 32; i++) { 115 | Serial.printf("%02X ", k1_key[i]); 116 | } 117 | Serial.println(); 118 | 119 | // Encrypt wire labels 120 | uint8_t e0[sizeof(GarbledCircuit::WireLabel)]; 121 | uint8_t e1[sizeof(GarbledCircuit::WireLabel)]; 122 | 123 | for(size_t i = 0; i < sizeof(GarbledCircuit::WireLabel); i++) { 124 | e0[i] = ((uint8_t*)&label0)[i] ^ k0_key[i % 32]; 125 | e1[i] = ((uint8_t*)&label1)[i] ^ k1_key[i % 32]; 126 | } 127 | 128 | Serial.print("Garbler encrypted label 0: "); 129 | for(size_t i = 0; i < sizeof(GarbledCircuit::WireLabel); i++) { 130 | Serial.printf("%02X ", e0[i]); 131 | } 132 | Serial.println(); 133 | 134 | Serial.print("Garbler encrypted label 1: "); 135 | for(size_t i = 0; i < sizeof(GarbledCircuit::WireLabel); i++) { 136 | Serial.printf("%02X ", e1[i]); 137 | } 138 | Serial.println(); 139 | 140 | client.write(e0, sizeof(e0)); 141 | client.write(e1, sizeof(e1)); 142 | 143 | // Cleanup 144 | mbedtls_ecp_point_free(&A); 145 | mbedtls_ecp_point_free(&B); 146 | mbedtls_ecp_point_free(&temp_point); 147 | mbedtls_mpi_free(&a); 148 | mbedtls_mpi_free(&one); 149 | mbedtls_mpi_free(&neg_one); 150 | mbedtls_ecp_point_free(&k0_point); 151 | mbedtls_ecp_point_free(&k1_point); 152 | } 153 | 154 | GarbledCircuit::WireLabel ObliviousTransfer::receiveWireLabel(WiFiClient& client, bool choice) { 155 | ECCHelper ecc; 156 | 157 | mbedtls_ecp_point A, B; 158 | mbedtls_mpi b; 159 | mbedtls_ecp_point_init(&A); 160 | mbedtls_ecp_point_init(&B); 161 | mbedtls_mpi_init(&b); 162 | 163 | Serial.println("Evaluator ECP variables initialized"); 164 | 165 | // Receive A from sender 166 | uint8_t A_buf[ECC_POINT_SIZE]; 167 | while (client.available() < ECC_POINT_SIZE) { 168 | Serial.println(client.available()); 169 | delay(1000); 170 | } 171 | client.readBytes(A_buf, ECC_POINT_SIZE); 172 | 173 | Serial.print("Evaluator received A point: "); 174 | for(int i = 0; i < ECC_POINT_SIZE; i++) { 175 | Serial.printf("%02X ", A_buf[i]); 176 | } 177 | Serial.println(); 178 | 179 | mbedtls_ecp_point_read_binary(ecc.getGroup(), &A, A_buf, ECC_POINT_SIZE); 180 | 181 | // Generate random b and debug output 182 | ecc.generateRandomScalar(b); 183 | uint8_t b_bytes[32]; 184 | mbedtls_mpi_write_binary(&b, (unsigned char*)b_bytes, sizeof(b_bytes)); 185 | Serial.print("Evaluator scalar b: "); 186 | for(int i = 0; i < 32; i++) { 187 | Serial.printf("%02X ", b_bytes[i]); 188 | } 189 | Serial.println(); 190 | 191 | // Compute g^b 192 | mbedtls_ecp_point temp; 193 | mbedtls_ecp_point_init(&temp); 194 | mbedtls_ecp_mul(ecc.getGroup(), &temp, &b, &ecc.getGroup()->G, 195 | mbedtls_ctr_drbg_random, ecc.getRNG()); 196 | 197 | // Debug output for g^b 198 | uint8_t gb_buf[ECC_POINT_SIZE]; 199 | size_t olen; 200 | mbedtls_ecp_point_write_binary(ecc.getGroup(), &temp, 201 | MBEDTLS_ECP_PF_UNCOMPRESSED, 202 | &olen, gb_buf, sizeof(gb_buf)); 203 | Serial.print("Evaluator g^b point: "); 204 | for(size_t i = 0; i < olen; i++) { 205 | Serial.printf("%02X ", gb_buf[i]); 206 | } 207 | Serial.println(); 208 | 209 | if (choice) { 210 | // B = A + g^b using muladd: B = 1*A + 1*g^b 211 | mbedtls_mpi one; 212 | mbedtls_mpi_init(&one); 213 | mbedtls_mpi_lset(&one, 1); 214 | 215 | mbedtls_ecp_muladd(ecc.getGroup(), &B, &one, &A, &one, &temp); 216 | 217 | Serial.println("Evaluator computed B = A + g^b"); 218 | 219 | mbedtls_mpi_free(&one); 220 | } else { 221 | // B = g^b 222 | mbedtls_ecp_copy(&B, &temp); 223 | 224 | Serial.println("Evaluator computed B = g^b"); 225 | } 226 | 227 | Serial.println("Evaluator computed B"); 228 | 229 | // Send B to sender 230 | uint8_t B_buf[ECC_POINT_SIZE]; 231 | mbedtls_ecp_point_write_binary(ecc.getGroup(), &B, 232 | MBEDTLS_ECP_PF_UNCOMPRESSED, 233 | &olen, B_buf, sizeof(B_buf)); 234 | 235 | Serial.print("Evaluator sending B point: "); 236 | for(size_t i = 0; i < olen; i++) { 237 | Serial.printf("%02X ", B_buf[i]); 238 | } 239 | Serial.println(); 240 | 241 | client.write(B_buf, ECC_POINT_SIZE); 242 | 243 | // Compute k = A^b 244 | mbedtls_ecp_point k_point; 245 | mbedtls_ecp_point_init(&k_point); 246 | ecc.pointMultiply(k_point, b, A); 247 | 248 | uint8_t k_buf[ECC_POINT_SIZE]; 249 | mbedtls_ecp_point_write_binary(ecc.getGroup(), &k_point, 250 | MBEDTLS_ECP_PF_UNCOMPRESSED, 251 | &olen, k_buf, sizeof(k_buf)); 252 | 253 | Serial.print("Evaluator k point (A^b): "); 254 | for(size_t i = 0; i < olen; i++) { 255 | Serial.printf("%02X ", k_buf[i]); 256 | } 257 | Serial.println(); 258 | 259 | uint8_t key[32]; 260 | mbedtls_sha256(k_buf, olen, key, 0); 261 | 262 | Serial.print("Evaluator derived key: "); 263 | for(int i = 0; i < 32; i++) { 264 | Serial.printf("%02X ", key[i]); 265 | } 266 | Serial.println(); 267 | 268 | // Receive encrypted wire labels 269 | uint8_t e0[sizeof(GarbledCircuit::WireLabel)]; 270 | uint8_t e1[sizeof(GarbledCircuit::WireLabel)]; 271 | while (client.available() < sizeof(e0) + sizeof(e1)) delay(10); 272 | client.readBytes(e0, sizeof(e0)); 273 | client.readBytes(e1, sizeof(e1)); 274 | 275 | Serial.print("Evaluator received e0: "); 276 | for(size_t i = 0; i < sizeof(GarbledCircuit::WireLabel); i++) { 277 | Serial.printf("%02X ", e0[i]); 278 | } 279 | Serial.println(); 280 | 281 | Serial.print("Evaluator received e1: "); 282 | for(size_t i = 0; i < sizeof(GarbledCircuit::WireLabel); i++) { 283 | Serial.printf("%02X ", e1[i]); 284 | } 285 | Serial.println(); 286 | 287 | // Decrypt chosen wire label 288 | GarbledCircuit::WireLabel result; 289 | uint8_t* encrypted = choice ? e1 : e0; 290 | 291 | for(size_t i = 0; i < sizeof(GarbledCircuit::WireLabel); i++) { 292 | ((uint8_t*)&result)[i] = encrypted[i] ^ key[i % 32]; 293 | } 294 | 295 | Serial.print("Evaluator decrypted label: "); 296 | for(size_t i = 0; i < sizeof(GarbledCircuit::WireLabel); i++) { 297 | Serial.printf("%02X ", ((uint8_t*)&result)[i]); 298 | } 299 | Serial.println(); 300 | 301 | // Cleanup 302 | mbedtls_ecp_point_free(&A); 303 | mbedtls_ecp_point_free(&B); 304 | mbedtls_mpi_free(&b); 305 | mbedtls_ecp_point_free(&k_point); 306 | mbedtls_ecp_point_free(&temp); 307 | 308 | return result; 309 | } -------------------------------------------------------------------------------- /src/oblivious_transfer.h: -------------------------------------------------------------------------------- 1 | #ifndef OBLIVIOUS_TRANSFER_H 2 | #define OBLIVIOUS_TRANSFER_H 3 | 4 | #include 5 | #include "garbled_circuit.h" 6 | #include "ecc_helper.h" 7 | 8 | #define ECC_KEY_SIZE 32 9 | #define ECC_POINT_SIZE (2 * ECC_KEY_SIZE + 1) 10 | 11 | class ObliviousTransfer { 12 | public: 13 | // Sender's side of ECC-based Chou-Orlandi OT 14 | static void sendWireLabels(WiFiClient& client, 15 | const GarbledCircuit::WireLabel& label0, 16 | const GarbledCircuit::WireLabel& label1); 17 | 18 | // Receiver's side of ECC-based Chou-Orlandi OT 19 | static GarbledCircuit::WireLabel receiveWireLabel(WiFiClient& client, bool choice); 20 | }; 21 | 22 | #endif --------------------------------------------------------------------------------