Skip to content
Oblivious pseudorandom function over an elliptic curve
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


npm version Build Status Coverage Status

Oblivious pseudo-random function over an elliptic curve (ED25519)


npm install oprf


The sumo version of libsodium must be used

await _sodium.ready;
const oprf = new OPRF(_sodium);

Security Guarantees

A client has input x while a server holds key k. The client receives the output of fk(x) for some pseudorandom function family fk. The server learns nothing.


Public Interface

Contains a masked point and the mask that was applied to it

export interface IMaskedData {
  readonly point: number[];
  readonly mask: BN; // big number

Public Functions

hashToPoint: maps string input to a point on the elliptic curve

public hashToPoint(input: string): number[]

maskInput: hashes string input as a point on an elliptic curve and applies a random mask to it

public maskInput(input: string): IMaskedData

generateRandomScalar: generates a random 32-byte array of numbers

public generateRandomScalar(): BN

isValidPoint: returns whether the given point exists on the elliptic curve

public isValidPoint(point: number[]): number

encodePoint: converts an elliptic.js point representation to number array representation

public encodePoint(point: any): number[]

decodePoint: converts a number array to elliptic.js point object representation

public decodePoint(point: number[]): any 

unmaskInput: applies the multiplicative inverse of the mask to the masked point

public unmaskInput(maskedPoint: number[], mask: BN): number[]

OPRF Steps

1.) Client: hash input and mask it using a randomly generated 32-byte number

const input = 'hello world';
const masked = oprf.maskInput(input);

// Send masked.point to server. Do not send masked.mask to the server since it can easily unmask your original input.

2.) Server: salt the masked point using a secret key

// Note: your actual secret key should be a static 32-byte Uint8Array. Do not generate a new scalar for each OPRF unless you have a specific use case for doing so.
const secretKey = oprf.generateRandomScalar(); 
const salted = oprf.scalarMult(maskedPoint, secretKey);

// Send salted back to the client

3.) Client: unmask the salted point from the server to get a high-entropy output

// Make sure that masked.mask corresponds to the original mask used. 
// Otherwise, this will not give you the correct output. 
const unmasked = oprf.unmaskInput(salted, masked.mask);

Implementation inspired by Burns et. al.

You can’t perform that action at this time.