diff --git a/nucypher-core-wasm/Cargo.toml b/nucypher-core-wasm/Cargo.toml index 21a68a99..be96ec77 100644 --- a/nucypher-core-wasm/Cargo.toml +++ b/nucypher-core-wasm/Cargo.toml @@ -24,3 +24,6 @@ wee_alloc = "0.4" ethereum-types = "0.12.1" serde-wasm-bindgen = "0.3.1" serde = { version = "1.0.130", feat = ["derive"] } + +[dev-dependencies] +wasm-bindgen-test = "0.3.17" \ No newline at end of file diff --git a/nucypher-core-wasm/src/lib.rs b/nucypher-core-wasm/src/lib.rs index 4f749abc..955d700c 100644 --- a/nucypher-core-wasm/src/lib.rs +++ b/nucypher-core-wasm/src/lib.rs @@ -6,7 +6,7 @@ extern crate wee_alloc; static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; extern crate alloc; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use alloc::{ boxed::Box, @@ -56,6 +56,7 @@ where // #[wasm_bindgen] +#[derive(PartialEq, Debug)] pub struct MessageKit { backend: nucypher_core::MessageKit, } @@ -94,13 +95,9 @@ impl MessageKit { ) -> Result, JsValue> { let cfrags: Vec = cfrags .into_serde() - .map_err(map_js_err) .unwrap_or_else(|_| panic!("cfrags must be an array of VerifiedCapsuleFrag")); - let backend_cfrags: Vec = cfrags - .iter() - .cloned() - .map(|vcfrag| vcfrag.inner().clone()) - .collect(); + let backend_cfrags: Vec = + cfrags.iter().map(|vcfrag| vcfrag.inner().clone()).collect(); self.backend .decrypt_reencrypted(sk.inner(), policy_encrypting_key.inner(), &backend_cfrags) @@ -139,6 +136,12 @@ impl AsBackend for HRAC { } } +impl FromBackend for HRAC { + fn from_backend(backend: nucypher_core::HRAC) -> Self { + Self { backend } + } +} + #[wasm_bindgen] impl HRAC { #[wasm_bindgen(constructor)] @@ -156,6 +159,11 @@ impl HRAC { } } + #[wasm_bindgen(js_name = fromBytes)] + pub fn from_bytes(data: &[u8]) -> Result { + from_bytes(data) + } + #[wasm_bindgen(js_name = toBytes)] pub fn to_bytes(&self) -> Box<[u8]> { to_bytes(self) @@ -173,6 +181,7 @@ impl HRAC { // #[wasm_bindgen] +#[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct EncryptedKeyFrag { backend: nucypher_core::EncryptedKeyFrag, } @@ -192,7 +201,7 @@ impl FromBackend for EncryptedKeyFrag { #[wasm_bindgen] impl EncryptedKeyFrag { #[wasm_bindgen(constructor)] - pub fn constructor( + pub fn new( signer: &Signer, recipient_key: &PublicKey, hrac: &HRAC, @@ -205,7 +214,7 @@ impl EncryptedKeyFrag { verified_kfrag.inner(), ) .map_err(map_js_err) - .map(Self::new) + .map(|ekfrag| EncryptedKeyFrag { backend: ekfrag }) } pub fn decrypt( @@ -217,8 +226,8 @@ impl EncryptedKeyFrag { self.backend .decrypt(sk.inner(), &hrac.inner(), publisher_verifying_key.inner()) .ok_or("Decryption failed") - .map(VerifiedKeyFrag::new) .map_err(map_js_err) + .map(VerifiedKeyFrag::new) } #[wasm_bindgen(js_name = fromBytes)] @@ -233,10 +242,6 @@ impl EncryptedKeyFrag { } impl EncryptedKeyFrag { - pub fn new(ekfrag: nucypher_core::EncryptedKeyFrag) -> EncryptedKeyFrag { - EncryptedKeyFrag { backend: ekfrag } - } - pub fn inner(&self) -> nucypher_core::EncryptedKeyFrag { self.backend.clone() } @@ -252,19 +257,25 @@ pub struct Address(ethereum_types::Address); #[wasm_bindgen] impl Address { - #[wasm_bindgen( js_name = fromChecksumAddress)] + #[wasm_bindgen(js_name = fromChecksumAddress)] pub fn from_checksum_address(checksum_address: &str) -> Self { // TODO: Check length of checksum_address Address(nucypher_core::to_canonical_address(checksum_address).unwrap()) } } +impl Address { + pub fn as_string(&self) -> String { + self.0.to_string() + } +} + // // TreasureMap // #[wasm_bindgen] -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Debug)] pub struct TreasureMap { backend: nucypher_core::TreasureMap, } @@ -301,7 +312,7 @@ impl TreasureMap { .map(|(address, (key, vkfrag))| { ( ethereum_types::Address::from_slice(address.as_bytes()), - *key.inner(), + key.inner().clone(), vkfrag.inner().clone(), ) }) @@ -325,20 +336,22 @@ impl TreasureMap { } } - // #[wasm_bindgen(method, getter)] - // pub fn destinations(&self) -> Vec<(Address, EncryptedKeyFrag)> { - // let mut result = Vec::new(); - // for (address, ekfrag) in &self.backend.destinations { - // let address_bytes = address.as_ref(); - // result.push(( - // address_bytes, - // EncryptedKeyFrag { - // backend: ekfrag.clone(), - // }, - // )); - // } - // result - // } + #[wasm_bindgen(method, getter)] + pub fn destinations(&self) -> Result { + let mut result = Vec::new(); + for (address, ekfrag) in &self.backend.destinations { + // Using String here to avoid issue where Deserialize is not implemented + // for every possible lifetime. + let address = String::from(from_canonical(address)); + result.push(( + address, + EncryptedKeyFrag { + backend: ekfrag.clone(), + }, + )); + } + Ok(serde_wasm_bindgen::to_value(&result)?) + } #[wasm_bindgen(method, getter)] pub fn hrac(&self) -> HRAC { @@ -374,6 +387,7 @@ impl TreasureMap { } #[wasm_bindgen] +#[derive(PartialEq, Debug)] pub struct EncryptedTreasureMap { backend: nucypher_core::EncryptedTreasureMap, } @@ -422,6 +436,7 @@ impl EncryptedTreasureMap { // #[wasm_bindgen] +#[derive(PartialEq, Debug)] pub struct ReencryptionRequest { backend: nucypher_core::ReencryptionRequest, } @@ -484,7 +499,9 @@ impl ReencryptionRequest { #[wasm_bindgen(method, getter)] pub fn encrypted_kfrag(&self) -> EncryptedKeyFrag { - EncryptedKeyFrag::new(self.backend.encrypted_kfrag.clone()) + EncryptedKeyFrag { + backend: self.backend.encrypted_kfrag.clone(), + } } #[wasm_bindgen(method, getter)] @@ -540,13 +557,13 @@ impl ReencryptionResponse { #[wasm_bindgen(constructor)] pub fn new( signer: &Signer, - capsules: JsValue, - vcfrags: JsValue, + capsules: &JsValue, + verified_capsule_frags: &JsValue, ) -> Result { let capsules: Vec = - serde_wasm_bindgen::from_value(capsules).map_err(map_js_err)?; + serde_wasm_bindgen::from_value(capsules.clone()).map_err(map_js_err)?; let vcfrags: Vec = - serde_wasm_bindgen::from_value(vcfrags).map_err(map_js_err)?; + serde_wasm_bindgen::from_value(verified_capsule_frags.clone()).map_err(map_js_err)?; let capsules_backend = capsules .iter() @@ -565,17 +582,16 @@ impl ReencryptionResponse { }) } - #[wasm_bindgen] pub fn verify( &self, - capsules: JsValue, + capsules: &JsValue, alice_verifying_key: &PublicKey, ursula_verifying_key: &PublicKey, policy_encrypting_key: &PublicKey, bob_encrypting_key: &PublicKey, ) -> Result { let capsules: Vec = - serde_wasm_bindgen::from_value(capsules).map_err(map_js_err)?; + serde_wasm_bindgen::from_value(capsules.clone()).map_err(map_js_err)?; let capsules_backend = capsules .iter() .map(|capsule| *capsule.inner()) @@ -640,8 +656,6 @@ impl RetrievalKit { } } - // TODO: wasm-bindgen-cli throws here - #[wasm_bindgen(constructor)] pub fn new(capsule: &Capsule, queried_addresses: JsValue) -> Result { // Using String here to avoid issue where Deserialize is not implemented @@ -663,13 +677,12 @@ impl RetrievalKit { } #[wasm_bindgen(method, getter)] - pub fn queried_addresses(&self) -> Option> { - self.backend.queried_addresses.as_ref().map(|addresses| { - addresses - .iter() - .map(|address| JsValue::from_serde(&address).unwrap()) - .collect::>() - }) + pub fn queried_addresses(&self) -> Vec { + self.backend + .queried_addresses + .iter() + .map(|address| JsValue::from_serde(&address).unwrap()) + .collect::>() } #[wasm_bindgen(js_name = fromBytes)] @@ -739,6 +752,11 @@ impl RevocationOrder { // NodeMetadataPayload // +// TODO: Find a way to avoid this conversion? +pub fn from_canonical(data: ðereum_types::H160) -> &str { + core::str::from_utf8(&data[..]).unwrap() +} + #[wasm_bindgen] pub struct NodeMetadataPayload { backend: nucypher_core::NodeMetadataPayload, @@ -779,10 +797,7 @@ impl NodeMetadataPayload { #[wasm_bindgen(method, getter)] pub fn canonical_address(&self) -> Address { - Address::from_checksum_address( - // TODO: Find a way to avoid this conversion? - core::str::from_utf8(&self.backend.canonical_address[..]).unwrap(), - ) + Address::from_checksum_address(from_canonical(&self.backend.canonical_address)) } #[wasm_bindgen(method, getter)] @@ -831,7 +846,7 @@ impl NodeMetadataPayload { // #[wasm_bindgen(method, getter)] -#[derive(Clone, Deserialize)] +#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] pub struct NodeMetadata { backend: nucypher_core::NodeMetadata, } @@ -894,6 +909,12 @@ impl AsBackend for FleetStateChecksum { } } +impl FromBackend for FleetStateChecksum { + fn from_backend(backend: nucypher_core::FleetStateChecksum) -> Self { + Self { backend } + } +} + #[wasm_bindgen] impl FleetStateChecksum { #[wasm_bindgen(constructor)] @@ -917,6 +938,11 @@ impl FleetStateChecksum { }) } + #[wasm_bindgen(js_name = fromBytes)] + pub fn from_bytes(data: &[u8]) -> Result { + from_bytes(data) + } + #[wasm_bindgen(js_name = toBytes)] pub fn to_bytes(&self) -> Box<[u8]> { to_bytes(self) diff --git a/nucypher-core-wasm/tests/wasm.rs b/nucypher-core-wasm/tests/wasm.rs new file mode 100644 index 00000000..5f75ac0d --- /dev/null +++ b/nucypher-core-wasm/tests/wasm.rs @@ -0,0 +1,558 @@ +use std::collections::BTreeMap; + +use nucypher_core_wasm::*; + +use umbral_pre::bindings_wasm::*; +use wasm_bindgen::convert::FromWasmAbi; +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::*; + +// +// Test utilities +// + +// Downcast a WASM type to a Rust type +// Reference: https://github.com/rustwasm/wasm-bindgen/issues/2231 +fn generic_of_jsval>(js: JsValue, classname: &str) -> Result { + use js_sys::{Object, Reflect}; + let ctor_name = Object::get_prototype_of(&js).constructor().name(); + if ctor_name == classname { + let ptr = Reflect::get(&js, &JsValue::from_str("ptr"))?; + let ptr_u32: u32 = ptr.as_f64().ok_or(JsValue::NULL)? as u32; + let foo = unsafe { T::from_abi(ptr_u32) }; + Ok(foo) + } else { + Err(JsValue::NULL) + } +} + +#[wasm_bindgen] +pub fn verified_key_frag_of_jsval(js: JsValue) -> Option { + generic_of_jsval(js, "VerifiedKeyFrag").unwrap_or(None) +} + +#[wasm_bindgen] +pub fn node_metadata_of_jsval(js: JsValue) -> Option { + generic_of_jsval(js, "NodeMetadata").unwrap_or(None) +} + +// +// MessageKit +// + +#[wasm_bindgen_test] +fn message_kit_decrypts() { + let sk = SecretKey::random(); + let policy_encrypting_key = sk.public_key(); + let plaintext = "Hello, world!".as_bytes(); + let message_kit = MessageKit::new(&policy_encrypting_key, plaintext).unwrap(); + + let decrypted = message_kit.decrypt(&sk).unwrap().to_vec(); + assert_eq!(decrypted, plaintext); +} + +#[wasm_bindgen_test] +fn message_kit_decrypt_reencrypted() { + // Create a message kit + let delegating_sk = SecretKey::random(); + let delegating_pk = delegating_sk.public_key(); + let plaintext = "Hello, world!".as_bytes(); + let message_kit = MessageKit::new(&delegating_pk, plaintext).unwrap(); + + // Create key fragments for reencryption + let receiving_sk = SecretKey::random(); + let receiving_pk = receiving_sk.public_key(); + let verified_kfrags = generate_kfrags( + &delegating_sk, + &receiving_pk, + &Signer::new(&delegating_sk), + 2, + 3, + false, + false, + ); + + // Simulate reencryption on the JS side + let cfrags: Vec = verified_kfrags + .iter() + .map(|kfrag| { + let kfrag = verified_key_frag_of_jsval(kfrag.clone()).unwrap(); + let cfrag = umbral_pre::reencrypt(&message_kit.capsule().inner(), &kfrag.inner()); + VerifiedCapsuleFrag::new(cfrag) + }) + .collect(); + let cfrags = serde_wasm_bindgen::to_value(&cfrags).unwrap(); + + // Decrypt on the Rust side + message_kit + .decrypt_reencrypted(&receiving_sk, &delegating_pk, &cfrags) + .unwrap(); +} + +#[wasm_bindgen_test] +fn message_kit_to_bytes_from_bytes() { + let sk = SecretKey::random(); + let policy_encrypting_key = sk.public_key(); + let plaintext = "Hello, world!".as_bytes(); + + let message_kit = MessageKit::new(&policy_encrypting_key, plaintext).unwrap(); + + assert_eq!( + message_kit, + MessageKit::from_bytes(&message_kit.to_bytes()).unwrap() + ); +} + +// +// HRAC +// + +fn make_hrac() -> HRAC { + let publisher_verifying_key = SecretKey::random().public_key(); + let bob_verifying_key = SecretKey::random().public_key(); + let label = "Hello, world!".as_bytes(); + let hrac = HRAC::new(&publisher_verifying_key, &bob_verifying_key, label); + hrac +} + +#[wasm_bindgen_test] +fn hrac_to_bytes_from_bytes() { + let hrac = make_hrac(); + + assert_eq!( + hrac.to_bytes(), + HRAC::from_bytes(&hrac.to_bytes()).unwrap().to_bytes() + ); +} + +// +// EncryptedKeyFrag +// + +fn make_kfrags(delegating_sk: &SecretKey, receiving_sk: &SecretKey) -> Vec { + let receiving_pk = receiving_sk.public_key(); + let signer = Signer::new(&delegating_sk); + let verified_kfrags: Vec = + generate_kfrags(&delegating_sk, &receiving_pk, &signer, 2, 3, false, false) + .iter() + .map(|kfrag| verified_key_frag_of_jsval(kfrag.clone()).unwrap()) + .collect(); + verified_kfrags +} + +#[wasm_bindgen_test] +fn encrypted_kfrag_decrypt() { + let hrac = make_hrac(); + let delegating_sk = SecretKey::random(); + let delegating_pk = delegating_sk.public_key(); + let receiving_sk = SecretKey::random(); + let receiving_pk = receiving_sk.public_key(); + let signer = Signer::new(&delegating_sk); + + let verified_kfrags = make_kfrags(&delegating_sk, &receiving_sk); + + let encrypted_kfrag = + EncryptedKeyFrag::new(&signer, &receiving_pk, &hrac, &verified_kfrags[0]).unwrap(); + + let decrypted = encrypted_kfrag + .decrypt(&receiving_sk, &hrac, &delegating_pk) + .unwrap(); + assert_eq!(decrypted.to_bytes(), verified_kfrags[0].to_bytes()); +} + +#[wasm_bindgen_test] +fn encrypted_to_bytes_from_bytes() { + let hrac = make_hrac(); + let delegating_sk = SecretKey::random(); + let receiving_sk = SecretKey::random(); + let receiving_pk = receiving_sk.public_key(); + let signer = Signer::new(&delegating_sk); + + let verified_kfrags = make_kfrags(&delegating_sk, &receiving_sk); + let encrypted_kfrag = + EncryptedKeyFrag::new(&signer, &receiving_pk, &hrac, &verified_kfrags[0]).unwrap(); + + assert_eq!( + encrypted_kfrag, + EncryptedKeyFrag::from_bytes(&encrypted_kfrag.to_bytes()).unwrap() + ); +} + +// +// Address +// + +#[wasm_bindgen_test] +fn address_from_checksum_address() { + let address = Address::from_checksum_address("0x0000000000000000000000000000000000000001"); + assert_eq!(address.as_string(), "0x0000…0001"); +} + +// +// TreasureMap +// + +fn make_assigned_kfrags( + verified_kfrags: Vec, +) -> BTreeMap { + let mut assigned_kfrags: BTreeMap = BTreeMap::new(); + assigned_kfrags.insert( + "00000000000000000001".to_string(), + (SecretKey::random().public_key(), verified_kfrags[0].clone()), + ); + assigned_kfrags.insert( + "00000000000000000002".to_string(), + (SecretKey::random().public_key(), verified_kfrags[1].clone()), + ); + assigned_kfrags.insert( + "00000000000000000003".to_string(), + (SecretKey::random().public_key(), verified_kfrags[2].clone()), + ); + assigned_kfrags +} + +fn make_treasure_map(publisher_sk: &SecretKey, receiving_sk: &SecretKey) -> TreasureMap { + let hrac = make_hrac(); + let verified_kfrags = make_kfrags(&publisher_sk, &receiving_sk); + + let assigned_kfrags = make_assigned_kfrags(verified_kfrags); + + TreasureMap::new( + &Signer::new(&publisher_sk), + &hrac, + &SecretKey::random().public_key(), + serde_wasm_bindgen::to_value(&assigned_kfrags).unwrap(), + 2, + ) + .unwrap() +} + +#[wasm_bindgen_test] +fn treasure_map_encrypt_decrypt() { + let publisher_sk = SecretKey::random(); + let receiving_sk = SecretKey::random(); + + let treasure_map = make_treasure_map(&publisher_sk, &receiving_sk); + + let publisher_pk = publisher_sk.public_key(); + let recipient_pk = receiving_sk.public_key(); + let signer = Signer::new(&publisher_sk); + let encrypted = treasure_map.encrypt(&signer, &recipient_pk); + + let decrypted = encrypted.decrypt(&receiving_sk, &publisher_pk).unwrap(); + + assert_eq!(decrypted, treasure_map) +} + +#[wasm_bindgen_test] +fn treasure_map_destinations() { + let publisher_sk = SecretKey::random(); + let receiving_sk = SecretKey::random(); + + let treasure_map = make_treasure_map(&publisher_sk, &receiving_sk); + let destinations = treasure_map.destinations().unwrap(); + let destinations: Vec<(String, EncryptedKeyFrag)> = + serde_wasm_bindgen::from_value(destinations).unwrap(); + + assert!(destinations.len() == 3); + assert_eq!(destinations[0].0, "00000000000000000001".to_string()); + assert_eq!(destinations[1].0, "00000000000000000002".to_string()); + assert_eq!(destinations[2].0, "00000000000000000003".to_string()); +} + +#[wasm_bindgen_test] +fn encrypted_treasure_map_from_bytes_to_bytes() { + let publisher_sk = SecretKey::random(); + let receiving_sk = SecretKey::random(); + let treasure_map = make_treasure_map(&publisher_sk, &receiving_sk); + + let encrypted = treasure_map.encrypt(&Signer::new(&publisher_sk), &receiving_sk.public_key()); + + assert_eq!( + encrypted, + EncryptedTreasureMap::from_bytes(&encrypted.to_bytes()).unwrap() + ); +} + +// +// ReencryptionRequest +// + +#[wasm_bindgen_test] +fn reencruption_request_from_bytes_to_bytes() { + let ursula_address = "00000000000000000001".as_bytes(); + + let publisher_sk = SecretKey::random(); + let receiving_sk = SecretKey::random(); + let treasure_map = make_treasure_map(&publisher_sk, &receiving_sk); + + let policy_encrypting_key = publisher_sk.public_key(); + let plaintext = "Hello, world!".as_bytes(); + let message_kit = MessageKit::new(&policy_encrypting_key, plaintext).unwrap(); + let capsule = message_kit.capsule(); + let capsules = serde_wasm_bindgen::to_value(&vec![capsule]).unwrap(); + + let reencryption_request = ReencryptionRequest::new( + ursula_address, + capsules, + &treasure_map, + &receiving_sk.public_key(), + ) + .unwrap(); + + assert_eq!( + reencryption_request, + ReencryptionRequest::from_bytes(&reencryption_request.to_bytes()).unwrap() + ) +} + +// +// ReencryptionResponse +// + +#[wasm_bindgen_test] +fn reencryption_response_verify() { + // Make capsules + let alice_sk = SecretKey::random(); + let policy_encrypting_key = alice_sk.public_key(); + let plaintext = "Hello, world!".as_bytes(); + let message_kit = MessageKit::new(&policy_encrypting_key, plaintext).unwrap(); + let capsule = message_kit.capsule(); + let capsules = &vec![capsule, capsule, capsule]; + let capsules_js = serde_wasm_bindgen::to_value(capsules).unwrap(); + + // Make verified key fragments + let bob_sk = SecretKey::random(); + let kfrags = make_kfrags(&alice_sk, &bob_sk); + + assert_eq!(capsules.len(), kfrags.len()); + + // Simulate the reencryption + let cfrags: Vec = kfrags + .iter() + .map(|kfrag| reencrypt(&capsule, kfrag)) + .collect(); + let cfrags_js = serde_wasm_bindgen::to_value(&cfrags).unwrap(); + + let ursula_sk = SecretKey::random(); + let signer = Signer::new(&ursula_sk); + let reencryption_response = + ReencryptionResponse::new(&signer, &capsules_js, &cfrags_js).unwrap(); + + let verified_js = reencryption_response + .verify( + &capsules_js, + &alice_sk.public_key(), + &ursula_sk.public_key(), + &policy_encrypting_key, + &bob_sk.public_key(), + ) + .unwrap(); + let verified: Vec = serde_wasm_bindgen::from_value(verified_js).unwrap(); + + assert_eq!(cfrags, verified); + + let as_bytes = reencryption_response.to_bytes(); + assert_eq!( + as_bytes, + ReencryptionResponse::from_bytes(&as_bytes) + .unwrap() + .to_bytes() + ); +} + +// +// RetrievalKit +// + +#[wasm_bindgen_test] +fn retrieval_kit() { + let alice_sk = SecretKey::random(); + let policy_encrypting_key = alice_sk.public_key(); + let plaintext = "Hello, world!".as_bytes(); + let message_kit = MessageKit::new(&policy_encrypting_key, plaintext).unwrap(); + + let retrieval_kit = RetrievalKit::from_message_kit(&message_kit); + + let queried_addresses = retrieval_kit.queried_addresses(); + assert_eq!(queried_addresses.len(), 0); + + let as_bytes = retrieval_kit.to_bytes(); + assert_eq!( + as_bytes, + RetrievalKit::from_bytes(&as_bytes).unwrap().to_bytes() + ); +} + +// +// RevocationOrder +// + +#[wasm_bindgen_test] +fn revocation_order() { + let delegating_sk = SecretKey::random(); + let receiving_sk = SecretKey::random(); + let verified_kfrags = make_kfrags(&delegating_sk, &receiving_sk); + + let hrac = make_hrac(); + let receiving_pk = receiving_sk.public_key(); + let signer = Signer::new(&delegating_sk); + let encrypted_kfrag = + EncryptedKeyFrag::new(&signer, &receiving_pk, &hrac, &verified_kfrags[0]).unwrap(); + + let ursula_address = "00000000000000000001".as_bytes(); + let revocation_order = RevocationOrder::new(&signer, ursula_address, &encrypted_kfrag); + + assert!(revocation_order.verify_signature(&delegating_sk.public_key())); + + let as_bytes = revocation_order.to_bytes(); + assert_eq!( + as_bytes, + RevocationOrder::from_bytes(&as_bytes).unwrap().to_bytes() + ); +} + +// +// NodeMetadataPayload +// + +// See below for the `NodeMetadata` struct. + +// +// NodeMetadata +// + +fn make_node_metadata() -> NodeMetadata { + let canonical_address = "00000000000000000001".as_bytes(); + let domain = "localhost"; + let timestamp_epoch = 1546300800; + let verifying_key = SecretKey::random().public_key(); + let encrypting_key = SecretKey::random().public_key(); + let certificate_bytes = "certificate_bytes".as_bytes(); + let host = "https://localhost.com"; + let port = 443; + let decentralized_identity_evidence = Some(vec![1, 2, 3]); + + let node_metadata_payload = NodeMetadataPayload::new( + canonical_address, + domain, + timestamp_epoch, + &verifying_key, + &encrypting_key, + certificate_bytes, + host, + port, + decentralized_identity_evidence, + ); + + let signer = Signer::new(&SecretKey::random()); + NodeMetadata::new(&signer, &node_metadata_payload) +} + +#[wasm_bindgen_test] +fn node_metadata() { + let node_metadata = make_node_metadata(); + + let as_bytes = node_metadata.to_bytes(); + assert_eq!( + as_bytes, + NodeMetadata::from_bytes(&as_bytes).unwrap().to_bytes() + ); +} + +// +// FleetStateChecksum +// + +fn make_fleet_state_checksum() -> FleetStateChecksum { + let this_node = Some(make_node_metadata()); + let other_nodes = vec![make_node_metadata(), make_node_metadata()]; + let other_nodes = serde_wasm_bindgen::to_value(&other_nodes).unwrap(); + FleetStateChecksum::new(this_node, other_nodes).unwrap() +} + +#[wasm_bindgen_test] +fn fleet_state_checksum() { + let fleet_state_checksum = make_fleet_state_checksum(); + + let as_bytes = fleet_state_checksum.to_bytes(); + assert_eq!( + as_bytes, + FleetStateChecksum::from_bytes(&as_bytes) + .unwrap() + .to_bytes() + ); +} + +// +// MetadataRequest +// + +#[wasm_bindgen_test] +fn metadata_request() { + let fleet_state_checksum = make_fleet_state_checksum(); + let announce_nodes = vec![make_node_metadata(), make_node_metadata()]; + let announce_nodes_js = serde_wasm_bindgen::to_value(&announce_nodes).unwrap(); + + let metadata_request = MetadataRequest::new(&fleet_state_checksum, announce_nodes_js).unwrap(); + + let nodes_js = metadata_request.announce_nodes(); + let nodes: Vec = nodes_js + .iter() + .cloned() + .map(|js_node| node_metadata_of_jsval(js_node).unwrap()) + .collect::>(); + assert_eq!(nodes, announce_nodes); + + let as_bytes = metadata_request.to_bytes(); + assert_eq!( + as_bytes, + MetadataRequest::from_bytes(&as_bytes).unwrap().to_bytes() + ); +} + +// +// VerifiedMetadataResponse +// + +#[wasm_bindgen_test] +fn verified_metadata_response() { + let announce_nodes = vec![make_node_metadata(), make_node_metadata()]; + let timestamp_epoch = 1546300800; + + let verified_metadata_response = VerifiedMetadataResponse::new( + timestamp_epoch, + serde_wasm_bindgen::to_value(&announce_nodes).unwrap(), + ); + + let nodes_js = verified_metadata_response.announce_nodes(); + let nodes: Vec = nodes_js + .iter() + .cloned() + .map(|js_node| node_metadata_of_jsval(js_node).unwrap()) + .collect::>(); + assert_eq!(nodes, announce_nodes); +} + +// +// MetadataResponse +// + +#[wasm_bindgen_test] +fn metadata_response() { + let announce_nodes = vec![make_node_metadata(), make_node_metadata()]; + let timestamp_epoch = 1546300800; + let verified_metadata_response = VerifiedMetadataResponse::new( + timestamp_epoch, + serde_wasm_bindgen::to_value(&announce_nodes).unwrap(), + ); + let signer = Signer::new(&SecretKey::random()); + + let metadata_response = MetadataResponse::new(&signer, &verified_metadata_response); + + let as_bytes = metadata_response.to_bytes(); + assert_eq!( + as_bytes, + MetadataResponse::from_bytes(&as_bytes).unwrap().to_bytes() + ); +} diff --git a/nucypher-core/src/retrieval_kit.rs b/nucypher-core/src/retrieval_kit.rs index 2f70bf63..dce0183d 100644 --- a/nucypher-core/src/retrieval_kit.rs +++ b/nucypher-core/src/retrieval_kit.rs @@ -16,7 +16,7 @@ pub struct RetrievalKit { pub capsule: Capsule, // TODO: change to a set, find one that works in no-std /// The addresses that have already been queried for reencryption. - pub queried_addresses: Option>, + pub queried_addresses: BTreeSet
, } impl RetrievalKit { @@ -24,7 +24,7 @@ impl RetrievalKit { pub fn from_message_kit(message_kit: &MessageKit) -> Self { Self { capsule: message_kit.capsule, - queried_addresses: None, + queried_addresses: BTreeSet::
::new(), } } @@ -36,7 +36,7 @@ impl RetrievalKit { // Can store cfrags too, if we're worried about Ursulas supplying duplicate ones. Self { capsule: *capsule, - queried_addresses: Some(BTreeSet::from_iter(queried_addresses.cloned())), + queried_addresses: BTreeSet::from_iter(queried_addresses.cloned()), } } }