Skip to content

Commit

Permalink
Merge pull request #15 from multiparty/ristretto
Browse files Browse the repository at this point in the history
Use ristretto255 with libsodium-wrappers-sumo instead of elliptic
  • Loading branch information
frederickjansen authored Mar 4, 2020
2 parents 6305e3c + 5cd8ebc commit 3738015
Show file tree
Hide file tree
Showing 47 changed files with 6,424 additions and 8,532 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ node_modules/
.npm
*.log
logs
dist/
lib/
coverage/
.nyc_output/
.DS_Store
.idea/
*.iml
build/
15 changes: 15 additions & 0 deletions .nycrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"nyc": {
"extension": [
".ts"
],
"include": [
"src/**.ts"
],
"exclude": [
"**/*.d.ts",
"**/*.js",
"**/*.spec.ts"
]
}
}
101 changes: 74 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,103 @@
[![Build Status](https://travis-ci.org/multiparty/oprf.svg?branch=master)](https://travis-ci.org/multiparty/oprf)
[![Coverage Status](https://coveralls.io/repos/github/multiparty/oprf/badge.svg?branch=master)](https://coveralls.io/github/multiparty/oprf?branch=master)

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

#### Oblivious pseudo-random function over an elliptic curve (Ristretto255)

## Installation
```npm install oprf```
For node.js, use:

```bash
npm install oprf
```

For the browser, include a script tag targeting either `dist/oprf.js` or `dist/oprf.slim.js`.

## Bundle vs slim

For browsers, we provide two built files: `dist/oprf.js` and `dist/oprf.slim.js`.

The first includes both OPRF bundled with [libsodium-wrappers-sumo](https://github.com/jedisct1/libsodium.js) version 0.7.6. The second includes only OPRF.

You can use the slim version for cases where your browser-side code uses a more recent version of libsodium, or if you want
to load libsodium asynchronously to reduce page load time.

The API for both versions is identical, except that the slim OPRF constructor expects a sodium instance to be passed in
as a parameter, while the bundled constructor does not expect any parameters.

In node.js, the slim OPRF is not exposed.

```javascript
const OPRF = require('oprf');
const oprf = new OPRF(); // will require('libsodium-wrappers-sumo');
```

## Initialization
The sumo version of libsodium must be used
OPRF is not safe to use until sodium is done loading.

```Typescript
await _sodium.ready;
const oprf = new OPRF(_sodium);
const oprf = new OPRF();
await oprf.ready; // wait for dependencies to load
```

## Security Guarantees
A client has input _x_ while a server holds key _k_. The client receives the output of *f<sub>k</sub>(x)* for some pseudorandom function family *f<sub>k</sub>*. The server learns nothing.


## Dependencies
* [elliptic](https://github.com/indutny/elliptic)
* [libsodium.js](https://github.com/jedisct1/libsodium.js)
The implementation uses [Ristretto255](https://libsodium.gitbook.io/doc/advanced/point-arithmetic/ristretto), and does not suffer from small cofactor attacks.

## Public Interface
Contains a masked point and the mask that was applied to it
```Typescript
export interface IMaskedData {
readonly point: number[];
readonly mask: BN; // big number
readonly point: Uint8Array;
readonly mask: Uint8Array;
}
```

## Public Functions

**hashToPoint**: maps string input to a point on the elliptic curve
```Typescript
public hashToPoint(input: string): number[]
public hashToPoint(input: string): Uint8Array
```

**isValidPoint**: returns whether the given point exists on the elliptic curve
```Typescript
public isValidPoint(point: Uint8Array): boolean
```

**maskInput**: hashes string input as a point on an elliptic curve and applies a random mask to it
```Typescript
public maskInput(input: string): IMaskedData
```
**generateRandomScalar**: generates a random 32-byte array of numbers

**maskPoint**: applies a random mask to an elliptic curve point
```Typescript
public generateRandomScalar(): BN
public maskPoint(point: Uint8Array): IMaskedData
```
**isValidPoint**: returns whether the given point exists on the elliptic curve

**unmaskInput**: applies the multiplicative inverse of the mask to the masked point
```Typescript
public isValidPoint(point: number[]): number
public unmaskPoint(maskedPoint: Uint8Array, mask: Uint8Array): Uint8Array
```
**encodePoint**: converts an elliptic.js point representation to number array representation

**generateRandomScalar**: generates a uniform random 32-byte number in [1, order of curve)
```Typescript
public encodePoint(point: any): number[]
public generateRandomScalar(): Uint8Array
```
**decodePoint**: converts a number array to elliptic.js point object representation

**scalarMult**: salts a point using a key as a scalar
```Typescript
public decodePoint(point: number[]): any
public scalarMult(point: Uint8Array, key: Uint8Array): Uint8Array
```
**unmaskInput**: applies the multiplicative inverse of the mask to the masked point

**encodePoint**: encodes a point representation to a string with either 'ASCII' or 'UTF-8' encoding
```Typescript
public unmaskInput(maskedPoint: number[], mask: BN): number[]
public encodePoint(point: Uint8Array, encoding: string): string
```

**decodePoint**: Decode elliptic curve point from a string
```Typescript
public decodePoint(code: string, encoding: string): Uint8Array
```

## OPRF Steps
Expand All @@ -69,22 +108,30 @@ public unmaskInput(maskedPoint: number[], mask: BN): 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.
// Send masked.point to server,
// Do not send masked.mask to the server.
send(oprf.encodePoint(masked.point, 'UTF-8'));
```

2.) **Server**: salt the masked point using a secret key
```Typescript
// 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();
// Note: your actual secret key should be fixed.
// Do not generate a new scalar for each OPRF
// application unless you have a specific use case for doing so.
const secretKey = oprf.generateRandomScalar();

const maskedPoint = oprf.decodePoint(receive(), 'UTF-8');
const salted = oprf.scalarMult(maskedPoint, secretKey);

// Send salted back to the client
send(oprf.encodePoint(salted, 'UTF-8'));
```

3.) **Client**: unmask the salted point from the server to get a high-entropy output
```Typescript
// Make sure that masked.mask corresponds to the original mask used.
// Otherwise, this will not give you the correct output.
// Otherwise, this will not give you the correct output.
const salted = oprf.decodePoint(receive(), 'UTF-8');
const unmasked = oprf.unmaskInput(salted, masked.mask);
```

Expand Down
1 change: 0 additions & 1 deletion dist-web/oprf.js

This file was deleted.

67 changes: 0 additions & 67 deletions dist-web/types/oprf.d.ts

This file was deleted.

22 changes: 0 additions & 22 deletions dist-web/types/tools.d.ts

This file was deleted.

8 changes: 8 additions & 0 deletions dist/oprf.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/oprf.slim.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3738015

Please sign in to comment.