Skip to content
This repository was archived by the owner on Jul 2, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
7f704bb
Add simple build script
antouhou Feb 2, 2019
4dab6f6
Add simple bindings
antouhou Feb 5, 2019
b340986
Changed WSIZE to 32 to make emscripten work (it's a 32-bit compiler);…
antouhou Feb 11, 2019
a7d6895
Add simple bindings for the Signature class
antouhou Feb 11, 2019
75e2832
Add a new helper to copy c++ vector<uin8_t> to js Buffer in order to …
antouhou Feb 12, 2019
74d4bc2
Add a new helper to copy c++ vector<uin8_t> to js Buffer in order to …
antouhou Feb 12, 2019
5912faa
Add bindings for the PublicKey and a test for the PrivateKey
antouhou Feb 12, 2019
1a7f6df
Add test for PublicKey
antouhou Feb 13, 2019
5e1fd99
Add aggregation methods for public and private keys
antouhou Feb 14, 2019
e9b66f6
Reformat code a bit
antouhou Feb 15, 2019
e07ab47
Add more helpers for bns, byte arrays and vectors; Add AggregationInf…
antouhou Feb 18, 2019
3fc79d6
Modify main cmake file to include specific emscripten instructions
antouhou Feb 18, 2019
6f5168d
Add some works on signature aggregation
antouhou Feb 18, 2019
e23ae74
Fixed cmake build for emscripten
antouhou Feb 19, 2019
3dcb61f
Make signature aggregation work
antouhou Feb 19, 2019
758716e
Reformat code
antouhou Feb 19, 2019
c149760
Reformat bindings
antouhou Feb 19, 2019
b4d97cb
Refactor helpers and wrappers
antouhou Feb 20, 2019
ef5d37d
Revert main cmake
antouhou Feb 20, 2019
70f9520
Add wrapper for extended private key
antouhou Feb 21, 2019
b5c696c
Add extended public key wrapper; Add extended private and public keys…
antouhou Feb 22, 2019
2366114
Add ChainCode wrapper and bindings
antouhou Feb 22, 2019
93e388b
Add initial typings
antouhou Feb 22, 2019
aa0ca9a
Add more ts typings; Add InsecureSignature wrapper and JS binding;
antouhou Feb 25, 2019
6c0a118
Refactored wrappers a bit
antouhou Feb 27, 2019
5fb2cc9
Add a base wrapper
antouhou Feb 27, 2019
2678b84
Add simple readme
antouhou Feb 27, 2019
b9c5960
Fix typos in readme
antouhou Feb 27, 2019
4596601
Add license to js bindings
antouhou Feb 28, 2019
5485a83
Make CMake copy js package files to the build dir; Make CMake to copy…
antouhou Feb 28, 2019
207c95e
Modify readme a bit
antouhou Feb 28, 2019
911c47c
Modify readme a bit
antouhou Feb 28, 2019
4824d74
Modify readme a bit
antouhou Feb 28, 2019
081c72a
Modify readme a bit
antouhou Feb 28, 2019
94a5ed2
Modify readme a bit
antouhou Feb 28, 2019
7d51e5e
Add repository to package.json
antouhou Feb 28, 2019
7c51949
Add some content to threshold wrapper; Port thershold signature test
antouhou Mar 1, 2019
d6e4978
Add test for Threshold
antouhou Mar 2, 2019
ead3927
Add tests for ExtendedPrivateKey, ExtendedPublicKey, ChainCode, add m…
antouhou Mar 4, 2019
d545bd4
Update name in package.json
antouhou Mar 4, 2019
9593c7d
Add bundling memfile to bindings; Fix bindings readme; Bumped patch v…
antouhou Mar 4, 2019
1e443d0
Reformat wrappers code
antouhou Mar 4, 2019
47a4537
Apply README grammar fixes
antouhou Mar 4, 2019
c7a6c2c
Make lib interface to interact with Uint8Array instead of Buffer; Cha…
antouhou Mar 5, 2019
088a788
Add information about deleting objects to README; Add .delete method …
antouhou Mar 6, 2019
bfba8fe
Add browser tests
antouhou Mar 8, 2019
ea3f79d
Mentioned firefox tests in Readme
antouhou Mar 8, 2019
bb2949b
Add simple test for typings
antouhou Mar 11, 2019
66ee882
Add tests for typings
antouhou Mar 16, 2019
4f8ae05
Add constants from bls classes
antouhou Mar 17, 2019
a6cb154
Add GROUP_ORDER constant
antouhou Mar 17, 2019
28a2499
Fix cpplint errors
antouhou Mar 17, 2019
88c1f42
Fix readme grammar
antouhou Mar 17, 2019
064ac45
Add bindings for DHKeyExchange
antouhou Mar 17, 2019
690ef87
Remove relic headers from helpers
antouhou Mar 20, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,15 @@ else()
set(ARITH "easy" CACHE STRING "")
endif()

if(EMSCRIPTEN)
# emscripten needs arch set to be none since it can't compile assembly
set(ARCH "" CACHE STRING "")
# emscripten is a 32 bit compiler
set(WSIZE 32 CACHE INTEGER "")
else()
set(WSIZE 64 CACHE INTEGER "")
endif()

set(WSIZE 64 CACHE INTEGER "")
set(TIMER "CYCLE" CACHE STRING "")
set(CHECK "off" CACHE STRING "")
set(VERBS "off" CACHE STRING "")
Expand Down Expand Up @@ -68,6 +75,12 @@ set(PP_EXT "LAZYR" CACHE STRING "")
set(PP_METHD "LAZYR;OATEP" CACHE STRING "")

add_subdirectory(contrib/relic)
add_subdirectory(contrib/pybind11)
add_subdirectory(src)
add_subdirectory(python-bindings)

if (EMSCRIPTEN)
add_subdirectory(js-bindings)
else()
# emscripten can't build python bindings, it produces only javascript
add_subdirectory(contrib/pybind11)
add_subdirectory(python-bindings)
endif()
39 changes: 39 additions & 0 deletions js-bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR)
set(CMAKE_CXX_STANDARD 11)

