Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into rename_fields_495
Browse files Browse the repository at this point in the history
  • Loading branch information
natalieesk committed Sep 15, 2023
2 parents af0acbf + c38305b commit 01207d5
Show file tree
Hide file tree
Showing 63 changed files with 1,015 additions and 51 deletions.
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- [Signing](tutorial/signing.md)
- [Distributed Key Generation](tutorial/dkg.md)
- [User Documentation](user.md)
- [Serialization Format](user/serialization.md)
- [FROST with Zcash](zcash.md)
- [Technical Details](zcash/technical-details.md)
- [Ywallet Demo](zcash/ywallet-demo.md)
Expand Down
26 changes: 19 additions & 7 deletions book/src/tutorial/importing.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Add to your `Cargo.toml` file:

```
[dependencies]
frost-ristretto255 = "0.6.0"
frost-ristretto255 = "0.7.0"
```

## Handling errors
Expand All @@ -20,18 +20,30 @@ generation or signing procedure.

FROST is a distributed protocol and thus it requires sending messages between
participants. While the ZF FROST library does not handle communication, it can
help with serialization by activating the `serde` feature. When it is enabled,
you can use [serde](https://serde.rs/) to serialize any structure that needs
to be transmitted. Import example:
help with serialization in the following ways:

### Default byte-oriented serialization

With the `serialization` feature, which is enabled by default, all structs that
need to communicated will have `serialize()` and `deserialize()` methods. The
serialization format is described in [Serialization
Format](../user/serialization.md).

### serde

Alternatively, if you would like to user another format such as JSON, you can
enable the `serde` feature (which is *not* enabled by default). When it is
enabled, you can use [serde](https://serde.rs/) to serialize any structure that
needs to be transmitted. The importing would look like:

```
[dependencies]
frost-ristretto255 = { version = "0.6.0", features = ["serde"] }
frost-ristretto255 = { version = "0.7.0", features = ["serde"] }
```

Note that serde usage is optional. Applications can use different encodings, and
to support that, all structures that need to be transmitted have public getters
and `new()` methods allowing the application to encode and decode them as it
wishes. (Note that fields like `Scalar` and `Element` do have standard byte
string encodings; the application can encode those byte strings as it wishes,
as well the structure themselves and things like maps and lists.)
string encodings; the application can encode those byte strings as it wishes, as
well the structure themselves and things like maps and lists.)
60 changes: 60 additions & 0 deletions book/src/user/serialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Serialization Format

With the `serialization` feature, which is enabled by default, all structs that
need to communicated will have `serialize()` and `deserialize()` methods.

The format is basically the `serde` encoding of the structs using the
[`postcard`](https://docs.rs/postcard/latest/postcard/) crate.

- Integers are encoded in [varint
format](https://postcard.jamesmunns.com/wire-format#varint-encoded-integers)
- Fixed-size byte arrays are encoded as-is (e.g. scalars, elements)
- Note that the encoding of scalars and elements are defined by the
ciphersuites.
- Variable-size byte arrays are encoded with a length prefix (varint-encoded)
and the array as-is (e.g. the message)
- Maps are encoded as the varint-encoded item count, followed by concatenated
item encodings.
- Ciphersuite IDs are encoded as the 4-byte CRC-32 of the ID string.
- Structs are encoded as the concatenation of the encodings of its items.

For example, the following Signing Package:

- Commitments (map):
- Identifier (byte array): `2a00000000000000000000000000000000000000000000000000000000000000`
- Signing Commitments:
- Hiding (byte array): `e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76`
- Bindng (byte array): `6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919`
- Ciphersuite ID: `"FROST(ristretto255, SHA-512)"`
- Message (variable size byte array): `68656c6c6f20776f726c64` (`"hello world"` in UTF-8)
- Ciphersuite ID (4 bytes): `"FROST(ristretto255, SHA-512)"`

Is encoded as

```
012a000000000000000000000000000000000000000000000000000000000000
00e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d
766a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b9
19e6811b690b68656c6c6f20776f726c64e6811b69
```

- `01`: the length of the map
- `2a00000000000000000000000000000000000000000000000000000000000000`: the identifier
- `e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76`: the hinding commitment
- `6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919`: the binding commitment
- `e6811b69`: the ciphersuite ID of the SigningCommitments, CRC-32 of "FROST(ristretto255, SHA-512)"
- `0b`: the length of the message
- `68656c6c6f20776f726c64`: the message
- `e6811b69`: the ciphersuite ID of the SigningPackage, CRC-32 of "FROST(ristretto255, SHA-512)"

```admonish note
The ciphersuite ID is encoded multiple times in this case because `SigningPackage` includes
`SigningCommitments`, which also need to be communicated in Round 1 and thus also encodes
its ciphersuite ID. This is the only instance where this happens.
```

## Test Vectors

Check the
[`snapshots`](https://github.com/search?q=repo%3AZcashFoundation%2Ffrost+path%3Asnapshots&type=code)
files in each ciphersuite crate for test vectors.
10 changes: 9 additions & 1 deletion frost-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Entries are listed in reverse chronological order.

## Unreleased

## 0.8.0

## Released

## 0.7.0

* Challenge hashing during DKG computation was changed to match the paper.
Expand All @@ -13,8 +17,12 @@ Entries are listed in reverse chronological order.
`new()` method and its serde serialization.
* `reconstruct()` was changed to take a slice of `KeyPackage`s instead of
`SecretShare`s since users are expect to store the former and not the latter.
* New `serialize()`/`deserialize()` methods were added so that a default
byte-oriented serialization is available for all structs that need to be
communicated. It is still possible to use serde with you own encoder. Note
that the format will likely change in the next release.
* Audit findings were addressed.

## Released

## 0.6.0

Expand Down
7 changes: 5 additions & 2 deletions frost-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ edition = "2021"
# When releasing to crates.io:
# - Update CHANGELOG.md
# - Create git tag.
version = "0.6.0"
version = "0.7.0"
authors = [
"Deirdre Connolly <durumcrustulum@gmail.com>",
"Chelsea Komlo <me@chelseakomlo.com>",
Expand All @@ -23,10 +23,12 @@ rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
byteorder = "1.4"
const-crc32 = "1.2.0"
document-features = "0.2.7"
debugless-unwrap = "0.0.4"
derive-getters = "0.3.0"
hex = "0.4.3"
postcard = { version = "1.0.0", features = ["use-std"], optional = true }
rand_core = "0.6"
serde = { version = "1.0.160", features = ["derive"], optional = true }
serdect = { version = "0.2.0", optional = true }
Expand All @@ -48,7 +50,7 @@ rand_chacha = "0.3"
serde_json = "1.0"

[features]
default = []
default = ["serialization"]
#! ## Features
## Expose internal types, which do not have SemVer guarantees. This is an advanced
## feature which can be useful if you need to build a modified version of FROST.
Expand All @@ -58,6 +60,7 @@ internals = []
## can use `serde` to serialize structs with any encoder that supports
## `serde` (e.g. JSON with `serde_json`).
serde = ["dep:serde", "dep:serdect"]
serialization = ["serde", "dep:postcard"]
# Exposes ciphersuite-generic tests for other crates to use
test-impl = ["proptest", "serde_json", "criterion"]

Expand Down
8 changes: 8 additions & 0 deletions frost-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ pub enum Error<C: Ciphersuite> {
/// The ciphersuite does not support deriving identifiers from strings.
#[error("The ciphersuite does not support deriving identifiers from strings.")]
IdentifierDerivationNotSupported,
/// Error serializing value.
#[error("Error serializing value.")]
SerializationError,
/// Error deserializing value.
#[error("Error deserializing value.")]
DeserializationError,
}

impl<C> Error<C>
Expand Down Expand Up @@ -147,6 +153,8 @@ where
| Error::UnknownIdentifier
| Error::IncorrectNumberOfIdentifiers
| Error::IncorrectNumberOfCommitments
| Error::SerializationError
| Error::DeserializationError
| Error::IdentifierDerivationNotSupported => None,
}
}
Expand Down
20 changes: 18 additions & 2 deletions frost-core/src/frost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ pub mod round1;
pub mod round2;

use crate::{
scalar_mul::VartimeMultiscalarMul, Ciphersuite, Element, Error, Field, Group, Scalar,
Signature, VerifyingKey,
scalar_mul::VartimeMultiscalarMul, Ciphersuite, Deserialize, Element, Error, Field, Group,
Scalar, Serialize, Signature, VerifyingKey,
};

pub use self::identifier::Identifier;
Expand Down Expand Up @@ -306,6 +306,22 @@ where
}
}

#[cfg(feature = "serialization")]
impl<C> SigningPackage<C>
where
C: Ciphersuite + serde::Serialize + for<'de> serde::Deserialize<'de>,
{
/// Serialize the struct into a Vec.
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}

/// Deserialize the struct from a slice of bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}

/// The product of all signers' individual commitments, published as part of the
/// final signature.
#[derive(Clone, PartialEq, Eq)]
Expand Down
51 changes: 50 additions & 1 deletion frost-core/src/frost/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use rand_core::{CryptoRng, RngCore};
use zeroize::{DefaultIsZeroes, Zeroize};

use crate::{
frost::Identifier, Ciphersuite, Element, Error, Field, Group, Scalar, SigningKey, VerifyingKey,
frost::Identifier, Ciphersuite, Deserialize, Element, Error, Field, Group, Scalar, Serialize,
SigningKey, VerifyingKey,
};

#[cfg(feature = "serde")]
Expand Down Expand Up @@ -420,6 +421,22 @@ where
}
}

