Skip to content

Commit

Permalink
Run test & build CI (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kus authored May 14, 2024
1 parent 1cb44c5 commit 201fe18
Show file tree
Hide file tree
Showing 16 changed files with 1,536 additions and 160 deletions.
111 changes: 0 additions & 111 deletions .circleci/config.yml

This file was deleted.

4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
target/
keypair
.env
solidity/cache
56 changes: 56 additions & 0 deletions .github/workflows/packages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Packages

on:
push:
branches:
- 'master'
tags:
- '*.*.*'
pull_request:
branches:
- 'master'

jobs:
build:
name: Build and push docker images to ghcr.io
runs-on: ubuntu-latest
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
DOCKER_REGISTRY: ghcr.io
DOCKER_IMAGE_BASE: ${{ github.repository_owner }}
outputs:
operator: ${{ steps.meta-tezos-operator.outputs.tags }}
steps:
- name: Check out the repo
uses: actions/checkout@v2

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1

- name: Log in to the registry
uses: docker/login-action@v1
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set image tags & labels
id: meta
uses: docker/metadata-action@v3
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_BASE }}/dkg-cli

- name: Image build & push
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm64,
file: crates/dkg-cli/Dockerfile
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
33 changes: 33 additions & 0 deletions .github/workflows/releases.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Releases

on:
push:
tags:
- '*.*'

jobs:
build:
name: Build and publish static binaries
runs-on: ubuntu-latest

strategy:
matrix:
target: [x86_64-unknown-linux-gnu]

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true

- name: Build
run: RUSTFLAGS="-C target-feature=-crt-static" NO_SOLC_BUILD=1 cargo build --release --target=${{ matrix.target }}

- name: Release
uses: softprops/action-gh-release@v2
with:
files: target/release/dkg-cli
29 changes: 29 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Tests

on:
pull_request:
push:
branches:
- 'master'

jobs:
test:
name: Check formatting and run unit tests
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy

- name: Check formatting
run: cargo fmt --check

- name: Run tests
run: NO_SOLC_BUILD=1 cargo test
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@ react-native

solidity/cache
solidity/build
solidity/artifacts
*.swp
*.bin
.DS_Store
*.json
crates/dkg-cli/src/dkg_contract.rs

keypair
dkg-output
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ run:

start:
./target/release/dkg-cli start -n $(NODE_URL) -p $(PRIVATE_KEY) -c $(CONTRACT_ADDRESS)

image:
docker build -t dkg-cli -f crates/dkg-cli/Dockerfile .
56 changes: 25 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,44 @@
<h1 align="center">Threshold BLS Signatures and DKG</h1>
# DKG tooling

