diff --git a/CHANGELOG.md b/CHANGELOG.md index b4fe0134..51ce9e45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `serde` support for types is now gated under the `serde-support` feature (not enabled by default). ([#82]) +### Added + +- `KeyFrag::skip_verification()`, `VerifiedKeyFrag::to_unverified()`, `CapsuleFrag::skip_verification()`, `VerifiedCapsuleFrag::to_unverified()`, and +the corresponding methods in Python and WASM bindings. ([#84]) + + [#82]: https://github.com/nucypher/rust-umbral/pull/82 +[#84]: https://github.com/nucypher/rust-umbral/pull/84 ## [0.3.3] - 2021-12-10 diff --git a/umbral-pre-python/docs/index.rst b/umbral-pre-python/docs/index.rst index 6757b2ee..86ca5eaa 100644 --- a/umbral-pre-python/docs/index.rst +++ b/umbral-pre-python/docs/index.rst @@ -190,6 +190,15 @@ API reference Verifies the integrity of the fragment using the signing key and, optionally, the delegating and the receiving keys (if they were included in the signature in :py:func:`generate_kfrags`). + .. py:method:: skip_verification() -> VerifiedKeyFrag: + + Explicitly skips verification. + Useful in cases when the verifying keys are impossible to obtain independently. + + .. warning:: + + Make sure you considered the implications of not enforcing verification. + .. py:method:: __bytes__() -> bytes Serializes the object into a bytestring. @@ -218,6 +227,11 @@ API reference Intended for internal storage; make sure that the bytes come from a trusted source. + .. py:method:: to_unverified() -> KeyFrag: + + Clears the verification status from the keyfrag. + Useful for the cases where it needs to be put in the protocol structure containing :py:class:`KeyFrag` types (since those are the ones that can be serialized/deserialized freely). + .. py:method:: __bytes__() -> bytes Serializes the object into a bytestring. @@ -234,6 +248,15 @@ API reference Verifies the integrity of the fragment. + .. py:method:: skip_verification() -> VerifiedCapsuleFrag: + + Explicitly skips verification. + Useful in cases when the verifying keys are impossible to obtain independently. + + .. warning:: + + Make sure you considered the implications of not enforcing verification. + .. py:method:: __bytes__() -> bytes Serializes the object into a bytestring. @@ -262,6 +285,11 @@ API reference Intended for internal storage; make sure that the bytes come from a trusted source. + .. py:method:: to_unverified() -> KeyFrag: + + Clears the verification status from the capsule frag. + Useful for the cases where it needs to be put in the protocol structure containing :py:class:`CapsuleFrag` types (since those are the ones that can be serialized/deserialized freely). + .. py:method:: __bytes__() -> bytes Serializes the object into a bytestring. diff --git a/umbral-pre-python/src/lib.rs b/umbral-pre-python/src/lib.rs index 368c58b0..acdc5e6a 100644 --- a/umbral-pre-python/src/lib.rs +++ b/umbral-pre-python/src/lib.rs @@ -482,6 +482,12 @@ impl KeyFrag { }) } + pub fn skip_verification(&self) -> VerifiedKeyFrag { + VerifiedKeyFrag { + backend: self.backend.clone().skip_verification(), + } + } + #[staticmethod] pub fn from_bytes(data: &[u8]) -> PyResult { from_bytes(data) @@ -538,6 +544,12 @@ impl VerifiedKeyFrag { umbral_pre::VerifiedKeyFrag::serialized_size() } + pub fn to_unverified(&self) -> KeyFrag { + KeyFrag { + backend: self.backend.to_unverified(), + } + } + fn __bytes__(&self) -> PyResult { to_bytes(self) } @@ -626,6 +638,12 @@ impl CapsuleFrag { }) } + pub fn skip_verification(&self) -> VerifiedCapsuleFrag { + VerifiedCapsuleFrag { + backend: self.backend.clone().skip_verification(), + } + } + #[staticmethod] pub fn from_bytes(data: &[u8]) -> PyResult { from_bytes(data) @@ -697,6 +715,12 @@ impl VerifiedCapsuleFrag { umbral_pre::VerifiedCapsuleFrag::serialized_size() } + pub fn to_unverified(&self) -> CapsuleFrag { + CapsuleFrag { + backend: self.backend.to_unverified(), + } + } + fn __bytes__(&self) -> PyResult { to_bytes(self) } diff --git a/umbral-pre-python/umbral_pre/__init__.pyi b/umbral-pre-python/umbral_pre/__init__.pyi index a833c8d3..5cdf827b 100644 --- a/umbral-pre-python/umbral_pre/__init__.pyi +++ b/umbral-pre-python/umbral_pre/__init__.pyi @@ -116,6 +116,9 @@ class KeyFrag: ) -> VerifiedKeyFrag: ... + def skip_verification(self) -> VerifiedKeyFrag: + ... + @staticmethod def from_bytes() -> KeyFrag: ... @@ -130,6 +133,9 @@ class VerifiedKeyFrag: def from_verified_bytes(data: bytes) -> VerifiedKeyFrag: ... + def to_unverified(self) -> KeyFrag: + ... + @staticmethod def serialized_size() -> int: ... @@ -158,6 +164,9 @@ class CapsuleFrag: ) -> VerifiedCapsuleFrag: ... + def skip_verification(self) -> VerifiedCapsuleFrag: + ... + @staticmethod def from_bytes() -> CapsuleFrag: ... @@ -172,6 +181,9 @@ class VerifiedCapsuleFrag: def from_verified_bytes(data: bytes) -> VerifiedCapsuleFrag: ... + def to_unverified(self) -> CapsuleFrag: + ... + @staticmethod def serialized_size() -> int: ... diff --git a/umbral-pre-wasm/src/lib.rs b/umbral-pre-wasm/src/lib.rs index 09008c2c..8941be05 100644 --- a/umbral-pre-wasm/src/lib.rs +++ b/umbral-pre-wasm/src/lib.rs @@ -267,6 +267,11 @@ impl CapsuleFrag { .map_err(map_js_err) } + #[wasm_bindgen(js_name = skipVerification)] + pub fn skip_verification(&self) -> VerifiedCapsuleFrag { + VerifiedCapsuleFrag(self.0.clone().skip_verification()) + } + #[wasm_bindgen(js_name = toBytes)] pub fn to_bytes(&self) -> Box<[u8]> { self.0.to_array().to_vec().into_boxed_slice() @@ -303,6 +308,11 @@ impl VerifiedCapsuleFrag { .map_err(map_js_err) } + #[wasm_bindgen(js_name = toUnverified)] + pub fn to_unverified(&self) -> CapsuleFrag { + CapsuleFrag(self.0.to_unverified()) + } + #[wasm_bindgen(js_name = toBytes)] pub fn to_bytes(&self) -> Box<[u8]> { self.0.to_array().to_vec().into_boxed_slice() @@ -462,6 +472,11 @@ impl KeyFrag { .map_err(map_js_err) } + #[wasm_bindgen(js_name = skipVerification)] + pub fn skip_verification(&self) -> VerifiedKeyFrag { + VerifiedKeyFrag(self.0.clone().skip_verification()) + } + #[wasm_bindgen(js_name = toBytes)] pub fn to_bytes(&self) -> Box<[u8]> { self.0.to_array().to_vec().into_boxed_slice() @@ -497,6 +512,11 @@ impl VerifiedKeyFrag { .map_err(map_js_err) } + #[wasm_bindgen(js_name = toUnverified)] + pub fn to_unverified(&self) -> KeyFrag { + KeyFrag(self.0.to_unverified()) + } + #[wasm_bindgen(js_name = toBytes)] pub fn to_bytes(&self) -> Box<[u8]> { self.0.to_array().to_vec().into_boxed_slice() diff --git a/umbral-pre/bench/bench.rs b/umbral-pre/bench/bench.rs index e3c6800b..508b5838 100644 --- a/umbral-pre/bench/bench.rs +++ b/umbral-pre/bench/bench.rs @@ -3,8 +3,7 @@ use criterion::{criterion_group, criterion_main, BenchmarkGroup, Criterion}; #[cfg(feature = "bench-internals")] use umbral_pre::bench::{ - capsule_from_public_key, capsule_open_original, capsule_open_reencrypted, get_cfrag, - unsafe_hash_to_point, + capsule_from_public_key, capsule_open_original, capsule_open_reencrypted, unsafe_hash_to_point, }; use umbral_pre::{ @@ -74,7 +73,7 @@ fn bench_capsule_open_reencrypted<'a, M: Measurement>(group: &mut BenchmarkGroup let cfrags: Vec<_> = vcfrags[0..threshold] .iter() - .map(|vcfrag| get_cfrag(&vcfrag).clone()) + .map(|vcfrag| vcfrag.to_unverified()) .collect(); group.bench_function("Capsule::open_reencrypted", |b| { diff --git a/umbral-pre/src/bench.rs b/umbral-pre/src/bench.rs index cb990f22..90b5ef19 100644 --- a/umbral-pre/src/bench.rs +++ b/umbral-pre/src/bench.rs @@ -5,7 +5,7 @@ use rand_core::OsRng; use crate::capsule::{Capsule, KeySeed, OpenReencryptedError}; -use crate::capsule_frag::{CapsuleFrag, VerifiedCapsuleFrag}; +use crate::capsule_frag::CapsuleFrag; use crate::keys::{PublicKey, SecretKey}; use crate::secret_box::SecretBox; @@ -30,8 +30,3 @@ pub fn capsule_open_reencrypted( ) -> Result, OpenReencryptedError> { capsule.open_reencrypted(receiving_sk, delegating_pk, cfrags) } - -/// Extracts the internal [`CapsuleFrag`] from a [`VerifiedCapsuleFrag`]. -pub fn get_cfrag(verified_cfrag: &VerifiedCapsuleFrag) -> &CapsuleFrag { - &verified_cfrag.cfrag -} diff --git a/umbral-pre/src/capsule.rs b/umbral-pre/src/capsule.rs index 532d8ee6..a9b35261 100644 --- a/umbral-pre/src/capsule.rs +++ b/umbral-pre/src/capsule.rs @@ -316,7 +316,10 @@ mod tests { .map(|kfrag| reencrypt(&capsule, &kfrag)) .collect(); - let cfrags: Vec<_> = vcfrags.iter().cloned().map(|vcfrag| vcfrag.cfrag).collect(); + let cfrags: Vec<_> = vcfrags + .iter() + .map(|vcfrag| vcfrag.to_unverified()) + .collect(); let key_seed_reenc = capsule .open_reencrypted(&receiving_sk, &delegating_pk, &cfrags) @@ -342,7 +345,7 @@ mod tests { .iter() .cloned() .chain(vcfrags2[1..2].iter().cloned()) - .map(|vcfrag| vcfrag.cfrag) + .map(|vcfrag| vcfrag.to_unverified()) .collect(); let result = capsule.open_reencrypted(&receiving_sk, &delegating_pk, &mismatched_cfrags); diff --git a/umbral-pre/src/capsule_frag.rs b/umbral-pre/src/capsule_frag.rs index 3c156fbf..5bca84cb 100644 --- a/umbral-pre/src/capsule_frag.rs +++ b/umbral-pre/src/capsule_frag.rs @@ -297,14 +297,22 @@ impl CapsuleFrag { cfrag: self.clone(), }) } + + /// Explicitly skips verification. + /// Useful in cases when the verifying keys are impossible to obtain independently. + /// + /// **Warning:** make sure you considered the implications of not enforcing verification. + pub fn skip_verification(self) -> VerifiedCapsuleFrag { + VerifiedCapsuleFrag { cfrag: self } + } } /// Verified capsule fragment, good for dencryption. /// Can be serialized, but cannot be deserialized directly. -/// It can only be obtained from [`CapsuleFrag::verify`]. +/// It can only be obtained from [`CapsuleFrag::verify`] or [`CapsuleFrag::skip_verification`]. #[derive(Debug, Clone, PartialEq)] pub struct VerifiedCapsuleFrag { - pub(crate) cfrag: CapsuleFrag, + cfrag: CapsuleFrag, } impl RepresentableAsArray for VerifiedCapsuleFrag { @@ -348,6 +356,14 @@ impl VerifiedCapsuleFrag { pub fn from_verified_bytes(data: impl AsRef<[u8]>) -> Result { CapsuleFrag::from_bytes(data).map(|cfrag| Self { cfrag }) } + + /// Clears the verification status from the capsule frag. + /// Useful for the cases where it needs to be put in the protocol structure + /// containing [`CapsuleFrag`] types (since those are the ones + /// that can be serialized/deserialized freely). + pub fn to_unverified(&self) -> CapsuleFrag { + self.cfrag.clone() + } } #[cfg(test)] diff --git a/umbral-pre/src/key_frag.rs b/umbral-pre/src/key_frag.rs index 345af232..894c1d2d 100644 --- a/umbral-pre/src/key_frag.rs +++ b/umbral-pre/src/key_frag.rs @@ -363,14 +363,22 @@ impl KeyFrag { kfrag: self.clone(), }) } + + /// Explicitly skips verification. + /// Useful in cases when the verifying keys are impossible to obtain independently. + /// + /// **Warning:** make sure you considered the implications of not enforcing verification. + pub fn skip_verification(self) -> VerifiedKeyFrag { + VerifiedKeyFrag { kfrag: self } + } } /// Verified key fragment, good for reencryption. /// Can be serialized, but cannot be deserialized directly. -/// It can only be obtained from [`KeyFrag::verify`]. +/// It can only be obtained from [`KeyFrag::verify`] or [`KeyFrag::skip_verification`]. #[derive(Debug, Clone, PartialEq)] pub struct VerifiedKeyFrag { - pub(crate) kfrag: KeyFrag, + kfrag: KeyFrag, } impl RepresentableAsArray for VerifiedKeyFrag { @@ -415,6 +423,14 @@ impl VerifiedKeyFrag { pub fn from_verified_bytes(data: impl AsRef<[u8]>) -> Result { KeyFrag::from_bytes(data).map(|kfrag| Self { kfrag }) } + + /// Clears the verification status from the keyfrag. + /// Useful for the cases where it needs to be put in the protocol structure + /// containing [`KeyFrag`] types (since those are the ones + /// that can be serialized/deserialized freely). + pub fn to_unverified(&self) -> KeyFrag { + self.kfrag.clone() + } } pub(crate) struct KeyFragBase { diff --git a/umbral-pre/src/pre.rs b/umbral-pre/src/pre.rs index 971eaadd..0c87235f 100644 --- a/umbral-pre/src/pre.rs +++ b/umbral-pre/src/pre.rs @@ -150,7 +150,8 @@ pub fn reencrypt_with_rng( capsule: &Capsule, verified_kfrag: &VerifiedKeyFrag, ) -> VerifiedCapsuleFrag { - VerifiedCapsuleFrag::reencrypted(rng, capsule, &verified_kfrag.kfrag) + let kfrag = verified_kfrag.to_unverified(); + VerifiedCapsuleFrag::reencrypted(rng, capsule, &kfrag) } /// A synonym for [`reencrypt_with_rng`] with the default RNG. @@ -179,8 +180,7 @@ pub fn decrypt_reencrypted( ) -> Result, ReencryptionError> { let cfrags: Vec<_> = verified_cfrags .iter() - .cloned() - .map(|vcfrag| vcfrag.cfrag) + .map(|vcfrag| vcfrag.to_unverified()) .collect(); let key_seed = capsule .open_reencrypted(receiving_sk, delegating_pk, &cfrags)