Skip to content

Commit

Permalink
add version field to serialization at the beginning; move ciphersuite…
Browse files Browse the repository at this point in the history
… after it (#540)

* add version field into a Header field along with the ciphersuite ID

* Change Ciphersuite ID to be the contextString from the spec

* Apply suggestions from code review

Co-authored-by: natalie <[email protected]>

---------

Co-authored-by: natalie <[email protected]>
  • Loading branch information
conradoplg and natalieesk authored Sep 20, 2023
1 parent eee505a commit 4ba88c0
Show file tree
Hide file tree
Showing 55 changed files with 1,281 additions and 577 deletions.
39 changes: 24 additions & 15 deletions book/src/user/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ 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.
[`postcard`](https://docs.rs/postcard/latest/postcard/) crate. But since this is
an implementation detail, we describe the format as follows:

- Integers are encoded in [varint
format](https://postcard.jamesmunns.com/wire-format#varint-encoded-integers)
Expand All @@ -15,37 +16,45 @@ The format is basically the `serde` encoding of the structs using the
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.
- Structs are encoded as the concatenation of the encodings of its items, with
a Header struct as the first item, which contains the format version (a u8)
and the ciphersuite ID.
- The format currently described is identified by the constant 0.
- Ciphersuite IDs are encoded as the 4-byte CRC-32 of the ID string (the
constant Ciphersuite::ID, which for default ciphersuites is the contextString
of the ciphersuite, per the FROST spec).

For example, the following Signing Package:

- Header (map):
- Version (u8): 0
- Ciphersuite ID (4 bytes): CRC-32 of `FROST-RISTRETTO255-SHA512-v1`
- Commitments (map):
- Identifier (byte array): `2a00000000000000000000000000000000000000000000000000000000000000`
- Signing Commitments:
- Hiding (byte array): `e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76`
- Bindng (byte array): `6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919`
- Ciphersuite ID: `"FROST(ristretto255, SHA-512)"`
- Identifier (byte array): `2a00000000000000000000000000000000000000000000000000000000000000`
- Signing Commitments:
- Hiding (byte array): `e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76`
- Bindng (byte array): `6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919`
- Ciphersuite ID (4 bytes): CRC-32 of `FROST-RISTRETTO255-SHA512-v1`
- 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
00d76ecff5012a00000000000000000000000000000000000000000000000000
00000000000000d76ecff5e2f2ae0a6abc4e71a884a961c500515f58e30b6aa5
82dd8db6a65945e08d2d766a493210f7499cd17fecb510ae0cea23a110e8d5b9
01f8acadd3095c73a3b9190b68656c6c6f20776f726c64
```

- `00`: the version of the format
- `d76ecff5`: the ciphersuite ID of the SigningPackage; CRC-32 of `FROST-RISTRETTO255-SHA512-v1`
- `01`: the length of the map
- `2a00000000000000000000000000000000000000000000000000000000000000`: the identifier
- `d76ecff5`: the ciphersuite ID of the SigningCommitments; CRC-32 of `FROST-RISTRETTO255-SHA512-v1`
- `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
Expand Down
8 changes: 8 additions & 0 deletions frost-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ Entries are listed in reverse chronological order.

## 0.8.0

* Both serde serialization and the default byte-oriented serialization now
include a version field (a u8) at the beginning which is always 0 for now. The
ciphersuite ID field was moved from the last field to the second field, after
the version. Both version and ciphersuite ID are now grouped into a "header"
struct, which affects self-describing formats like JSON. The ciphersuite ID
string was also changed for all ciphersuites: it is now equal to the
`contextString` of each ciphersuite per the FROST spec.

## Released

## 0.7.0
Expand Down
18 changes: 5 additions & 13 deletions frost-core/src/frost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub mod round2;

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

pub use self::identifier::Identifier;
Expand Down Expand Up @@ -214,6 +214,9 @@ fn derive_interpolating_value<C: Ciphersuite>(
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SigningPackage<C: Ciphersuite> {
/// Serialization header
#[getter(skip)]
pub(crate) header: Header<C>,
/// The set of commitments participants published in the first round of the
/// protocol.
signing_commitments: BTreeMap<Identifier<C>, round1::SigningCommitments<C>>,
Expand All @@ -229,17 +232,6 @@ pub struct SigningPackage<C: Ciphersuite> {
)
)]
message: Vec<u8>,
/// Ciphersuite ID for serialization
#[cfg_attr(
feature = "serde",
serde(serialize_with = "crate::ciphersuite_serialize::<_, C>")
)]
#[cfg_attr(
feature = "serde",
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
)]
#[getter(skip)]
ciphersuite: (),
}

impl<C> SigningPackage<C>
Expand All @@ -254,9 +246,9 @@ where
message: &[u8],
) -> SigningPackage<C> {
SigningPackage {
header: Header::default(),
signing_commitments,
message: message.to_vec(),
ciphersuite: (),
}
}

