Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Messages RFC #85

Merged
merged 70 commits into from
Jun 15, 2021
Merged
Changes from 22 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
5a86e0c
add a messages rfc
oxarbitrage May 2, 2021
c8eda81
update MsgDealerBroadcast
oxarbitrage May 4, 2021
d0a569c
remove msg type numbers, fix version msg
oxarbitrage May 4, 2021
0e4a911
update MsgCommitments
oxarbitrage May 4, 2021
994a67a
update MsgSigningPackage and MsgSignatureShare
oxarbitrage May 4, 2021
e4ecef9
remove non needed fields from MsgDealerBroadcast
oxarbitrage May 4, 2021
4cf6b87
update validate section
oxarbitrage May 4, 2021
4b88806
include the receiver side in validation section
oxarbitrage May 4, 2021
3d54c96
start a Serialized Size section
oxarbitrage May 4, 2021
f74f57c
complete the rest of the messages sizes
oxarbitrage May 4, 2021
b725e22
join serialization sections, readd `group_public` to initial msg
oxarbitrage May 5, 2021
b80a5a6
add frost:: to frost types, update intro, others
oxarbitrage May 5, 2021
dd0b7de
change better name for alias
oxarbitrage May 6, 2021
d0c8f18
unpack SigningPackage in MsgSigningPackage
oxarbitrage May 6, 2021
b3902e5
unpack commitments in MsgDealerBroadcast
oxarbitrage May 6, 2021
647d199
use affinepoint everywhere
oxarbitrage May 6, 2021
7394400
unpack VerificationKey
oxarbitrage May 6, 2021
c587e84
unpack Signature in MsgFinalSignature
oxarbitrage May 6, 2021
f98c5ce
update validation section
oxarbitrage May 6, 2021
1ee8059
byte order note
oxarbitrage May 6, 2021
61740e2
add size fields in MsgSigningPackage
oxarbitrage May 6, 2021
b608732
fix closing vector
oxarbitrage May 6, 2021
dc90235
replace tuples with new types
oxarbitrage May 8, 2021
104d0f5
add Other considerations section
oxarbitrage May 9, 2021
debcbc1
change other considerations section to not included
oxarbitrage May 9, 2021
0ea8af9
fix typos
oxarbitrage May 10, 2021
42763c1
use to_bytes in primitive types and reduce serialization size
oxarbitrage May 10, 2021
81ceee0
add note about large messages
oxarbitrage May 10, 2021
987cddd
change comments to doc comments
oxarbitrage May 10, 2021
b82e414
remove lenght of msg to be signed from rust
oxarbitrage May 10, 2021
28aefe2
replace CollectedCommitment with a HashMap
oxarbitrage May 10, 2021
c90f1e3
remove participants field from rust in MsgSigningPackage
oxarbitrage May 10, 2021
2293e1a
fix typo
oxarbitrage May 10, 2021
e14631b
change Participant to ParticipantID
oxarbitrage May 10, 2021
4284ddb
update payloads rust code
oxarbitrage May 11, 2021
300e503
add a new not included item
oxarbitrage May 11, 2021
b8abdf5
add line to AffinePoint description
oxarbitrage May 11, 2021
cf84c6f
update serialization
oxarbitrage May 11, 2021
0d51a74
add a new validation rules section
oxarbitrage May 11, 2021
632ed96
split rules in header and payload sub sections
oxarbitrage May 11, 2021
43a302b
fix missing field name and type in MsgCommitments serialization
oxarbitrage May 11, 2021
2d6290e
use some escape characters
oxarbitrage May 11, 2021
899ea9e
add definitions
oxarbitrage May 11, 2021
70eb9aa
Fix a typo
teor2345 May 12, 2021
a3d01a5
Name, Doc and Serialization Tweaks, and a Test Plan
teor2345 May 13, 2021
a53b40c
Remove the separate MsgCommitments type
teor2345 May 13, 2021
8955be9
Fix a missed type
teor2345 May 13, 2021
284d465
Add a constant for this serialization version
teor2345 May 13, 2021
86f5773
Reserve specific participant IDs for the dealer and aggregator
teor2345 May 13, 2021
79eda4e
Clarify participant ID changes
teor2345 May 13, 2021
9db4453
fix missing msg names
oxarbitrage May 13, 2021
ed337b6
split doc comment in lines
oxarbitrage May 13, 2021
5f3184e
remove some spaces after newlines
oxarbitrage May 13, 2021
e892d30
fix definitions after changes to ParticipantID
oxarbitrage May 13, 2021
111eab2
replace ParticipantID with ParticipantId everywhere remaining
oxarbitrage May 13, 2021
a1b9266
Make state-based validation out of scope
teor2345 May 13, 2021
c92b892
remove `msg_type` validation rule
oxarbitrage May 14, 2021
21c309f
change some validation rules
oxarbitrage May 14, 2021
29904a4
forbid multi-bytes in serialization
oxarbitrage May 17, 2021
1f5f04f
change group_public
oxarbitrage May 17, 2021
3c8494d
put variable-length fields last in messages
oxarbitrage May 19, 2021
74df415
text updates
oxarbitrage May 20, 2021
9b057f2
change ParticipantId to u64
oxarbitrage May 21, 2021
83794c5
change some primitives to frost types
oxarbitrage May 21, 2021
f9e73af
update a field description
oxarbitrage May 21, 2021
189efc2
use FrostSignature instead of Scalar primitive
oxarbitrage May 22, 2021
fa886e3
change type to `SignatureResponse`
oxarbitrage May 26, 2021
c4cb055
use BTreeMap, update sizes, etc
oxarbitrage May 31, 2021
de1f625
Convert `share_commitment` to a BTreeMap
oxarbitrage May 31, 2021
fa74969
add missing checks
oxarbitrage Jun 1, 2021
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
278 changes: 278 additions & 0 deletions rfcs/0001-messages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
# FROST messages

