1use elliptic_curve::{ops::Invert, scalar::IsHigh, Field, Group, ScalarPrimitive};
2use subtle::ConditionallySelectable;
3
4use crate::{
5 compat::{self, CSCurve},
6 participants::{ParticipantCounter, ParticipantList},
7 protocol::{
8 internal::{make_protocol, Context, SharedChannel},
9 InitializationError, Participant, Protocol, ProtocolError,
10 },
11 PresignOutput,
12};
13
14#[derive(Clone)]
26pub struct FullSignature<C: CSCurve> {
27 pub big_r: C::AffinePoint,
29 pub s: C::Scalar,
31}
32
33impl<C: CSCurve> FullSignature<C> {
34 #[must_use]
35 fn verify(&self, public_key: &C::AffinePoint, msg_hash: &C::Scalar) -> bool {
36 let r: C::Scalar = compat::x_coordinate::<C>(&self.big_r);
37 if r.is_zero().into() || self.s.is_zero().into() {
38 return false;
39 }
40 let s_inv = self.s.invert_vartime().unwrap();
41 let reproduced = (C::ProjectivePoint::generator() * (*msg_hash * s_inv))
42 + (C::ProjectivePoint::from(*public_key) * (r * s_inv));
43 compat::x_coordinate::<C>(&reproduced.into()) == r
44 }
45}
46
47async fn do_sign<C: CSCurve>(
48 mut chan: SharedChannel,
49 participants: ParticipantList,
50 me: Participant,
51 public_key: C::AffinePoint,
52 presignature: PresignOutput<C>,
53 msg_hash: C::Scalar,
54) -> Result<FullSignature<C>, ProtocolError> {
55 let lambda = participants.lagrange::<C>(me);
57 let k_i = lambda * presignature.k;
58
59 let sigma_i = lambda * presignature.sigma;
61
62 let r = compat::x_coordinate::<C>(&presignature.big_r);
64 let s_i: C::Scalar = msg_hash * k_i + r * sigma_i;
65
66 let wait0 = chan.next_waitpoint();
68 {
69 let s_i: ScalarPrimitive<C> = s_i.into();
70 chan.send_many(wait0, &s_i).await;
71 }
72
73 let mut seen = ParticipantCounter::new(&participants);
75 let mut s: C::Scalar = s_i;
76 seen.put(me);
77 while !seen.full() {
78 let (from, s_j): (_, ScalarPrimitive<C>) = chan.recv(wait0).await?;
79 if !seen.put(from) {
80 continue;
81 }
82 s += C::Scalar::from(s_j)
83 }
84
85 s.conditional_assign(&(-s), s.is_high());
88 let sig = FullSignature {
89 big_r: presignature.big_r,
90 s,
91 };
92 if !sig.verify(&public_key, &msg_hash) {
93 return Err(ProtocolError::AssertionFailed(
94 "signature failed to verify".to_string(),
95 ));
96 }
97
98 Ok(sig)
100}
101
102pub fn sign<C: CSCurve>(
108 participants: &[Participant],
109 me: Participant,
110 public_key: C::AffinePoint,
111 presignature: PresignOutput<C>,
112 msg_hash: C::Scalar,
113) -> Result<impl Protocol<Output = FullSignature<C>>, InitializationError> {
114 if participants.len() < 2 {
115 return Err(InitializationError::BadParameters(format!(
116 "participant count cannot be < 2, found: {}",
117 participants.len()
118 )));
119 };
120
121 let participants = ParticipantList::new(participants).ok_or_else(|| {
122 InitializationError::BadParameters("participant list cannot contain duplicates".to_string())
123 })?;
124
125 let ctx = Context::new();
126 let fut = do_sign(
127 ctx.shared_channel(),
128 participants,
129 me,
130 public_key,
131 presignature,
132 msg_hash,
133 );
134 Ok(make_protocol(ctx, fut))
135}
136
137#[cfg(test)]
138mod test {
139 use std::error::Error;
140
141 use ecdsa::Signature;
142 use k256::{
143 ecdsa::signature::Verifier, ecdsa::VerifyingKey, ProjectivePoint, PublicKey, Scalar,
144 Secp256k1,
145 };
146 use rand_core::OsRng;
147
148 use crate::{compat::scalar_hash, math::Polynomial, protocol::run_protocol};
149
150 use super::*;
151
152 #[test]
153 fn test_sign() -> Result<(), Box<dyn Error>> {
154 let threshold = 2;
155 let msg = b"hello?";
156
157 for _ in 0..4 {
159 let f = Polynomial::<Secp256k1>::random(&mut OsRng, threshold);
160 let x = f.evaluate_zero();
161 let public_key = (ProjectivePoint::GENERATOR * x).to_affine();
162
163 let g = Polynomial::<Secp256k1>::random(&mut OsRng, threshold);
164
165 let k: Scalar = g.evaluate_zero();
166 let big_k = (ProjectivePoint::GENERATOR * k.invert().unwrap()).to_affine();
167
168 let sigma = k * x;
169
170 let h = Polynomial::<Secp256k1>::extend_random(&mut OsRng, threshold, &sigma);
171
172 let participants = vec![Participant::from(0u32), Participant::from(1u32)];
173 #[allow(clippy::type_complexity)]
174 let mut protocols: Vec<(
175 Participant,
176 Box<dyn Protocol<Output = FullSignature<Secp256k1>>>,
177 )> = Vec::with_capacity(participants.len());
178 for p in &participants {
179 let p_scalar = p.scalar::<Secp256k1>();
180 let presignature = PresignOutput {
181 big_r: big_k,
182 k: g.evaluate(&p_scalar),
183 sigma: h.evaluate(&p_scalar),
184 };
185 let protocol = sign(
186 &participants,
187 *p,
188 public_key,
189 presignature,
190 scalar_hash(msg),
191 )?;
192 protocols.push((*p, Box::new(protocol)));
193 }
194
195 let result = run_protocol(protocols)?;
196 let sig = result[0].1.clone();
197 let sig =
198 Signature::from_scalars(compat::x_coordinate::<Secp256k1>(&sig.big_r), sig.s)?;
199 VerifyingKey::from(&PublicKey::from_affine(public_key).unwrap())
200 .verify(&msg[..], &sig)?;
201 }
202 Ok(())
203 }
204}