mppj

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 15, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

README

MPPJ-Go: a Go Implementation of the DH-MPPJ Protocol

This package implements the DH-MPPJ protocol, as proposed in the paper "Multi-party Private Joins" by by Anja Lehmann, Christian Mouchet and Andrey Sidorenko, PETS 2026. It implement this protocol over the P-256 elliptic curve.

Synopsis

For each party, this package provides an implementation as a type: mppj.Source, mppj.Helper and mppj.Receiver. Each type can be instantiated from public parameters and provide the main cryptographic operations as public methods.

The protocol has two rounds, so each type has one main method which correspond to its local operation in the protocol:

  • mppj.Source.Prepare encrypts a single source's data towards the receiver's public key. The data is to be sent to the Helper.
  • mppj.Helper.Convert takes as input all the sources' encrypted data tables, and computes an encrypted joined table, which is to be sent to the Receiver.
  • mppj.Receiver.JoinTables decrypts the joined tables and extracts the join.

Each operation has a channel-based counterpart which enables each party to process the tables in a streaming fashion. The streamed and the non-streamed methods enable processing over multiple cores via a parameterizable number of goroutines.

See the examples/minimal/main.go file for a minimal working program demonstrating the use of the types. The documentation is hosted at pkg.go.dev.

Package Structure

  • party_datasource.go: the source-related operations.
  • party_helper.go: the helper-related operations.
  • party_receiver.go: the receiver-related operations.
  • group.go a group abstraction for ElGamal.
  • encryption.go the PKE / SE functionality
  • prf.go the Hash-DH OPRF (for use with ElGamal PKE)
  • table.go some basic types (plaintext table, joined table) and functions for tables
  • mppj_test.go some end-to-end tests.
  • benchmark_test.go some micro-benchmarks for individual operations.
  • api a gRPC-based service for the helper (server) and source/receiver (clients).
  • examples example uses of the package in conjunction with different data formats.

Current Limitations

  • The number of sources is limited to 256, as the origin table is encoded in a single byte.
  • The table values are also assumed to be smaller than 30 bytes, to enable reversible encoding to a single group element
  • The large-values extension proposed of the paper is not yet implemented.
  • The parties can send any number of rows and the implementation does not add any dummy value to pad to a given number.

Security

This repository contains a prototype implementation of the MPPJ protocol. This is for academic research purposes and should not be considered production-ready. Notably, the code was not externally audited and includes several non-constant-time algorithms.

Documentation

Overview

Package mppj implements implements the MPPJ protocol, as proposed in the paper "Multi-party Private Join" by by Anja Lehmann, Christian Mouchet and Andrey Sidorenko, PETS 2026.

Index

Constants

View Source
const KeySize = 16

KeySize is the size of symmetric keys in bytes.

View Source
const MaxValueSize = 30

MaxValueSize is the maximum size of the input tables' values in bytes.

Variables

This section is empty.

Functions

func GenTestTables

func GenTestTables(sourceIDs []PartyID, nRows, intersectionSize int) map[PartyID]TablePlain

GenTestTables generates test tables for the given source IDs with specified number of rows and intersection size.

func GetTestKeys

func GetTestKeys(seed []byte) (SecretKey, PublicKey)

Generates keys *deterministically* from a seed

func KeyGen

func KeyGen() (SecretKey, PublicKey)

func SourceIDToOutgoingContext

func SourceIDToOutgoingContext(ctx context.Context, id PartyID) context.Context

Types

type Ciphertext

type Ciphertext struct {
	// contains filtered or unexported fields
}

Ciphertext represents an ElGamal ciphertext. c0 = g^r, c1 = m * pk^r

func DeserializeCiphertext

func DeserializeCiphertext(data []byte) (*Ciphertext, error)

DeserializeCiphertext deserializes a byte slice into a Ciphertext.

func (*Ciphertext) Equals

func (ct *Ciphertext) Equals(other *Ciphertext) bool

Equals checks if two Ciphertexts are equal.

func (*Ciphertext) Serialize

