tinybid: Secure Single-Item First-Price Auction Demo

This secure single-item first-price auction demo (source code available on GitHub) simulates a secure multi-party computation (MPC) protocol entirely in your browser by importing and invoking the tinybid and underlying tinynmc libraries using PyScript.

Within the implementation of the library, vectors of finite field elements are used to represent both submitted bids and the overall outcome of an auction. In the visualizations below, instances of these data structures are rendered using a variant of a heat map in which the brightness value corresponds to the difference between the finite field element and zero. For example, a vector such as 1 mod 115 mod 118 mod 113 mod 1110 mod 11 would be represented by   . Note also that bidders and nodes are numbered starting from zero so that their interface identifiers match their indices in the source code.

  1. For each bidder, use the slider to choose a bid value and then click Bid. The bids are encoded as vectors, masks are requested from the nodes, and the masked vectors are broadcast to all the nodes.

Bidder 0

Bidder 1

Bidder 2

Bidder 3

  1. Each node receives the masked vectors corresponding to the four bids, and then locally computes its secret share of the overall result vector.

Node 0

Masked Bids

Secret Share of Outcome

Node 1

Masked Bids

Secret Share of Outcome

Node 2

Masked Bids

Secret Share of Outcome

  1. The auction operator receives the secret shares of the result vector from each node and reconstructs it to determine the winner and their bid.

Network Output

packages = ["tinybid~=0.2"]
from pyodide.ffi import create_proxy import js from tinybid import * def modulo_to_uint8(m): return (256 * int(m)) // m.modulus def compute_outcome_if_ready(): if all(bid is not None for bid in bids): shares = [node.outcome(bids) for node in nodes] for node_id in range(3): js.nodeShowShare( node_id, [modulo_to_uint8(value) for value in shares[node_id]] ) result = list(sorted(reveal(shares))) js.recipientEnable() js.document.getElementById('recipient-output').innerHTML = \ 'Winning bidder ID(s): ' + (', '.join([str(i) for i in result])) + '.' def make_bid_handler(bid_id): def bid_handler(_): request_ = request(identifier=bid_id) masks = [node.masks(request_) for node in nodes] price = js.clientGetPriceAndDisable(bid_id) bids[bid_id] = bid(masks, price) js.diagramInputUpdate() js.nodesEnable() for node_id in range(3): js.nodeShowBidMasked( bid_id, node_id, [modulo_to_uint8(list(d.values())[0]) for d in bids[bid_id]] ) compute_outcome_if_ready() return bid_handler bids = [None, None, None, None] prices = 15 nodes = [node(), node(), node()] preprocess(nodes, bids=len(bids), prices=prices) for bid_id in range(len(bids)): js.document.getElementById('bid-' + str(bid_id)).addEventListener( 'click', create_proxy(make_bid_handler(bid_id)) )