Skip to content

Commit

Permalink
First draft of HandoverTranscript - a.k.a. The Baton
Browse files Browse the repository at this point in the history
HandoverTranscript, a.k.a. "The Baton", represents the message an incoming node produces to initiate a handover with an outgoing node. After the handover, the incoming node replaces the outgoing node in an existing cohort, securely obtaining a new blinded key share, but under the incoming node's private key.
  • Loading branch information
cygnusv committed May 29, 2024
1 parent 580fcc2 commit a858847
Showing 1 changed file with 71 additions and 1 deletion.
72 changes: 71 additions & 1 deletion ferveo/src/refresh.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::{collections::HashMap, ops::Mul, usize};

use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup, Group};
use ark_ff::{Field, Zero};
use ark_ff::{Field, One, Zero};
use ark_poly::{
univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain,
Polynomial,
};
use ark_std::UniformRand;
use ferveo_common::{serialization, Keypair};
use ferveo_tdec::{
prepare_combine_simple, BlindedKeyShare, CiphertextHeader,
Expand Down Expand Up @@ -314,6 +315,75 @@ impl<E: Pairing> UpdateTranscript<E> {
}
}

// HandoverTranscript, a.k.a. "The Baton", represents the message an incoming
// node produces to initiate a handover with an outgoing node.
// After the handover, the incoming node replaces the outgoing node in an
// existing cohort, securely obtaining a new blinded key share, but under the
// incoming node's private key.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HandoverTranscript<E: Pairing> {
pub double_blind_share: E::G2,
pub commitment_to_share: E::G2,
pub commitment_to_g1: E::G1,
pub commitment_to_g2: E::G2,
pub incoming_pubkey: E::G2Affine,
pub outgoing_pubkey: E::G2Affine,
}

impl<E: Pairing> HandoverTranscript<E> {
pub fn new(
outgoing_blinded_share: &UpdatableBlindedKeyShare<E>,
outgoing_pubkey: E::G2Affine,
incoming_validator_keypair: &Keypair<E>,
rng: &mut impl RngCore,
) -> Self {
let random_scalar = E::ScalarField::rand(rng);
let incoming_decryption_key = incoming_validator_keypair.decryption_key;
let double_blind_share = outgoing_blinded_share
.0
.blinded_key_share
.mul(incoming_decryption_key);
let commitment_to_share = outgoing_pubkey
.mul(incoming_validator_keypair.decryption_key.mul(random_scalar));

Self {
double_blind_share,
commitment_to_share,
commitment_to_g1: E::G1::generator().mul(random_scalar),
commitment_to_g2: E::G2::generator().mul(random_scalar),
incoming_pubkey: incoming_validator_keypair
.public_key()
.encryption_key,
outgoing_pubkey,
}
}

// See similarity with transcript check #4 (do_verify_full in pvss)
pub fn validate(&self, share_commitment_a_i: E::G1) -> Result<bool> {
// let g1_inv = E::G1Prepared::from(-self.g);
// e(comm_G1, double_blind_share) == e(A_i, comm_share)
let commitment_to_g1_inv = -self.commitment_to_g1;
let mut is_valid = E::multi_pairing(
[commitment_to_g1_inv, share_commitment_a_i],
[self.double_blind_share, self.commitment_to_share],
)
.0 == E::TargetField::one();

is_valid = is_valid
&& E::multi_pairing(
[commitment_to_g1_inv, E::G1::generator()],
[E::G2::generator(), self.commitment_to_g2],
)
.0 == E::TargetField::one();

if is_valid {
Ok(true)
} else {
Err(Error::InvalidShareUpdate) // TODO: review error
}
}
}

/// Prepare share updates with a given root (0 for refresh, some x coord for recovery)
/// This is a helper function for `ShareUpdate::create_share_updates_for_recovery` and `ShareUpdate::create_share_updates_for_refresh`
/// It generates a new random polynomial with a defined root and evaluates it at each of the participants' indices.
Expand Down

0 comments on commit a858847

Please sign in to comment.