1use std::collections::HashMap;
9
10#[cfg(any(test, feature = "test-support"))]
11use std::sync::Arc;
12
13use k256::{
14 elliptic_curve::subtle::ConstantTimeEq, NonZeroScalar, ProjectivePoint,
15 Scalar, Secp256k1,
16};
17#[cfg(any(test, feature = "test-support"))]
18use rand::prelude::*;
19#[cfg(any(test, feature = "test-support"))]
20use sha2::{Digest, Sha256};
21
22use sl_mpc_mate::math::birkhoff_coeffs;
23
24#[cfg(any(test, feature = "test-support"))]
25use crate::setup::{keygen::SetupMessage, *};
26
27#[cfg(any(test, feature = "test-support"))]
28use crate::setup::{
29 keygen::SetupMessage as KeygenSetupMessage,
30 quorum_change::SetupMessage as QuorumChangeSetupMessage,
31};
32use crate::sign::get_lagrange_coeff_list;
33
34#[cfg(any(test, feature = "test-support"))]
35use super::Keyshare;
36
37use super::KeygenError;
38
39pub(crate) fn get_lagrange_coeff(
52 x_i: &NonZeroScalar,
53 x_i_list: &[NonZeroScalar],
54 party_ids: &[u8],
55) -> Scalar {
56 let mut coeff = Scalar::ONE;
57 let x_i = x_i as &Scalar;
58 for &party_id in party_ids {
59 let x_j = &x_i_list[party_id as usize] as &Scalar;
60 if x_i.ct_ne(x_j).into() {
61 let sub = x_j - x_i;
62 coeff *= x_j * &sub.invert().unwrap();
63 }
64 }
65
66 coeff
67}
68
69pub(crate) fn get_birkhoff_coefficients(
82 rank_list: &[u8],
83 x_i_list: &[NonZeroScalar],
84 party_ids: &[u8],
85) -> HashMap<usize, Scalar> {
86 let params = party_ids
87 .iter()
88 .map(|&pid| {
89 (x_i_list[pid as usize], rank_list[pid as usize] as usize)
90 })
91 .collect::<Vec<_>>();
92
93 let betta_vec = birkhoff_coeffs::<Secp256k1>(¶ms);
94
95 party_ids
96 .iter()
97 .zip(betta_vec)
98 .map(|(&pid, w_i)| (pid as usize, w_i))
99 .collect::<HashMap<_, _>>()
100}
101
102#[allow(dead_code)]
117pub(crate) fn check_secret_recovery(
118 x_i_list: &[NonZeroScalar],
119 rank_list: &[u8],
120 big_s_list: &[ProjectivePoint],
121 public_key: &ProjectivePoint,
122) -> Result<(), KeygenError> {
123 let exp_public_key = if rank_list.iter().all(|&r| r == 0) {
125 let coeff_vector = get_lagrange_coeff_list(x_i_list, |x| x);
126 big_s_list
127 .iter()
128 .zip(coeff_vector)
129 .fold(ProjectivePoint::IDENTITY, |acc, (point, betta_i)| {
130 acc + point * &betta_i
131 })
132 } else {
133 let mut party_params_list = x_i_list
135 .iter()
136 .zip(rank_list)
137 .zip(big_s_list)
138 .collect::<Vec<((&NonZeroScalar, &u8), &ProjectivePoint)>>();
139
140 party_params_list.sort_by_key(|((_, &n_i), _)| n_i);
141
142 let params = party_params_list
143 .iter()
144 .map(|((&x_i, &n_i), _)| (x_i, n_i as usize))
145 .collect::<Vec<_>>();
146
147 let betta_vector = birkhoff_coeffs(¶ms);
148
149 party_params_list
150 .into_iter()
151 .map(|((_, _), &big_s_i)| big_s_i)
152 .zip(betta_vector)
153 .fold(ProjectivePoint::IDENTITY, |acc, (point, betta_i)| {
154 acc + point * betta_i
155 })
156 };
157
158 (public_key == &exp_public_key)
159 .then_some(())
160 .ok_or(KeygenError::PublicKeyMismatch)
161}
162
163#[cfg(any(test, feature = "test-support"))]
178pub fn setup_keygen(
179 instance: Option<[u8; 32]>,
180 t: u8,
181 n: u8,
182 ranks: Option<&[u8]>,
183) -> Vec<(KeygenSetupMessage, [u8; 32])> {
184 use std::time::Duration;
185
186 use sl_mpc_mate::message::InstanceId;
187
188 let ranks = if let Some(ranks) = ranks {
189 assert_eq!(ranks.len(), n as usize);
190 ranks.to_vec()
191 } else {
192 vec![0u8; n as usize]
193 };
194
195 let instance = instance.unwrap_or_else(rand::random);
196
197 let party_sk: Vec<NoSigningKey> = std::iter::repeat_with(|| NoSigningKey)
199 .take(n as usize)
200 .collect();
201
202 let party_vk: Vec<NoVerifyingKey> = party_sk
203 .iter()
204 .enumerate()
205 .map(|(party_id, _)| NoVerifyingKey::new(party_id))
206 .collect();
207
208 party_sk
209 .into_iter()
210 .enumerate()
211 .map(|(party_id, sk)| {
212 SetupMessage::new(
213 InstanceId::new(instance),
214 sk,
215 party_id,
216 party_vk.clone(),
217 &ranks,
218 t as usize,
219 )
220 .with_ttl(Duration::from_secs(1000)) })
222 .map(|setup| {
223 let mixin = [setup.participant_index() as u8 + 1];
224
225 (
226 setup,
227 Sha256::new()
228 .chain_update(instance)
229 .chain_update(b"party-seed")
230 .chain_update(mixin)
231 .finalize()
232 .into(),
233 )
234 })
235 .collect::<Vec<_>>()
236}
237
238#[cfg(any(test, feature = "test-support"))]
251pub async fn gen_keyshares(
252 t: u8,
253 n: u8,
254 ranks: Option<&[u8]>,
255) -> Vec<Arc<Keyshare>> {
256 let coord = sl_mpc_mate::coord::SimpleMessageRelay::new();
257
258 let mut parties = tokio::task::JoinSet::new();
259 for (setup, seed) in setup_keygen(None, t, n, ranks) {
260 parties.spawn({
261 let relay = coord.connect();
262 crate::keygen::run(setup, seed, relay)
263 });
264 }
265
266 let mut shares = vec![];
267
268 while let Some(fini) = parties.join_next().await {
269 if let Err(ref err) = fini {
270 println!("error {err:?}");
271 } else {
272 match fini.unwrap() {
273 Err(err) => panic!("err {:?}", err),
274 Ok(share) => shares.push(Arc::new(share)),
275 }
276 }
277 }
278
279 shares.sort_by_key(|share| share.party_id);
280
281 shares
282}
283
284#[cfg(any(test, feature = "test-support"))]
297pub fn setup_quorum_change(
298 old_keyshares: &[Arc<Keyshare>],
299 new_threshold: u8,
300 new_n_i_list: &[u8],
301) -> Vec<(QuorumChangeSetupMessage, [u8; 32])> {
302 let old_threshold = old_keyshares[0].threshold as usize;
303 let old_participants = old_keyshares.len();
304 assert!(old_keyshares.len() >= old_threshold);
305
306 let public_key = old_keyshares[0].public_key();
307
308 let total_parties = old_participants + new_n_i_list.len();
309
310 let old_parties = (0..old_participants).collect::<Vec<usize>>();
311 let new_parties = new_n_i_list
312 .iter()
313 .enumerate()
314 .map(|(p, &r)| ((p + old_participants), r))
315 .collect::<Vec<_>>();
316
317 let mut rng = rand::thread_rng();
318
319 let instance = rng.gen::<[u8; 32]>().into();
320
321 let party_sk: Vec<NoSigningKey> = std::iter::repeat_with(|| NoSigningKey)
323 .take(total_parties)
324 .collect();
325
326 let party_vk: Vec<NoVerifyingKey> = party_sk
327 .iter()
328 .enumerate()
329 .map(|(p, _)| NoVerifyingKey::new(p))
330 .collect();
331
332 party_sk
333 .into_iter()
334 .enumerate()
335 .map(|(p, sk)| {
336 let keyshare = if p < old_participants {
338 Some(old_keyshares[p].clone())
339 } else {
340 None
341 };
342
343 QuorumChangeSetupMessage::new(
344 instance,
345 p,
346 &old_parties,
347 &new_parties,
348 new_threshold as usize,
349 sk,
350 party_vk.clone(),
351 public_key,
352 )
353 .with_keyshare_opt(keyshare)
354 })
355 .map(|setup| (setup, rng.gen()))
356 .collect::<Vec<_>>()
357}
358
359#[cfg(any(test, feature = "test-support"))]
373pub fn setup_quorum_change_extend_parties(
374 old_keyshares: &[Arc<Keyshare>],
375 new_threshold: u8,
376 new_participants_len: u8,
377 new_n_i_list: &[u8],
378) -> Vec<(QuorumChangeSetupMessage, [u8; 32])> {
379 let new_n = old_keyshares.len() + new_participants_len as usize;
380
381 let old_threshold = old_keyshares[0].threshold as usize;
382 let old_participants = old_keyshares.len();
383 assert!(old_keyshares.len() >= old_threshold);
384
385 let public_key = old_keyshares[0].public_key();
386
387 let total_parties = new_n;
388
389 let old_parties = (0..old_keyshares.len()).collect::<Vec<_>>();
390 let new_parties = new_n_i_list
391 .iter()
392 .enumerate()
393 .map(|(p, &r)| (p, r))
394 .collect::<Vec<_>>();
395
396 let mut rng = rand::thread_rng();
397
398 let instance = rng.gen::<[u8; 32]>().into();
399
400 let party_sk: Vec<NoSigningKey> = std::iter::repeat_with(|| NoSigningKey)
402 .take(total_parties)
403 .collect();
404 let party_vk: Vec<NoVerifyingKey> = party_sk
405 .iter()
406 .enumerate()
407 .map(|(p, _)| NoVerifyingKey::new(p))
408 .collect();
409
410 party_sk
411 .into_iter()
412 .enumerate()
413 .map(|(p, sk)| {
414 let keyshare = if p < old_participants {
416 Some(old_keyshares[p].clone())
417 } else {
418 None
419 };
420
421 QuorumChangeSetupMessage::new(
422 instance,
423 p,
424 &old_parties,
425 &new_parties,
426 new_threshold as usize,
427 sk,
428 party_vk.clone(),
429 public_key,
430 )
431 .with_keyshare_opt(keyshare)
432 })
433 .map(|setup| (setup, rng.gen()))
434 .collect::<Vec<_>>()
435}
436
437#[cfg(any(test, feature = "test-support"))]
450pub fn setup_quorum_change_threshold(
451 old_keyshares: &[Arc<Keyshare>],
452 new_threshold: u8,
453 new_n_i_list: &[u8],
454) -> Vec<(QuorumChangeSetupMessage, [u8; 32])> {
455 assert!(old_keyshares.len() >= old_keyshares[0].threshold as usize);
456
457 let total_parties = old_keyshares.len();
458
459 let old_participants = old_keyshares.len();
460
461 let public_key = old_keyshares[0].public_key();
462
463 let old_parties = (0..old_keyshares.len()).collect::<Vec<_>>();
464
465 let new_parties =
466 new_n_i_list.iter().copied().enumerate().collect::<Vec<_>>();
467
468 let mut rng = rand::thread_rng();
469
470 let instance = rng.gen::<[u8; 32]>().into();
471
472 let party_sk: Vec<NoSigningKey> = std::iter::repeat_with(|| NoSigningKey)
474 .take(total_parties)
475 .collect();
476 let party_vk: Vec<NoVerifyingKey> = party_sk
477 .iter()
478 .enumerate()
479 .map(|(p, _)| NoVerifyingKey::new(p))
480 .collect();
481
482 party_sk
483 .into_iter()
484 .enumerate()
485 .map(|(p, sk)| {
486 let keyshare = if p < old_participants {
488 Some(old_keyshares[p].clone())
489 } else {
490 None
491 };
492
493 QuorumChangeSetupMessage::new(
494 instance,
495 p,
496 &old_parties,
497 &new_parties,
498 new_threshold as usize,
499 sk,
500 party_vk.clone(),
501 public_key,
502 )
503 .with_keyshare_opt(keyshare)
504 })
505 .map(|setup| (setup, rng.gen()))
506 .collect::<Vec<_>>()
507}