server: add multi-message support (#125)
This commit is contained in:
parent
cb77d35f26
commit
601cc8a409
|
@ -16,10 +16,17 @@ pub(crate) async fn create_new_session(
|
||||||
State(state): State<SharedState>,
|
State(state): State<SharedState>,
|
||||||
Json(args): Json<CreateNewSessionArgs>,
|
Json(args): Json<CreateNewSessionArgs>,
|
||||||
) -> Result<Json<CreateNewSessionOutput>, AppError> {
|
) -> Result<Json<CreateNewSessionOutput>, AppError> {
|
||||||
|
if args.message_count == 0 {
|
||||||
|
return Err(AppError(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
eyre!("invalid message_count"),
|
||||||
|
));
|
||||||
|
}
|
||||||
// Create new session object.
|
// Create new session object.
|
||||||
let id = Uuid::new_v4();
|
let id = Uuid::new_v4();
|
||||||
let session = Session {
|
let session = Session {
|
||||||
identifiers: args.identifiers.iter().cloned().collect(),
|
identifiers: args.identifiers.iter().cloned().collect(),
|
||||||
|
message_count: args.message_count,
|
||||||
state: SessionState::WaitingForCommitments {
|
state: SessionState::WaitingForCommitments {
|
||||||
commitments: Default::default(),
|
commitments: Default::default(),
|
||||||
},
|
},
|
||||||
|
@ -30,6 +37,24 @@ pub(crate) async fn create_new_session(
|
||||||
Ok(Json(user))
|
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
|
/// Implement the send_commitments API
|
||||||
// TODO: get identifier from channel rather from arguments
|
// TODO: get identifier from channel rather from arguments
|
||||||
pub(crate) async fn send_commitments(
|
pub(crate) async fn send_commitments(
|
||||||
|
@ -52,6 +77,12 @@ pub(crate) async fn send_commitments(
|
||||||
if !session.identifiers.contains(&args.identifier) {
|
if !session.identifiers.contains(&args.identifier) {
|
||||||
return Err(AppError(StatusCode::NOT_FOUND, eyre!("invalid 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.
|
// Add commitment to map.
|
||||||
// Currently ignores the possibility of overwriting previous values
|
// Currently ignores the possibility of overwriting previous values
|
||||||
// (it seems better to ignore overwrites, which could be caused by
|
// (it seems better to ignore overwrites, which could be caused by
|
||||||
|
@ -88,7 +119,17 @@ pub(crate) async fn get_commitments(
|
||||||
|
|
||||||
match &session.state {
|
match &session.state {
|
||||||
SessionState::CommitmentsReady { commitments } => Ok(Json(GetCommitmentsOutput {
|
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(
|
_ => Err(AppError(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
@ -114,10 +155,19 @@ pub(crate) async fn send_signing_package(
|
||||||
|
|
||||||
match &mut session.state {
|
match &mut session.state {
|
||||||
SessionState::CommitmentsReady { .. } => {
|
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 {
|
session.state = SessionState::WaitingForSignatureShares {
|
||||||
signing_package: args.signing_package,
|
signing_package: args.signing_package,
|
||||||
signature_shares: Default::default(),
|
signature_shares: Default::default(),
|
||||||
randomizer: args.randomizer,
|
randomizer: args.randomizer,
|
||||||
|
aux_msg: args.aux_msg,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -147,9 +197,11 @@ pub(crate) async fn get_signing_package(
|
||||||
signing_package,
|
signing_package,
|
||||||
signature_shares: _,
|
signature_shares: _,
|
||||||
randomizer,
|
randomizer,
|
||||||
|
aux_msg,
|
||||||
} => Ok(Json(GetSigningPackageOutput {
|
} => Ok(Json(GetSigningPackageOutput {
|
||||||
signing_package: signing_package.clone(),
|
signing_package: signing_package.clone(),
|
||||||
randomizer: *randomizer,
|
randomizer: randomizer.clone(),
|
||||||
|
aux_msg: aux_msg.clone(),
|
||||||
})),
|
})),
|
||||||
_ => Err(AppError(
|
_ => Err(AppError(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
@ -179,10 +231,17 @@ pub(crate) async fn send_signature_share(
|
||||||
signing_package: _,
|
signing_package: _,
|
||||||
signature_shares,
|
signature_shares,
|
||||||
randomizer: _,
|
randomizer: _,
|
||||||
|
aux_msg: _,
|
||||||
} => {
|
} => {
|
||||||
if !session.identifiers.contains(&args.identifier) {
|
if !session.identifiers.contains(&args.identifier) {
|
||||||
return Err(AppError(StatusCode::NOT_FOUND, eyre!("invalid 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
|
// Currently ignoring the possibility of overwriting previous values
|
||||||
// (it seems better to ignore overwrites, which could be caused by
|
// (it seems better to ignore overwrites, which could be caused by
|
||||||
// poor networking connectivity leading to retries)
|
// poor networking connectivity leading to retries)
|
||||||
|
@ -219,7 +278,17 @@ pub(crate) async fn get_signature_shares(
|
||||||
match &session.state {
|
match &session.state {
|
||||||
SessionState::SignatureSharesReady { signature_shares } => {
|
SessionState::SignatureSharesReady { signature_shares } => {
|
||||||
Ok(Json(GetSignatureSharesOutput {
|
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(
|
_ => Err(AppError(
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub fn router() -> Router {
|
||||||
let shared_state = state::SharedState::default();
|
let shared_state = state::SharedState::default();
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/create_new_session", post(functions::create_new_session))
|
.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("/send_commitments", post(functions::send_commitments))
|
||||||
.route("/get_commitments", post(functions::get_commitments))
|
.route("/get_commitments", post(functions::get_commitments))
|
||||||
.route(
|
.route(
|
||||||
|
|
|
@ -11,30 +11,38 @@ use reddsa::frost::redpallas as frost;
|
||||||
pub enum SessionState {
|
pub enum SessionState {
|
||||||
/// Waiting for participants to send their commitments.
|
/// Waiting for participants to send their commitments.
|
||||||
WaitingForCommitments {
|
WaitingForCommitments {
|
||||||
/// Commitments sent by participants so far.
|
/// Commitments sent by participants so far, for each message being
|
||||||
commitments: BTreeMap<frost::Identifier, frost::round1::SigningCommitments>,
|
/// signed.
|
||||||
|
commitments: BTreeMap<frost::Identifier, Vec<frost::round1::SigningCommitments>>,
|
||||||
},
|
},
|
||||||
/// Commitments have been sent by all participants; ready to be fetched by
|
/// Commitments have been sent by all participants; ready to be fetched by
|
||||||
/// the coordinator. Waiting for coordinator to send the SigningPackage.
|
/// the coordinator. Waiting for coordinator to send the SigningPackage.
|
||||||
CommitmentsReady {
|
CommitmentsReady {
|
||||||
/// All commitments sent by participants.
|
/// All commitments sent by participants, for each message being signed.
|
||||||
commitments: BTreeMap<frost::Identifier, frost::round1::SigningCommitments>,
|
commitments: BTreeMap<frost::Identifier, Vec<frost::round1::SigningCommitments>>,
|
||||||
},
|
},
|
||||||
/// SigningPackage ready to be fetched by participants. Waiting for
|
/// SigningPackage ready to be fetched by participants. Waiting for
|
||||||
/// participants to send their signature shares.
|
/// participants to send their signature shares.
|
||||||
WaitingForSignatureShares {
|
WaitingForSignatureShares {
|
||||||
/// SigningPackage sent by the coordinator to be sent to participants.
|
/// SigningPackage sent by the coordinator to be sent to participants,
|
||||||
signing_package: frost::SigningPackage,
|
/// for each message being signed.
|
||||||
/// Randomizer sent by coordinator to be sent to participants
|
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?)
|
/// (Rerandomized FROST only. TODO: make it optional?)
|
||||||
randomizer: frost::round2::Randomizer,
|
randomizer: Vec<frost::round2::Randomizer>,
|
||||||
/// Signature shares sent by participants so far.
|
/// Auxiliary (optional) message. A context-specific data that is
|
||||||
signature_shares: BTreeMap<frost::Identifier, frost::round2::SignatureShare>,
|
/// 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
|
/// SignatureShares have been sent by all participants; ready to be fetched
|
||||||
/// by the coordinator.
|
/// by the coordinator.
|
||||||
SignatureSharesReady {
|
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>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +58,8 @@ impl Default for SessionState {
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
/// The set of identifiers for the session.
|
/// The set of identifiers for the session.
|
||||||
pub(crate) identifiers: BTreeSet<frost::Identifier>,
|
pub(crate) identifiers: BTreeSet<frost::Identifier>,
|
||||||
|
/// The number of messages being simultaneously signed.
|
||||||
|
pub(crate) message_count: u8,
|
||||||
/// The session state.
|
/// The session state.
|
||||||
pub(crate) state: SessionState,
|
pub(crate) state: SessionState,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use reddsa::frost::redpallas as frost;
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct CreateNewSessionArgs {
|
pub struct CreateNewSessionArgs {
|
||||||
pub identifiers: Vec<frost::Identifier>,
|
pub identifiers: Vec<frost::Identifier>,
|
||||||
|
pub message_count: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -15,11 +16,22 @@ pub struct CreateNewSessionOutput {
|
||||||
pub session_id: Uuid,
|
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)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SendCommitmentsArgs {
|
pub struct SendCommitmentsArgs {
|
||||||
pub session_id: Uuid,
|
pub session_id: Uuid,
|
||||||
pub identifier: frost::Identifier,
|
pub identifier: frost::Identifier,
|
||||||
pub commitments: frost::round1::SigningCommitments,
|
pub commitments: Vec<frost::round1::SigningCommitments>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -29,14 +41,15 @@ pub struct GetCommitmentsArgs {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct GetCommitmentsOutput {
|
pub struct GetCommitmentsOutput {
|
||||||
pub commitments: BTreeMap<frost::Identifier, frost::round1::SigningCommitments>,
|
pub commitments: Vec<BTreeMap<frost::Identifier, frost::round1::SigningCommitments>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SendSigningPackageArgs {
|
pub struct SendSigningPackageArgs {
|
||||||
pub session_id: Uuid,
|
pub session_id: Uuid,
|
||||||
pub signing_package: frost::SigningPackage,
|
pub signing_package: Vec<frost::SigningPackage>,
|
||||||
pub randomizer: frost::round2::Randomizer,
|
pub aux_msg: Vec<u8>,
|
||||||
|
pub randomizer: Vec<frost::round2::Randomizer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -46,15 +59,16 @@ pub struct GetSigningPackageArgs {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct GetSigningPackageOutput {
|
pub struct GetSigningPackageOutput {
|
||||||
pub signing_package: frost::SigningPackage,
|
pub signing_package: Vec<frost::SigningPackage>,
|
||||||
pub randomizer: frost::round2::Randomizer,
|
pub randomizer: Vec<frost::round2::Randomizer>,
|
||||||
|
pub aux_msg: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SendSignatureShareArgs {
|
pub struct SendSignatureShareArgs {
|
||||||
pub session_id: Uuid,
|
pub session_id: Uuid,
|
||||||
pub identifier: frost::Identifier,
|
pub identifier: frost::Identifier,
|
||||||
pub signature_share: frost::round2::SignatureShare,
|
pub signature_share: Vec<frost::round2::SignatureShare>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -64,7 +78,7 @@ pub struct GetSignatureSharesArgs {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct GetSignatureSharesOutput {
|
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)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
|
|
@ -14,6 +14,7 @@ use reddsa::frost::redpallas as frost;
|
||||||
/// each client will run independently.
|
/// each client will run independently.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_main_router() -> Result<(), Box<dyn std::error::Error>> {
|
async fn test_main_router() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// Create key shares
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
let (shares, pubkeys) =
|
let (shares, pubkeys) =
|
||||||
frost::keys::generate_with_dealer(3, 2, frost::keys::IdentifierList::Default, &mut rng)
|
frost::keys::generate_with_dealer(3, 2, frost::keys::IdentifierList::Default, &mut rng)
|
||||||
|
@ -28,33 +29,66 @@ async fn test_main_router() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
// Instantiate test server using axum_test
|
||||||
let router = router();
|
let router = router();
|
||||||
let server = TestServer::new(router)?;
|
let server = TestServer::new(router)?;
|
||||||
|
|
||||||
|
// As the coordinator, create a new signing session with all participants,
|
||||||
|
// for 2 messages
|
||||||
let res = server
|
let res = server
|
||||||
.post("/create_new_session")
|
.post("/create_new_session")
|
||||||
.json(&server::CreateNewSessionArgs {
|
.json(&server::CreateNewSessionArgs {
|
||||||
identifiers: key_packages.keys().copied().collect::<Vec<_>>(),
|
identifiers: key_packages.keys().copied().collect::<Vec<_>>(),
|
||||||
|
message_count: 2,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
res.assert_status_ok();
|
res.assert_status_ok();
|
||||||
let r: server::CreateNewSessionOutput = res.json();
|
let r: server::CreateNewSessionOutput = res.json();
|
||||||
let session_id = r.session_id;
|
let session_id = r.session_id;
|
||||||
|
|
||||||
|
// Generate commitments (one SigningCommitments for each message)
|
||||||
|
// and send them to the server; for each participant
|
||||||
|
|
||||||
|
// Map to store the SigningNonces (for each message, for each participant)
|
||||||
let mut nonces_map = BTreeMap::<_, _>::new();
|
let mut nonces_map = BTreeMap::<_, _>::new();
|
||||||
for (identifier, key_package) in key_packages.iter() {
|
for (identifier, key_package) in key_packages.iter() {
|
||||||
let (nonces, commitments) = frost::round1::commit(key_package.signing_share(), &mut rng);
|
// As participant `identifier`
|
||||||
nonces_map.insert(*identifier, nonces);
|
|
||||||
|
// Get the number of messages (the participants wouldn't know without
|
||||||
|
// asking the server).
|
||||||
|
let res = server
|
||||||
|
.post("/get_session_info")
|
||||||
|
.json(&server::GetSessionInfoArgs { session_id })
|
||||||
|
.await;
|
||||||
|
res.assert_status_ok();
|
||||||
|
let r: server::GetSessionInfoOutput = res.json();
|
||||||
|
|
||||||
|
// Generate SigningCommitments and SigningNonces for each message
|
||||||
|
let mut nonces_vec = Vec::new();
|
||||||
|
let mut commitments_vec = Vec::new();
|
||||||
|
for _ in 0..r.message_count {
|
||||||
|
let (nonces, commitments) =
|
||||||
|
frost::round1::commit(key_package.signing_share(), &mut rng);
|
||||||
|
nonces_vec.push(nonces);
|
||||||
|
commitments_vec.push(commitments);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store nonces for later use
|
||||||
|
nonces_map.insert(*identifier, nonces_vec);
|
||||||
|
|
||||||
|
// Send commitments to server
|
||||||
let res = server
|
let res = server
|
||||||
.post("/send_commitments")
|
.post("/send_commitments")
|
||||||
.json(&server::SendCommitmentsArgs {
|
.json(&server::SendCommitmentsArgs {
|
||||||
identifier: *identifier,
|
identifier: *identifier,
|
||||||
session_id,
|
session_id,
|
||||||
commitments,
|
commitments: commitments_vec,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
res.assert_status_ok();
|
res.assert_status_ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As the coordinator, get the commitments
|
||||||
let res = server
|
let res = server
|
||||||
.post("/get_commitments")
|
.post("/get_commitments")
|
||||||
.json(&server::GetCommitmentsArgs { session_id })
|
.json(&server::GetCommitmentsArgs { session_id })
|
||||||
|
@ -63,22 +97,40 @@ async fn test_main_router() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let r: server::GetCommitmentsOutput = res.json();
|
let r: server::GetCommitmentsOutput = res.json();
|
||||||
let commitments = r.commitments;
|
let commitments = r.commitments;
|
||||||
|
|
||||||
let message = "Hello, world!".as_bytes();
|
// As the coordinator, choose messages and create one SigningPackage
|
||||||
let signing_package = frost::SigningPackage::new(commitments, message);
|
// and one RandomizedParams for each.
|
||||||
let randomized_params =
|
let message1 = "Hello, world!".as_bytes();
|
||||||
frost::RandomizedParams::new(pubkeys.verifying_key(), &signing_package, &mut rng)?;
|
let message2 = "Ola mundo!".as_bytes();
|
||||||
|
let aux_msg = "Aux msg".as_bytes();
|
||||||
|
let messages = [message1, message2];
|
||||||
|
let signing_packages = messages
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, msg)| frost::SigningPackage::new(commitments[i].clone(), msg))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let randomized_params = signing_packages
|
||||||
|
.iter()
|
||||||
|
.map(|p| frost::RandomizedParams::new(pubkeys.verifying_key(), p, &mut rng))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
// As the coordinator, send the SigningPackages to the server
|
||||||
let res = server
|
let res = server
|
||||||
.post("/send_signing_package")
|
.post("/send_signing_package")
|
||||||
.json(&server::SendSigningPackageArgs {
|
.json(&server::SendSigningPackageArgs {
|
||||||
session_id,
|
session_id,
|
||||||
signing_package: signing_package.clone(),
|
signing_package: signing_packages.clone(),
|
||||||
randomizer: *randomized_params.randomizer(),
|
randomizer: randomized_params.iter().map(|p| *p.randomizer()).collect(),
|
||||||
|
aux_msg: aux_msg.to_owned(),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
res.assert_status_ok();
|
res.assert_status_ok();
|
||||||
|
|
||||||
|
// As each participant, get SigningPackages and generate the SignatureShares
|
||||||
|
// for each.
|
||||||
for (identifier, key_package) in key_packages.iter() {
|
for (identifier, key_package) in key_packages.iter() {
|
||||||
|
// As participant `identifier`
|
||||||
|
|
||||||
|
// Get SigningPackages
|
||||||
let res = server
|
let res = server
|
||||||
.post("get_signing_package")
|
.post("get_signing_package")
|
||||||
.json(&server::GetSigningPackageArgs { session_id })
|
.json(&server::GetSigningPackageArgs { session_id })
|
||||||
|
@ -86,13 +138,23 @@ async fn test_main_router() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
res.assert_status_ok();
|
res.assert_status_ok();
|
||||||
let r: server::GetSigningPackageOutput = res.json();
|
let r: server::GetSigningPackageOutput = res.json();
|
||||||
|
|
||||||
let signature_share = frost::round2::sign(
|
// Generate SignatureShares for each SigningPackage
|
||||||
&r.signing_package,
|
let signature_share = r
|
||||||
&nonces_map[identifier],
|
.signing_package
|
||||||
|
.iter()
|
||||||
|
.zip(r.randomizer.iter())
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, (signing_package, randomizer))| {
|
||||||
|
frost::round2::sign(
|
||||||
|
signing_package,
|
||||||
|
&nonces_map[identifier][i],
|
||||||
key_package,
|
key_package,
|
||||||
r.randomizer,
|
*randomizer,
|
||||||
)?;
|
)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
// Send SignatureShares to the server
|
||||||
let res = server
|
let res = server
|
||||||
.post("/send_signature_share")
|
.post("/send_signature_share")
|
||||||
.json(&server::SendSignatureShareArgs {
|
.json(&server::SendSignatureShareArgs {
|
||||||
|
@ -104,6 +166,7 @@ async fn test_main_router() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
res.assert_status_ok();
|
res.assert_status_ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As the coordinator, get SignatureShares
|
||||||
let res = server
|
let res = server
|
||||||
.post("/get_signature_shares")
|
.post("/get_signature_shares")
|
||||||
.json(&server::GetSignatureSharesArgs { session_id })
|
.json(&server::GetSignatureSharesArgs { session_id })
|
||||||
|
@ -111,24 +174,25 @@ async fn test_main_router() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
res.assert_status_ok();
|
res.assert_status_ok();
|
||||||
let r: server::GetSignatureSharesOutput = res.json();
|
let r: server::GetSignatureSharesOutput = res.json();
|
||||||
|
|
||||||
let signature = frost::aggregate(
|
// Generate the final Signature for each message
|
||||||
&signing_package,
|
let signatures = signing_packages
|
||||||
&r.signature_shares,
|
.iter()
|
||||||
&pubkeys,
|
.enumerate()
|
||||||
&randomized_params,
|
.map(|(i, p)| frost::aggregate(p, &r.signature_shares[i], &pubkeys, &randomized_params[i]))
|
||||||
)?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
randomized_params
|
|
||||||
.randomized_verifying_key()
|
|
||||||
.verify(message, &signature)?;
|
|
||||||
|
|
||||||
|
// Close the session
|
||||||
let res = server
|
let res = server
|
||||||
.post("/close_session")
|
.post("/close_session")
|
||||||
.json(&server::CloseSessionArgs { session_id })
|
.json(&server::CloseSessionArgs { session_id })
|
||||||
.await;
|
.await;
|
||||||
res.assert_status_ok();
|
res.assert_status_ok();
|
||||||
println!("{}", res.text());
|
|
||||||
let _: () = res.json();
|
// Verify signatures to test if they were generated correctly
|
||||||
|
for (i, p) in randomized_params.iter().enumerate() {
|
||||||
|
p.randomized_verifying_key()
|
||||||
|
.verify(messages[i], &signatures[i])?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -172,6 +236,7 @@ async fn test_http() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.post("http://127.0.0.1:2744/create_new_session")
|
.post("http://127.0.0.1:2744/create_new_session")
|
||||||
.json(&server::CreateNewSessionArgs {
|
.json(&server::CreateNewSessionArgs {
|
||||||
identifiers: key_packages.keys().copied().collect::<Vec<_>>(),
|
identifiers: key_packages.keys().copied().collect::<Vec<_>>(),
|
||||||
|
message_count: 1,
|
||||||
})
|
})
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
|
|
Loading…
Reference in New Issue