Skip to content

Commit

Permalink
fix dkg compiling issues
Browse files Browse the repository at this point in the history
  • Loading branch information
conradoplg committed Jul 21, 2023
1 parent 393ff2c commit a9c910a
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 54 deletions.
57 changes: 34 additions & 23 deletions src/frost/redjubjub/dkg.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The DKG module supports generating FROST key shares in a distributed manner,
without a trusted dealer.

Before starting, each participant needs a unique identifier, which can be built from
Before starting, each participant needs an unique identifier, which can be built from
a `u16`. The process in which these identifiers are allocated is up to the application.

The distributed key generation process has 3 parts, with 2 communication rounds
Expand All @@ -25,20 +25,22 @@ they can proceed to sign messages with FROST.
## Example

```rust
# // ANCHOR: dkg_import
use rand::thread_rng;
use std::collections::HashMap;

use reddsa::frost::redjubjub as frost;

let mut rng = thread_rng();

let max_signers = 5;
let min_signers = 3;
# // ANCHOR_END: dkg_import

////////////////////////////////////////////////////////////////////////////
// Key generation, Round 1
////////////////////////////////////////////////////////////////////////////

let max_signers = 5;
let min_signers = 3;

// Keep track of each participant's round 1 secret package.
// In practice each participant will keep its copy; no one
// will have all the participant's packages.
Expand All @@ -53,16 +55,18 @@ let mut received_round1_packages = HashMap::new();
// In practice, each participant will perform this on their own environments.
for participant_index in 1..=max_signers {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
let (secret_package, round1_package) = frost::keys::dkg::part1(
# // ANCHOR: dkg_part1
let (round1_secret_package, round1_package) = frost::keys::dkg::part1(
participant_identifier,
max_signers,
min_signers,
&mut rng,
)?;
# // ANCHOR_END: dkg_part1

// Store the participant's secret package for later use.
// In practice each participant will store it in their own environment.
round1_secret_packages.insert(participant_identifier, secret_package);
round1_secret_packages.insert(participant_identifier, round1_secret_package);

// "Send" the round 1 package to all other participants. In this
// test this is simulated using a HashMap; in practice this will be
Expand All @@ -76,8 +80,8 @@ for participant_index in 1..=max_signers {
.expect("should be nonzero");
received_round1_packages
.entry(receiver_participant_identifier)
.or_insert_with(Vec::new)
.push(round1_package.clone());
.or_insert_with(HashMap::new)
.insert(participant_identifier, round1_package.clone());
}
}

Expand All @@ -99,12 +103,14 @@ let mut received_round2_packages = HashMap::new();
// In practice, each participant will perform this on their own environments.
for participant_index in 1..=max_signers {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
let (round2_secret_package, round2_packages) = frost::keys::dkg::part2(
round1_secret_packages
.remove(&participant_identifier)
.unwrap(),
&received_round1_packages[&participant_identifier],
)?;
let round1_secret_package = round1_secret_packages
.remove(&participant_identifier)
.unwrap();
let round1_packages = &received_round1_packages[&participant_identifier];
# // ANCHOR: dkg_part2
let (round2_secret_package, round2_packages) =
frost::keys::dkg::part2(round1_secret_package, round1_packages)?;
# // ANCHOR_END: dkg_part2

// Store the participant's secret package for later use.
// In practice each participant will store it in their own environment.
Expand All @@ -115,11 +121,11 @@ for participant_index in 1..=max_signers {
// sent through some communication channel.
// Note that, in contrast to the previous part, here each other participant
// gets its own specific package.
for round2_package in round2_packages {
for (receiver_identifier, round2_package) in round2_packages {
received_round2_packages
.entry(round2_package.receiver_identifier)
.or_insert_with(Vec::new)
.push(round2_package);
.entry(receiver_identifier)
.or_insert_with(HashMap::new)
.insert(participant_identifier, round2_package);
}
}

Expand All @@ -142,13 +148,18 @@ let mut pubkey_packages = HashMap::new();
// In practice, each participant will perform this on their own environments.
for participant_index in 1..=max_signers {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
let (key_package, pubkey_package_for_participant) = frost::keys::dkg::part3(
&round2_secret_packages[&participant_identifier],
&received_round1_packages[&participant_identifier],
&received_round2_packages[&participant_identifier],
let round2_secret_package = &round2_secret_packages[&participant_identifier];
let round1_packages = &received_round1_packages[&participant_identifier];
let round2_packages = &received_round2_packages[&participant_identifier];
# // ANCHOR: dkg_part3
let (key_package, pubkey_package) = frost::keys::dkg::part3(
round2_secret_package,
round1_packages,
round2_packages,
)?;
# // ANCHOR_END: dkg_part3
key_packages.insert(participant_identifier, key_package);
pubkey_packages.insert(participant_identifier, pubkey_package_for_participant);
pubkey_packages.insert(participant_identifier, pubkey_package);
}

// With its own key package and the pubkey package, each participant can now proceed
Expand Down
8 changes: 4 additions & 4 deletions src/frost/redjubjub/keys/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ pub fn part1<R: RngCore + CryptoRng>(
/// must be sent to other participants.
pub fn part2(
secret_package: round1::SecretPackage,
round1_packages: &[round1::Package],
) -> Result<(round2::SecretPackage, Vec<round2::Package>), Error> {
round1_packages: &HashMap<Identifier, round1::Package>,
) -> Result<(round2::SecretPackage, HashMap<Identifier, round2::Package>), Error> {
frost::keys::dkg::part2(secret_package, round1_packages)
}

Expand All @@ -80,8 +80,8 @@ pub fn part2(
/// signatures.
pub fn part3(
round2_secret_package: &round2::SecretPackage,
round1_packages: &[round1::Package],
round2_packages: &[round2::Package],
round1_packages: &HashMap<Identifier, round1::Package>,
round2_packages: &HashMap<Identifier, round2::Package>,
) -> Result<(KeyPackage, PublicKeyPackage), Error> {
frost::keys::dkg::part3(round2_secret_package, round1_packages, round2_packages)
}
57 changes: 34 additions & 23 deletions src/frost/redpallas/dkg.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The DKG module supports generating FROST key shares in a distributed manner,
without a trusted dealer.

Before starting, each participant needs a unique identifier, which can be built from
Before starting, each participant needs an unique identifier, which can be built from
a `u16`. The process in which these identifiers are allocated is up to the application.

The distributed key generation process has 3 parts, with 2 communication rounds
Expand All @@ -25,20 +25,22 @@ they can proceed to sign messages with FROST.
## Example

```rust
# // ANCHOR: dkg_import
use rand::thread_rng;
use std::collections::HashMap;