Proposes a message layout to exchange information between participants of a FROST setup using the [jubjub](https://github.com/zkcrypto/jubjub) curve.

## Motivation

Currently FROST library is complete for 2 round signatures with a dealer/aggregator setup.
This proposal is only considering that specific features, additions and upgrades will need to be made when DKG is implemented.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

Assuming all participants have a FROST library available we need to define message structures in a way that data can be exchanged between participants. The proposal is a collection of data types so each side can do all the actions needed for a real life situation.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

## Definitions

- `dealer`
- `aggregator`
- `signer`
- `nonce`
- `commitment`
-

## Guide-level explanation

We propose a message separated in 2 parts, a header and a payload:

```rust
struct Message {
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
header: Header,
payload: Payload,
}
```

`Header` will look as follows:

```rust
struct Header {
msg_type: MsgType,
version: MsgVersion,
sender: Participant,
receiver: Participant,
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
}
```

While `Payload` will be defined as:

```rust
enum Payload {
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
DealerBroadcast(MsgDealerBroadcast),
Commitments(MsgCommitments),
SigningPackage(MsgSigningPackage),
SignatureShare(MsgSignatureShare),
FinalSignature(MsgFinalSignature),
}
```

All the messages and new types will be defined in a new file `src/frost/messages.rs`
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

## Reference-level explanation

Here we explore in detail the header types and all the message payloads.

### Header

Fields of the header define new types. Proposed implementation for them is as follows:

```rust
#[repr(u8)]
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
#[non_exhaustive]
enum MsgType {
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
DealerBroadcast,
Commitments,
SigningPackage,
SignatureShare,
FinalSignature,
}

struct MsgVersion(u8);

struct Participant(u8);
```

### Payloads

Each payload defines a new message:

```rust
// Dealer must send this message with initial data to each participant involved.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
// With this, the participant should be able to build a `SharePackage` and use
// the `sign()` function.
// `public_key` can be calculated from the `secret_key`.
// from `secret_key`.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
struct MsgDealerBroadcast {
// The secret key as a frost::Scalar.
secret_key: frost::Scalar,
// Commitments for the signer as jubjub::AffinePoint.
commitment: jubjub::AffinePoint,
// The point and verification bytes needed to generate the group public key
group_public: (jubjub::AffinePoint, [u8; 32]),
}

// Each signer participant send to the aggregator the 2 points
// needed for commitment building.
struct MsgCommitments {
// The hiding Point.
hiding: jubjub::AffinePoint,
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
// The binding Point.
binding: jubjub::AffinePoint,
}

// The aggergator decide what message is going to be signed and
// send it to each participant with all the commitments collected.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
struct MsgSigningPackage {
// The number of participants.
participants: u8,
// The collected unpacked commitments for each signer
commitments: Vec<(u8, jubjub::AffinePoint, jubjub::AffinePoint)>,
// The lenght of the message
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
message_length: u64,
// The message to be signed as bytes
message: &'static [u8],
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
}

// Each signer send the signatures to the agregator who is going to collect them
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
// and generate a final spend signature.
struct MsgSignatureShare {
// The signature to be shared as a Scalar
signature: frost::Scalar,
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
}

// The final signature is broadcasted by the aggegator
// to any participant.
struct MsgFinalSignature {
// The r_bytes and s_bytes needed to build the frost::Signature
final_signature: ([u8; 32], [u8; 32]),
}
```

## Validation

Validation is implemented to each new data type as needed. This will ensure the creation of valid messages before they are send and right after they are received. We create a trait for this as follows:

```rust
pub trait Validate {
fn validate(&self) -> Result<&Self, MsgErr>;
}
```

And we implement where needed. For example, in the header, sender and receiver can't be the same:

```rust
impl Validate for Header {
fn validate(&self) -> Result<&Self, MsgErr> {
if self.sender.0 == self.receiver.0 {
return Err(MsgErr::SameSenderAndReceiver);
}
Ok(self)
}
}
```

This will require to have validation error messages as:

```rust
use thiserror::Error;

#[derive(Clone, Error, Debug)]
pub enum MsgErr {
#[error("sender and receiver are the same")]
SameSenderAndReceiver,
}
```

Then to create a valid `Header` in the sender side we call:

```rust
let header = Validate::validate(&Header {
..
}).expect("a valid header");
```

The receiver side will validate the header using the same method. Instead of panicking the error can be ignored to don't crash and keep waiting for other (potentially valid) messages.

```rust
if let Ok(header) = msg.header.validate() {
..
}
```

## Serialization/Deserialization

Each message struct needs to serialize to bytes representation before it is sent through the wire and must deserialize to the same struct (round trip) on the receiver side. We use `serde` and macro derivations (`Serialize` and `Deserialize`) to automatically implement where possible.

This will require deriving serde in several types defined in `frost.rs`.
Manual implementation of serialization/deserialization will be located at a new mod `src/frost/serialize.rs`.

### Byte order

Each byte chunk specified below is in little-endian order unless is specified otherwise.

### Header

The `Header` part of the message is 4 bytes total:

Bytes | Field name | Data type
------|------------|-----------
1 | msg_type | u8
1 | version | u8
1 | sender | u8
1 | receiver | u8

### Primitive types

`Payload`s use data types that we need to specify first. We have 2 primitive types inside the payload messages:

#### `Scalar`

`Scalar` is a an alias for `jubjub::Fr` and this is a `[u64; 4]` as documented in https://github.com/zkcrypto/jubjub/blob/main/src/fr.rs#L16

#### `AffinePoint`

Much of the math in FROST is done using `jubjub::ExtendedPoint`. This is a structure with 5 `jubjub::Fq`s as defined in https://github.com/zkcrypto/jubjub/blob/main/src/lib.rs#L128-L134

Each `Fq` needed to form a `jubjub::ExtendedPoint` are `Scalar`s of `bls12_381` crate. Scalar here is `[u64; 4]` as documented in https://github.com/zkcrypto/bls12_381/blob/main/src/scalar.rs#L16

For message exchange `jubjub::AffinePoint`s are a better choice as they are shorter in bytes, they are formed of 2 `jubjub::Fq` instead of 5: https://github.com/zkcrypto/jubjub/blob/main/src/lib.rs#L70-L73

Conversion from one type to the other is trivial:

https://docs.rs/jubjub/0.6.0/jubjub/struct.AffinePoint.html#impl-From%3CExtendedPoint%3E
https://docs.rs/jubjub/0.6.0/jubjub/struct.ExtendedPoint.html#impl-From%3CAffinePoint%3E
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

### Payload

Payload part of the message is variable in size and depends on message type.

#### `MsgDealerBroadcast`

Bytes | Field name | Data type
-------|-------------|-----------
256 | secret_key | Scalar
512 | commitments | AffinePoint
256+32 | group_public| (AffinePoint, [u8; 32])
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

#### `MsgCommitments`

Bytes | Field name | Data type
------|------------|-----------
512 | hiding | AffinePoint
512 | binding | AffinePoint

#### `MsgSigningPackage`

Bytes | Field name | Data type
-----------------------|----------------|-----------
1 | participants | u8
(1+256+256)*partipants | commitments | Vec<(u8, AffinePoint, AffinePoint)>
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
8 | message_length | u64
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
message_length | message | [u8]

#### `SignatureShare`

Bytes | Field name | Data type
------|------------|-----------
256 | signature | Scalar

#### `MsgFinalSignature`

Bytes | Field name | Data type
------|------------|-----------
64 | signature | ([u8; 32], [u8; 32])
teor2345 marked this conversation as resolved.
Show resolved Hide resolved


oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
## Testing plan

- Create a happy path unit test similar to https://github.com/ZcashFoundation/redjubjub/blob/frost-messages/tests/frost.rs#L7 and:
- Make messages on each step.
- Simulate send/receive.
- Test round trip serialization/deserialization on each message.
- Create property tests for each message.
teor2345 marked this conversation as resolved.
Show resolved Hide resolved