• Stars
    star
    107
  • Rank 323,587 (Top 7 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created almost 4 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A threshold cryptography library in Rust

Tofn (t-of-n): a threshold cryptography library in Rust

Tofn provides the following:

  • An implementation of the GG20 threshold-ECDSA protocol.
  • A general-purpose SDK (software development kit) to facilitate the development and use of threshold cryptography protocols such as GG20.

Setup

  • Get the latest version of Rust stable (currently 1.53.0).
  • Clone this repo.
  • You might need to install the GMP library. On MacOS:
    brew install gmp
    

On Ubuntu: sudo apt install libgmp-dev

Demo and tests

Tofn integration tests (in tests/integration) serve to demo use of the library. (These demos would be in the examples directory but we want them to run automatically as part of the normal test sequence.)

Demo test hieararchy:

tests
└── integration
    ├── multi_thread
    └── single_thread
        └── malicious
            ├── keygen.rs
            ├── sign.rs
            └── timeout_corrupt.rs

Multi-threaded tests

Tests in multi_thread are a more accurate reflection of typical use than those in single_thread.

Threshold cryptography protocols are multi-party computation protocols: parties exchange messages with one another and perform local computations in order to reach consensus on an output of the protocol.

The multi_thread tests aim to simulate such an environment by spawning an independent thread for each party. These tests simulate network communication by using concurrency primitives from Rust's standard library (sync::mpsc) to pass messages between threads.

Run all multi-threaded integration tests:

cargo test --test integration -- multi_thread

Single-threaded tests

Multi-threaded code is inherently more difficult to write, test, and debug. For development purposes it is useful to have a single-threaded reference implementation so as to eliminate concurrency as a source of bugs. Most examples of tofn functionality occur in single_thread.

Some tests illustrate the fault protection and identification properties of the GG20 protocol. These tests require one or more parties to act maliciously during protocol execution. Malicious behaviour is enabled in tofn via the malicious crate feature---see Malicious crate feature below.

Run all single-threaded integration tests with only honest parties:

cargo test --test integration -- single_thread

Run all single-threaded integration tests, including those with malicious parties:

cargo test --all-features --test integration -- single_thread

Tests using malicious display extensive log messages to the terminal. For example:

Jul 23 10:46:04.933  INFO integration::single_thread::malicious::sign: sign with malicious behaviour R6BadProof
Jul 23 10:46:13.005  INFO tofn::gg20::sign::malicious: malicious peer 3 does R6BadProof
Jul 23 10:46:13.273  WARN tofn::gg20::sign::r7::happy: peer 0 says: pedersen proof wc failed to verify for peer 3 because ['wc' check fail]
Jul 23 10:46:13.312  WARN tofn::gg20::sign::r7::happy: peer 1 says: pedersen proof wc failed to verify for peer 3 because ['wc' check fail]
Jul 23 10:46:13.350  WARN tofn::gg20::sign::r7::happy: peer 2 says: pedersen proof wc failed to verify for peer 3 because ['wc' check fail]
Jul 23 10:46:13.391  WARN tofn::gg20::sign::r7::happy: peer 3 says: pedersen proof wc failed to verify for peer 3 because ['wc' check fail]
Jul 23 10:46:13.429  WARN tofn::gg20::sign::r7::happy: peer 4 says: pedersen proof wc failed to verify for peer 3 because ['wc' check fail]
Jul 23 10:46:13.470  WARN tofn::gg20::sign::r7::happy: peer 5 says: pedersen proof wc failed to verify for peer 3 because ['wc' check fail]

Two types of tofn user

The tofn SDK supports two types of users:

  1. Library users
  2. Protocol implementers

Library users

A typical library user should need code from only the following tofn modules:

  • tofn::sdk::api and tofn::collections for generic tofn SDK.
  • tofn::gg20 for protocol-specific code for the GG20 protocol.

See Demo and tests for working code to illustrate use of tofn.

See the Tofnd crate for usage of tofn in production code.

The core of the API is a generic Protocol type:

pub enum Protocol<F, K, P> {
    NotDone(Round<F, K, P>),
    Done(ProtocolOutput<F, P>),
}

where

  • F is the type of the final output of the protocol. (Examples: keygen produces a secret key share, sign produces a signature.)
  • K, P are marker types for typed collection indices. See Typed collection indices below.

Specific protocol implementations provide constructors that create a new concrete Protocol instance. Examples:

  • tofn::gg20::keygen::new_keygen returns a new keygen protocol
  • tofn::gg20::sign::new_sign returns a new sign protocol

Each party in the protocol has its own Protocol instance. A Protocol can be either Done or NotDone. The Done variant has ProtocolOutput data defined like so:

pub type ProtocolOutput<F, P> = Result<F, ProtocolFaulters<P>>;
pub type ProtocolFaulters<P> = FillVecMap<P, Fault>;

where the ProtocolOutput variants are:

  • Ok(output): the protocol completed in happy path, producing output of type F (eg. secret key share or signature).
  • Err(faulters): the protocol completed in sad path. An output of type F could not be produced because one or more parties was malicious. faulters is a list of malicious parties detected by this Protocol instance during execution. ProtocolFaulters is a custom collection type describing the faulty parties.

The NotDone variant has Round data with several core methods used to exchange messages and progress the protocol to the next round:

  • bcast_out, p2ps_out: outgoing messages to be sent over the network to other parties.
  • msg_in: incoming messages received over the network from other parties.
  • expecting_more_msgs_this_round: have we received all the incoming messages we expect for this round? Library users use this method to determine whether it's safe to progress to the next round.
  • execute_next_round: proceed to the next round of the protocol with whatever messages we have received so far. Consumes self and returns a new Protocol instance for the next round.
    • If a message from party A is missing then A is flagged as a faulter. This is how tofn facilitates timeout faults.

Protocol implementers

A typical protocol implementer would use code from the following tofn modules:

  • tofn::sdk::api
  • tofn::sdk::implementer_api
  • tofn::collections

See the tofn::gg20 module for an example of a protocol built using the tofn SDK.

The intent of the implementer API is to allow the protocol implementer to concentrate only on the stateless math functions for each round that map

(current_state, incoming_messages) -> (next_state, outgoing_messages)

The implementer does not need to worry about generic work such as collecting incoming messages, deserializing data, identifying generic faults (timeout, message corruption), etc.

Concretely, protocol implementers must supply:

  • A constructor for a party in the protocol. Examples: gg20::keygen::new_keygen, gg20::sign::new_sign.
  • For each round of the protocol: a struct implementing the Executer trait from one of the modules no_messages, bcast_only, p2p_only, bcast_and_p2p according to which types of messages are expected in this round.

All messages delivered to all parties

Tofn requires that all messages be delivered to all parties. Specifically:

  • p2p: Any p2p message from A to B should also be delivered to all other parties C.
  • self-delivery: A party A treats a missing message from any party P the same way, even if P=A: party P is declared as a faulter.

Support for multiple shares per party

Tofn protocols may allow one party to have multiple shares in the protocol. For example, keygen could be invoked with 5 parties having share counts 2,3,6,2,1 for a total of 14 shares.

Protocol implementers need not concern themselves with the distinction between parties and shares. Indeed, the tofn SDK does not even expose information about parties in the Executer trait implemented by each protocol round.

Each Protocol instance corresponds to a share, not a party. Rounds that produce outgoing p2p messages must produce one message for each other share.

Incoming messages indicate only the party from whom the message is sent and not the individual share controlled by that party. The tofn SDK automatically bundles metadata into each message so that incoming messages can be routed to the appropriate share.

Protocol implementers identify faulty shares but the tofn API attributes faults only to a party, not a share. The tofn SDK automatically translates share faults provided by the protocol implementer into party faults consumed by tofn users.

Avoid panic: TofnResult is for fatal errors only

Tofn strives to avoid panics. (Currently most but not all potential panic points have been eliminated from tofn.)

Instead, tofn has a TofnResult type reserved only for fatal errors:

pub type TofnResult<T> = Result<T, TofnFatal>;
pub struct TofnFatal;

A library user who encounters a TofnFatal should gracefully terminate the protocol according to the context of the specific application. Any Protocol method that returns TofnFatal should be viewed as a confession of fault by that party.

Protocol implementers should not return TofnFatal when malicious behaviour is detected. Instead, move the protocol to Done state and return a faulters list Ok(Done(Err(faulters))) that is processed by the tofn SDK---see gg20 protocol implementation for details.

Malicious crate feature

Enabling the malicious crate feature allows the user to specify that a given party should behave maliciously at a certain point during the protocol.

Example

With malicious enabled the new_keygen function takes an additional argument of type Behaviour.

The following code instructs the party to corrupt her commitment to the elliptic curve point y_i computed during round 1 of the GG20 keygen protocol:

new_keygen(
    party_share_counts,
    threshold,
    party_id,
    subshare_id,
    secret_recovery_key,
    session_nonce,
    Behaviour::R1BadCommit,
)

Tofn collection types

The module tofn::collections provides several custom collection types such as VecMap, FillVecMap, HoleVecMap, etc. These collection types are especially useful for threshold cryptography. They build on the Vec collection type from Rust's standard library.

TODO: more to come.

Typed collection indices

The VecMap collection type is a wrapper for Vec from Rust's standard library except that items in the collection are not indexed by usize. Instead items are indexed by a wrapper type TypedUsize defined as follows:

pub struct TypedUsize<K>(usize, PhantomData<K>);

Users create their own marker type like so:

pub struct SignPartyId;

and then specify the index type of the collection:

let my_vecmap = VecMap<SignPartyId, T>::from_vec(vec![t0, t1, t2]);

Several other crates exist for this purpose but none of them has the unique combination of features we desire in tofn. See the typed_index_collections crate for a list of similar cates.

The purpose of TypedUsize is to avoid accidental misuse of indices as a source of bugs.

Example

Threshold signature schemes consist of two protocols: keygen and sign. A group of 6 parties will participate in keygen in order to produce secret shares of an ECDSA public key PK. Let us label these parties 0,1,2,3,4,5.

Later a subset 1,3,5 of those parties participates in sign in order to sign a message under PK. These sign participants are each assigned a new label for the duration of the sign protocol: 0,1,2. So each sign party label has an associated keygen party label: 0->1, 1->3, 2->5.

Some collection types used in the sign implementation index only over sign parties, whereas others index over all keygen parties. If both of these index types are usize then it is easy to confuse them, creating bugs. TypedUsize allows us to leverage Rust's type system to eliminate index confusion at compile time.

To complicate matters further, tofn supports multiple shares per party. Each keygen protocol specifies both the number of parties in the protocol and the number of shares allocated to each party.

For example, keygen could be invoked with 5 parties having share counts 2,3,6,2,1 for a total of 14 shares. We thus have four distinct index types: keygen parties, keygen shares, sign parties, and sign shares.

Security notes

  • In our security model, we don't guarantee security if the attacker has access to the device.

Message authenticity and integrity

Protocol messages from other parties are delivered via the msg_in API call:

msg_in(from, bytes)

where

  • from is an identifier for the party A from whom the message is received. (Party identifiers in tofn are implemented as a usize.)
  • bytes is the serialized payload of A's message.

It is assumed that these messages have both authenticity and integrity: if party B receives a call to msg_in containing a message bytes from party A then that message really did come from A, it really was intended for B, and the bytes are exactly what A intended.

As such, if bytes is malformed or malicious then B will accuse A of faulty behaviour.

Message ordering

  • We assume that an honest party's Round x message is sent before Round x + i.
  • We also assume that no party receives a Round x + i message from any other party before their Round x message.

License

All crates licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

More Repositories

1

axelar-examples

Sample cross-chain dapps & contracts using the Axelar protocol.
TypeScript
183
star
2

axelar-core

Axelar: A Decentralized Blockchain Interoperability Network
Go
162
star
3

axelar-docs

Resources & Documentation for Axelar Network
MDX
57
star
4

axelar-local-dev

A local developer environment for building your cross-chain dapps.
TypeScript
46
star
5

axelarate-community

Tools to join the axelar network
Shell
44
star
6

axelar-cgp-solidity

No description
JavaScript
39
star
7

axelarjs-sdk

No description
TypeScript
27
star
8

axelar-gmp-sdk-solidity

Solidity libraries and utilities provided by Axelar.
JavaScript
26
star
9

tofnd

A gRPC server wrapper for the https://github.com/axelarnetwork/tofn library.
Rust
25
star
10

interchain-token-service

A protocol implementation for cross chain token transfers.
JavaScript
19
star
11

axelar-amplifier

Permissionless Connections Service run on the Axelar Network
Rust
18
star
12

evm-cosmos-gmp-sample

No description
Rust
13
star
13

devfest-lagos-interchain-dapp-workshop

An interchain decentralized application using React, Solidity, and Axelar General Message Passing that allows users to send messages between two chains.
JavaScript
13
star
14

foundry-axelar-gmp-example

An example repository showcasing the integration of Foundry with Axelar General Message Passing (GMP)
Solidity
11
star
15

axelar-contract-deployments

Contract deployment scripts and resources for Axelar
JavaScript
11
star
16

token-linker

A token linker to be used to permissionlessly link tokens on different EVM compatible chains.
Solidity
10
star
17

axelar-configs

No description
TypeScript
10
star
18

fullstack-interchain-dapp-example

An interchain decentralized application using React, Solidity, and Axelar General Message Passing that allows users to send messages between two chains.
JavaScript
10
star
19

axelarjs

Axelar Network foundations for Javascript/Typescript application development
TypeScript
9
star
20

axelar-cgp-sui

Axelar cross-chain contracts for Sui Move
Move
8
star
21

cgp-spec

Cross-Chain Gateway Protocol Specification
Solidity
7
star
22

axelar-satellite

No description
HTML
7
star
23

axelar-web-app

Axelar web app
TypeScript
6
star
24

cross-chain-airdrop-dapp

How to Build a Cross-chain Airdrop DApp with Solidity, Next.js & Axelar
JavaScript
6
star
25

audits

Axelar network audits
5
star
26

cosmwasm-gateway

Axelar Gateway smart contracts for CosmWasm blockchains.
Rust
3
star
27

interchain-governance-orchestrator

No description
Solidity
3
star
28

axelar-cgp-soroban

Axelar Cross-chain Gateway Protocol for Soroban platform
Rust
3
star
29

support

Your source for support with the Axelar Network
3
star
30

evm-cosmos-relayer

No description
TypeScript
2
star
31

ampd

Rust
2
star
32

axelar-xc20-wrapper

Wraps/Unwraps Moonbeam XC20s.
Solidity
2
star
33

axelarscan-crosschain-ui

Axelarscan Cross-Chain UI
JavaScript
1
star
34

AxelarJS-Tutorial

No description
Solidity
1
star
35

axelar-cgp-aptos

No description
Move
1
star
36

services-portal

Axelar services portal UI
TypeScript
1
star
37

tm-events

Tendermint event utilities
Go
1
star
38

cis

Cross-Chain Interoperability Standards
1
star
39

gmp-caching-docker

Caching DB and executor service for the General Message Passing
JavaScript
1
star
40

grpc-protobuf

Protobuf files used for gRPC calls between https://github.com/axelarnetwork/axelar-core and https://github.com/axelarnetwork/tofn
1
star
41

crosschain-usdc-demo

A demo for the cross-chain usdc without fragmentation issue (it is officially minted by Circle).
TypeScript
1
star
42

whitepaper

No description
1
star