clementine_core/rpc/parser/
verifier.rs1use super::ParserError;
2use crate::citrea::CitreaClientT;
3use crate::deposit::DepositData;
4use crate::errors::BridgeError;
5use crate::fetch_next_optional_message_from_stream;
6use crate::rpc::clementine::{
7 nonce_gen_response, verifier_deposit_sign_params, DepositSignSession, NonceGenFirstResponse,
8 OperatorKeys, OperatorKeysWithDeposit, PartialSig, VerifierDepositSignParams, VerifierParams,
9};
10use crate::verifier::Verifier;
11use crate::{
12 fetch_next_message_from_stream,
13 rpc::{
14 clementine::{
15 self, verifier_deposit_finalize_params, NonceGenResponse,
16 VerifierDepositFinalizeParams, VerifierPublicKeys,
17 },
18 error::{self, invalid_argument},
19 },
20};
21use bitcoin::secp256k1::schnorr;
22use bitcoin::secp256k1::schnorr::Signature;
23use bitcoin::secp256k1::PublicKey;
24use bitcoin::XOnlyPublicKey;
25use eyre::Context;
26use secp256k1::musig::{AggregatedNonce, PartialSignature, PublicNonce};
27use tonic::Status;
28
29impl<C> TryFrom<&Verifier<C>> for VerifierParams
30where
31 C: CitreaClientT,
32{
33 type Error = Status;
34
35 fn try_from(verifier: &Verifier<C>) -> Result<Self, Self::Error> {
36 Ok(VerifierParams {
37 public_key: verifier.signer.public_key.serialize().to_vec(),
38 })
39 }
40}
41
42impl TryFrom<VerifierPublicKeys> for Vec<PublicKey> {
43 type Error = BridgeError;
44
45 fn try_from(value: VerifierPublicKeys) -> Result<Self, Self::Error> {
46 let inner = value.verifier_public_keys;
47
48 Ok(inner
49 .iter()
50 .map(|inner_vec| {
51 PublicKey::from_slice(inner_vec).wrap_err_with(|| {
52 ParserError::RPCParamMalformed("verifier_public_keys".to_string())
53 })
54 })
55 .collect::<Result<Vec<PublicKey>, eyre::Report>>()?)
56 }
57}
58impl From<Vec<PublicKey>> for VerifierPublicKeys {
59 fn from(value: Vec<PublicKey>) -> Self {
60 let verifier_public_keys: Vec<Vec<u8>> = value
61 .into_iter()
62 .map(|inner| inner.serialize().to_vec())
63 .collect();
64
65 VerifierPublicKeys {
66 verifier_public_keys,
67 }
68 }
69}
70
71impl From<DepositSignSession> for VerifierDepositSignParams {
72 fn from(value: DepositSignSession) -> Self {
73 VerifierDepositSignParams {
74 params: Some(verifier_deposit_sign_params::Params::DepositSignFirstParam(
75 value,
76 )),
77 }
78 }
79}
80
81impl From<DepositSignSession> for VerifierDepositFinalizeParams {
82 fn from(value: DepositSignSession) -> Self {
83 VerifierDepositFinalizeParams {
84 params: Some(verifier_deposit_finalize_params::Params::DepositSignFirstParam(value)),
85 }
86 }
87}
88
89impl From<&Signature> for VerifierDepositFinalizeParams {
90 fn from(value: &Signature) -> Self {
91 VerifierDepositFinalizeParams {
92 params: Some(verifier_deposit_finalize_params::Params::SchnorrSig(
93 value.serialize().to_vec(),
94 )),
95 }
96 }
97}
98
99impl From<NonceGenFirstResponse> for NonceGenResponse {
100 fn from(value: NonceGenFirstResponse) -> Self {
101 NonceGenResponse {
102 response: Some(nonce_gen_response::Response::FirstResponse(value)),
103 }
104 }
105}
106
107impl From<&PublicNonce> for NonceGenResponse {
108 fn from(value: &PublicNonce) -> Self {
109 NonceGenResponse {
110 response: Some(nonce_gen_response::Response::PubNonce(
111 value.serialize().to_vec(),
112 )),
113 }
114 }
115}
116
117impl From<PartialSignature> for PartialSig {
118 fn from(value: PartialSignature) -> Self {
119 PartialSig {
120 partial_sig: value.serialize().to_vec(),
121 }
122 }
123}
124
125#[allow(clippy::result_large_err)]
126pub fn parse_deposit_sign_session(
127 deposit_sign_session: clementine::DepositSignSession,
128 verifier_pk: &PublicKey,
129) -> Result<(DepositData, u128), Status> {
130 let deposit_params = deposit_sign_session
131 .deposit_params
132 .ok_or(Status::invalid_argument("No deposit params received"))?;
133
134 let deposit_data: DepositData = deposit_params.try_into()?;
135
136 let verifier_idx = deposit_data
137 .get_verifier_index(verifier_pk)
138 .map_err(|e| Status::invalid_argument(e.to_string()))?;
139
140 let session_id = deposit_sign_session
141 .nonce_gen_first_responses
142 .get(verifier_idx)
143 .ok_or(Status::invalid_argument(format!(
144 "Verifier with index {verifier_idx} and public key of {verifier_pk} doesn't exists in nonce_gen_first_responses!"
145 )))?
146 .id.parse()
147 .map_err(|e| Status::invalid_argument(format!("Invalid nonce session id: {e}")))?;
148
149 Ok((deposit_data, session_id))
150}
151
152#[allow(clippy::result_large_err)]
153pub fn parse_partial_sigs(partial_sigs: Vec<Vec<u8>>) -> Result<Vec<PartialSignature>, Status> {
154 partial_sigs
155 .iter()
156 .enumerate()
157 .map(|(idx, sig)| {
158 PartialSignature::from_byte_array(
159 &sig.as_slice()
160 .try_into()
161 .map_err(|_| Status::invalid_argument("PartialSignature must be 32 bytes"))?,
162 )
163 .map_err(|e| {
164 error::invalid_argument(
165 "partial_sig",
166 format!("Verifier {idx} returned an invalid partial signature").as_str(),
167 )(e)
168 })
169 })
170 .collect::<Result<Vec<_>, _>>()
171}
172
173#[allow(clippy::result_large_err)]
174pub fn parse_op_keys_with_deposit(
175 data: OperatorKeysWithDeposit,
176) -> Result<(DepositData, OperatorKeys, XOnlyPublicKey), Status> {
177 let deposit_params = data
178 .deposit_params
179 .ok_or(Status::invalid_argument("deposit_params is empty"))?;
180
181 let deposit_data: DepositData = deposit_params.try_into()?;
182
183 let op_keys = data
184 .operator_keys
185 .ok_or(Status::invalid_argument("OperatorDepositKeys is empty"))?;
186
187 let operator_xonly_pk = XOnlyPublicKey::from_slice(&data.operator_xonly_pk).map_err(
188 invalid_argument("operator_xonly_pk", "Invalid xonly public key"),
189 )?;
190
191 Ok((deposit_data, op_keys, operator_xonly_pk))
192}
193
194pub async fn parse_next_deposit_finalize_param_schnorr_sig(
195 stream: &mut tonic::Streaming<VerifierDepositFinalizeParams>,
196) -> Result<Option<schnorr::Signature>, Status> {
197 let sig = match fetch_next_optional_message_from_stream!(stream, params) {
198 Some(sig) => sig,
199 None => return Ok(None),
200 };
201
202 let final_sig = match sig {
203 verifier_deposit_finalize_params::Params::SchnorrSig(final_sig) => {
204 schnorr::Signature::from_slice(&final_sig)
205 .map_err(invalid_argument("FinalSig", "Invalid signature length"))?
206 }
207 _ => {
208 return Err(Status::internal(format!(
209 "Expected SchnorrSig, got {sig:?}",
210 )));
211 }
212 };
213
214 Ok(Some(final_sig))
215}
216
217pub async fn parse_deposit_finalize_param_move_tx_agg_nonce(
218 stream: &mut tonic::Streaming<VerifierDepositFinalizeParams>,
219) -> Result<AggregatedNonce, Status> {
220 let sig = fetch_next_message_from_stream!(stream, params)?;
221
222 match sig {
223 verifier_deposit_finalize_params::Params::MoveTxAggNonce(aggnonce) => {
224 let arr: [u8; 66] = aggnonce
225 .as_slice()
226 .try_into()
227 .map_err(|_| Status::invalid_argument("AggregatedNonce must be 66 bytes"))?;
228
229 Ok(AggregatedNonce::from_byte_array(&arr)
230 .map_err(invalid_argument("AggregatedNonce", "failed to parse"))?)
231 }
232 _ => Err(Status::internal(format!(
233 "Expected MoveTxAggNonce, got {sig:?}",
234 ))),
235 }
236}
237
238pub async fn parse_deposit_finalize_param_emergency_stop_agg_nonce(
239 stream: &mut tonic::Streaming<VerifierDepositFinalizeParams>,
240) -> Result<AggregatedNonce, Status> {
241 let sig = fetch_next_message_from_stream!(stream, params)?;
242
243 match sig {
244 verifier_deposit_finalize_params::Params::EmergencyStopAggNonce(aggnonce) => {
245 Ok(AggregatedNonce::from_byte_array(
246 &aggnonce
247 .as_slice()
248 .try_into()
249 .map_err(|_| Status::invalid_argument("AggregatedNonce must be 66 bytes"))?,
250 )
251 .map_err(invalid_argument("AggregatedNonce", "failed to parse"))?)
252 }
253 _ => Err(Status::internal(format!(
254 "Expected EmergencyStopAggNonce, got {sig:?}",
255 ))),
256 }
257}
258
259pub async fn parse_nonce_gen_first_response(
260 stream: &mut tonic::Streaming<NonceGenResponse>,
261) -> Result<clementine::NonceGenFirstResponse, Status> {
262 let nonce_gen_response = fetch_next_message_from_stream!(stream, response)?;
263
264 if let clementine::nonce_gen_response::Response::FirstResponse(nonce_gen_first_response) =
265 nonce_gen_response
266 {
267 Ok(nonce_gen_first_response)
268 } else {
269 Err(Status::invalid_argument("Expected first_response"))
270 }
271}