clementine_core/rpc/parser/
verifier.rs

1use 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}