Obliv-Java: a Java Virtual Machine for Secure Computation and its Application to Smart Contracts

The five ascending levels of intellect: Smart, Intelligent, Brilliant, Genius, Simple.

Albert Einstein

Beyond the genius of secure computation, there is the simplicity of its use. Previous approaches to secure computation have developed their own programming languages and new type systems. We go a step further: now you can securely compute on your original code without introducing breaking changes, faithfully respecting the standard Java language and thus maintaining retro-compatibility with all your previous code. Ultimately, we aim to multiply developer productivity by enabling the easy refactorization of Java code for secure computation. Additionally, all your previous developer tooling will still be compatible with Obliv-Java: static analyzers, developer environments, and unit testing frameworks, among many others.

In Obliv-Java, field definitions in a class have to be annotated using the new “@Obliv(X)” type annotation, with X being the assigned number of the party within the secure computation. For example,

@Obliv(1) 
float inputA;
@Obliv(2)
float inputB;
@Obliv(0) 
float compResult;

In the previous code fragment, inputA is the field to be securely assigned a value by party 1, inputB is the field for party 2 and compResult is the field used for both parties to obtain the resulting value during its revelation at the end of the secure computation (thus assigned party 0, that is, any of the parties in the secure computation). The developer can use the fields defined as oblivious as usual (addition, subtraction, multiplication, division, casting to other oblivious variables, …) obviating any cryptographic details about their secure computation and thus freeing their mind to solve challenging programming tasks, much like memory safe languages help to improve developer productivity by taking care of all the tasks related to memory management.

For secure computation, we use modern implementations of Secure Multi-Party Computation protocols (SMPC), one of the best well-kept secrets of the toolbox of the modern cryptographer: after achieving a speed-up of 700.000x over the previous decade, MPC protocols are orders of magnitude faster than homomorphic encryption and zero-knowledge protocols. The latest research advances have produced MPC protocols specially tailored for decentralized settings where all parties could be malicious, as with blockchain environments (e.g., Global-Scale Secure Multiparty Computation).

Our Private and Verifiable Smart Contracts are developed in Obliv-Java, a modified JVM for secure computation and Proof-Carrying Code. For example, see the following example:

public class Example {
  @Obliv(1)
  float inputA;
  @Obliv(2)
  float inputB;
  @Obliv(0)
  float compResult;

  public static void main(String args[]) {
    inputA = Float.parseFloat(args[0]);
    inputB = Float.parseFloat(args[1]);

    securelyCompute();

    System.out.println(Example.class.getField(“compResult”).revealOblivFloat(Example.class));
  }

  //@ ensures inputA > inputB ==> compResult == inputA-inputB
  //@ ensures inputA <= inputB ==> compResult == inputA+inputB
  public static securelyCompute()
  {
    if (inputA > inputB)
      compResult = inputA – inputB;
    else
      compResult = inputA + inputB);
  }
}

 Note that all the secure computation is fully transparent to the developer, who doesn’t have to know anything about cryptographic protocols:

  • Lines 2-7: variables definitions with the “@Obliv” type annotation.
  • Lines 10-11: input variables from command line (args[0], args[1]) are converted to floating point type. Then, they are internally converted for secure computation during their assignment to oblivious variables inputA, inputB.
  • Lines 15: the variable compResult is retrieved using Java reflection, and the new method revealOblivFloat returns its unencrypted value to both parties because it was defined with party identifier 0.
  • Lines 22-25: this is where all the magic happens. The variable compResult is equal to inputA minus the inputB if inputA is bigger than inputB, or equal to inputA plus inputB if inputA is less than inputB: secure computation uses exactly the same source code and there is no need to introduce any modification.

Moreover, the JML annotations in lines 18-19 can be converted to proof obligations that other parties can check before executing non-trusted code (although this would be the subject of another post). All your tools for proving the software correct remains as useful as ever.

APPLICATIONS TO SMART CONTRACTS

The following examples teach how Obliv-Java improves the state-of-the-art of smart contracts:

  • Vickrey Auctions: a truthful auction where bidders are incentivized to bid their true valuation and the auctioneer ends up maximizing its revenue. It’s a sealed-bid auction so it can’t be run on permissionless blockchains because all the bids are open to everyone.

But not so with Obliv-Java. Consider the following implementation in Java (slightly modified from Vickrey-JADE):

public AID getWinner(){
  AID winner = bidderList[0].getName();
  for(AID agent:bids.keySet()){
    if (bids.get(agent) >= max){
      max = bids.get(agent);
      winner = agent;
    }
  }
  return winner;
}

public void computeSecondPrice() {
  for(AID agent:bids.keySet()){
    if(bids.get(agent) >= max){
      secondMax = max;
      max = bids.get(agent);
    } else if (bids.get(agent) >= secondMax) {
      secondMax = bids.get(agent);
    }
  }
}

The method getWinner() returns the high bidder and the method computeSecondPrice() obtains the second maximum price in the variable secondMax. In Obliv-Java, you’ll only need to annotate the class fields secondMax and max with “@Obliv”, as well as each of the bids: no other modifications are needed.

@Obliv(0)
Double max = Double.NEGATIVE_INFINITY;
@Obliv(0)
Double secondMax = Double.NEGATIVE_INFINITY;
  • Initial Coin Offerings (ICOs) and other crowdfunding investments:

On permissionless blockchains, all transfers are publicly visible to all participants including those made when participating in an ICO, creating all kind of unintended consequences. For example, a clever participant could play a wait-and-see approach to learn from the bids of other participants to better reason about price formation: how many whales are participating? What are the general statistics of the bids -mean, median, mode…- ? Is it going to be over-subscribed?

But not so with Obliv-Java. A simple example to check whether private contributions have reached a secret cap is as follows.

public class ICO {
  @Obliv(1)
  int maxCap;
  @Obliv(0)
  int cumulativeContributions;
  @Obliv(0)
  boolean isCapReached;

  public void isCapReached() {
    isCapReached = cumulativeContributions >= maxCap;
    if (ICO.class.getField("isCapReached").revealOblivBoolean(ICO.class))
      stopAcceptingTransfers();
  }
}
  • Decentralized Exchanges (front-running and other attacks):

In decentralized exchanges, all orders are publicly visible to all traders so front-running attacks get even worse than those that could be carried out by a broker in traditional exchanges: everyone is out to get you. This issue has been noticed many times before, with some even creating practical attacks (“Implementing Ethereum trading front-runs on the Bancor exchange in Python”). Solutions are very unsatisfactory: for example, taking the order book off-chain re-introduces centralization issues and front-running from the matcher.

But not so with Obliv-Java. Consider the following simple market order book refactored for secure computation:

if (side == buy)
  mapOrders = asks;
else if (side == sell)
  mapOrders = bids;

for (Order ord:mapOrders.keySet()) {
  price = mapOrders.getPrice(ord);
  currentSize = targetSize - sizeCompleted;

  if (mapOrders.getSize(ord) < currentSize)
    sizeCurrentOrder = mapOrders.getSize(ord);
  else
    sizeCurrentOrder = currentSize;

  sizeCompleted += sizeCurrentOrder;
  amount += sizeCurrentOrder * price;

  if (sizeCompleted == targetSize) {
    if (!foundAmount) {
      foundAmount = true;
      retAmount = amount;
    }
  }
}

As with previous cases, annotating the involved variables as “@Obliv” would be enough to refactor the previous algorithm for secure computation.

We’re happy to open-source Obliv-Java: stay tuned for the coming Initial Distribution.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.