Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Phase 2: add multi-message support to server #125

Merged
merged 1 commit into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 72 additions & 3 deletions server/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ pub(crate) async fn create_new_session(
State(state): State<SharedState>,
Json(args): Json<CreateNewSessionArgs>,
) -> Result<Json<CreateNewSessionOutput>, AppError> {
if args.message_count == 0 {
return Err(AppError(
StatusCode::INTERNAL_SERVER_ERROR,
eyre!("invalid message_count"),
));
}
// Create new session object.
let id = Uuid::new_v4();
let session = Session {
identifiers: args.identifiers.iter().cloned().collect(),
message_count: args.message_count,
state: SessionState::WaitingForCommitments {
commitments: Default::default(),
},
Expand All @@ -30,6 +37,24 @@ pub(crate) async fn create_new_session(
Ok(Json(user))
}

/// Implement the get_session_info API
pub(crate) async fn get_session_info(
State(state): State<SharedState>,
Json(args): Json<GetSessionInfoArgs>,
) -> Result<Json<GetSessionInfoOutput>, AppError> {
let state_lock = state.read().unwrap();

let session = state_lock.sessions.get(&args.session_id).ok_or(AppError(
StatusCode::NOT_FOUND,
eyre!("session ID not found"),
))?;

Ok(Json(GetSessionInfoOutput {
identifiers: session.identifiers.iter().copied().collect(),
message_count: session.message_count,
}))
}

/// Implement the send_commitments API
// TODO: get identifier from channel rather from arguments
pub(crate) async fn send_commitments(
Expand All @@ -52,6 +77,12 @@ pub(crate) async fn send_commitments(
if !session.identifiers.contains(&args.identifier) {
return Err(AppError(StatusCode::NOT_FOUND, eyre!("invalid identifier")));
}
if args.commitments.len() != session.message_count as usize {
return Err(AppError(
StatusCode::INTERNAL_SERVER_ERROR,
eyre!("wrong number of commitments"),
));
}
// Add commitment to map.
// Currently ignores the possibility of overwriting previous values
// (it seems better to ignore overwrites, which could be caused by
Expand Down Expand Up @@ -88,7 +119,17 @@ pub(crate) async fn get_commitments(

match &session.state {
SessionState::CommitmentsReady { commitments } => Ok(Json(GetCommitmentsOutput {
commitments: commitments.clone(),
// Convert the BTreeMap<Identifier, Vec<SigningCommitments>> map
// into a Vec<BTreeMap<Identifier, SigningCommitments>> map to make
// it easier for the coordinator to build the SigningPackages.
commitments: (0..session.message_count)
.map(|i| {
commitments
.iter()
.map(|(id, c)| (*id, c[i as usize]))
.collect()
})
.collect(),
})),
_ => Err(AppError(
StatusCode::INTERNAL_SERVER_ERROR,
Expand All @@ -114,10 +155,19 @@ pub(crate) async fn send_signing_package(

match &mut session.state {
SessionState::CommitmentsReady { .. } => {
if args.signing_package.len() != session.message_count as usize
|| args.randomizer.len() != session.message_count as usize
{
return Err(AppError(
StatusCode::INTERNAL_SERVER_ERROR,
eyre!("wrong number of inputs"),
));
}
session.state = SessionState::WaitingForSignatureShares {
signing_package: args.signing_package,
signature_shares: Default::default(),
randomizer: args.randomizer,
aux_msg: args.aux_msg,
};
}
_ => {
Expand Down Expand Up @@ -147,9 +197,11 @@ pub(crate) async fn get_signing_package(
signing_package,
signature_shares: _,
randomizer,
aux_msg,
} => Ok(Json(GetSigningPackageOutput {
signing_package: signing_package.clone(),
randomizer: *randomizer,
randomizer: randomizer.clone(),
aux_msg: aux_msg.clone(),
})),
_ => Err(AppError(
StatusCode::INTERNAL_SERVER_ERROR,
Expand Down Expand Up @@ -179,10 +231,17 @@ pub(crate) async fn send_signature_share(
signing_package: _,
signature_shares,
randomizer: _,
aux_msg: _,
} => {
if !session.identifiers.contains(&args.identifier) {
return Err(AppError(StatusCode::NOT_FOUND, eyre!("invalid identifier")));
}
if args.signature_share.len() != session.message_count as usize {
return Err(AppError(
StatusCode::INTERNAL_SERVER_ERROR,
eyre!("wrong number of signature shares"),
));
}
// Currently ignoring the possibility of overwriting previous values
// (it seems better to ignore overwrites, which could be caused by
// poor networking connectivity leading to retries)
Expand Down Expand Up @@ -219,7 +278,17 @@ pub(crate) async fn get_signature_shares(
match &session.state {
SessionState::SignatureSharesReady { signature_shares } => {
Ok(Json(GetSignatureSharesOutput {
signature_shares: signature_shares.clone(),
// Convert the BTreeMap<Identifier, Vec<SigningCommitments>> map
// into a Vec<BTreeMap<Identifier, SigningCommitments>> map to make
// it easier for the coordinator to build the SigningPackages.
signature_shares: (0..session.message_count)
.map(|i| {
signature_shares
.iter()
.map(|(id, s)| (*id, s[i as usize]))
.collect()
})
.collect(),
}))
}
_ => Err(AppError(
Expand Down
1 change: 1 addition & 0 deletions server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub fn router() -> Router {
let shared_state = state::SharedState::default();
Router::new()
.route("/create_new_session", post(functions::create_new_session))
.route("/get_session_info", post(functions::get_session_info))
.route("/send_commitments", post(functions::send_commitments))
.route("/get_commitments", post(functions::get_commitments))
.route(
Expand Down
32 changes: 21 additions & 11 deletions server/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,38 @@ use reddsa::frost::redpallas as frost;
pub enum SessionState {
/// Waiting for participants to send their commitments.
WaitingForCommitments {
/// Commitments sent by participants so far.
commitments: BTreeMap<frost::Identifier, frost::round1::SigningCommitments>,
/// Commitments sent by participants so far, for each message being
/// signed.
commitments: BTreeMap<frost::Identifier, Vec<frost::round1::SigningCommitments>>,
},
/// Commitments have been sent by all participants; ready to be fetched by
/// the coordinator. Waiting for coordinator to send the SigningPackage.
CommitmentsReady {
/// All commitments sent by participants.
commitments: BTreeMap<frost::Identifier, frost::round1::SigningCommitments>,
/// All commitments sent by participants, for each message being signed.
commitments: BTreeMap<frost::Identifier, Vec<frost::round1::SigningCommitments>>,
},
/// SigningPackage ready to be fetched by participants. Waiting for
/// participants to send their signature shares.
WaitingForSignatureShares {
/// SigningPackage sent by the coordinator to be sent to participants.
signing_package: frost::SigningPackage,
/// Randomizer sent by coordinator to be sent to participants
/// SigningPackage sent by the coordinator to be sent to participants,
/// for each message being signed.
signing_package: Vec<frost::SigningPackage>,
/// Randomizer sent by coordinator to be sent to participants, for each
/// message being signed.
/// (Rerandomized FROST only. TODO: make it optional?)
randomizer: frost::round2::Randomizer,
/// Signature shares sent by participants so far.
signature_shares: BTreeMap<frost::Identifier, frost::round2::SignatureShare>,
randomizer: Vec<frost::round2::Randomizer>,
/// Auxiliary (optional) message. A context-specific data that is
/// supposed to be interpreted by the participants.
aux_msg: Vec<u8>,
/// Signature shares sent by participants so far, for each message being
/// signed.
signature_shares: BTreeMap<frost::Identifier, Vec<frost::round2::SignatureShare>>,
},
/// SignatureShares have been sent by all participants; ready to be fetched
/// by the coordinator.
SignatureSharesReady {
signature_shares: BTreeMap<frost::Identifier, frost::round2::SignatureShare>,
/// Signature shares sent by participants, for each message being signed.
signature_shares: BTreeMap<frost::Identifier, Vec<frost::round2::SignatureShare>>,
},
}

Expand All @@ -50,6 +58,8 @@ impl Default for SessionState {
pub struct Session {
/// The set of identifiers for the session.
pub(crate) identifiers: BTreeSet<frost::Identifier>,
/// The number of messages being simultaneously signed.
pub(crate) message_count: u8,
/// The session state.
pub(crate) state: SessionState,
}
Expand Down
30 changes: 22 additions & 8 deletions server/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,30 @@ use reddsa::frost::redpallas as frost;
#[derive(Serialize, Deserialize)]
pub struct CreateNewSessionArgs {
pub identifiers: Vec<frost::Identifier>,
pub message_count: u8,
}

#[derive(Serialize, Deserialize)]
pub struct CreateNewSessionOutput {
pub session_id: Uuid,
}

#[derive(Serialize, Deserialize)]
pub struct GetSessionInfoArgs {
pub session_id: Uuid,
}

#[derive(Serialize, Deserialize)]
pub struct GetSessionInfoOutput {
pub identifiers: Vec<frost::Identifier>,
pub message_count: u8,
}

#[derive(Serialize, Deserialize)]
pub struct SendCommitmentsArgs {
pub session_id: Uuid,
pub identifier: frost::Identifier,
pub commitments: frost::round1::SigningCommitments,
pub commitments: Vec<frost::round1::SigningCommitments>,
}

#[derive(Serialize, Deserialize)]
Expand All @@ -29,14 +41,15 @@ pub struct GetCommitmentsArgs {

#[derive(Serialize, Deserialize)]
pub struct GetCommitmentsOutput {
pub commitments: BTreeMap<frost::Identifier, frost::round1::SigningCommitments>,
pub commitments: Vec<BTreeMap<frost::Identifier, frost::round1::SigningCommitments>>,
}

#[derive(Serialize, Deserialize)]
pub struct SendSigningPackageArgs {
pub session_id: Uuid,
pub signing_package: frost::SigningPackage,
pub randomizer: frost::round2::Randomizer,
pub signing_package: Vec<frost::SigningPackage>,
pub aux_msg: Vec<u8>,
pub randomizer: Vec<frost::round2::Randomizer>,
}

#[derive(Serialize, Deserialize)]
Expand All @@ -46,15 +59,16 @@ pub struct GetSigningPackageArgs {

#[derive(Serialize, Deserialize)]
pub struct GetSigningPackageOutput {
pub signing_package: frost::SigningPackage,
pub randomizer: frost::round2::Randomizer,
pub signing_package: Vec<frost::SigningPackage>,
pub randomizer: Vec<frost::round2::Randomizer>,
pub aux_msg: Vec<u8>,
}

#[derive(Serialize, Deserialize)]
pub struct SendSignatureShareArgs {
pub session_id: Uuid,
pub identifier: frost::Identifier,
pub signature_share: frost::round2::SignatureShare,
pub signature_share: Vec<frost::round2::SignatureShare>,
}

#[derive(Serialize, Deserialize)]
Expand All @@ -64,7 +78,7 @@ pub struct GetSignatureSharesArgs {

#[derive(Serialize, Deserialize)]
pub struct GetSignatureSharesOutput {
pub signature_shares: BTreeMap<frost::Identifier, frost::round2::SignatureShare>,
pub signature_shares: Vec<BTreeMap<frost::Identifier, frost::round2::SignatureShare>>,
}

#[derive(Serialize, Deserialize)]
Expand Down
Loading