lit_rust_sdk/client/
decrypt.rs1use crate::client::LitNodeClient;
2use crate::types::{
3 DecryptRequest, DecryptResponse, EncryptionSignRequest, EncryptionSignResponse,
4};
5use crate::utils;
6use alloy::providers::Provider as ProviderTrait;
7use eyre::{eyre, Result};
8use sha2::{Digest, Sha256};
9use tracing::{debug, info};
10
11impl<P> LitNodeClient<P>
12where
13 P: ProviderTrait,
14{
15 pub async fn decrypt(&self, params: DecryptRequest) -> Result<DecryptResponse> {
26 if !self.ready {
28 return Err(eyre!(
29 "LitNodeClient is not ready. Please call await client.connect() first."
30 ));
31 }
32
33 let has_conditions = params.access_control_conditions.is_some()
35 || params.evm_contract_conditions.is_some()
36 || params.sol_rpc_conditions.is_some()
37 || params.unified_access_control_conditions.is_some();
38
39 if !has_conditions {
40 return Err(eyre!(
41 "You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions"
42 ));
43 }
44
45 let epoch = self.epoch.as_ref().ok_or_else(|| eyre!("Epoch not set"))?;
47 let epoch_number = epoch.number.try_into().unwrap_or(0);
48
49 let decryption_shares = self
51 .retrieve_decryption_shares(¶ms, epoch_number)
52 .await?;
53
54 info!(
55 "Retrieved {} decryption shares from nodes",
56 decryption_shares.len()
57 );
58
59 let network_pub_key = self
61 .network_pub_key
62 .as_ref()
63 .ok_or_else(|| eyre!("network_pub_key not set"))?;
64
65 let hash_of_conditions_str = self.hash_access_control_conditions(¶ms)?;
67 let identity_param = self.get_identity_param_for_encryption(
68 &hash_of_conditions_str,
69 ¶ms.data_to_encrypt_hash,
70 );
71
72 debug!("Identity param for decryption: {}", identity_param);
73
74 let decrypted_data = self.verify_and_decrypt_shares(
76 network_pub_key,
77 &identity_param,
78 ¶ms.ciphertext,
79 decryption_shares,
80 )?;
81
82 Ok(DecryptResponse { decrypted_data })
83 }
84
85 async fn retrieve_decryption_shares(
87 &self,
88 params: &DecryptRequest,
89 epoch: u64,
90 ) -> Result<Vec<EncryptionSignResponse>> {
91 let nodes: Vec<_> = self.connection_state.iter().collect();
92 let mut shares = Vec::new();
93
94 for node in nodes {
95 let url = node.url.clone();
96 let session_sig = params
97 .session_sigs
98 .get(&url)
99 .ok_or_else(|| eyre!("No session signature for node: {}", url))?;
100
101 let auth_sig = crate::types::AuthSig {
103 sig: session_sig.sig.clone(),
104 derived_via: session_sig.derived_via.clone(),
105 signed_message: session_sig.signed_message.clone(),
106 address: session_sig.address.clone(),
107 algo: session_sig.algo.clone(),
108 };
109
110 let request = EncryptionSignRequest {
111 access_control_conditions: params.access_control_conditions.clone(),
112 evm_contract_conditions: params.evm_contract_conditions.clone(),
113 sol_rpc_conditions: params.sol_rpc_conditions.clone(),
114 unified_access_control_conditions: params.unified_access_control_conditions.clone(),
115 chain: params.chain.clone(),
116 data_to_encrypt_hash: params.data_to_encrypt_hash.clone(),
117 auth_sig,
118 epoch,
119 };
120
121 let response = self.send_encryption_sign_request(&url, request).await?;
122 shares.push(response);
123 }
124
125 Ok(shares)
126 }
127
128 async fn send_encryption_sign_request(
130 &self,
131 node_url: &str,
132 request: EncryptionSignRequest,
133 ) -> Result<EncryptionSignResponse> {
134 let url = format!("{}/web/encryption/sign", node_url);
135 debug!("Sending encryption sign request to: {}", url);
136
137 let response = self.http_client.post(&url).json(&request).send().await?;
138
139 if !response.status().is_success() {
140 let error_text = response.text().await?;
141 return Err(eyre!(
142 "Failed to get decryption share from {}: {}",
143 node_url,
144 error_text
145 ));
146 }
147
148 let result: EncryptionSignResponse = response.json().await?;
149 Ok(result)
150 }
151
152 fn verify_and_decrypt_shares(
154 &self,
155 _network_pub_key: &str,
156 _identity_param: &str,
157 ciphertext: &str,
158 shares: Vec<EncryptionSignResponse>,
159 ) -> Result<Vec<u8>> {
160 use base64::{engine::general_purpose::STANDARD, Engine as _};
162 let ciphertext_bytes = STANDARD.decode(ciphertext)?;
163
164 let signature_shares: Vec<blsful::SignatureShare<blsful::Bls12381G2Impl>> =
166 shares.into_iter().map(|s| s.signature_share).collect();
167
168 let combined_signature = blsful::Signature::from_shares(&signature_shares)?;
169
170 let sig_bytes = serde_bare::to_vec(&combined_signature)?;
172
173 let decrypted = crate::bls::decrypt(&ciphertext_bytes, &sig_bytes)?;
175
176 Ok(decrypted)
177 }
178
179 pub fn hash_access_control_conditions(&self, req: &DecryptRequest) -> Result<String> {
180 let mut hasher = Sha256::new();
182
183 if let Some(access_control_conditions) = &req.access_control_conditions {
185 let stringified_access_control_conditions =
186 serde_json::to_string(access_control_conditions)?;
187 debug!(
188 "stringified_access_control_conditions: {:?}",
189 stringified_access_control_conditions
190 );
191 hasher.update(stringified_access_control_conditions.as_bytes());
192 } else if let Some(evm_contract_conditions) = &req.evm_contract_conditions {
193 let stringified_access_control_conditions =
194 serde_json::to_string(evm_contract_conditions)?;
195 debug!(
196 "stringified_access_control_conditions: {:?}",
197 stringified_access_control_conditions
198 );
199 hasher.update(stringified_access_control_conditions.as_bytes());
200 } else if req.sol_rpc_conditions.is_some() {
201 return Err(eyre!("SolRpcConditions are not supported for decryption"));
202 } else if let Some(unified_access_control_conditions) =
203 &req.unified_access_control_conditions
204 {
205 let stringified_access_control_conditions =
206 serde_json::to_string(unified_access_control_conditions)?;
207 debug!(
208 "stringified_access_control_conditions: {:?}",
209 stringified_access_control_conditions
210 );
211 hasher.update(stringified_access_control_conditions.as_bytes());
212 } else {
213 return Err(eyre!("Missing access control conditions"));
214 }
215
216 let hashed_access_control_conditions = utils::bytes_to_hex(hasher.finalize());
217 debug!(
218 "hashed access control conditions: {:?}",
219 hashed_access_control_conditions
220 );
221 Ok(hashed_access_control_conditions)
222 }
223}