|
15 | 15 | // along with the Provable SDK library. If not, see <https://www.gnu.org/licenses/>.
|
16 | 16 |
|
17 | 17 | use crate::{
|
| 18 | + Address, |
18 | 19 | Field,
|
19 | 20 | Group,
|
20 | 21 | RecordCiphertext,
|
21 | 22 | RecordPlaintext,
|
22 | 23 | Transition,
|
23 | 24 | ViewKey,
|
24 | 25 | types::native::{
|
| 26 | + AddressNative, |
25 | 27 | CiphertextEntryNative,
|
26 | 28 | CurrentNetwork,
|
27 | 29 | FieldNative,
|
| 30 | + GroupNative, |
28 | 31 | PlaintextEntryNative,
|
29 | 32 | PlaintextNative,
|
30 | 33 | RecordPlaintextNative,
|
31 | 34 | U8Native,
|
32 | 35 | },
|
33 | 36 | };
|
34 | 37 | use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
35 |
| -use snarkvm_console::prelude::{FromFields, Itertools, Network, Visibility}; |
| 38 | +use snarkvm_console::prelude::{FromField, FromFields, Itertools, Network, One, Visibility}; |
36 | 39 |
|
37 | 40 | use indexmap::IndexMap;
|
38 | 41 | use wasm_bindgen::prelude::wasm_bindgen;
|
@@ -253,12 +256,58 @@ impl EncryptionToolkit {
|
253 | 256 |
|
254 | 257 | Ok(owned_records)
|
255 | 258 | }
|
| 259 | + |
| 260 | + /// Decrypt the sender ciphertext associated with a record. |
| 261 | + /// |
| 262 | + /// @param {ViewKey} view_key View key associated with the record. |
| 263 | + /// @param {RecordPlaintext} record Record plaintext associated with a sender. |
| 264 | + /// @param {Field} sender_ciphertext Sender ciphertext associated with the record. |
| 265 | + /// |
| 266 | + /// @returns {Address} address of the sender. |
| 267 | + #[wasm_bindgen(js_name = decryptSender)] |
| 268 | + pub fn decrypt_sender( |
| 269 | + view_key: &ViewKey, |
| 270 | + record: &RecordPlaintext, |
| 271 | + sender_ciphertext: &Field, |
| 272 | + ) -> Result<Address, String> { |
| 273 | + let record_view_key = record.record_view_key(view_key); |
| 274 | + Self::decrypt_sender_with_rvk(&record_view_key, sender_ciphertext) |
| 275 | + } |
| 276 | + |
| 277 | + /// Decrypt the sender ciphertext associated with the record with the record view key. |
| 278 | + /// |
| 279 | + /// @param {Field} record_view_key Record view key associated with the record. |
| 280 | + /// @param {Field} sender_ciphertext Sender ciphertext associated with the record. |
| 281 | + /// |
| 282 | + /// @return {Address} the address of the sender. |
| 283 | + #[wasm_bindgen(js_name = decryptSenderWithRvk)] |
| 284 | + pub fn decrypt_sender_with_rvk(record_view_key: &Field, sender_ciphertext: &Field) -> Result<Address, String> { |
| 285 | + let encryption_domain = <CurrentNetwork as Network>::encryption_domain(); |
| 286 | + let record_view_key = FieldNative::from(record_view_key); |
| 287 | + let randomizer = |
| 288 | + <CurrentNetwork as Network>::hash_psd4(&[encryption_domain, record_view_key, FieldNative::one()]) |
| 289 | + .map_err(|e| e.to_string())?; |
| 290 | + let address_x_coordinate = FieldNative::from(sender_ciphertext) - randomizer; |
| 291 | + Ok(Address::from(AddressNative::new( |
| 292 | + GroupNative::from_field(&address_x_coordinate).map_err(|e| e.to_string())?, |
| 293 | + ))) |
| 294 | + } |
256 | 295 | }
|
257 | 296 |
|
258 | 297 | #[cfg(test)]
|
259 | 298 | mod tests {
|
260 | 299 | use super::*;
|
261 | 300 |
|
| 301 | + use crate::{ |
| 302 | + test::{ |
| 303 | + CREDITS_RECORD_V1, |
| 304 | + CREDITS_RECORD_VIEW_KEY, |
| 305 | + CREDITS_SENDER_CIPHERTEXT, |
| 306 | + CREDITS_SENDER_PLAINTEXT, |
| 307 | + get_env, |
| 308 | + }, |
| 309 | + types::native::{PrivateKeyNative, ViewKeyNative}, |
| 310 | + }; |
262 | 311 | use std::str::FromStr;
|
263 | 312 | use wasm_bindgen_test::wasm_bindgen_test;
|
264 | 313 |
|
@@ -366,4 +415,25 @@ mod tests {
|
366 | 415 | assert_eq!(owned_records.len(), 1, "Only one owned record should be returned");
|
367 | 416 | assert_eq!(owned_records[0].to_string(), OWNER_CIPHERTEXT, "Owned record should match the owner's ciphertext");
|
368 | 417 | }
|
| 418 | + |
| 419 | + #[wasm_bindgen_test] |
| 420 | + fn test_encryption_toolkit_decrypt_record_sender_ciphertext() { |
| 421 | + // Get the private key corresponding to the record. |
| 422 | + let private_key = PrivateKeyNative::from_str(&get_env("PUZZLE_PK")).unwrap(); |
| 423 | + let view_key = ViewKey::from(ViewKeyNative::try_from(private_key).unwrap()); |
| 424 | + |
| 425 | + // Construct the record and the sender ciphertext. |
| 426 | + let record = RecordPlaintext::from_string(CREDITS_RECORD_V1).unwrap(); |
| 427 | + let record_view_key = Field::from_string(CREDITS_RECORD_VIEW_KEY).unwrap(); |
| 428 | + let sender_ciphertext = Field::from_string(CREDITS_SENDER_CIPHERTEXT).unwrap(); |
| 429 | + |
| 430 | + // Decrypt the sender ciphertext using the view and record and ensure it's from the expected address. |
| 431 | + let credits_sender = CREDITS_SENDER_PLAINTEXT.to_string(); |
| 432 | + let sender = EncryptionToolkit::decrypt_sender(&view_key, &record, &sender_ciphertext).unwrap(); |
| 433 | + assert_eq!(sender.to_string(), credits_sender); |
| 434 | + |
| 435 | + // Decrypt the sender ciphertext using only the record view key and ensure it's from the expected address. |
| 436 | + let sender = EncryptionToolkit::decrypt_sender_with_rvk(&record_view_key, &sender_ciphertext).unwrap(); |
| 437 | + assert_eq!(sender.to_string(), credits_sender); |
| 438 | + } |
369 | 439 | }
|
0 commit comments