diff --git a/async-test/async.cpp b/async-test/async.cpp index 3311df1..925b514 100644 --- a/async-test/async.cpp +++ b/async-test/async.cpp @@ -2,71 +2,167 @@ #include #include #include +#include +#include "emp-tool/io/i_raw_io.h" #include "emp-ag2pc/2pc.h" -#include "Buffer.hpp" +void run_impl(int party); -void start_impl(); +// Implement send_js function to send data from C++ to JavaScript +EM_JS(void, send_js, (const void* data, size_t len), { + if (!Module.send) { + throw new Error("Module.send is not defined in JavaScript."); + } + + // Copy data from WebAssembly memory to a JavaScript Uint8Array + const dataArray = HEAPU8.slice(data, data + len); + + Module.send(dataArray); +}); + +// Implement recv_js function to receive data from JavaScript to C++ +EM_ASYNC_JS(void, recv_js, (void* data, size_t len), { + if (!Module.recv) { + reject(new Error("Module.recv is not defined in JavaScript.")); + return; + } + + // Wait for data from JavaScript + const dataArray = await Module.recv(); + + // Copy data from JavaScript Uint8Array to WebAssembly memory + HEAPU8.set(dataArray, data); +}); + +class RawIOJS : public IRawIO { +public: + void send(const void* data, size_t len) override { + send_js(data, len); + } + + void recv(void* data, size_t len) override { + recv_js(data, len); + } + + void flush() override { + // Ignored for now + } +}; + +EM_JS(char*, get_circuit_raw, (int* lengthPtr), { + if (!Module.getCircuit) { + throw new Error("Module.getCircuit is not defined in JavaScript."); + } + + const circuitString = Module.getCircuit(); // Get the string from JavaScript + const length = lengthBytesUTF8(circuitString) + 1; // Calculate length including the null terminator + + // Allocate memory for the string + const strPtr = Module._js_malloc(length); + stringToUTF8(circuitString, strPtr, length); + + // Set the length at the provided pointer location + setValue(lengthPtr, length, 'i32'); + + // Return the pointer + return strPtr; +}); + +emp::BristolFormat get_circuit() { + int length = 0; + char* circuit_raw = get_circuit_raw(&length); + + emp::BristolFormat circuit(circuit_raw); + free(circuit_raw); + + return circuit; +} + +EM_JS(uint8_t*, get_input_bits_raw, (int* lengthPtr), { + if (!Module.getInputBits) { + throw new Error("Module.getInputBits is not defined in JavaScript."); + } + + const inputBits = Module.getInputBits(); // Assume this returns a Uint8Array + + // Allocate memory for the input array + const bytePtr = Module._js_malloc(inputBits.length); + Module.HEAPU8.set(inputBits, bytePtr); + + // Set the length at the provided pointer location + setValue(lengthPtr, inputBits.length, 'i32'); + + // Return the pointer + return bytePtr; +}); + +std::vector get_input_bits() { + int length = 0; + uint8_t* input_bits_raw = get_input_bits_raw(&length); + + std::vector input_bits(length); + + for (int i = 0; i < length; ++i) { + input_bits[i] = input_bits_raw[i]; + } + + free(input_bits_raw); + + return input_bits; +} + +EM_JS(void, handle_output_bits_raw, (uint8_t* outputBits, int length), { + if (!Module.handleOutputBits) { + throw new Error("Module.handleOutputBits is not defined in JavaScript."); + } + + // Copy the output bits to a Uint8Array + const outputBitsArray = new Uint8Array(Module.HEAPU8.buffer, outputBits, length); + + // Call the JavaScript function with the output bits + Module.handleOutputBits(outputBitsArray); +}); + +void handle_output_bits(const std::vector& output_bits) { + uint8_t* output_bits_raw = new uint8_t[output_bits.size()]; + + for (size_t i = 0; i < output_bits.size(); ++i) { + output_bits_raw[i] = output_bits[i]; + } + + handle_output_bits_raw(output_bits_raw, output_bits.size()); + + delete[] output_bits_raw; +} extern "C" { + EMSCRIPTEN_KEEPALIVE + void run(int party) { + run_impl(party); + } + EMSCRIPTEN_KEEPALIVE uint8_t* js_malloc(int size) { return (uint8_t*)malloc(size); } - - EMSCRIPTEN_KEEPALIVE - void start() { - start_impl(); - } } -EM_ASYNC_JS(uint8_t*, get_data_impl, (int* lengthPtr), { - console.log("JavaScript: Waiting for data..."); +void run_impl(int party) { + auto io = emp::IOChannel(std::make_shared()); + auto circuit = get_circuit(); - // Simulate asynchronous data retrieval - const data = await new Promise((resolve) => { - Module.provideData = (dataArray) => { - console.log("JavaScript: Data received."); - // const dataArray = [1, 2, 3]; // Example data - resolve(dataArray); - }; - }); + auto twopc = emp::C2PC(io, party, &circuit); - const len = data.length; - const dataPtr = Module._js_malloc(len); // Use the exported js_malloc + twopc.function_independent(); + twopc.function_dependent(); - // Copy data into the WebAssembly memory - Module.HEAPU8.set(data, dataPtr); + std::vector input_bits = get_input_bits(); - // Get the pointer to the length variable in C++ - var lengthPtr = arguments[0]; - - // Set the length back to the C++ side - Module.setValue(lengthPtr, len, 'i32'); - - return dataPtr; -}); - -Buffer get_data() { - int length; - uint8_t* data = get_data_impl(&length); - return Buffer(data, length); + std::vector output_bits = twopc.online(input_bits, true); + handle_output_bits(output_bits); } int main() { return 0; } - -void start_impl() { - puts("C++: Before calling get_data"); - - Buffer data = get_data(); - - printf("C++: After calling get_data, data length is %d\n", data.size()); - - // Process the data - for (int i = 0; i < data.size(); ++i) { - printf("C++: Data[%d] = %d\n", i, data[i]); - } -} diff --git a/async-test/build.sh b/async-test/build.sh index df636e3..4f3c6c3 100755 --- a/async-test/build.sh +++ b/async-test/build.sh @@ -4,5 +4,10 @@ em++ async.cpp Buffer.cpp -sASYNCIFY -o index.html \ -I ../src/ \ -I $(brew --prefix openssl)/include \ -L $(brew --prefix openssl)/lib \ + -lcrypto \ + -lssl \ + -lembind \ + -s MODULARIZE=1 -s EXPORT_ES6=1 \ + -s ENVIRONMENT='web,worker' \ -sEXPORTED_FUNCTIONS=['_js_malloc','_main'] \ -sEXPORTED_RUNTIME_METHODS=['HEAPU8','setValue']