This forum thread is to consolidate and continue our discussion on the Oblivious Message Detection / Retrieval issue.
Some of the previous places this discussion took place:
- Taiga github repo issue #17: Optimize transaction scanning with private set intersection/private information retrieval · Issue #17 · anoma/taiga · GitHub
- This hackmd note I prepared a while ago: Oblivious Message Detection - HackMD
- Discord chat with @cwgoes and J – some main points are brought over to this post below
In short, the primary topic of the discussion is whether the OMD/R model presented in the paper is performant enough to be considered for integration with Taiga.
I did performance testing of the original model codebase (the detection part) some time ago in a single threaded mode and got the following results. With ell
set to 4, the original C/C++ implementation reaches the speed of 12 ms/message using SEAL+HEXL on an Intel CPU (M6i instance in AWS) and 13ms/message on an M1 Max using SEAL without HEXL. This part could be done by the server side, then the client side only needs to run a very limited computation locally. For 500k messages, this adds up to ~100 minutes (single threaded).
J tried to reimplement the code in rust (GitHub - Janmajayamall/ObliviousMessageRetrieval) and managed to achieve impressive performance after several iterations, but it is still lower then the C++ implementation. For consistency, I will additionally benchmark latest code by J in the same environments and post the results here.
To have a baseline, I also implemented a little benchmark of the trial decryption approach using OpenSSL implementation of ECC Diffie-Hellman key exchange. I wrote it in plain C, but this should be easy to port to rust.
We setup an environment with N users (1000 peers + 1 recipient in the benchmark), each has a pair of EC keys. When peer A sends a note to peer B, peer A uses DH key exchange to generate a shared secret from A’s private key and B’s public key. The shared secret is then used to generate AES-128 parameters, which are used to encrypt a clue, which is 16 ubytes 0x01
. An encrypted clue also takes 16 bytes.
Recipient then scans the entire set of clues (in the benchmark, 500k clues). For every clue, recipient gets a sender’s public key, uses it to recover the shared secret, instantiates AES decryptor and attempts to decrypt the clue. Recipient then checks if the decrypted clue is 16 0x01
ubytes. For a pertinent message it will always be so, for a non-pertinent message it may by chance be and then this is a false positive (which is ok).
For 1001 peers and 500k messages, out of which 100 are pertinent, these are the benchmark result for some of the shortlisted curves (which were faster than others). On average, for 500k messages we see ~6 false positives.
CURVE | PubKey Length | Total B/clue | Total Bytes | Detection time | Detection/message
secp224r1 | 29 bytes | 45 bytes | 22.5 MiB | 30'654 ms | 0.0613 ms
sect113r1 | 16 bytes | 32 bytes | 16.0 MiB | 43'876 ms | 0.0878 ms
sect113r2 | 16 bytes | 32 bytes | 16.0 MiB | 43'759 ms | 0.0875 ms
prime256v1 | 33 bytes | 49 bytes | 24.5 MiB | 25'742 ms | 0.0515 ms
This is measured with a C implementation using OpenSSL library and we see 0.05–0.09 ms/clue, which is down from 3-4 ms/clue in my first crude benchmark calling OpenSSL binary from a bash script In this context “per clue” means the same as “per message”. The numbers are measured on an Intel CPU (3rd Gen Intel Xeon Ice Lake with AVX-512) in a single thread mode. This should parallelize linearly. The whole computation takes place on a local device (laptop, phone, etc), there’s is no work done by any service, eg a validator.
Here are the raw results: openssl-omd/results.txt at b9871a51d113aa9a84f648f31d4f057ae24fc240 · bazzilic/openssl-omd · GitHub
Here’s the code: openssl-omd/ecdh-openssl.c at b9871a51d113aa9a84f648f31d4f057ae24fc240 · bazzilic/openssl-omd · GitHub
I am re-working this benchmark a little bit and will post new results later on.