Skip to content

Commit

Permalink
Support serde (#398)
Browse files Browse the repository at this point in the history
* Implement serde for network messages.

* Make sure marker type implements serde.

* add serde support to all required structs

* use serdect

* gate under serde feature

* ci: add build with default features job

* add serde tests and required changes/fixes

* add support for encoding ciphersuite ID

---------

Co-authored-by: David Craven <[email protected]>
  • Loading branch information
conradoplg and dvc94ch authored Jun 23, 2023
1 parent 8b09d9d commit 4712153
Show file tree
Hide file tree
Showing 31 changed files with 1,289 additions and 55 deletions.
16 changes: 14 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,26 @@ on:

jobs:

build_default:
name: build with default features
runs-on: ubuntu-latest

steps:
- uses: actions/[email protected]
- uses: actions-rs/[email protected]
with:
toolchain: beta
override: true
- uses: actions-rs/[email protected]
with:
command: build

test_beta:
name: test on beta
runs-on: ubuntu-latest

steps:
- uses: actions/[email protected]
# Because we use nightly features for building docs,
# using --all-features will fail without nightly toolchain.
- uses: actions-rs/[email protected]
with:
toolchain: beta
Expand Down
6 changes: 6 additions & 0 deletions frost-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ Entries are listed in reverse chronological order.
## 0.5.0

* add SigningShare type to ciphersuite libraries
* most structs now have a private field which mean that they can no longer be
instantiated directly. `new()` methods have been added to them.
* change `SigningPackage::new()` to take `&[u8]P instead of `Vec<u8>`
* expose `NonceCommitment` and `SignatureResponse` in ciphersuite crates
* add `serde` support under `serde` feature to allow encoding structs which
need to be communicated between participants.

## Released

Expand Down
3 changes: 3 additions & 0 deletions frost-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ debugless-unwrap = "0.0.4"
digest = "0.10"
hex = { version = "0.4.3", features = ["serde"] }
rand_core = "0.6"
serde = { version = "1.0.160", features = ["derive"], optional = true }
serdect = { version = "0.2.0", optional = true }
thiserror = "1.0"
visibility = "0.0.1"
zeroize = { version = "1.5.4", default-features = false, features = ["derive"] }
Expand All @@ -46,6 +48,7 @@ sha2 = "0.10.2"
nightly = []
default = []
internals = []
serde = ["dep:serde", "dep:serdect"]
# Exposes ciphersuite-generic tests for other crates to use
test-impl = ["proptest", "proptest-derive", "serde_json", "criterion"]

Expand Down
2 changes: 1 addition & 1 deletion frost-core/src/benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ pub fn bench_sign<C: Ciphersuite, R: RngCore + CryptoRng + Clone>(

let message = "message to sign".as_bytes();
let comms = commitments.clone().into_values().collect();
let signing_package = frost::SigningPackage::new(comms, message.to_vec());
let signing_package = frost::SigningPackage::new(comms, message);

group.bench_with_input(
BenchmarkId::new("Round 2", min_signers),
Expand Down
28 changes: 24 additions & 4 deletions frost-core/src/frost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ fn derive_interpolating_value<C: Ciphersuite>(

/// Generated by the coordinator of the signing operation and distributed to
/// each signing party
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SigningPackage<C: Ciphersuite> {
/// The set of commitments participants published in the first round of the
/// protocol.
Expand All @@ -192,26 +194,44 @@ pub struct SigningPackage<C: Ciphersuite> {
///
/// Each signer should perform protocol-specific verification on the
/// message.
#[cfg_attr(
feature = "serde",
serde(
serialize_with = "serdect::slice::serialize_hex_lower_or_bin",
deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec"
)
)]
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>")
)]
ciphersuite: (),
}

impl<C> SigningPackage<C>
where
C: Ciphersuite,
{
/// Create a new `SigingPackage`
/// Create a new `SigningPackage`
///
/// The `signing_commitments` are sorted by participant `identifier`.
pub fn new(
signing_commitments: Vec<round1::SigningCommitments<C>>,
message: Vec<u8>,
message: &[u8],
) -> SigningPackage<C> {
SigningPackage {
signing_commitments: signing_commitments
.into_iter()
.map(|s| (s.identifier, s))
.collect(),
message,
message: message.to_vec(),
ciphersuite: (),
}
}

Expand Down
31 changes: 29 additions & 2 deletions frost-core/src/frost/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,26 @@ use std::{

use crate::{Ciphersuite, Error, Field, FieldError, Group, Scalar};

#[cfg(feature = "serde")]
use crate::ScalarSerialization;

/// A FROST participant identifier.
///
/// The identifier is a field element in the scalar field that the secret polynomial is defined
/// over, corresponding to some x-coordinate for a polynomial f(x) = y. MUST NOT be zero in the
/// field, as f(0) = the shared secret.
#[derive(Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "ScalarSerialization<C>"))]
#[cfg_attr(feature = "serde", serde(into = "ScalarSerialization<C>"))]
pub struct Identifier<C: Ciphersuite>(Scalar<C>);

impl<C> Identifier<C>
where
C: Ciphersuite,
{
/// Serialize the identifier using the ciphersuite encoding.
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn serialize(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
pub fn serialize(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field>::serialize(&self.0)
}

Expand All @@ -39,6 +44,28 @@ where
}
}

#[cfg(feature = "serde")]
impl<C> TryFrom<ScalarSerialization<C>> for Identifier<C>
where
C: Ciphersuite,
{
type Error = Error<C>;

fn try_from(value: ScalarSerialization<C>) -> Result<Self, Self::Error> {
Self::deserialize(&value.0)
}
}

#[cfg(feature = "serde")]
impl<C> From<Identifier<C>> for ScalarSerialization<C>
where
C: Ciphersuite,
{
fn from(value: Identifier<C>) -> Self {
Self(value.serialize())
}
}

impl<C> Eq for Identifier<C> where C: Ciphersuite {}

impl<C> Debug for Identifier<C>
Expand Down
Loading

0 comments on commit 4712153

Please sign in to comment.