# tweetnacl

## TweetNaCl.js

Port of [TweetNaCl](http://tweetnacl.cr.yp.to) / [NaCl](http://nacl.cr.yp.to/) to JavaScript for modern browsers and Node.js. Public domain.

[![Build Status](https://travis-ci.org/dchest/tweetnacl-js.svg?branch=master)](https://travis-ci.org/dchest/tweetnacl-js)

Demo: <https://tweetnacl.js.org>

:warning: **The library is stable and API is frozen, however it has not been independently reviewed. If you can help reviewing it, please** [**contact me**](mailto:dmitry@codingrobots.com)**.**

## Documentation

* [Overview](#overview)
* [Installation](#installation)
* [Usage](#usage)
  * [Public-key authenticated encryption (box)](#public-key-authenticated-encryption-box)
  * [Secret-key authenticated encryption (secretbox)](#secret-key-authenticated-encryption-secretbox)
  * [Scalar multiplication](#scalar-multiplication)
  * [Signatures](#signatures)
  * [Hashing](#hashing)
  * [Random bytes generation](#random-bytes-generation)
  * [Constant-time comparison](#constant-time-comparison)
* [System requirements](#system-requirements)
* [Development and testing](#development-and-testing)
* [Benchmarks](#benchmarks)
* [Contributors](#contributors)
* [Who uses it](#who-uses-it)

### Overview

The primary goal of this project is to produce a translation of TweetNaCl to JavaScript which is as close as possible to the original C implementation, plus a thin layer of idiomatic high-level API on top of it.

There are two versions, you can use either of them:

* `nacl.js` is the port of TweetNaCl with minimum differences from the original + high-level API.
* `nacl-fast.js` is like `nacl.js`, but with some functions replaced with faster versions.

### Installation

You can install TweetNaCl.js via a package manager:

[Bower](http://bower.io):

```
$ bower install tweetnacl
```

[NPM](https://www.npmjs.org/):

```
$ npm install tweetnacl
```

or [download source code](https://github.com/dchest/tweetnacl-js/releases).

### Usage

All API functions accept and return bytes as `Uint8Array`s. If you need to encode or decode strings, use functions from <https://github.com/dchest/tweetnacl-util-js> or one of the more robust codec packages.

In Node.js v4 and later `Buffer` objects are backed by `Uint8Array`s, so you can freely pass them to TweetNaCl.js functions as arguments. The returned objects are still `Uint8Array`s, so if you need `Buffer`s, you'll have to convert them manually; make sure to convert using copying: `new Buffer(array)`, instead of sharing: `new Buffer(array.buffer)`, because some functions return subarrays of their buffers.

#### Public-key authenticated encryption (box)

Implements *curve25519-xsalsa20-poly1305*.

**nacl.box.keyPair()**

Generates a new random key pair for box and returns it as an object with `publicKey` and `secretKey` members:

```
{
   publicKey: ...,  // Uint8Array with 32-byte public key
   secretKey: ...   // Uint8Array with 32-byte secret key
}
```

**nacl.box.keyPair.fromSecretKey(secretKey)**

Returns a key pair for box with public key corresponding to the given secret key.

**nacl.box(message, nonce, theirPublicKey, mySecretKey)**

Encrypt and authenticates message using peer's public key, our secret key, and the given nonce, which must be unique for each distinct message for a key pair.

Returns an encrypted and authenticated message, which is `nacl.box.overheadLength` longer than the original message.

**nacl.box.open(box, nonce, theirPublicKey, mySecretKey)**

Authenticates and decrypts the given box with peer's public key, our secret key, and the given nonce.

Returns the original message, or `false` if authentication fails.

**nacl.box.before(theirPublicKey, mySecretKey)**

Returns a precomputed shared key which can be used in `nacl.box.after` and `nacl.box.open.after`.

**nacl.box.after(message, nonce, sharedKey)**

Same as `nacl.box`, but uses a shared key precomputed with `nacl.box.before`.

**nacl.box.open.after(box, nonce, sharedKey)**

Same as `nacl.box.open`, but uses a shared key precomputed with `nacl.box.before`.

**nacl.box.publicKeyLength = 32**

Length of public key in bytes.

**nacl.box.secretKeyLength = 32**

Length of secret key in bytes.

**nacl.box.sharedKeyLength = 32**

Length of precomputed shared key in bytes.

**nacl.box.nonceLength = 24**

Length of nonce in bytes.

**nacl.box.overheadLength = 16**

Length of overhead added to box compared to original message.

#### Secret-key authenticated encryption (secretbox)

Implements *xsalsa20-poly1305*.

**nacl.secretbox(message, nonce, key)**

Encrypt and authenticates message using the key and the nonce. The nonce must be unique for each distinct message for this key.

Returns an encrypted and authenticated message, which is `nacl.secretbox.overheadLength` longer than the original message.

**nacl.secretbox.open(box, nonce, key)**

Authenticates and decrypts the given secret box using the key and the nonce.

Returns the original message, or `false` if authentication fails.

**nacl.secretbox.keyLength = 32**

Length of key in bytes.

**nacl.secretbox.nonceLength = 24**

Length of nonce in bytes.

**nacl.secretbox.overheadLength = 16**

Length of overhead added to secret box compared to original message.

#### Scalar multiplication

Implements *curve25519*.

**nacl.scalarMult(n, p)**

Multiplies an integer `n` by a group element `p` and returns the resulting group element.

**nacl.scalarMult.base(n)**

Multiplies an integer `n` by a standard group element and returns the resulting group element.

**nacl.scalarMult.scalarLength = 32**

Length of scalar in bytes.

**nacl.scalarMult.groupElementLength = 32**

Length of group element in bytes.

#### Signatures

Implements [ed25519](http://ed25519.cr.yp.to).

**nacl.sign.keyPair()**

Generates new random key pair for signing and returns it as an object with `publicKey` and `secretKey` members:

```
{
   publicKey: ...,  // Uint8Array with 32-byte public key
   secretKey: ...   // Uint8Array with 64-byte secret key
}
```

**nacl.sign.keyPair.fromSecretKey(secretKey)**

Returns a signing key pair with public key corresponding to the given 64-byte secret key. The secret key must have been generated by `nacl.sign.keyPair` or `nacl.sign.keyPair.fromSeed`.

**nacl.sign.keyPair.fromSeed(seed)**

Returns a new signing key pair generated deterministically from a 32-byte seed. The seed must contain enough entropy to be secure. This method is not recommended for general use: instead, use `nacl.sign.keyPair` to generate a new key pair from a random seed.

**nacl.sign(message, secretKey)**

Signs the message using the secret key and returns a signed message.

**nacl.sign.open(signedMessage, publicKey)**

Verifies the signed message and returns the message without signature.

Returns `null` if verification failed.

**nacl.sign.detached(message, secretKey)**

Signs the message using the secret key and returns a signature.

**nacl.sign.detached.verify(message, signature, publicKey)**

Verifies the signature for the message and returns `true` if verification succeeded or `false` if it failed.

**nacl.sign.publicKeyLength = 32**

Length of signing public key in bytes.

**nacl.sign.secretKeyLength = 64**

Length of signing secret key in bytes.

**nacl.sign.seedLength = 32**

Length of seed for `nacl.sign.keyPair.fromSeed` in bytes.

**nacl.sign.signatureLength = 64**

Length of signature in bytes.

#### Hashing

Implements *SHA-512*.

**nacl.hash(message)**

Returns SHA-512 hash of the message.

**nacl.hash.hashLength = 64**

Length of hash in bytes.

#### Random bytes generation

**nacl.randomBytes(length)**

Returns a `Uint8Array` of the given length containing random bytes of cryptographic quality.

**Implementation note**

TweetNaCl.js uses the following methods to generate random bytes, depending on the platform it runs on:

* `window.crypto.getRandomValues` (WebCrypto standard)
* `window.msCrypto.getRandomValues` (Internet Explorer 11)
* `crypto.randomBytes` (Node.js)

If the platform doesn't provide a suitable PRNG, the following functions, which require random numbers, will throw exception:

* `nacl.randomBytes`
* `nacl.box.keyPair`
* `nacl.sign.keyPair`

Other functions are deterministic and will continue working.

If a platform you are targeting doesn't implement secure random number generator, but you somehow have a cryptographically-strong source of entropy (not `Math.random`!), and you know what you are doing, you can plug it into TweetNaCl.js like this:

```
nacl.setPRNG(function(x, n) {
  // ... copy n random bytes into x ...
});
```

Note that `nacl.setPRNG` *completely replaces* internal random byte generator with the one provided.

#### Constant-time comparison

**nacl.verify(x, y)**

Compares `x` and `y` in constant time and returns `true` if their lengths are non-zero and equal, and their contents are equal.

Returns `false` if either of the arguments has zero length, or arguments have different lengths, or their contents differ.

### System requirements

TweetNaCl.js supports modern browsers that have a cryptographically secure pseudorandom number generator and typed arrays, including the latest versions of:

* Chrome
* Firefox
* Safari (Mac, iOS)
* Internet Explorer 11

Other systems:

* Node.js

### Development and testing

Install NPM modules needed for development:

```
$ npm install
```

To build minified versions:

```
$ npm run build
```

Tests use minified version, so make sure to rebuild it every time you change `nacl.js` or `nacl-fast.js`.

#### Testing

To run tests in Node.js:

```
$ npm run test-node
```

By default all tests described here work on `nacl.min.js`. To test other versions, set environment variable `NACL_SRC` to the file name you want to test. For example, the following command will test fast minified version:

```
$ NACL_SRC=nacl-fast.min.js npm run test-node
```

To run full suite of tests in Node.js, including comparing outputs of JavaScript port to outputs of the original C version:

```
$ npm run test-node-all
```

To prepare tests for browsers:

```
$ npm run build-test-browser
```

and then open `test/browser/test.html` (or `test/browser/test-fast.html`) to run them.

To run headless browser tests with `tape-run` (powered by Electron):

```
$ npm run test-browser
```

(If you get `Error: spawn ENOENT`, install *xvfb*: `sudo apt-get install xvfb`.)

To run tests in both Node and Electron:

```
$ npm test
```

#### Benchmarking

To run benchmarks in Node.js:

```
$ npm run bench
$ NACL_SRC=nacl-fast.min.js npm run bench
```

To run benchmarks in a browser, open `test/benchmark/bench.html` (or `test/benchmark/bench-fast.html`).

### Benchmarks

For reference, here are benchmarks from MacBook Pro (Retina, 13-inch, Mid 2014) laptop with 2.6 GHz Intel Core i5 CPU (Intel) in Chrome 53/OS X and Xiaomi Redmi Note 3 smartphone with 1.8 GHz Qualcomm Snapdragon 650 64-bit CPU (ARM) in Chrome 52/Android:

|              | nacl.js Intel | nacl-fast.js Intel | nacl.js ARM | nacl-fast.js ARM |
| ------------ | :-----------: | :----------------: | :---------: | :--------------: |
| salsa20      |    1.3 MB/s   |      128 MB/s      |   0.4 MB/s  |      43 MB/s     |
| poly1305     |    13 MB/s    |      171 MB/s      |    4 MB/s   |      52 MB/s     |
| hash         |     4 MB/s    |       34 MB/s      |   0.9 MB/s  |      12 MB/s     |
| secretbox 1K |   1113 op/s   |     57583 op/s     |   334 op/s  |    14227 op/s    |
| box 1K       |    145 op/s   |      718 op/s      |   37 op/s   |     368 op/s     |
| scalarMult   |    171 op/s   |      733 op/s      |   56 op/s   |     380 op/s     |
| sign         |    77 op/s    |      200 op/s      |   20 op/s   |      61 op/s     |
| sign.open    |    39 op/s    |      102 op/s      |   11 op/s   |      31 op/s     |

(You can run benchmarks on your devices by clicking on the links at the bottom of the [home page](https://tweetnacl.js.org)).

In short, with *nacl-fast.js* and 1024-byte messages you can expect to encrypt and authenticate more than 57000 messages per second on a typical laptop or more than 14000 messages per second on a $170 smartphone, sign about 200 and verify 100 messages per second on a laptop or 60 and 30 messages per second on a smartphone, per CPU core (with Web Workers you can do these operations in parallel), which is good enough for most applications.

### Contributors

See AUTHORS.md file.

### Third-party libraries based on TweetNaCl.js

* [forward-secrecy](https://github.com/alax/forward-secrecy) — Axolotl ratchet implementation
* [nacl-stream](https://github.com/dchest/nacl-stream-js) - streaming encryption
* [tweetnacl-auth-js](https://github.com/dchest/tweetnacl-auth-js) — implementation of [`crypto_auth`](http://nacl.cr.yp.to/auth.html)
* [chloride](https://github.com/dominictarr/chloride) - unified API for various NaCl modules

### Who uses it

Some notable users of TweetNaCl.js:

* [miniLock](http://minilock.io/)
* [Stellar](https://www.stellar.org/)