use reddsa::frost::redpallas as frost;

let mut rng = thread_rng();

let max_signers = 5;
let min_signers = 3;
# // ANCHOR_END: dkg_import

////////////////////////////////////////////////////////////////////////////
// Key generation, Round 1
////////////////////////////////////////////////////////////////////////////

let max_signers = 5;
let min_signers = 3;

// Keep track of each participant's round 1 secret package.
// In practice each participant will keep its copy; no one
// will have all the participant's packages.
Expand All @@ -53,16 +55,18 @@ let mut received_round1_packages = HashMap::new();
// In practice, each participant will perform this on their own environments.
for participant_index in 1..=max_signers {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
let (secret_package, round1_package) = frost::keys::dkg::part1(
# // ANCHOR: dkg_part1
let (round1_secret_package, round1_package) = frost::keys::dkg::part1(
participant_identifier,
max_signers,
min_signers,
&mut rng,
)?;
# // ANCHOR_END: dkg_part1

// Store the participant's secret package for later use.
// In practice each participant will store it in their own environment.
round1_secret_packages.insert(participant_identifier, secret_package);
round1_secret_packages.insert(participant_identifier, round1_secret_package);

// "Send" the round 1 package to all other participants. In this
// test this is simulated using a HashMap; in practice this will be
Expand All @@ -76,8 +80,8 @@ for participant_index in 1..=max_signers {
.expect("should be nonzero");
received_round1_packages
.entry(receiver_participant_identifier)
.or_insert_with(Vec::new)
.push(round1_package.clone());
.or_insert_with(HashMap::new)
.insert(participant_identifier, round1_package.clone());
}
}

Expand All @@ -99,12 +103,14 @@ let mut received_round2_packages = HashMap::new();
// In practice, each participant will perform this on their own environments.
for participant_index in 1..=max_signers {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
let (round2_secret_package, round2_packages) = frost::keys::dkg::part2(
round1_secret_packages
.remove(&participant_identifier)
.unwrap(),
&received_round1_packages[&participant_identifier],
)?;
let round1_secret_package = round1_secret_packages
.remove(&participant_identifier)
.unwrap();
let round1_packages = &received_round1_packages[&participant_identifier];
# // ANCHOR: dkg_part2
let (round2_secret_package, round2_packages) =
frost::keys::dkg::part2(round1_secret_package, round1_packages)?;
# // ANCHOR_END: dkg_part2

// Store the participant's secret package for later use.
// In practice each participant will store it in their own environment.
Expand All @@ -115,11 +121,11 @@ for participant_index in 1..=max_signers {
// sent through some communication channel.
// Note that, in contrast to the previous part, here each other participant
// gets its own specific package.
for round2_package in round2_packages {
for (receiver_identifier, round2_package) in round2_packages {
received_round2_packages
.entry(round2_package.receiver_identifier)
.or_insert_with(Vec::new)
.push(round2_package);
.entry(receiver_identifier)
.or_insert_with(HashMap::new)
.insert(participant_identifier, round2_package);
}
}

Expand All @@ -142,13 +148,18 @@ let mut pubkey_packages = HashMap::new();
// In practice, each participant will perform this on their own environments.
for participant_index in 1..=max_signers {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
let (key_package, pubkey_package_for_participant) = frost::keys::dkg::part3(
&round2_secret_packages[&participant_identifier],
&received_round1_packages[&participant_identifier],
&received_round2_packages[&participant_identifier],
let round2_secret_package = &round2_secret_packages[&participant_identifier];
let round1_packages = &received_round1_packages[&participant_identifier];
let round2_packages = &received_round2_packages[&participant_identifier];
# // ANCHOR: dkg_part3
let (key_package, pubkey_package) = frost::keys::dkg::part3(
round2_secret_package,
round1_packages,
round2_packages,
)?;
# // ANCHOR_END: dkg_part3
key_packages.insert(participant_identifier, key_package);
pubkey_packages.insert(participant_identifier, pubkey_package_for_participant);
pubkey_packages.insert(participant_identifier, pubkey_package);
}

// With its own key package and the pubkey package, each participant can now proceed
Expand Down
8 changes: 4 additions & 4 deletions src/frost/redpallas/keys/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ pub fn part1<R: RngCore + CryptoRng>(
/// must be sent to other participants.
pub fn part2(
secret_package: round1::SecretPackage,
round1_packages: &[round1::Package],
) -> Result<(round2::SecretPackage, Vec<round2::Package>), Error> {
round1_packages: &HashMap<Identifier, round1::Package>,
) -> Result<(round2::SecretPackage, HashMap<Identifier, round2::Package>), Error> {
frost::keys::dkg::part2(secret_package, round1_packages)
}

Expand All @@ -80,8 +80,8 @@ pub fn part2(
/// signatures.
pub fn part3(
round2_secret_package: &round2::SecretPackage,
round1_packages: &[round1::Package],
round2_packages: &[round2::Package],
round1_packages: &HashMap<Identifier, round1::Package>,
round2_packages: &HashMap<Identifier, round2::Package>,
) -> Result<(KeyPackage, PublicKeyPackage), Error> {
frost::keys::dkg::part3(round2_secret_package, round1_packages, round2_packages)
}
42 changes: 42 additions & 0 deletions src/orchard/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::println;

use crate::scalar_mul::{self, VartimeMultiscalarMul};
use crate::{orchard, Signature, SigningKey, VerificationKey, VerificationKeyBytes};
use alloc::vec::Vec;
use group::ff::Field;
use group::{ff::PrimeField, GroupEncoding};
Expand All @@ -9,6 +10,47 @@ use rand::thread_rng;
use pasta_curves::arithmetic::CurveExt;
use pasta_curves::pallas;

#[test]
fn orchard_sign() {
let msg =
hex::decode("8ca86a5e2f89da4dd6b8f26f740f360667ec1526cdb0ac7719ddd1c4a1e62981").unwrap();

// Generate a secret key and sign the message
let sk_bytes: [u8; 32] =
hex::decode("6a0df875bb9747883d518dd12223c986bb8166468263f0ab27f235c90d07db30")
.unwrap()
.try_into()
.unwrap();
let sk = SigningKey::<orchard::SpendAuth>::try_from(sk_bytes).unwrap();
let ak: VerificationKey<_> = (&sk).into();
let ak: VerificationKeyBytes<_> = ak.into();
let ak: [u8; 32] = ak.into();
println!("ak: {}", hex::encode(ak));

let randomizer_bytes: [u8; 32] =
hex::decode("10e10752b172b0bfbce1fcc577da34023b67749aa37c50845a35fdc04dc4d51f")
.unwrap()
.try_into()
.unwrap();
let randomizer = pasta_curves::pallas::Scalar::from_repr(randomizer_bytes).unwrap();

let sk = sk.randomize(&randomizer);

let sig = sk.sign(thread_rng(), &msg);

// Types can be converted to raw byte arrays using From/Into
let sig_bytes: [u8; 64] = sig.into();
println!("Signature: {}", hex::encode(sig_bytes));
let pk: VerificationKey<orchard::SpendAuth> = (&sk).into();
let pk_bytes: [u8; 32] = pk.into();

// Deserialize and verify the signature.
let sig: Signature<orchard::SpendAuth> = sig_bytes.into();
assert!(VerificationKey::try_from(pk_bytes)
.and_then(|pk| pk.verify(&msg, &sig))
.is_ok());
}

#[test]
fn orchard_spendauth_basepoint() {
use super::ORCHARD_SPENDAUTHSIG_BASEPOINT_BYTES;
Expand Down

0 comments on commit a9c910a

Please sign in to comment.