#[cfg(feature = "serialization")]
impl<C> SecretShare<C>
where
C: Ciphersuite + serde::Serialize + for<'de> serde::Deserialize<'de>,
{
/// Serialize the struct into a Vec.
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}

/// Deserialize the struct from a slice of bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}

/// The identifier list to use when generating key shares.
pub enum IdentifierList<'a, C: Ciphersuite> {
/// Use the default values (1 to max_signers, inclusive).
Expand Down Expand Up @@ -608,6 +625,22 @@ where
}
}

#[cfg(feature = "serialization")]
impl<C> KeyPackage<C>
where
C: Ciphersuite + serde::Serialize + for<'de> serde::Deserialize<'de>,
{
/// Serialize the struct into a Vec.
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}

/// Deserialize the struct from a slice of bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}

impl<C> TryFrom<SecretShare<C>> for KeyPackage<C>
where
C: Ciphersuite,
Expand Down Expand Up @@ -679,6 +712,22 @@ where
}
}

#[cfg(feature = "serialization")]
impl<C> PublicKeyPackage<C>
where
C: Ciphersuite + serde::Serialize + for<'de> serde::Deserialize<'de>,
{
/// Serialize the struct into a Vec.
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}

/// Deserialize the struct from a slice of bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}

fn validate_num_of_signers<C: Ciphersuite>(
min_signers: u16,
max_signers: u16,
Expand Down
36 changes: 36 additions & 0 deletions frost-core/src/frost/keys/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub mod round1 {
use derive_getters::Getters;
use zeroize::Zeroize;

use crate::{Deserialize, Serialize};

use super::*;

/// The package that must be broadcast by each participant to all other participants
Expand Down Expand Up @@ -92,6 +94,22 @@ pub mod round1 {
}
}

#[cfg(feature = "serialization")]
impl<C> Package<C>
where
C: Ciphersuite + serde::Serialize + for<'de> serde::Deserialize<'de>,
{
/// Serialize the struct into a Vec.
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}

/// Deserialize the struct from a slice of bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}

/// The secret package that must be kept in memory by the participant
/// between the first and second parts of the DKG protocol (round 1).
///
Expand Down Expand Up @@ -145,6 +163,8 @@ pub mod round2 {
use derive_getters::Getters;
use zeroize::Zeroize;

use crate::{Deserialize, Serialize};

use super::*;

/// A package that must be sent by each participant to some other participants
Expand Down Expand Up @@ -186,6 +206,22 @@ pub mod round2 {
}
}

#[cfg(feature = "serialization")]
impl<C> Package<C>
where
C: Ciphersuite + serde::Serialize + for<'de> serde::Deserialize<'de>,
{
/// Serialize the struct into a Vec.
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}

/// Deserialize the struct from a slice of bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}

/// The secret package that must be kept in memory by the participant
/// between the second and third parts of the DKG protocol (round 2).
///
Expand Down
Loading

0 comments on commit 01207d5

Please sign in to comment.