Skip to content

stealthsoftwareinc/pulsar-mpc

Repository files navigation

PULSAR-MPC

PULSAR-MPC is a special-purpose library for secure multiparty computation (MPC) that was written by Stealth Software Technologies, Inc. as part of the DARPA Brandeis project. The library was primarily intended to be used as part of the CoffeeBreak Android application. For additional inquiry in the use and deployment of our software, please reach out to us at contact@stealthsoftwareinc.com.

Essentially, CoffeeBreak is an application that securely computes the centroid of a set of private locations to find a single meeting place, such as a coffee shop. We model this computation as a circuit, which is securely evaluated by our core MPC engine. Each party’s private location is hidden.

Precompiled Android library

A precompiled Android library, pulsar-mpc-<version>.aar, is provided on the Releases page. The library includes the following:

  • A set of coffeeshop_*.cbg circuits.

  • The MpcTask class.

  • The bmc native library and all of its prerequisite native libraries, compiled for AArch64 and x86_64.

Building for Android

For reference, a set of precompiled Android files, pulsar-mpc-<version>-android.tar.xz, is provided on the Releases page. The archive includes the same content as the precompiled Android library.

You can also build the Android native libraries yourself as follows (this requires that you have docker installed):

./configure

make parcels/pulsar-mpc-VERSION-aarch64-linux-android-api27.tar.xz

make parcels/pulsar-mpc-VERSION-x86_64-linux-android-api27.tar.xz

Building for Linux

This section walks through building and installing PULSAR-MPC on an Ubuntu machine.

Run the following commands to build and install the bmc native library and the circuit_builder_main utility:

sudo apt-get install g++ make openjdk-11-jdk libgmp-dev nettle-dev

./configure \
  --disable-static \
  CPPFLAGS="-I/usr/lib/jvm/java-11-openjdk-amd64/include \
            -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux" \
  CFLAGS="-O2 -march=native" \
  CXXFLAGS="-O2 -march=native" \
;

make

sudo make install

After installing, you can test the MpcTask class using the MpcTaskTest program by following the comments inside the MpcTaskTest source code. The MpcTaskTest program includes an implementation of the MpcTask.Channel interface for RabbitMQ. As this is a push channel implementation, note how the basicConsume() handlers call the MpcTask.recv() method from elsewhere to feed it bytes. Also note how this code calls the System.loadLibrary() method similarly to as described previously.

Compiling circuits

After building and installing PULSAR-MPC on a Linux machine, the installed circuit_builder_main utility can be used to compile circuits. See CircuitBuilderREADME.adoc for more information on using this utility.

Using the library

The main API is the MpcTask Java class, which can be used to securely evaluate an arbitrary circuit. Underneath this class lies the core MPC engine, which is a native library written in C++ called bmc. The MpcTask class calls the bmc native library using JNI.

All parties run the circuit evaluation at the same time and communicate with each other using the MpcTask.Channel interface, which you must implement for each type of network channel you wish to use:

  • The void send(byte[] buf) method should send all buf.length bytes in buf to the other party, or throw an exception upon error.

    The ongoing computation may call the send() method from multiple threads at the same time. However, it is guaranteed that, for each channel, only one send() call will be occurring on that channel at any given time.

  • For receiving bytes, there are two options:

    1. If you want a push channel, meaning you’ll call the MpcTask.recv() method to feed bytes into the ongoing computation as you receive them (in another thread), then you need not implement anything but the send() method.

      You can call the MpcTask.recv() method from multiple threads at the same time. However, you must guarantee that, for each channel, only one call will be occurring on that channel at any given time.

    2. If you want a pull channel, meaning the ongoing computation will call back to you (from an unspecified thread) to receive bytes as it needs them, then you need to implement the recv() and isPush() methods. The void recv(byte[] buf) method should fill buf with the next buf.length bytes received from the other party, or throw an exception upon error. The boolean isPush() method should return false to indicate that this is a pull channel.

      The ongoing computation may call the recv() method from multiple threads at the same time. However, it is guaranteed that, for each channel, only one recv() call will be occurring on that channel at any given time.

Before you can use the MpcTask class, you must load the bmc native library along with its prerequisite libraries, Nettle and GMP. This is typically done with the System.loadLibrary() method. Be sure to do this in the following order:

You may need to use the System.load() method for any .so library files that do not match the typical libfoo.so naming form, such as libnettle.so.6. This method takes an absolute path to the library file to load, so something like System.load(getApplicationInfo().nativeLibraryDir + "/libnettle.so.6") should work.

After you have the MpcTask.Channel interface implemented and the native libraries loaded, you’re ready to create an MpcTask.

First, you need to pick a circuit for the parties to evaluate. Various circuit files are provided in the src/circuits directory. Each circuit is designed for a specific number of parties n, and each party must provide an appropriate input string to the circuit. The circuit produces an output string, which is a comma separated list of numbers. All parties receive the same output string.

For the coffeeshop_*.cbg circuits, n is indicated in the filename, and the input string for party i (where 0 ≤ i < n) is of the form xi_lat=a,xi_lng=b, where a and b are integers. The output string is a list of two integers that are the sum of all parties' a values and the sum of all parties' b values, respectively. For example, with two parties with input strings x0_lat=1,x0_lng=-1 and x1_lat=1,x1_lng=-1, the output string will be 2,-2.

You’ll need to make the circuit files be stored on disk in your Android project so the native code can access them, which unfortunately takes some work. You can do this by adding the files to the assets folder of your Android project and adding code to write them to disk as necessary. You can open an asset as an InputStream with the Context.getAssets() and AssetManager.open() methods, and you can write the asset to disk somewhere in the directory returned by the Context.getFilesDir() method.

Next, you need to create a list of n channels for the MpcTask to use to communicate with the other n-1 parties. The list should have a null at the index of this party itself (which is why the list has n entries, not n-1).

Now you’re ready to create an MpcTask:

MpcTask mpcTask = new MpcTask(
  circuitFile,
  inputString,
  channelList,
  true // whether to enable logging
);

Constructing the MpcTask merely prepares it to run. To actually run it, the MpcTask class implements the Callable<String> interface, which you can use in any normal way. The simplest way is to call the call() method in the current thread:

String result = mpcTask.call();

You can also call the MpcTask.getLog() method to retrieve the log after the call() method returns or throws an exception. If logging was enabled when the MpcTask was created and the log was successfully captured, this method returns the log as a String. Otherwise, it returns null. The log can be particularly helpful for diagnosing errors.

License

PULSAR-MPC is licensed under the MIT license.

Acknowledgments

This work was supported by DARPA and NIWC Pacific under contract N66001-15-C-4065. The U.S. Government is authorized to reproduce and distribute reprints for Governmental purposes not withstanding any copyright notation thereon. The views, opinions, and/or findings expressed are those of the author(s) and should not be interpreted as representing the official views or policies of the Department of Defense or the U.S. Government.

Contributors

  • Paul Bunn <paul@stealthsoftwareinc.com>

  • Quinn Grier <quinn@stealthsoftwareinc.com>

  • Steve Lu <steve@stealthsoftwareinc.com>

Attributions

See the ATTRIBUTIONS.adoc file.

Distribution Statement

Distribution Statement "A" (Approved for Public Release, Distribution Unlimited)