Expand Down
58 changes: 17 additions & 41 deletions frost-core/src/frost/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use rand_core::{CryptoRng, RngCore};
use zeroize::{DefaultIsZeroes, Zeroize};

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

#[cfg(feature = "serde")]
Expand Down Expand Up @@ -352,6 +352,9 @@ where
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SecretShare<C: Ciphersuite> {
/// Serialization header
#[getter(skip)]
pub(crate) header: Header<C>,
/// The participant identifier of this [`SecretShare`].
#[zeroize(skip)]
pub(crate) identifier: Identifier<C>,
Expand All @@ -360,17 +363,6 @@ pub struct SecretShare<C: Ciphersuite> {
#[zeroize(skip)]
/// The commitments to be distributed among signers.
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
/// Ciphersuite ID for serialization
#[cfg_attr(
feature = "serde",
serde(serialize_with = "crate::ciphersuite_serialize::<_, C>")
)]
#[cfg_attr(
feature = "serde",
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
)]
#[getter(skip)]
ciphersuite: (),
}

impl<C> SecretShare<C>
Expand All @@ -384,10 +376,10 @@ where
commitment: VerifiableSecretSharingCommitment<C>,
) -> Self {
SecretShare {
header: Header::default(),
identifier,
signing_share,
commitment,
ciphersuite: (),
}
}

Expand Down Expand Up @@ -520,9 +512,9 @@ pub fn split<C: Ciphersuite, R: RngCore + CryptoRng>(
Ok((
secret_shares_by_id,
PublicKeyPackage {
header: Header::default(),
verifying_shares,
verifying_key,
ciphersuite: (),
},
))
}
Expand Down Expand Up @@ -577,6 +569,9 @@ fn evaluate_vss<C: Ciphersuite>(
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct KeyPackage<C: Ciphersuite> {
/// Serialization header
#[getter(skip)]
pub(crate) header: Header<C>,
/// Denotes the participant identifier each secret share key package is owned by.
#[zeroize(skip)]
pub(crate) identifier: Identifier<C>,
Expand All @@ -589,17 +584,6 @@ pub struct KeyPackage<C: Ciphersuite> {
#[zeroize(skip)]
pub(crate) verifying_key: VerifyingKey<C>,
pub(crate) min_signers: u16,
/// Ciphersuite ID for serialization
#[cfg_attr(
feature = "serde",
serde(serialize_with = "crate::ciphersuite_serialize::<_, C>")
)]
#[cfg_attr(
feature = "serde",
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
)]
#[getter(skip)]
ciphersuite: (),
}

impl<C> KeyPackage<C>
Expand All @@ -615,12 +599,12 @@ where
min_signers: u16,
) -> Self {
Self {
header: Header::default(),
identifier,
signing_share,
verifying_share,
verifying_key,
min_signers,
ciphersuite: (),
}
}
}
Expand Down Expand Up @@ -659,12 +643,12 @@ where
let (verifying_share, verifying_key) = secret_share.verify()?;

Ok(KeyPackage {
header: Header::default(),
identifier: secret_share.identifier,
signing_share: secret_share.signing_share,
verifying_share,
verifying_key,
min_signers: secret_share.commitment.0.len() as u16,
ciphersuite: (),
})
}
}
Expand All @@ -677,22 +661,14 @@ where
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct PublicKeyPackage<C: Ciphersuite> {
/// Serialization header
#[getter(skip)]
pub(crate) header: Header<C>,
/// The verifying shares for all participants. Used to validate signature
/// shares they generate.
pub(crate) verifying_shares: HashMap<Identifier<C>, VerifyingShare<C>>,
/// The joint public key for the entire group.
pub(crate) verifying_key: VerifyingKey<C>,
/// Ciphersuite ID for serialization
#[cfg_attr(
feature = "serde",
serde(serialize_with = "crate::ciphersuite_serialize::<_, C>")
)]
#[cfg_attr(
feature = "serde",
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
)]
#[getter(skip)]
ciphersuite: (),
}

impl<C> PublicKeyPackage<C>
Expand All @@ -705,9 +681,9 @@ where
verifying_key: VerifyingKey<C>,
) -> Self {
Self {
header: Header::default(),
verifying_shares,
verifying_key,
ciphersuite: (),
}
}
}
Expand Down Expand Up @@ -821,10 +797,10 @@ pub(crate) fn generate_secret_shares<C: Ciphersuite>(
let value = evaluate_polynomial(*id, &coefficients);

secret_shares.push(SecretShare {
header: Header::default(),
identifier: *id,
signing_share: SigningShare(value),
commitment: commitment.clone(),
ciphersuite: (),
});
}

Expand Down
Loading

0 comments on commit 4ba88c0

Please sign in to comment.