include_directories(
${INCLUDE_DIRECTORIES}
${CMAKE_CURRENT_SOURCE_DIR}/../contrib/relic/include
${CMAKE_BINARY_DIR}/contrib/relic/include
${CMAKE_CURRENT_SOURCE_DIR}/../contrib/catch
)

file(GLOB_RECURSE WRAP_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/wrappers/*.h)
file(GLOB_RECURSE WRAP_SRC ${CMAKE_CURRENT_SOURCE_DIR}/wrappers/*.cpp)

add_executable(blsjs ${CMAKE_CURRENT_SOURCE_DIR}/jsbindings.cpp
${WRAP_HEADERS} ${WRAP_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/helpers.h ${CMAKE_CURRENT_SOURCE_DIR}/helpers.cpp
)
add_custom_target(install_npm_dependencies npm ci)
add_dependencies(blsjs install_npm_dependencies)

if (SODIUM_FOUND)
target_link_libraries(blsjs PRIVATE blstmp relic_s sodium)
else ()
target_link_libraries(blsjs PRIVATE blstmp relic_s)
endif ()

# Copy necessary files for the npm package
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package.json package.json COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package-lock.json package-lock.json COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/blsjs.d.ts blsjs.d.ts COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/README.md README.md COPYONLY)

# Copy test files
file(GLOB JS_BINDINGS_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/tests/ ${CMAKE_CURRENT_SOURCE_DIR}/tests/*)
foreach(file ${JS_BINDINGS_TESTS})
message(FILE ${file})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/${file} tests/${file} COPYONLY)
endforeach()

set_target_properties(blsjs PROPERTIES LINK_FLAGS "--bind -s SINGLE_FILE=1 -s MODULARIZE_INSTANCE=1 -s BINARYEN_ASYNC_COMPILATION=0")
49 changes: 49 additions & 0 deletions js-bindings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## bls-signatures

JavaScript library that implements BLS signatures with aggregation as in [Boneh, Drijvers, Neven 2018](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html), using the relic toolkit for cryptographic primitives (pairings, EC, hashing).

This library is a JavaScript port of the [Chia Network's BLS lib](https://github.com/Chia-Network/bls-signatures). We also have typings, so you can use it with TypeScript too!

### Usage

```bash
npm i bls-signatures --save
```
```javascript
const { PrivateKey } = require('bls-signatures');
const privateKey = PrivateKey.fromSeed(Uint8Array.from([1,2,3]));
const sig = privateKey.sign(Uint8Array.from(Buffer.from("Hello world!")));
const isValidSignature = sig.verify();

if (isValidSignature) {
// Do stuff...
}

privateKey.delete();
sig.delete();
```

Please refer to the library's [typings](../../js-bindings/blsjs.d.ts) for detailed API information. Use cases can be found in the [original lib's readme](../../README.md).

__Important note on usage:__ Since this library is a WebAssembly port of the c++ library, JavaScript's automatic memory management isn't available. Please, delete all objects manually if they are not needed anymore by calling the delete method on them, as shown in the example above.

### Build

Building requires Node.js (with npm) and [Emscripten](https://emscripten.org/docs/getting_started/downloads.html) to be installed.
The build process is the same as for the c++ lib, with one additional step: pass the Emscripten toolchain file as an option to CMake.
From the project root directory, run:
```
git submodule update --init --recursive
mkdir js_build
cd js_build
cmake ../ -DCMAKE_TOOLCHAIN_FILE={path_to_your_emscripten_installation}/emsdk/emscripten/{version}/cmake/Modules/Platform/Emscripten.cmake
cmake --build . --
```

Run the build after any changes to the library, including readme and tests, as the library will be deployed from the build directory, and the build system copies all the files from the source dir.
### Run tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the browser compatibility like? We should add a note on that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will work in all browsers that support WASM, meaning Chrome, Firefox, Safari, Edge (Not IE, unfortunately). It is ~85% of currently existing devices: https://caniuse.com/#feat=wasm. Browsers support can be extended further by including asm.js build as well. asm.js has broader support among older browsers (it's supported by all major browsers since the middle of 2013, except Safari, which is WASM-only). I'm not sure what is the best way to include both builds at the same time in one package, so I've added only WASM build. WASM has wider adoption (because of Safari), and has about 10x faster execution times.

Tests are run in node.js and Firefox, therefore you need to install node.js and Firefox.
To run tests, build the library, then go to the `js_bindings` folder in the build directory and run
```bash
npm test
```
172 changes: 172 additions & 0 deletions js-bindings/blsjs.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
export class PrivateKey {
static PRIVATE_KEY_SIZE: number;

static fromSeed(seed: Uint8Array): PrivateKey;

static fromBytes(bytes: Uint8Array, modOrder: boolean): PrivateKey;

static aggregate(privateKeys: PrivateKey[], publicKeys: PublicKey[]): PrivateKey;

static aggregateInsecure(privateKeys: PrivateKey[]): PrivateKey;

getPublicKey(): PublicKey;

serialize(): Uint8Array;

sign(message: Uint8Array): Signature;

signInsecure(message: Uint8Array): InsecureSignature;

signPrehashed(messageHash: Uint8Array): Signature;

delete(): void;
}

export class InsecureSignature {
static SIGNATURE_SIZE: number;

static fromBytes(bytes: Uint8Array);

static aggregate(signatures: InsecureSignature[]): InsecureSignature;

verify(hashes: Uint8Array[], pubKeys: PublicKey[]): boolean;

divideBy(insecureSignatures: InsecureSignature[]): InsecureSignature;

serialize(): Uint8Array;

delete(): void;
}

export class Signature {
static SIGNATURE_SIZE: number;

static fromBytes(bytes: Uint8Array): Signature;

static fromBytesAndAggregationInfo(bytes: Uint8Array, aggregationInfo: AggregationInfo): Signature;

static aggregateSigs(signatures: Signature[]): Signature;

serialize(): Uint8Array;

verify(): boolean;

getAggregationInfo(): AggregationInfo;

setAggregationInfo(aggregationInfo: AggregationInfo): void;

delete(): void;
}

export class PublicKey {
static PUBLIC_KEY_SIZE: number;

static fromBytes(bytes: Uint8Array): PublicKey;

static aggregate(publicKeys: PublicKey[]): PublicKey;

static aggregateInsecure(publicKeys: PublicKey[]): PublicKey;

getFingerprint(): number;

serialize(): Uint8Array;

delete(): void;
}

export class AggregationInfo {
static fromMsgHash(publicKey: PublicKey, messageHash: Uint8Array): AggregationInfo;

static fromMsg(publicKey: PublicKey, message: Uint8Array): AggregationInfo;

static fromBuffers(pubKeys: PublicKey[], msgHashes: Uint8Array[], exponents: Uint8Array[]): AggregationInfo;

getPublicKeys(): PublicKey[];

getMessageHashes(): Uint8Array[];

getExponents(): Uint8Array[];

delete(): void;
}

export class ExtendedPrivateKey {
static EXTENDED_PRIVATE_KEY_SIZE: number;

static fromSeed(seed: Uint8Array): ExtendedPrivateKey;

static fromBytes(bytes: Uint8Array): ExtendedPrivateKey;

privateChild(index: number): ExtendedPrivateKey;

publicChild(index: number): ExtendedPublicKey;

getVersion(): number;

getDepth(): number;

getParentFingerprint(): number;

getChildNumber(): number;

getChainCode(): ChainCode;

getPrivateKey(): PrivateKey;

getPublicKey(): PublicKey;

getExtendedPublicKey(): ExtendedPublicKey;

serialize(): Uint8Array;

delete(): void;
}

export class ExtendedPublicKey {
static VERSION: number;
static EXTENDED_PUBLIC_KEY_SIZE: number;

static fromBytes(bytes: Uint8Array): ExtendedPublicKey;

publicChild(index: number): ExtendedPublicKey;

getVersion(): number;

getDepth(): number;

getParentFingerprint(): number;

getChildNumber(): number;

getPublicKey(): PublicKey;

getChainCode(): ChainCode;

serialize(): Uint8Array;

delete(): void;
}

export class ChainCode {
static CHAIN_CODE_SIZE: number;

static fromBytes(bytes: Uint8Array);

serialize(): Uint8Array;

delete(): void;
}

export namespace Threshold {
export function create(commitment: PublicKey[], secretFragments: PrivateKey[], threshold: number, playersCount: number): PrivateKey;

export function signWithCoefficient(sk: PrivateKey, message: Uint8Array, playerIndex: number, players: number[]): InsecureSignature;

export function aggregateUnitSigs(signatures: InsecureSignature[], message: Uint8Array, players: number[]): InsecureSignature;

export function verifySecretFragment(playerIndex: number, secretFragment: PrivateKey, commitment: PublicKey[], threshold: number): boolean;
}

export function DHKeyExchange(privateKey: PrivateKey, publicKey: PublicKey);

export const GROUP_ORDER: string;
90 changes: 90 additions & 0 deletions js-bindings/helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2018 Chia Network Inc

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "./helpers.h"

namespace helpers {
val toUint8Array(std::vector<uint8_t> vec) {
val arr = helpers::toJSArray<uint8_t>(vec);
return val::global("Uint8Array").call<val>("from", arr);
}

val toUint8Array(uint8_t *pointer, size_t data_size) {
std::vector<uint8_t> vec = toVector(pointer, data_size);
val buffer = toUint8Array(vec);
return buffer;
}

val toUint8Array(bn_t bn) {
std::vector<uint8_t> vec = toVector(bn);
val buffer = toUint8Array(vec);
return buffer;
}

std::vector<uint8_t> toVector(uint8_t *pointer, size_t data_size) {
std::vector<uint8_t> data;
data.reserve(data_size);
std::copy(pointer, pointer + data_size, std::back_inserter(data));
return data;
}

std::vector<uint8_t> toVector(val jsUint8Array) {
auto l = jsUint8Array["length"].as<unsigned>();
std::vector<uint8_t> vec;
for (unsigned i = 0; i < l; ++i) {
vec.push_back(jsUint8Array[i].as<uint8_t>());
}
return vec;
}

std::vector<uint8_t> toVector(bn_t bn) {
uint8_t buf[bn_size_bin(bn)];
bn_write_bin(buf, bn_size_bin(bn), bn);
std::vector<uint8_t> vec = helpers::toVector(buf, bn_size_bin(bn));
return vec;
}

std::vector<std::vector<uint8_t>> jsBuffersArrayToVector(val buffersArray) {
auto l = buffersArray["length"].as<unsigned>();
std::vector<std::vector<uint8_t>> vec;
for (unsigned i = 0; i < l; ++i) {
vec.push_back(toVector(buffersArray[i].as<val>()));
}
return vec;
}

std::vector<bn_t *> jsBuffersArrayToBnVector(val buffersArray) {
auto l = buffersArray["length"].as<unsigned>();
std::vector<bn_t *> vec;
for (unsigned i = 0; i < l; ++i) {
bn_t data;
bn_new(data);
std::vector<uint8_t> bnVec = toVector(buffersArray[i]);
bn_read_bin(data, bnVec.data(), static_cast<int>(bnVec.size()));
bn_t *point = &data;
vec.push_back(point);
}
return vec;
}

val byteArraysVectorToJsBuffersArray(std::vector<uint8_t *> arraysVector, size_t element_size) {
auto vecSize = arraysVector.size();
std::vector<val> valVector;
for (unsigned i = 0; i < vecSize; ++i) {
valVector.push_back(toUint8Array(arraysVector[i], element_size));
}
val arr = helpers::toJSArray<val>(valVector);
return arr;
}
} // namespace helpers
Loading