mirror of https://github.com/zcash/orchard.git
Rename `sk_iss` to `isk`, the `IssuanceKey` struct to `IssuanceAuthorizingKey`, and move to a two key structure (#92)
This performs a consistent renaming of the issuance authorizing key to make it consistent with the ZIP. It also reworks the `IssuanceAuthorizingKey` struct in place of the `IssuanceKey` and `IssuanceAuthorizingKey` structs, as part of using a two key structure for issuance, as specified in ZIP 227.
This commit is contained in:
parent
7b943e197e
commit
f38d6b9e4c
|
@ -69,7 +69,7 @@ mod tests {
|
|||
/// Creates an item of bundle burn list for a given asset description and value.
|
||||
///
|
||||
/// This function is deterministic and guarantees that each call with the same parameters
|
||||
/// will return the same result. It achieves determinism by using a static `IssuanceKey`.
|
||||
/// will return the same result. It achieves determinism by using a static `IssuanceAuthorizingKey`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
@ -81,10 +81,9 @@ mod tests {
|
|||
/// A tuple `(AssetBase, Amount)` representing the burn list item.
|
||||
///
|
||||
pub fn get_burn_tuple(asset_desc: &str, value: i64) -> (AssetBase, i64) {
|
||||
use crate::keys::{IssuanceAuthorizingKey, IssuanceKey, IssuanceValidatingKey};
|
||||
use crate::keys::{IssuanceAuthorizingKey, IssuanceValidatingKey};
|
||||
|
||||
let sk_iss = IssuanceKey::from_bytes([0u8; 32]).unwrap();
|
||||
let isk: IssuanceAuthorizingKey = (&sk_iss).into();
|
||||
let isk = IssuanceAuthorizingKey::from_bytes([0u8; 32]).unwrap();
|
||||
|
||||
(
|
||||
AssetBase::derive(&IssuanceValidatingKey::from(&isk), asset_desc),
|
||||
|
|
|
@ -532,7 +532,7 @@ pub fn verify_issue_bundle(
|
|||
pub enum Error {
|
||||
/// The requested IssueAction not exists in the bundle.
|
||||
IssueActionNotFound,
|
||||
/// The provided `isk` and the driven `ik` does not match at least one note type.
|
||||
/// The provided `isk` and the derived `ik` does not match at least one note type.
|
||||
IssueBundleIkMismatchAssetBase,
|
||||
/// `asset_desc` should be between 1 and 512 bytes.
|
||||
WrongAssetDescSize,
|
||||
|
@ -562,7 +562,7 @@ impl fmt::Display for Error {
|
|||
IssueBundleIkMismatchAssetBase => {
|
||||
write!(
|
||||
f,
|
||||
"the provided `isk` and the driven `ik` does not match at least one note type"
|
||||
"the provided `isk` and the derived `ik` do not match at least one note type"
|
||||
)
|
||||
}
|
||||
WrongAssetDescSize => {
|
||||
|
@ -606,8 +606,7 @@ mod tests {
|
|||
};
|
||||
use crate::issuance::{verify_issue_bundle, IssueAction, Signed, Unauthorized};
|
||||
use crate::keys::{
|
||||
FullViewingKey, IssuanceAuthorizingKey, IssuanceKey, IssuanceValidatingKey, Scope,
|
||||
SpendingKey,
|
||||
FullViewingKey, IssuanceAuthorizingKey, IssuanceValidatingKey, Scope, SpendingKey,
|
||||
};
|
||||
use crate::note::{AssetBase, Nullifier};
|
||||
use crate::value::{NoteValue, ValueSum};
|
||||
|
@ -629,8 +628,7 @@ mod tests {
|
|||
) {
|
||||
let mut rng = OsRng;
|
||||
|
||||
let sk_iss = IssuanceKey::random(&mut rng);
|
||||
let isk: IssuanceAuthorizingKey = (&sk_iss).into();
|
||||
let isk = IssuanceAuthorizingKey::random(&mut rng);
|
||||
let ik: IssuanceValidatingKey = (&isk).into();
|
||||
|
||||
let fvk = FullViewingKey::from(&SpendingKey::random(&mut rng));
|
||||
|
@ -951,7 +949,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let wrong_isk: IssuanceAuthorizingKey = (&IssuanceKey::random(&mut OsRng)).into();
|
||||
let wrong_isk: IssuanceAuthorizingKey = IssuanceAuthorizingKey::random(&mut OsRng);
|
||||
|
||||
let err = bundle
|
||||
.prepare([0; 32])
|
||||
|
@ -1183,7 +1181,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let wrong_isk: IssuanceAuthorizingKey = (&IssuanceKey::random(&mut rng)).into();
|
||||
let wrong_isk: IssuanceAuthorizingKey = IssuanceAuthorizingKey::random(&mut rng);
|
||||
|
||||
let mut signed = bundle.prepare(sighash).sign(rng, &isk).unwrap();
|
||||
|
||||
|
@ -1278,8 +1276,7 @@ mod tests {
|
|||
|
||||
let mut signed = bundle.prepare(sighash).sign(rng, &isk).unwrap();
|
||||
|
||||
let incorrect_sk_iss = IssuanceKey::random(&mut rng);
|
||||
let incorrect_isk: IssuanceAuthorizingKey = (&incorrect_sk_iss).into();
|
||||
let incorrect_isk = IssuanceAuthorizingKey::random(&mut rng);
|
||||
let incorrect_ik: IssuanceValidatingKey = (&incorrect_isk).into();
|
||||
|
||||
// Add "bad" note
|
||||
|
|
83
src/keys.rs
83
src/keys.rs
|
@ -223,25 +223,25 @@ type IssuanceAuth = SpendAuth;
|
|||
|
||||
/// An issuance key, from which all key material is derived.
|
||||
///
|
||||
/// $\mathsf{sk}$ as defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
|
||||
/// $\mathsf{isk}$ as defined in [ZIP 227][issuancekeycomponents].
|
||||
///
|
||||
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
|
||||
/// [issuancekeycomponents]: https://qed-it.github.io/zips/zip-0227#issuance-key-derivation
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct IssuanceKey([u8; 32]);
|
||||
pub struct IssuanceAuthorizingKey([u8; 32]);
|
||||
|
||||
impl From<SpendingKey> for IssuanceKey {
|
||||
impl From<SpendingKey> for IssuanceAuthorizingKey {
|
||||
fn from(sk: SpendingKey) -> Self {
|
||||
IssuanceKey(*sk.to_bytes())
|
||||
IssuanceAuthorizingKey(*sk.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstantTimeEq for IssuanceKey {
|
||||
impl ConstantTimeEq for IssuanceAuthorizingKey {
|
||||
fn ct_eq(&self, other: &Self) -> Choice {
|
||||
self.to_bytes().ct_eq(other.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl IssuanceKey {
|
||||
impl IssuanceAuthorizingKey {
|
||||
/// Generates a random issuance key.
|
||||
///
|
||||
/// This is only used when generating a random AssetBase.
|
||||
|
@ -255,11 +255,9 @@ impl IssuanceKey {
|
|||
/// Constructs an Orchard issuance key from uniformly-random bytes.
|
||||
///
|
||||
/// Returns `None` if the bytes do not correspond to a valid Orchard issuance key.
|
||||
pub fn from_bytes(sk_iss: [u8; 32]) -> CtOption<Self> {
|
||||
let sk_iss = IssuanceKey(sk_iss);
|
||||
// If isk = 0 (A scalar value), discard this key.
|
||||
let isk = IssuanceAuthorizingKey::derive_inner(&sk_iss);
|
||||
CtOption::new(sk_iss, !isk.is_zero())
|
||||
pub fn from_bytes(isk_bytes: [u8; 32]) -> CtOption<Self> {
|
||||
let isk = IssuanceAuthorizingKey(isk_bytes);
|
||||
CtOption::new(isk, 1u8.into())
|
||||
}
|
||||
|
||||
/// Returns the raw bytes of the issuance key.
|
||||
|
@ -267,7 +265,7 @@ impl IssuanceKey {
|
|||
&self.0
|
||||
}
|
||||
|
||||
/// Derives the Orchard issuance key for the given seed, coin type, and account.
|
||||
/// Derives the Orchard-ZSA issuance key for the given seed, coin type, and account.
|
||||
pub fn from_zip32_seed(
|
||||
seed: &[u8],
|
||||
coin_type: u32,
|
||||
|
@ -282,22 +280,10 @@ impl IssuanceKey {
|
|||
ExtendedSpendingKey::from_path(seed, path, ZIP32_ORCHARD_PERSONALIZATION_FOR_ISSUANCE)
|
||||
.map(|esk| esk.sk().into())
|
||||
}
|
||||
}
|
||||
|
||||
/// An issuance authorizing key, used to create issuance authorization signatures.
|
||||
/// This type enforces that the corresponding public point (ik^ℙ) has ỹ = 0.
|
||||
///
|
||||
/// $\mathsf{isk}$ as defined in
|
||||
/// [Issuance of Zcash Shielded Assets ZIP-0227 § Asset Identifier Generation (DRAFT ZIP)][IssuanceZSA].
|
||||
///
|
||||
/// [IssuanceZSA]: https://qed-it.github.io/zips/draft-ZIP-0227.html#asset-identifier-generation
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IssuanceAuthorizingKey(redpallas::SigningKey<IssuanceAuth>);
|
||||
|
||||
impl IssuanceAuthorizingKey {
|
||||
/// Derives isk from sk_iss. Internal use only, does not enforce all constraints.
|
||||
fn derive_inner(sk_iss: &IssuanceKey) -> pallas::Scalar {
|
||||
to_scalar(PrfExpand::ZsaIsk.expand(&sk_iss.0))
|
||||
/// Derives the RedPallas signing key from isk. Internal use only, does not enforce all constraints.
|
||||
fn derive_inner(&self) -> pallas::Scalar {
|
||||
to_scalar(PrfExpand::ZsaIsk.expand(&self.0))
|
||||
}
|
||||
|
||||
/// Sign the provided message using the `IssuanceAuthorizingKey`.
|
||||
|
@ -306,32 +292,23 @@ impl IssuanceAuthorizingKey {
|
|||
rng: &mut (impl RngCore + CryptoRng),
|
||||
msg: &[u8],
|
||||
) -> redpallas::Signature<IssuanceAuth> {
|
||||
self.0.sign(rng, msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&IssuanceKey> for IssuanceAuthorizingKey {
|
||||
fn from(sk_iss: &IssuanceKey) -> Self {
|
||||
let isk = IssuanceAuthorizingKey::derive_inner(sk_iss);
|
||||
// IssuanceAuthorizingKey cannot be constructed such that this assertion would fail.
|
||||
assert!(!bool::from(isk.is_zero()));
|
||||
IssuanceAuthorizingKey(conditionally_negate(isk))
|
||||
conditionally_negate(self.derive_inner()).sign(rng, msg)
|
||||
}
|
||||
}
|
||||
|
||||
/// A key used to validate issuance authorization signatures.
|
||||
///
|
||||
/// Defined in [Issuance of Zcash Shielded Assets ZIP-0227 § Asset Identifier Generation (DRAFT PR)][IssuanceZSA].
|
||||
/// Defined in [ZIP 227: Issuance of Zcash Shielded Assets § Issuance Key Generation][IssuanceZSA].
|
||||
/// Note that this is $\mathsf{ik}^\mathbb{P}$, which by construction is equivalent to
|
||||
/// $\mathsf{ik}$ but stored here as a RedPallas verification key.
|
||||
///
|
||||
/// [IssuanceZSA]: https://qed-it.github.io/zips/draft-ZIP-0227.html#asset-identifier-generation
|
||||
/// [IssuanceZSA]: https://qed-it.github.io/zips/zip-0227#issuance-key-derivation
|
||||
#[derive(Debug, Clone, PartialOrd, Ord)]
|
||||
pub struct IssuanceValidatingKey(VerificationKey<IssuanceAuth>);
|
||||
|
||||
impl From<&IssuanceAuthorizingKey> for IssuanceValidatingKey {
|
||||
fn from(isk: &IssuanceAuthorizingKey) -> Self {
|
||||
IssuanceValidatingKey((&isk.0).into())
|
||||
IssuanceValidatingKey((&(conditionally_negate(isk.derive_inner()))).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1116,11 +1093,10 @@ impl SharedSecret {
|
|||
#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
|
||||
pub mod testing {
|
||||
use super::{
|
||||
DiversifierIndex, DiversifierKey, EphemeralSecretKey, IssuanceAuthorizingKey, IssuanceKey,
|
||||
DiversifierIndex, DiversifierKey, EphemeralSecretKey, IssuanceAuthorizingKey,
|
||||
IssuanceValidatingKey, SpendingKey,
|
||||
};
|
||||
use proptest::prelude::*;
|
||||
use rand::{rngs::StdRng, SeedableRng};
|
||||
|
||||
prop_compose! {
|
||||
/// Generate a uniformly distributed Orchard spending key.
|
||||
|
@ -1137,15 +1113,15 @@ pub mod testing {
|
|||
}
|
||||
|
||||
prop_compose! {
|
||||
/// Generate a uniformly distributed Orchard issuance key.
|
||||
pub fn arb_issuance_key()(
|
||||
/// Generate a uniformly distributed Orchard issuance master key.
|
||||
pub fn arb_issuance_authorizing_key()(
|
||||
key in prop::array::uniform32(prop::num::u8::ANY)
|
||||
.prop_map(IssuanceKey::from_bytes)
|
||||
.prop_map(IssuanceAuthorizingKey::from_bytes)
|
||||
.prop_filter(
|
||||
"Values must correspond to valid Orchard issuance keys.",
|
||||
|opt| bool::from(opt.is_some())
|
||||
)
|
||||
) -> IssuanceKey {
|
||||
) -> IssuanceAuthorizingKey {
|
||||
key.unwrap()
|
||||
}
|
||||
}
|
||||
|
@ -1182,14 +1158,6 @@ pub mod testing {
|
|||
}
|
||||
}
|
||||
|
||||
prop_compose! {
|
||||
/// Generate a uniformly distributed RedDSA issuance authorizing key.
|
||||
pub fn arb_issuance_authorizing_key()(rng_seed in prop::array::uniform32(prop::num::u8::ANY)) -> IssuanceAuthorizingKey {
|
||||
let mut rng = StdRng::from_seed(rng_seed);
|
||||
IssuanceAuthorizingKey::from(&IssuanceKey::random(&mut rng))
|
||||
}
|
||||
}
|
||||
|
||||
prop_compose! {
|
||||
/// Generate a uniformly distributed RedDSA issuance validating key.
|
||||
pub fn arb_issuance_validating_key()(isk in arb_issuance_authorizing_key()) -> IssuanceValidatingKey {
|
||||
|
@ -1267,10 +1235,7 @@ mod tests {
|
|||
let ask: SpendAuthorizingKey = (&sk).into();
|
||||
assert_eq!(<[u8; 32]>::from(&ask.0), tv.ask);
|
||||
|
||||
let sk_iss = IssuanceKey::from_bytes(tv.sk).unwrap();
|
||||
|
||||
let isk: IssuanceAuthorizingKey = (&sk_iss).into();
|
||||
assert_eq!(<[u8; 32]>::from(&isk.0), tv.isk);
|
||||
let isk = IssuanceAuthorizingKey::from_bytes(tv.sk).unwrap();
|
||||
|
||||
let ak: SpendValidatingKey = (&ask).into();
|
||||
assert_eq!(<[u8; 32]>::from(ak.0), tv.ak);
|
||||
|
|
|
@ -10,7 +10,7 @@ use subtle::{Choice, ConstantTimeEq, CtOption};
|
|||
use crate::constants::fixed_bases::{
|
||||
NATIVE_ASSET_BASE_V_BYTES, VALUE_COMMITMENT_PERSONALIZATION, ZSA_ASSET_BASE_PERSONALIZATION,
|
||||
};
|
||||
use crate::keys::{IssuanceAuthorizingKey, IssuanceKey, IssuanceValidatingKey};
|
||||
use crate::keys::{IssuanceAuthorizingKey, IssuanceValidatingKey};
|
||||
|
||||
/// Note type identifier.
|
||||
#[derive(Clone, Copy, Debug, Eq)]
|
||||
|
@ -102,8 +102,7 @@ impl AssetBase {
|
|||
///
|
||||
/// This is only used in tests.
|
||||
pub(crate) fn random(rng: &mut impl RngCore) -> Self {
|
||||
let sk_iss = IssuanceKey::random(rng);
|
||||
let isk = IssuanceAuthorizingKey::from(&sk_iss);
|
||||
let isk = IssuanceAuthorizingKey::random(rng);
|
||||
let ik = IssuanceValidatingKey::from(&isk);
|
||||
let asset_descr = "zsa_asset";
|
||||
AssetBase::derive(&ik, asset_descr)
|
||||
|
@ -136,19 +135,18 @@ pub mod testing {
|
|||
|
||||
use proptest::prelude::*;
|
||||
|
||||
use crate::keys::{testing::arb_issuance_key, IssuanceAuthorizingKey, IssuanceValidatingKey};
|
||||
use crate::keys::{testing::arb_issuance_authorizing_key, IssuanceValidatingKey};
|
||||
|
||||
prop_compose! {
|
||||
/// Generate a uniformly distributed note type
|
||||
pub fn arb_asset_id()(
|
||||
is_native in prop::bool::ANY,
|
||||
sk in arb_issuance_key(),
|
||||
isk in arb_issuance_authorizing_key(),
|
||||
str in "[A-Za-z]{255}",
|
||||
) -> AssetBase {
|
||||
if is_native {
|
||||
AssetBase::native()
|
||||
} else {
|
||||
let isk = IssuanceAuthorizingKey::from(&sk);
|
||||
AssetBase::derive(&IssuanceValidatingKey::from(&isk), &str)
|
||||
}
|
||||
}
|
||||
|
@ -165,10 +163,9 @@ pub mod testing {
|
|||
prop_compose! {
|
||||
/// Generate an asset ID
|
||||
pub fn arb_zsa_asset_id()(
|
||||
sk_iss in arb_issuance_key(),
|
||||
isk in arb_issuance_authorizing_key(),
|
||||
str in "[A-Za-z]{255}"
|
||||
) -> AssetBase {
|
||||
let isk = IssuanceAuthorizingKey::from(&sk_iss);
|
||||
AssetBase::derive(&IssuanceValidatingKey::from(&isk), &str)
|
||||
}
|
||||
}
|
||||
|
@ -176,10 +173,9 @@ pub mod testing {
|
|||
prop_compose! {
|
||||
/// Generate an asset ID using a specific description
|
||||
pub fn zsa_asset_id(asset_desc: String)(
|
||||
sk_iss in arb_issuance_key(),
|
||||
isk in arb_issuance_authorizing_key(),
|
||||
) -> AssetBase {
|
||||
assert!(super::is_asset_desc_of_valid_size(&asset_desc));
|
||||
let isk = IssuanceAuthorizingKey::from(&sk_iss);
|
||||
AssetBase::derive(&IssuanceValidatingKey::from(&isk), &asset_desc)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,10 +80,9 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
fn create_test_asset(asset_desc: &str) -> AssetBase {
|
||||
use crate::keys::{IssuanceAuthorizingKey, IssuanceKey, IssuanceValidatingKey};
|
||||
use crate::keys::{IssuanceAuthorizingKey, IssuanceValidatingKey};
|
||||
|
||||
let sk_iss = IssuanceKey::from_bytes([0u8; 32]).unwrap();
|
||||
let isk: IssuanceAuthorizingKey = (&sk_iss).into();
|
||||
let isk = IssuanceAuthorizingKey::from_bytes([0u8; 32]).unwrap();
|
||||
|
||||
AssetBase::derive(&IssuanceValidatingKey::from(&isk), asset_desc)
|
||||
}
|
||||
|
|
|
@ -13,10 +13,7 @@ use orchard::{
|
|||
builder::Builder,
|
||||
bundle::Flags,
|
||||
circuit::{ProvingKey, VerifyingKey},
|
||||
keys::{
|
||||
FullViewingKey, IssuanceKey, PreparedIncomingViewingKey, Scope, SpendAuthorizingKey,
|
||||
SpendingKey,
|
||||
},
|
||||
keys::{FullViewingKey, PreparedIncomingViewingKey, Scope, SpendAuthorizingKey, SpendingKey},
|
||||
value::NoteValue,
|
||||
Address, Anchor, Bundle, Note,
|
||||
};
|
||||
|
@ -61,8 +58,7 @@ fn prepare_keys() -> Keychain {
|
|||
let fvk = FullViewingKey::from(&sk);
|
||||
let recipient = fvk.address_at(0u32, Scope::External);
|
||||
|
||||
let sk_iss = IssuanceKey::from_bytes([0; 32]).unwrap();
|
||||
let isk = IssuanceAuthorizingKey::from(&sk_iss);
|
||||
let isk = IssuanceAuthorizingKey::from_bytes([0; 32]).unwrap();
|
||||
let ik = IssuanceValidatingKey::from(&isk);
|
||||
Keychain {
|
||||
pk,
|
||||
|
|
Loading…
Reference in New Issue