-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4e368ff
Showing
16 changed files
with
5,636 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
pull_request: | ||
|
||
jobs: | ||
test-native: | ||
runs-on: ${{matrix.os}} | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
os: [ubuntu-latest, macOS-latest] | ||
node-version: [14.x, 16.x, 18.x] | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
with: | ||
submodules: true | ||
- name: Set up Node.js ${{matrix.node-version}} | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: ${{matrix.node-version}} | ||
- name: Build | ||
run: npm install | ||
- name: Test | ||
run: npm test | ||
build-wasm: | ||
runs-on: ubuntu-latest | ||
env: | ||
NODE_VERSION: 18.x | ||
EMSDK_VERSION: 3.1.14 | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
with: | ||
submodules: true | ||
- name: Set up Node.js ${{env.NODE_VERSION}} | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: ${{env.NODE_VERSION}} | ||
- name: Set up Emscripten SDK ${{env.EMSDK_VERSION}} | ||
uses: mymindstorm/setup-emsdk@v11 | ||
with: | ||
version: ${{env.EMSDK_VERSION}} | ||
- name: Install dependencies | ||
run: npm install --ignore-scripts | ||
- name: Build WebAssembly module | ||
run: npm run build-wasm | ||
- name: Upload build output | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: wasm-gen | ||
path: | | ||
wasm/gen | ||
if-no-files-found: error | ||
test-wasm: | ||
needs: build-wasm | ||
runs-on: ${{matrix.os}} | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
os: [ubuntu-latest, macOS-latest, windows-latest] | ||
node-version: [14.x, 16.x, 18.x] | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
- name: Set up Node.js ${{matrix.node-version}} | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: ${{matrix.node-version}} | ||
- name: Install dependencies | ||
run: npm install --ignore-scripts | ||
- name: Download WebAssembly module | ||
uses: actions/download-artifact@v3 | ||
with: | ||
name: wasm-gen | ||
path: wasm/gen | ||
- name: Test | ||
run: npm test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
build/ | ||
node_modules/ | ||
package-lock.json | ||
wasm/gen/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "deps/PQClean"] | ||
path = deps/PQClean | ||
url = https://github.com/PQClean/PQClean.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
# PQClean bindings for Node.js | ||
|
||
This package provides Node.js bindings for [PQClean][], a collection of | ||
post-quantum cryptography algorithm implementations, including 46 key | ||
encapsulation mechanisms and 53 digital signature algorithms. | ||
|
||
## Installation | ||
|
||
```sh | ||
npm i pqclean | ||
``` | ||
|
||
During installation, node-pqclean will attempt to compile PQClean as a native | ||
addon for Node.js. If that fails, for example, because the operating system is | ||
unsupported, the package will continue with the installation, but only the | ||
WebAssembly backend will be available at runtime. | ||
|
||
## Example | ||
|
||
PQClean provides a consistent API for key encapsulation mechanisms. The Node.js | ||
bindings expose this through the `KEM` class. | ||
|
||
```javascript | ||
const PQClean = require('pqclean'); | ||
|
||
const mceliece = new PQClean.KEM('mceliece8192128'); | ||
const { publicKey, privateKey } = mceliece.keypair(); | ||
|
||
const { key, encryptedKey } = mceliece.generateKey(publicKey); | ||
console.log(`Bob is using the key ${key.toString('hex')}`); | ||
|
||
const receivedKey = mceliece.decryptKey(privateKey, encryptedKey); | ||
console.log(`Alice is using the key ${receivedKey.toString('hex')}`); | ||
``` | ||
|
||
Similarly, PQClean's digital signature API is exposed through the `Sign` class. | ||
|
||
```javascript | ||
const PQClean = require('pqclean'); | ||
|
||
const falcon = new PQClean.Sign('falcon-1024'); | ||
const { publicKey, privateKey } = falcon.keypair(); | ||
|
||
const message = Buffer.from('Hello world!'); | ||
const signature = falcon.sign(privateKey, message); | ||
|
||
const ok = falcon.verify(publicKey, message, signature); | ||
console.assert(ok, 'signature is valid'); | ||
``` | ||
|
||
## API | ||
|
||
The package exports two classes: `KEM` and `Sign`. | ||
|
||
### Class `KEM` | ||
|
||
The `KEM` class provides access to implementations of key encapsulation | ||
mechanisms. Public keys can be used to encapsulate a shared secret key and | ||
corresponding private keys can be used to recover the shared secret key. | ||
|
||
#### `new KEM(algorithm)` | ||
|
||
Creates a new instance using the specified algorithm. `algorithm` must be one of | ||
the values contained in `KEM.supportedAlgorithms`. | ||
|
||
#### `KEM.supportedAlgorithms` | ||
|
||
This static field is an array of all supported algorithm names. | ||
|
||
#### `instance.keySize` | ||
|
||
The (maximum) key size in bytes that this instance can encapsulate. | ||
|
||
#### `instance.encryptedKeySize` | ||
|
||
The size of the encapsulated key in bytes. | ||
|
||
#### `instance.publicKeySize` | ||
|
||
The size of the public key in bytes. | ||
|
||
#### `instance.privateKeySize` | ||
|
||
The size of the private key in bytes. | ||
|
||
#### `instance.keypair([callback])` | ||
|
||
Creates and returns a new key pair `{ publicKey, privateKey }`. Both keys will | ||
be returned as `Buffer`s. | ||
|
||
If `callback` is given, `keypair` immediately returns `undefined` and calls | ||
`callback(err, { publicKey, privateKey })` as soon as a new keypair has been | ||
generated. | ||
|
||
#### `instance.generateKey(publicKey[, callback])` | ||
|
||
Generates a new symmetric key and encrypts (encapsulates) it using the given | ||
`publicKey`. Returns `{ key, encryptedKey }`. Both objects will be `Buffer`s. | ||
|
||
If `callback` is given, `generateKey` immediately returns `undefined` and calls | ||
`callback(err, { key, encryptedKey })` as soon as the operation is completed. | ||
|
||
#### `instance.decryptKey(privateKey, encryptedKey[, callback])` | ||
|
||
Decrypts (decapsulates) the `encryptedKey` that was returned by | ||
`instance.generateKey(publicKey)` and returns the decrypted key as a `Buffer`. | ||
|
||
If `callback` is given, `decryptKey` immediately returns `undefined` and | ||
calls `callback(err, key)` as soon as the key has been decrypted. | ||
|
||
### Class `Sign` | ||
|
||
The `Sign` class provides access to implementations of digital signature | ||
algorithms. Private keys can be used to sign messages and the corresponding | ||
public keys can be used to verify the authenticity of digital signatures. | ||
|
||
#### `new Sign(algorithm)` | ||
|
||
Creates a new instance using the specified algorithm. `algorithm` must be one of | ||
the values contained in `Sign.supportedAlgorithms`. | ||
|
||
#### `Sign.supportedAlgorithms` | ||
|
||
This static field is an array of all supported algorithm names. | ||
|
||
#### `instance.signatureSize` | ||
|
||
The (maximum) signature size in bytes that this instance produces. | ||
|
||
#### `instance.publicKeySize` | ||
|
||
The size of the public key in bytes. | ||
|
||
#### `instance.privateKeySize` | ||
|
||
The size of the private key in bytes. | ||
|
||
#### `instance.keypair([callback])` | ||
|
||
Creates and returns a new key pair `{ publicKey, privateKey }`. Both keys will | ||
be returned as `Buffer`s. | ||
|
||
If `callback` is given, `keypair` immediately returns `undefined` and calls | ||
`callback(err, { publicKey, privateKey })` when the requested keypair has been | ||
generated. | ||
|
||
#### `instance.sign(privateKey, message[, callback])` | ||
|
||
Signs the given `message` using the given `privateKey` and returns the signature | ||
as a `Buffer`. | ||
|
||
If `callback` is given, `sign` immediately returns `undefined` and calls | ||
`callback(err, signature)` when the operation is completed. | ||
|
||
#### `instance.verify(publicKey, message, signature[, callback])` | ||
|
||
Verifies the given `signature` for the given `message` using the given | ||
`publicKey`. Returns `true` if verification succeeds, `false` otherwise. | ||
|
||
If `callback` is given, `verify` immediately returns `undefined` and | ||
calls `callback(err, result)` when the verification result is available. | ||
|
||
## License | ||
|
||
This project is distributed under the ISC license. Please check | ||
[deps/PQClean](deps) for licenses that apply to individual algorithm | ||
implementations. | ||
|
||
[PQClean]: https://github.com/PQClean/PQClean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"targets": [ | ||
{ | ||
"target_name": "node_pqclean", | ||
"sources": ["native/node_pqclean.cc"], | ||
"include_dirs": [ | ||
"<!@(node -p \"require('node-addon-api').include\")", | ||
"<(module_root_dir)/deps/PQClean" | ||
], | ||
"dependencies": [ | ||
"<!(node -p \"require('node-addon-api').gyp\")", | ||
"<(module_root_dir)/native/gen/binding.gyp:pqclean" | ||
], | ||
"defines": [ | ||
"NAPI_DISABLE_CPP_EXCEPTIONS", | ||
"NODE_ADDON_API_DISABLE_DEPRECATED" | ||
] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
'use strict'; | ||
|
||
let KEM, Sign; | ||
try { | ||
// Try to load native bindings first. | ||
({ KEM, Sign } = require('bindings')('node_pqclean')); | ||
} catch (err) { | ||
// If native bindings are not available, use WebAssembly instead. | ||
({ KEM, Sign } = require('./wasm/')); | ||
process.emitWarning(`Using WebAssembly backend: ${err.message}`); | ||
} | ||
|
||
Object.freeze(KEM.supportedAlgorithms); | ||
Object.freeze(Sign.supportedAlgorithms); | ||
|
||
Object.defineProperties(module.exports, { | ||
KEM: { value: KEM }, | ||
Sign: { value: Sign } | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#ifndef NATIVE_ALGORITHM_H | ||
#define NATIVE_ALGORITHM_H | ||
|
||
#include <string> | ||
|
||
namespace pqclean { | ||
namespace kem { | ||
|
||
typedef int (*keypair_fn)(unsigned char* pk, unsigned char* sk); | ||
|
||
typedef int (*enc_fn)(unsigned char* ct, unsigned char* k, | ||
const unsigned char* pk); | ||
|
||
typedef int (*dec_fn)(unsigned char* k, const unsigned char* ct, | ||
const unsigned char* sk); | ||
|
||
struct Algorithm { | ||
std::string id; | ||
std::string description; | ||
size_t publicKeySize; | ||
size_t privateKeySize; | ||
size_t ciphertextSize; | ||
size_t keySize; | ||
keypair_fn keypair; | ||
enc_fn enc; | ||
dec_fn dec; | ||
}; | ||
|
||
} // namespace kem | ||
|
||
namespace sign { | ||
|
||
typedef int (*keypair_fn)(unsigned char* pk, unsigned char* sk); | ||
|
||
typedef int (*signature_fn)(uint8_t* sig, size_t* siglen, | ||
const uint8_t* m, size_t mlen, | ||
const uint8_t* sk); | ||
|
||
typedef int (*verify_fn)(const uint8_t* sig, size_t siglen, | ||
const uint8_t* m, size_t mlen, | ||
const uint8_t* pk); | ||
|
||
struct Algorithm { | ||
std::string id; | ||
std::string description; | ||
size_t publicKeySize; | ||
size_t privateKeySize; | ||
size_t signatureSize; | ||
size_t seedSize; | ||
keypair_fn keypair; | ||
signature_fn signature; | ||
verify_fn verify; | ||
}; | ||
|
||
} // namespace sign | ||
} // namespace pqclean | ||
|
||
#endif // NATIVE_ALGORITHM_H |
Oops, something went wrong.