From f3a03b927e7c9b1287e9bbcaa246e793c8baea19 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Wed, 31 Jul 2024 11:01:27 -0300 Subject: [PATCH 1/3] Allow creating a FullViewingKey from a given SpendValidatingKey Allows creating a FullViewingKey from a given SpendValidatingKey and from the other components which can be randomly generated, but there may be some utility in specifying them too like supporting FROST backup schemes that don't centralize spend authority closes #431 see related #430 PR Suggestions --- CHANGELOG.md | 4 ++++ src/keys.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f487021d3..161f54e95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Added `orchard::keys::FullViewingKey::from_sk_and_ak` under the +`unstable-frost` feature flag +- Added `orchard::keys::FullViewingKey::from_checked_parts` under the +`unstable-frost` feature flag ## [0.9.1] - 2024-08-13 diff --git a/src/keys.rs b/src/keys.rs index f66928eeb..1a6ed5351 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -225,6 +225,7 @@ impl SpendValidatingKey { /// [`Note`]: crate::note::Note /// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents #[derive(Copy, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) struct NullifierDerivingKey(pallas::Base); impl NullifierDerivingKey { @@ -266,6 +267,7 @@ impl NullifierDerivingKey { /// /// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents #[derive(Copy, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) struct CommitIvkRandomness(pallas::Scalar); impl From<&SpendingKey> for CommitIvkRandomness { @@ -333,6 +335,32 @@ impl From for SpendValidatingKey { } impl FullViewingKey { + /// Creates a `FullViewingKey` from a `SpendingKey` and `SpendValidatingKey`. + /// This is necessary for FROST key management. + /// + /// Note: See [FROST Book - Technical details](https://frost.zfnd.org/zcash/technical-details.html) + #[cfg(feature = "unstable-frost")] + pub fn from_sk_and_ak(sk: &SpendingKey, ak: SpendValidatingKey) -> FullViewingKey { + FullViewingKey { + ak, + nk: NullifierDerivingKey::from(sk), + rivk: CommitIvkRandomness::from(sk), + } + } + + /// Creates a `FullViewingKey` from its checked parts. This is necessary for FROST + /// key management in order to avoid centralizing spend authority in a backup scheme. + /// + /// Note: See [FROST Book - Technical details - Backing Up Key Shares](https://frost.zfnd.org/zcash/technical-details.html) + #[cfg(feature = "unstable-frost")] + pub fn from_checked_parts( + ak: SpendValidatingKey, + nk: NullifierDerivingKey, + rivk: CommitIvkRandomness, + ) -> FullViewingKey { + FullViewingKey { ak, nk, rivk } + } + pub(crate) fn nk(&self) -> &NullifierDerivingKey { &self.nk } From cc5ae1df3a88c4d82e9de1cf1528aa5c0ea5987e Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Sat, 3 Aug 2024 19:17:20 -0300 Subject: [PATCH 2/3] Adds functions to convert `nk`, `ak`, `rivk` from and to bytes. Exposes FVK's components for FROST clients --- CHANGELOG.md | 12 ++++++++++++ src/keys.rs | 22 +++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 161f54e95..23ecb0988 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,18 @@ and this project adheres to Rust's notion of `unstable-frost` feature flag. These are temporary APIs exposed for development purposes, and will be replaced by type-safe FROST APIs once ZIP 312 key generation is specified (https://github.com/zcash/zips/pull/883). +- `orchard::keys::SpendValidatingKey` exposes its composing parts through functions +gated by the `unstable-frost` feature flag. These functions are intended to be used +by FROST clients to backup the key elements. +- `orchard::keys::NullifierDerivingKey::from_bytes` made `pub` behind the +`unstable-frost` feature flag. +- `orchard::keys::NullifierDerivingKey::to_bytes` made `pub` behind the +`unstable-frost` feature flag. +- `orchard::keys::CommitIvkRandomness::from_bytes` made `pub` behind the +`unstable-frost` feature flag. +- `orchard::keys::CommitIvkRandomness::to_bytes` made `pub` behind the +`unstable-frost` feature flag. + ### Changed - Migrated to `incrementalmerkletree 0.6`, `bridgetree 0.5`. diff --git a/src/keys.rs b/src/keys.rs index 1a6ed5351..c792f3db0 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -246,10 +246,13 @@ impl NullifierDerivingKey { } /// Converts this nullifier deriving key to its serialized form. + #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) fn to_bytes(self) -> [u8; 32] { <[u8; 32]>::from(self.0) } + /// Converts this nullifier deriving key from its serialized form. + #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) fn from_bytes(bytes: &[u8]) -> Option { let nk_bytes = <[u8; 32]>::try_from(bytes).ok()?; let nk = pallas::Base::from_repr(nk_bytes).map(NullifierDerivingKey); @@ -281,11 +284,14 @@ impl CommitIvkRandomness { self.0 } - /// Converts this nullifier deriving key to its serialized form. + /// Converts this [`CommitIvkRandomness`] to its serialized form. + #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) fn to_bytes(self) -> [u8; 32] { <[u8; 32]>::from(self.0) } + #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] + /// Converts this [`CommitIvkRandomness`] from its serialized form. pub(crate) fn from_bytes(bytes: &[u8]) -> Option { let rivk_bytes = <[u8; 32]>::try_from(bytes).ok()?; let rivk = pallas::Scalar::from_repr(rivk_bytes).map(CommitIvkRandomness); @@ -361,11 +367,25 @@ impl FullViewingKey { FullViewingKey { ak, nk, rivk } } + /// Returns the `SpendValidatingKey` of this `FullViewingKey` + /// - Note: this is intended for the "unstable-frost" feature to + /// facilitate the DKG'd key backup scheme. See [Backing Up Key Shares](https://frost.zfnd.org/zcash/technical-details.html#backing-up-key-shares) + #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] + pub fn ak(&self) -> &SpendValidatingKey { + &self.ak + } + /// Returns the `NullifierDerivingKey` of this `FullViewingKey` + /// - Note: this is `pub` for the "unstable-frost" feature to + /// facilitate the DKG'd key backup scheme. See [Backing Up Key Shares](https://frost.zfnd.org/zcash/technical-details.html#backing-up-key-shares) + #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) fn nk(&self) -> &NullifierDerivingKey { &self.nk } /// Returns either `rivk` or `rivk_internal` based on `scope`. + /// - Note: this is `pub` for the "unstable-frost" feature to + /// facilitate the DKG'd key backup scheme. See [Backing Up Key Shares](https://frost.zfnd.org/zcash/technical-details.html#backing-up-key-shares) + #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) fn rivk(&self, scope: Scope) -> CommitIvkRandomness { match scope { Scope::External => self.rivk, From d0d6d2c1ab141d503725d0691e9f4318797558f6 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Mon, 5 Aug 2024 16:40:59 -0300 Subject: [PATCH 3/3] PR Suggestions Fix compile error on non-randomized flavor --- src/keys.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/keys.rs b/src/keys.rs index c792f3db0..5c99f466b 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -290,8 +290,8 @@ impl CommitIvkRandomness { <[u8; 32]>::from(self.0) } - #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] /// Converts this [`CommitIvkRandomness`] from its serialized form. + #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) fn from_bytes(bytes: &[u8]) -> Option { let rivk_bytes = <[u8; 32]>::try_from(bytes).ok()?; let rivk = pallas::Scalar::from_repr(rivk_bytes).map(CommitIvkRandomness); @@ -343,8 +343,6 @@ impl From for SpendValidatingKey { impl FullViewingKey { /// Creates a `FullViewingKey` from a `SpendingKey` and `SpendValidatingKey`. /// This is necessary for FROST key management. - /// - /// Note: See [FROST Book - Technical details](https://frost.zfnd.org/zcash/technical-details.html) #[cfg(feature = "unstable-frost")] pub fn from_sk_and_ak(sk: &SpendingKey, ak: SpendValidatingKey) -> FullViewingKey { FullViewingKey { @@ -356,8 +354,6 @@ impl FullViewingKey { /// Creates a `FullViewingKey` from its checked parts. This is necessary for FROST /// key management in order to avoid centralizing spend authority in a backup scheme. - /// - /// Note: See [FROST Book - Technical details - Backing Up Key Shares](https://frost.zfnd.org/zcash/technical-details.html) #[cfg(feature = "unstable-frost")] pub fn from_checked_parts( ak: SpendValidatingKey, @@ -369,14 +365,14 @@ impl FullViewingKey { /// Returns the `SpendValidatingKey` of this `FullViewingKey` /// - Note: this is intended for the "unstable-frost" feature to - /// facilitate the DKG'd key backup scheme. See [Backing Up Key Shares](https://frost.zfnd.org/zcash/technical-details.html#backing-up-key-shares) + /// facilitate the DKG'd key backup scheme. #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub fn ak(&self) -> &SpendValidatingKey { &self.ak } /// Returns the `NullifierDerivingKey` of this `FullViewingKey` /// - Note: this is `pub` for the "unstable-frost" feature to - /// facilitate the DKG'd key backup scheme. See [Backing Up Key Shares](https://frost.zfnd.org/zcash/technical-details.html#backing-up-key-shares) + /// facilitate the DKG'd key backup scheme. #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) fn nk(&self) -> &NullifierDerivingKey { &self.nk @@ -384,7 +380,7 @@ impl FullViewingKey { /// Returns either `rivk` or `rivk_internal` based on `scope`. /// - Note: this is `pub` for the "unstable-frost" feature to - /// facilitate the DKG'd key backup scheme. See [Backing Up Key Shares](https://frost.zfnd.org/zcash/technical-details.html#backing-up-key-shares) + /// facilitate the DKG'd key backup scheme. #[cfg_attr(feature = "unstable-frost", visibility::make(pub))] pub(crate) fn rivk(&self, scope: Scope) -> CommitIvkRandomness { match scope {