zcash_primitives: Refactor `zip32::ChildIndex` to be an opaque struct
This commit is contained in:
parent
a9310e3969
commit
61bb18d97f
|
@ -62,9 +62,9 @@ pub mod sapling {
|
|||
ExtendedSpendingKey::from_path(
|
||||
&ExtendedSpendingKey::master(seed),
|
||||
&[
|
||||
ChildIndex::Hardened(32),
|
||||
ChildIndex::Hardened(coin_type),
|
||||
ChildIndex::Hardened(account.into()),
|
||||
ChildIndex::hardened(32),
|
||||
ChildIndex::hardened(coin_type),
|
||||
account.into(),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -71,6 +71,10 @@ and this library adheres to Rust's notion of
|
|||
- `GRACE_ACTIONS`
|
||||
- `P2PKH_STANDARD_INPUT_SIZE`
|
||||
- `P2PKH_STANDARD_OUTPUT_SIZE`
|
||||
- `zcash_primitives::zip32`:
|
||||
- `ChildIndex::hardened`
|
||||
- `ChildIndex::index`
|
||||
- `impl From<AccountId> for ChildIndex`
|
||||
- Test helpers, behind the `test-dependencies` feature flag:
|
||||
- `zcash_primitives::sapling::prover::mock::{MockSpendProver, MockOutputProver}`
|
||||
- Additions related to `zcash_primitive::components::amount::Amount`
|
||||
|
@ -155,6 +159,9 @@ and this library adheres to Rust's notion of
|
|||
- `fees::fixed::FeeRule::fixed_fee`
|
||||
- `fees::zip317::FeeRule::marginal_fee`
|
||||
- `sighash::TransparentAuthorizingContext::input_amounts`
|
||||
- `zcash_primitives::zip32`:
|
||||
- `ChildIndex` has been changed from an enum to an opaque struct, and no
|
||||
longer supports non-hardened indices.
|
||||
|
||||
### Removed
|
||||
- `zcash_primitives::constants`:
|
||||
|
@ -189,6 +196,7 @@ and this library adheres to Rust's notion of
|
|||
`Bundle::<InProgress<Proven, Unsigned>>::apply_signatures` instead).
|
||||
- `impl From<zcash_primitive::components::transaction::Amount> for u64`
|
||||
- `zcash_primitives::zip32`:
|
||||
- `ChildIndex::Hardened` (use `ChildIndex::hardened` instead).
|
||||
- `ChildIndex::NonHardened`
|
||||
- `sapling::ExtendedFullViewingKey::derive_child`
|
||||
|
||||
|
|
|
@ -35,6 +35,13 @@ impl From<AccountId> for u32 {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AccountId> for ChildIndex {
|
||||
fn from(id: AccountId) -> Self {
|
||||
// Account IDs are always hardened in derivation paths.
|
||||
ChildIndex::hardened(id.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConditionallySelectable for AccountId {
|
||||
fn conditional_select(a0: &Self, a1: &Self, c: Choice) -> Self {
|
||||
AccountId(u32::conditional_select(&a0.0, &a1.0, c))
|
||||
|
@ -43,30 +50,34 @@ impl ConditionallySelectable for AccountId {
|
|||
|
||||
// ZIP 32 structures
|
||||
|
||||
/// A child index for a derived key
|
||||
/// A child index for a derived key.
|
||||
///
|
||||
/// Only hardened derivation is supported.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ChildIndex {
|
||||
Hardened(u32), // Hardened(n) == n + (1 << 31) == n' in path notation
|
||||
}
|
||||
pub struct ChildIndex(u32);
|
||||
|
||||
impl ChildIndex {
|
||||
pub fn from_index(i: u32) -> Option<Self> {
|
||||
if i >= (1 << 31) {
|
||||
Some(ChildIndex::Hardened(i - (1 << 31)))
|
||||
Some(ChildIndex(i))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn master() -> Self {
|
||||
// TODO: This is invalid; fixed in next commit.
|
||||
ChildIndex::Hardened(0)
|
||||
/// Constructs a hardened `ChildIndex` from the given value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `value >= (1 << 31)`.
|
||||
pub const fn hardened(value: u32) -> Self {
|
||||
assert!(value < (1 << 31));
|
||||
Self(value + (1 << 31))
|
||||
}
|
||||
|
||||
fn value(&self) -> u32 {
|
||||
match *self {
|
||||
ChildIndex::Hardened(i) => i + (1 << 31),
|
||||
}
|
||||
/// Returns the index as a 32-bit integer, including the hardened bit.
|
||||
pub fn index(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -231,12 +231,39 @@ impl DiversifierKey {
|
|||
}
|
||||
}
|
||||
|
||||
/// The derivation index associated with a key.
|
||||
///
|
||||
/// Master keys are never derived via the ZIP 32 child derivation process, but they have
|
||||
/// an index in their encoding. This type allows the encoding to be represented, while
|
||||
/// also enabling the derivation methods to only accept [`ChildIndex`].
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum KeyIndex {
|
||||
Master,
|
||||
Child(ChildIndex),
|
||||
}
|
||||
|
||||
impl KeyIndex {
|
||||
fn new(depth: u8, i: u32) -> Option<Self> {
|
||||
match i {
|
||||
0 if depth == 0 => Some(KeyIndex::Master),
|
||||
_ => ChildIndex::from_index(i).map(KeyIndex::Child),
|
||||
}
|
||||
}
|
||||
|
||||
fn index(&self) -> u32 {
|
||||
match self {
|
||||
KeyIndex::Master => 0,
|
||||
KeyIndex::Child(i) => i.index(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A Sapling extended spending key
|
||||
#[derive(Clone)]
|
||||
pub struct ExtendedSpendingKey {
|
||||
depth: u8,
|
||||
parent_fvk_tag: FvkTag,
|
||||
child_index: ChildIndex,
|
||||
child_index: KeyIndex,
|
||||
chain_code: ChainCode,
|
||||
pub expsk: ExpandedSpendingKey,
|
||||
dk: DiversifierKey,
|
||||
|
@ -279,7 +306,7 @@ impl ExtendedSpendingKey {
|
|||
ExtendedSpendingKey {
|
||||
depth: 0,
|
||||
parent_fvk_tag: FvkTag::master(),
|
||||
child_index: ChildIndex::master(),
|
||||
child_index: KeyIndex::Master,
|
||||
chain_code: ChainCode(c_m),
|
||||
expsk: ExpandedSpendingKey::from_spending_key(sk_m),
|
||||
dk: DiversifierKey::master(sk_m),
|
||||
|
@ -303,7 +330,7 @@ impl ExtendedSpendingKey {
|
|||
|
||||
let mut ci_bytes = [0u8; 4];
|
||||
ci_bytes[..].copy_from_slice(&b[5..9]);
|
||||
let child_index = ChildIndex::from_index(u32::from_le_bytes(ci_bytes))
|
||||
let child_index = KeyIndex::new(depth, u32::from_le_bytes(ci_bytes))
|
||||
.ok_or(DecodingError::UnsupportedChildIndex)?;
|
||||
|
||||
let mut chain_code = ChainCode([0u8; 32]);
|
||||
|
@ -331,7 +358,7 @@ impl ExtendedSpendingKey {
|
|||
let mut tag = [0; 4];
|
||||
reader.read_exact(&mut tag)?;
|
||||
let child_index = reader.read_u32::<LittleEndian>().and_then(|i| {
|
||||
ChildIndex::from_index(i).ok_or_else(|| {
|
||||
KeyIndex::new(depth, i).ok_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"Non-hardened keys are not supported",
|
||||
|
@ -360,7 +387,7 @@ impl ExtendedSpendingKey {
|
|||
let mut result = [0u8; 169];
|
||||
result[0] = self.depth;
|
||||
result[1..5].copy_from_slice(&self.parent_fvk_tag.as_bytes()[..]);
|
||||
result[5..9].copy_from_slice(&self.child_index.value().to_le_bytes()[..]);
|
||||
result[5..9].copy_from_slice(&self.child_index.index().to_le_bytes()[..]);
|
||||
result[9..41].copy_from_slice(&self.chain_code.as_bytes()[..]);
|
||||
result[41..137].copy_from_slice(&self.expsk.to_bytes()[..]);
|
||||
result[137..169].copy_from_slice(&self.dk.as_bytes()[..]);
|
||||
|
@ -385,15 +412,13 @@ impl ExtendedSpendingKey {
|
|||
#[must_use]
|
||||
pub fn derive_child(&self, i: ChildIndex) -> Self {
|
||||
let fvk = FullViewingKey::from_expanded_spending_key(&self.expsk);
|
||||
let tmp = match i {
|
||||
ChildIndex::Hardened(i) => {
|
||||
let mut le_i = [0; 4];
|
||||
LittleEndian::write_u32(&mut le_i, i + (1 << 31));
|
||||
prf_expand_vec(
|
||||
&self.chain_code.0,
|
||||
&[&[0x11], &self.expsk.to_bytes(), &self.dk.0, &le_i],
|
||||
)
|
||||
}
|
||||
let tmp = {
|
||||
let mut le_i = [0; 4];
|
||||
LittleEndian::write_u32(&mut le_i, i.index());
|
||||
prf_expand_vec(
|
||||
&self.chain_code.0,
|
||||
&[&[0x11], &self.expsk.to_bytes(), &self.dk.0, &le_i],
|
||||
)
|
||||
};
|
||||
let i_l = &tmp.as_bytes()[..32];
|
||||
let mut c_i = [0u8; 32];
|
||||
|
@ -402,7 +427,7 @@ impl ExtendedSpendingKey {
|
|||
ExtendedSpendingKey {
|
||||
depth: self.depth + 1,
|
||||
parent_fvk_tag: FvkFingerprint::from(&fvk).tag(),
|
||||
child_index: i,
|
||||
child_index: KeyIndex::Child(i),
|
||||
chain_code: ChainCode(c_i),
|
||||
expsk: {
|
||||
let mut ask = jubjub::Fr::from_bytes_wide(prf_expand(i_l, &[0x13]).as_array());
|
||||
|
@ -483,7 +508,7 @@ impl ExtendedSpendingKey {
|
|||
pub struct ExtendedFullViewingKey {
|
||||
depth: u8,
|
||||
parent_fvk_tag: FvkTag,
|
||||
child_index: ChildIndex,
|
||||
child_index: KeyIndex,
|
||||
chain_code: ChainCode,
|
||||
pub fvk: FullViewingKey,
|
||||
pub(crate) dk: DiversifierKey,
|
||||
|
@ -518,7 +543,7 @@ impl ExtendedFullViewingKey {
|
|||
let mut tag = [0; 4];
|
||||
reader.read_exact(&mut tag)?;
|
||||
let child_index = reader.read_u32::<LittleEndian>().and_then(|i| {
|
||||
ChildIndex::from_index(i).ok_or_else(|| {
|
||||
KeyIndex::new(depth, i).ok_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"Non-hardened keys are not supported",
|
||||
|
@ -544,7 +569,7 @@ impl ExtendedFullViewingKey {
|
|||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
writer.write_u8(self.depth)?;
|
||||
writer.write_all(&self.parent_fvk_tag.0)?;
|
||||
writer.write_u32::<LittleEndian>(self.child_index.value())?;
|
||||
writer.write_u32::<LittleEndian>(self.child_index.index())?;
|
||||
writer.write_all(&self.chain_code.0)?;
|
||||
writer.write_all(&self.fvk.to_bytes())?;
|
||||
writer.write_all(&self.dk.0)?;
|
||||
|
@ -787,7 +812,7 @@ mod tests {
|
|||
let seed = [0; 32];
|
||||
let xsk_m = ExtendedSpendingKey::master(&seed);
|
||||
|
||||
let i_5h = ChildIndex::Hardened(5);
|
||||
let i_5h = ChildIndex::hardened(5);
|
||||
let _ = xsk_m.derive_child(i_5h);
|
||||
}
|
||||
|
||||
|
@ -796,17 +821,17 @@ mod tests {
|
|||
let seed = [0; 32];
|
||||
let xsk_m = ExtendedSpendingKey::master(&seed);
|
||||
|
||||
let xsk_5h = xsk_m.derive_child(ChildIndex::Hardened(5));
|
||||
let xsk_5h = xsk_m.derive_child(ChildIndex::hardened(5));
|
||||
assert_eq!(
|
||||
ExtendedSpendingKey::from_path(&xsk_m, &[ChildIndex::Hardened(5)]),
|
||||
ExtendedSpendingKey::from_path(&xsk_m, &[ChildIndex::hardened(5)]),
|
||||
xsk_5h
|
||||
);
|
||||
|
||||
let xsk_5h_7 = xsk_5h.derive_child(ChildIndex::Hardened(7));
|
||||
let xsk_5h_7 = xsk_5h.derive_child(ChildIndex::hardened(7));
|
||||
assert_eq!(
|
||||
ExtendedSpendingKey::from_path(
|
||||
&xsk_m,
|
||||
&[ChildIndex::Hardened(5), ChildIndex::Hardened(7)]
|
||||
&[ChildIndex::hardened(5), ChildIndex::hardened(7)]
|
||||
),
|
||||
xsk_5h_7
|
||||
);
|
||||
|
@ -1567,9 +1592,9 @@ mod tests {
|
|||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
];
|
||||
|
||||
let i1h = ChildIndex::Hardened(1);
|
||||
let i2h = ChildIndex::Hardened(2);
|
||||
let i3h = ChildIndex::Hardened(3);
|
||||
let i1h = ChildIndex::hardened(1);
|
||||
let i2h = ChildIndex::hardened(2);
|
||||
let i3h = ChildIndex::hardened(3);
|
||||
|
||||
let m = ExtendedSpendingKey::master(&seed);
|
||||
let m_1h = m.derive_child(i1h);
|
||||
|
|
Loading…
Reference in New Issue