func (ct *Ciphertext) Serialize() ([]byte, error)

Serialize serializes a Ciphertext into a byte slice.

type ConvertRowTask

type ConvertRowTask struct {
	EncRowMsg EncRow
	SourceID  PartyID
}

ConvertRowTask represents a task to convert a single encrypted row from a data source.

type DataSource

type DataSource struct {
	// contains filtered or unexported fields
}

DataSource represents a data source party in the MPPJ protocol, for a given session. Its main method is Prepare, which prepares a plaintext table for joining.

func NewDataSource

func NewDataSource(sess *Session) *DataSource

NewDataSource creates a new DataSource for the given session.

func (*DataSource) Prepare

func (s *DataSource) Prepare(table TablePlain) (EncTable, error)

Prepare prepares a table for joining by adding hashing the UIDs and encrypting its contents towards the receiver.

func (*DataSource) PrepareStream

func (s *DataSource) PrepareStream(table TablePlain, goroutines ...int) (encRows <-chan EncRow, err error)

PrepareStream is the streaming version of [Prepare]. It sends encrypted rows through the encRows channel, as they are processed. It is optionally possible to specify the number of goroutines workers to use.

func (*DataSource) ProcessRow

func (s *DataSource) ProcessRow(uid, val string) (cuid *Ciphertext, cval []*Ciphertext, err error)

ProcessRow processes a single row, returning the encrypted UID and encrypted value.

type EncRow

type EncRow struct {
	Cuid *Ciphertext
	Cval []*Ciphertext
}

EncRow represents a single encrypted row with encrypted UID and encrypted value(s).

func (EncRow) MarshalBinary

func (er EncRow) MarshalBinary() ([]byte, error)

MarshalBinary serializes an EncRow into a byte slice.

type EncRowWithHint

type EncRowWithHint struct {
	Cnyme   Ciphertext
	CVal    SymmetricCiphertext
	CValKey Ciphertext
	CHint   Ciphertext
}

EncRowWithHint represents a single encrypted row after processing by the helper.

type EncTable

type EncTable []EncRow

EncTable represents an encrypted table as a slice of encrypted rows. It is the output type for the data source and the input type for the helper.

type EncTableWithHint

type EncTableWithHint []EncRowWithHint

EncTableWithHint represents an encrypted table after processing by the helper. It is the output type for the helper and the input type for the receiver.

type Helper

type Helper struct {
	// contains filtered or unexported fields
}

Helper represents a helper party in the MPPJ protocol, for a given session. Its main method is Convert, which converts encrypted tables from data sources into a format suitable for joining by the receiver.

func NewHelper

func NewHelper(sess *Session) *Helper

NewHelper creates a new Helper for the given session.

func (*Helper) Convert

func (h *Helper) Convert(tables map[PartyID]EncTable) (EncTableWithHint, error)

Convert converts the encrypted tables from data sources into a format suitable for joining by the receiver.

func (*Helper) ConvertRow

func (h *Helper) ConvertRow(rpk PublicKey, r *EncRow, sourceID PartyID) (*EncRowWithHint, error)

ConvertRow converts a single row `r` received from datasource sourceID.

func (*Helper) ConvertStream

func (h *Helper) ConvertStream(rpk PublicKey, encRowsTasks chan ConvertRowTask, goroutines ...int) (EncTableWithHint, error)

ConvertStream is the streaming version of [Convert]. It reads encrypted rows from the encRowsTasks channel, processes them, and returns the converted table when all the rows have been processed. It is optionally possible to specify the number of goroutines workers to use.

type JoinTable

type JoinTable struct {
	// contains filtered or unexported fields
}

JoinTable represents the final joined table produced by the receiver. It is the output type for the receiver.

func IntersectPlain

func IntersectPlain(tables map[PartyID]TablePlain, sources []PartyID) JoinTable

IntersectPlain performs a join on plain tables

func NewJoinTable

func NewJoinTable(sourceIDs []PartyID) JoinTable

NewJoinTable creates a new empty JoinTable for the given source IDs.

func (*JoinTable) EqualContents

