1use k256::{NonZeroScalar, ProjectivePoint, Scalar};
5use rand::{CryptoRng, RngCore};
6use sl_mpc_mate::math::Polynomial;
7
8use crate::keygen::key_refresh::KeyshareForRefresh;
9
10pub fn ecdsa_secret_shares<T: RngCore + CryptoRng>(
12 threshold: u8,
13 rank_list: Vec<u8>,
14 private_key: &NonZeroScalar,
15 root_chain_code: [u8; 32],
16 skip: Option<&[u8]>,
17 rng: &mut T,
18) -> Vec<KeyshareForRefresh> {
19 let lost = skip.unwrap_or(&[]).to_vec();
20
21 let private_key: &Scalar = private_key;
22 let public_key = ProjectivePoint::GENERATOR * private_key;
23
24 let mut polynomial =
26 Polynomial::<ProjectivePoint>::random(rng, threshold as usize - 1);
27
28 polynomial.set_constant(*private_key); let x_i_list = (0..rank_list.len())
31 .map(|i| NonZeroScalar::from_uint((i as u64 + 1).into()).unwrap())
32 .collect::<Vec<_>>();
33
34 let shares = rank_list
35 .iter()
36 .zip(&x_i_list)
37 .enumerate()
38 .filter(|&(i, _)| !lost.contains(&(i as u8)))
39 .map(|(i, (&n_i, x_i))| {
40 let s_i: Scalar = polynomial.derivative_at(n_i as usize, x_i);
41
42 KeyshareForRefresh::new(
43 rank_list.clone(),
44 threshold,
45 public_key,
46 root_chain_code,
47 Some(s_i),
48 Some(x_i_list.clone()),
49 lost.clone(),
50 i as u8,
51 )
52 })
53 .collect();
54
55 polynomial.reset_contant();
57
58 shares
59}
60
61#[cfg(test)]
62mod tests {
63 use std::sync::Arc;
64
65 use k256::{
66 elliptic_curve::sec1::ToEncodedPoint, NonZeroScalar, ProjectivePoint,
67 };
68 use rand::Rng;
69 use sl_mpc_mate::coord::SimpleMessageRelay;
70 use tokio::task::JoinSet;
71
72 use crate::{
73 key_import::ecdsa_secret_shares,
74 keygen::{
75 key_refresh::{run, setup_key_refresh, KeyshareForRefresh},
76 Keyshare,
77 },
78 sign::setup_dsg,
79 };
80
81 async fn refresh(
82 keyshares: Vec<KeyshareForRefresh>,
83 ) -> Vec<Arc<Keyshare>> {
84 let coord = SimpleMessageRelay::new();
85 let mut parties = JoinSet::new();
86
87 for (setup, seed, share) in
88 setup_key_refresh(2, 3, Some(&[0, 0, 0]), keyshares)
89 {
90 parties.spawn(run(setup, seed, coord.connect(), share));
91 }
92
93 let mut new_shares = vec![];
94 while let Some(fini) = parties.join_next().await {
95 let fini = fini.unwrap();
96
97 if let Err(ref err) = fini {
98 println!("error {}", err);
99 }
100
101 assert!(fini.is_ok());
102
103 let new_share = fini.unwrap();
104 new_shares.push(Arc::new(new_share));
105 }
106
107 new_shares
108 }
109
110 #[tokio::test(flavor = "multi_thread")]
111 async fn import_key() {
112 let mut rng = rand::thread_rng();
113 let private_key = NonZeroScalar::random(&mut rng);
114 let original_pubkey = ProjectivePoint::GENERATOR * *private_key;
115
116 let keyshares = ecdsa_secret_shares(
117 2,
118 vec![0, 0, 0],
119 &private_key,
120 rng.gen(),
121 None,
122 &mut rng,
123 );
124 let original_chain_code = keyshares[0].root_chain_code;
125
126 let mut new_shares = refresh(keyshares).await;
127
128 let pubkey = new_shares[0].public_key;
129 let new_chain_code = new_shares[0].root_chain_code;
130 assert_ne!(new_chain_code, [0; 32]);
132
133 assert_eq!(pubkey, original_pubkey.to_encoded_point(true).as_bytes());
136 assert_eq!(new_chain_code, original_chain_code);
137
138 let coord = SimpleMessageRelay::new();
140
141 new_shares.sort_by_key(|share| share.party_id);
142 let subset = &new_shares[0..2_usize];
143
144 let mut parties: JoinSet<Result<_, _>> = JoinSet::new();
145 for (setup, seed) in setup_dsg(None, subset, "m") {
146 parties.spawn(crate::sign::run(setup, seed, coord.connect()));
147 }
148
149 while let Some(fini) = parties.join_next().await {
150 let fini = fini.unwrap();
151
152 if let Err(ref err) = fini {
153 println!("error {err:?}");
154 }
155 let _fini = fini.unwrap();
156 }
157 }
158
159 #[tokio::test(flavor = "multi_thread")]
162 async fn import_key_2x3() {
163 let mut rng = rand::thread_rng();
164 let private_key = NonZeroScalar::random(&mut rng);
165 let original_pubkey = ProjectivePoint::GENERATOR * *private_key;
166
167 let mut keyshares = ecdsa_secret_shares(
168 2,
169 vec![0, 0, 0],
170 &private_key,
171 rng.gen(),
172 Some(&[2]), &mut rng,
174 );
175 let original_chain_code = keyshares[0].root_chain_code;
176
177 keyshares.push(KeyshareForRefresh::from_lost_keyshare(
178 vec![0; 3],
179 2,
180 original_pubkey,
181 vec![2],
182 2,
183 ));
184
185 let new_shares = refresh(keyshares).await;
186
187 let pubkey = new_shares[0].public_key;
188 let new_chain_code = new_shares[0].root_chain_code;
189 assert_ne!(new_chain_code, [0; 32]);
191
192 assert_eq!(pubkey, original_pubkey.to_encoded_point(true).as_bytes());
195 assert_eq!(new_chain_code, original_chain_code);
196
197 let coord = SimpleMessageRelay::new();
198 let subset = &new_shares[0..2_usize];
199
200 let mut parties: JoinSet<Result<_, _>> = JoinSet::new();
201 for (setup, seed) in setup_dsg(None, subset, "m") {
202 parties.spawn(crate::sign::run(setup, seed, coord.connect()));
203 }
204
205 while let Some(fini) = parties.join_next().await {
206 let fini = fini.unwrap();
207
208 if let Err(ref err) = fini {
209 println!("error {err:?}");
210 }
211 let _fini = fini.unwrap();
212 }
213 }
214}