Fork of the Celo [project](https://github.com/celo-org/celo-threshold-bls-rs).
This is a fork of the Celo's [threshold-bls](https://github.com/celo-org/celo-threshold-bls-rs) project.

## Overview

This crate provides libraries and command line interfaces for producing threshold BLS signatures. The signatures can also be [blind](https://en.wikipedia.org/wiki/Blind_signature) in order to preserve the privacy of the user asking for a signature from another set of parties.
This project provides tooling for running an interactive distributed key generation protocol.
All participants (administrator and key holders) use a command line app to participate in the protocol, and all the communication is hapenning through a smart contract.

Distributed Key Generation for generating the threshold public key is based on [Secure Distributed Key Generation for Discrete-Log Based Cryptosystems
](https://link.springer.com/article/10.1007/s00145-006-0347-3)

## Build Guide

Build with `cargo build (--release)`.
In the beginning of the DKG procedure:
- The list of account addresses belonging to key holders is publicly known
- There is a designated administrator that deploys and initialized the contract

Test with `cargo test`.

All crates require Rust 2021 edition and are tested on the following channels:
- `1.64.0`
In the result of the DKG procedure:
- All key holders have their secret key share locally
- Individual public key shares and master public key are available publicly

If you do not have Rust installed, run: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`
This project implements the JF-DKG scheme described in [Secure Distributed Key Generation for Discrete-Log Based Cryptosystems
](https://link.springer.com/article/10.1007/s00145-006-0347-3)

## Android and iOS
## Install

The library compiles to Android and iOS. This has been tested with Rust v1.64.0.
Get latest binaries from the [releases](https://github.com/trilitech/dkg-tooling/releases) page.

To compile to Android:
Alternatively use Docker images:
```
docker run ghcr.io/trilitech/dkg-cli:$RELEASE_TAG -h
```

1. Download Android NDK r21 and unzip it
2. Set the `NDK_HOME` env var to the extracted directory
3. `cd cross`
4. `./create-ndk-standalone`
5. `make android`
## Use

To compile to ios:
3. `cd cross`
4. `make ios`
Check out the [instructions](crates/dkg-cli).

## Directory Structure
## Build from sources

This repository contains several Rust crates that implement the different building blocks of the MPC. The high-level structure of the repository is as follows:
Build with `NO_SOLC_BUILD=1 cargo build --release`.

- [`dkg-cli`](crates/dkg-cli): Rust crate that provides a CLI for the distributed key generation
- [`dkg-core`](crates/dkg-core): Rust crate that provides the implementation utilities for the DKG
- [`threshold-bls`](crates/threshold-bls): (blind) threshold BLS signatures for BLS12-381 and BLS12-377
- [`threshold-bls-ffi`](crates/threshold-bls-ffi): FFI and WASM bindings to `threshold-bls` for cross platform interoperability
All crates require Rust 2021 edition and are tested on the following channels:
- `1.76.0`

If you do not have Rust installed, run: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`

## Disclaimers

Expand Down
19 changes: 8 additions & 11 deletions crates/dkg-cli/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
FROM cimg/rust:1.65.0

ENV HOME=/home/circleci
ENV PATH=$HOME/bin:$PATH

RUN cd $HOME && git clone https://github.com/m-kus/threshold-bls-rs
RUN mkdir $HOME/bin && wget -q https://github.com/ethereum/solidity/releases/download/v0.6.6/solc-static-linux -O $HOME/bin/solc && chmod u+x $HOME/bin/solc && solc --version
RUN cd $HOME && cd threshold-bls-rs/crates/dkg-cli && RUSTFLAGS="-C target-feature=-crt-static" cargo build --release
FROM rust:1.76
WORKDIR /root
COPY . /root/dkg-tooling/
#RUN git clone https://github.com/trilitech/dkg-tooling
RUN cd $HOME/dkg-tooling/crates/dkg-cli \
&& RUSTFLAGS="-C target-feature=-crt-static" NO_SOLC_BUILD=1 cargo build --release

FROM ubuntu:22.04
COPY --from=0 /home/circleci/threshold-bls-rs/target/release/dkg-cli /dkgbin
WORKDIR /dkg
ENTRYPOINT [ "/dkgbin" ]
COPY --from=0 /root/dkg-tooling/target/release/dkg-cli /usr/bin/
ENTRYPOINT [ "dkg-cli" ]
1 change: 0 additions & 1 deletion crates/dkg-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ in the [Solidity docs](https://solidity.readthedocs.io/en/latest/installing-soli


Install the DKG CLI with `cargo build --release`.
We will use the Alfajores testnet for this example, which you can access by using `https://alfajores-forno.celo-testnet.org` as a `NODE_URL`. You can fund your account by inserting your `address` to the [Alfajores faucet](https://celo.org/developers/faucet).

1. `dkg-cli keygen --path ./keypair`

Expand Down
1 change: 1 addition & 0 deletions crates/dkg-cli/artifacts/dkg.bin

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions crates/dkg-cli/artifacts/dkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"language":"Solidity","sources":{"contracts/DKG.sol":{"content":"// Using the ABIEncoderV2 poses little risk here because we only use it for fetching the byte arrays\n// of shares/responses/justifications\npragma experimental ABIEncoderV2;\npragma solidity ^0.8;\n\ncontract DKG {\n enum UserState {\n CannotRegister,\n CanRegister,\n Registered\n }\n\n /// Mapping of Ethereum Address => UserState for the actions a user can do\n mapping(address => UserState) public userState;\n\n /// Mapping of Ethereum Address => BLS public keys\n mapping(address => bytes) public keys;\n\n /// Mapping of Ethereum Address => DKG Phase 1 Shares\n mapping(address => bytes) public shares;\n\n /// Mapping of Ethereum Address => DKG Phase 2 Responses\n mapping(address => bytes) public responses;\n\n /// Mapping of Ethereum Address => DKG Phase 3 Justifications\n mapping(address => bytes) public justifications;\n\n /// List of registered Ethereum keys (used for conveniently fetching data)\n address[] public participants;\n\n /// The duration of each phase\n uint256 public immutable PHASE_DURATION;\n\n /// The threshold of the DKG\n uint256 public immutable THRESHOLD;\n\n /// If it's 0 then the DKG is still pending start. If >0, it is the DKG's start block\n uint256 public startBlock = 0;\n\n /// The owner of the DKG is the address which can call the `start` function\n address public owner;\n\n /// A registered participant is one whose pubkey's length > 0\n modifier onlyRegistered() {\n require(userState[msg.sender] == UserState.Registered, \"you are not registered!\");\n _;\n }\n\n /// The DKG starts when startBlock > 0\n modifier onlyWhenNotStarted() {\n require(startBlock == 0, \"DKG has already started\");\n _;\n }\n\n constructor(uint256 threshold, uint256 duration) public {\n PHASE_DURATION = duration;\n THRESHOLD = threshold;\n owner = msg.sender;\n }\n\n /// Kickoff function which starts the counter\n function start() external onlyWhenNotStarted {\n require(msg.sender == owner, \"only owner may start the DKG\");\n startBlock = block.number;\n }\n\n /// The administrator must allowlist an addrss for participation in the DKG\n function allowlist(address user) external onlyWhenNotStarted {\n require(msg.sender == owner, \"only owner may allowlist users\");\n\n require(userState[user] == UserState.CannotRegister, \"user is already allowlisted\");\n userState[user] = UserState.CanRegister;\n }\n\n /// This function ties a DKG participant's on-chain address with their BLS Public Key\n function register(bytes calldata blsPublicKey) external onlyWhenNotStarted {\n require(userState[msg.sender] == UserState.CanRegister, \"user is not allowlisted or has already registered\");\n\n participants.push(msg.sender);\n keys[msg.sender] = blsPublicKey;\n\n // the user is now registered\n userState[msg.sender] = UserState.Registered;\n }\n\n /// Participant publishes their data and depending on the phase the data gets inserted\n /// in the shares, responses or justifications mapping. Reverts if the participant\n /// has already published their data for a phase or if the DKG has ended.\n function publish(bytes calldata value) external onlyRegistered {\n uint256 blocksSinceStart = block.number - startBlock;\n\n if (blocksSinceStart <= PHASE_DURATION) {\n require(\n shares[msg.sender].length == 0,\n \"you have already published your shares\"\n );\n shares[msg.sender] = value;\n } else if (blocksSinceStart <= 2 * PHASE_DURATION) {\n require(\n responses[msg.sender].length == 0,\n \"you have already published your responses\"\n );\n responses[msg.sender] = value;\n } else if (blocksSinceStart <= 3 * PHASE_DURATION) {\n require(\n justifications[msg.sender].length == 0,\n \"you have already published your justifications\"\n );\n justifications[msg.sender] = value;\n } else {\n revert(\"DKG has ended\");\n }\n }\n\n // Helpers to fetch data in the mappings. If a participant has registered but not\n // published their data for a phase, the array element at their index is expected to be 0\n\n /// Gets the participants' shares\n function getShares() external view returns (bytes[] memory) {\n bytes[] memory _shares = new bytes[](participants.length);\n for (uint256 i = 0; i < participants.length; i++) {\n _shares[i] = shares[participants[i]];\n }\n\n return _shares;\n }\n\n /// Gets the participants' responses\n function getResponses() external view returns (bytes[] memory) {\n bytes[] memory _responses = new bytes[](participants.length);\n for (uint256 i = 0; i < participants.length; i++) {\n _responses[i] = responses[participants[i]];\n }\n\n return _responses;\n }\n\n /// Gets the participants' justifications\n function getJustifications() external view returns (bytes[] memory) {\n bytes[] memory _justifications = new bytes[](participants.length);\n for (uint256 i = 0; i < participants.length; i++) {\n _justifications[i] = justifications[participants[i]];\n }\n\n return _justifications;\n }\n\n /// Gets the participants' ethereum addresses\n function getParticipants() external view returns (address[] memory) {\n return participants;\n }\n\n /// Gets the participants' BLS keys along with the thershold of the DKG\n function getBlsKeys() external view returns (uint256, bytes[] memory) {\n bytes[] memory _keys = new bytes[](participants.length);\n for (uint256 i = 0; i < participants.length; i++) {\n _keys[i] = keys[participants[i]];\n }\n\n return (THRESHOLD, _keys);\n }\n\n /// Returns the current phase of the DKG.\n function inPhase() public view returns (uint256) {\n if (startBlock == 0) {\n return 0;\n }\n\n uint256 blocksSinceStart = block.number - startBlock;\n\n if (blocksSinceStart <= PHASE_DURATION) {\n return 1;\n }\n\n if (blocksSinceStart <= 2 * PHASE_DURATION) {\n return 2;\n }\n\n if (blocksSinceStart <= 3 * PHASE_DURATION) {\n return 3;\n }\n\n revert(\"DKG Ended\");\n }\n}\n"}},"settings":{"optimizer":{"enabled":false,"runs":200},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"evmVersion":"shanghai","libraries":{}}}
9 changes: 7 additions & 2 deletions crates/dkg-cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ const CONTRACT_PATH: &str = "../../solidity/contracts/DKG.sol";
const CONTRACT_NAME: &str = "DKG";
// Generates the bindings under `src/`
fn main() {
if option_env!("NO_SOLC_BUILD").is_some() {
return;
}

// Only re-run the builder script if the contract changes
println!("cargo:rerun-if-changed={}", PATH);

Expand All @@ -25,7 +29,7 @@ fn main() {
let compiler_output = project.compile().unwrap();
let contract = compiler_output.find(full_path, CONTRACT_NAME).unwrap();

let mut f = File::create("dkg.bin").expect("could not create DKG bytecode file");
let mut f = File::create("artifacts/dkg.bin").expect("could not create DKG bytecode file");
let bytecode: String = contract.bytecode.clone().unwrap().object.encode_hex();

f.write_all(bytecode.as_bytes())
Expand All @@ -46,7 +50,8 @@ fn main() {
let verification_input = project
.standard_json_input(project.sources_path().join("DKG.sol"))
.unwrap();
let mut j = File::create("dkg.json").expect("could not create DKG standard sol input file");
let mut j =
File::create("artifacts/dkg.json").expect("could not create DKG standard sol input file");

j.write_all(
serde_json::to_string(&verification_input)
Expand Down
Loading

0 comments on commit 201fe18

Please sign in to comment.