func (t1 *JoinTable) EqualContents(t2 *JoinTable) bool

EqualContents checks only the contents of the joined tables, ignoring the order of rows.

func (*JoinTable) Insert

func (t *JoinTable) Insert(values map[PartyID]string) error

Insert adds a new row to the joined table with the given values mapped by source ID.

func (JoinTable) Len

func (t JoinTable) Len() int

Len returns the number of rows in the joined table.

func (JoinTable) String

func (t JoinTable) String() string

String returns the joined table as a CSV-formatted string.

func (JoinTable) WriteTo

func (t JoinTable) WriteTo(w *csv.Writer) error

WriteTo writes the joined table to a CSV writer.

type PartyID

type PartyID string

func SourceIDFromIncomingContext

func SourceIDFromIncomingContext(ctx context.Context) (PartyID, bool)

type PublicKey

type PublicKey struct {
	// contains filtered or unexported fields
}

func (*PublicKey) String

func (pkt *PublicKey) String() string

type Receiver

type Receiver struct {
	// contains filtered or unexported fields
}

Receiver represents the receiver party in the MPPJ protocol, for a given session. Its main method is JoinTables, which joins the converted encrypted tables from the helper.

func NewReceiver

func NewReceiver(sess *Session, sk SecretKey) *Receiver

NewReceiver creates a new receiver for the given session.

func (*Receiver) GetPK

func (r *Receiver) GetPK() PublicKey

GetPK returns the receiver's public key.

func (*Receiver) GetSK

func (r *Receiver) GetSK() SecretKey

GetSK returns the receiver's secret key.

func (*Receiver) JoinTables

func (r *Receiver) JoinTables(joinedTables EncTableWithHint) (JoinTable, error)

JoinTables extracts the intersection from the joined tables received from the helper.

func (*Receiver) JoinTablesStream

func (r *Receiver) JoinTablesStream(in chan EncRowWithHint, goroutines ...int) (JoinTable, error)

JoinTablesStream is the streaming version of [JoinTables]. It reads encrypted rows from the in channel, processes them, and returns the joined table when all the rows have been processed. It is optionally possible to specify the number of goroutines workers to use.

type SecretKey

type SecretKey struct {
	// contains filtered or unexported fields
}

type Session

type Session struct {
	ID         SessionID
	Sources    []PartyID
	Helper     PartyID
	Receiver   PartyID
	ReceiverPK PublicKey
}

func NewSession

func NewSession(sources []PartyID, helper, receiver PartyID, receiverPK PublicKey) (*Session, error)

type SessionID

type SessionID []byte

func NewSessionID

func NewSessionID(sources []PartyID, helper, receiver string) SessionID

NewSessionID generates a new session ID based on session participants and randomness.

type SourceList

type SourceList []PartyID

func (*SourceList) Set

func (s *SourceList) Set(value string) error

func (*SourceList) String

func (s *SourceList) String() string

type SymmetricCiphertext

type SymmetricCiphertext []byte

type TablePlain

type TablePlain map[string]string

TablePlain represents a plain table with UID as key and value as string. It is the protocol input type for data sources.

func GenTestTable

func GenTestTable(sourceId PartyID, nRows int, intersection []string) TablePlain

GenTestTable generates a test table for a given source ID with specified number of rows and intersection UIDs.

func NewTablePlain

func NewTablePlain(uids []string, values []string) TablePlain

NewTablePlain creates a new Table from a UID list and optional values.

func (*TablePlain) Equal

func (t1 *TablePlain) Equal(t2 *TablePlain) bool

Equal checks both the keys and the values for plain tables.

func (TablePlain) String

func (t TablePlain) String() string

String returns the plain table as a formatted string.

type TableRow

type TableRow struct {
	// contains filtered or unexported fields
}

TableRow represents a single row in a plain table.

Directories

Path Synopsis
api
pb
examples
csv command
local command
minimal command
Minimal, local example of using the MPPJ library to perform a private join among three parties.
Minimal, local example of using the MPPJ library to perform a private join among three parties.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL