// Copyright 2019-2025 Parity Technologies (UK) Ltd. // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. use codec::{Decode, Encode}; // This code is taken from sp_core::crypto::DeriveJunction. The logic should be identical, // though the API is tweaked a touch. /// The length of the junction identifier. Note that this is also referred to as the /// `CHAIN_CODE_LENGTH` in the context of Schnorrkel. pub const JUNCTION_ID_LEN: usize = 32; /// A since derivation junction description. It is the single parameter used when creating /// a new secret key from an existing secret key and, in the case of `SoftRaw` and `SoftIndex` /// a new public key from an existing public key. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)] pub enum DeriveJunction { /// Soft (vanilla) derivation. Public keys have a correspondent derivation. Soft([u8; JUNCTION_ID_LEN]), /// Hard ("hardened") derivation. Public keys do not have a correspondent derivation. Hard([u8; JUNCTION_ID_LEN]), } impl DeriveJunction { /// Consume self to return a soft derive junction with the same chain code. pub fn soften(self) -> Self { DeriveJunction::Soft(self.into_inner()) } /// Consume self to return a hard derive junction with the same chain code. pub fn harden(self) -> Self { DeriveJunction::Hard(self.into_inner()) } /// Create a new soft (vanilla) DeriveJunction from a given, encodable, value. /// /// If you need a hard junction, use `hard()`. pub fn soft(index: T) -> Self { let mut cc: [u8; JUNCTION_ID_LEN] = Default::default(); index.using_encoded(|data| { if data.len() > JUNCTION_ID_LEN { cc.copy_from_slice(&pezsp_crypto_hashing::blake2_256(data)); } else { cc[0..data.len()].copy_from_slice(data); } }); DeriveJunction::Soft(cc) } /// Create a new hard (hardened) DeriveJunction from a given, encodable, value. /// /// If you need a soft junction, use `soft()`. pub fn hard(index: T) -> Self { Self::soft(index).harden() } /// Consume self to return the chain code. pub fn into_inner(self) -> [u8; JUNCTION_ID_LEN] { match self { DeriveJunction::Hard(c) | DeriveJunction::Soft(c) => c, } } /// Get a reference to the inner junction id. pub fn inner(&self) -> &[u8; JUNCTION_ID_LEN] { match self { DeriveJunction::Hard(c) | DeriveJunction::Soft(c) => c, } } /// Return `true` if the junction is soft. pub fn is_soft(&self) -> bool { matches!(*self, DeriveJunction::Soft(_)) } /// Return `true` if the junction is hard. pub fn is_hard(&self) -> bool { matches!(*self, DeriveJunction::Hard(_)) } } impl> From for DeriveJunction { fn from(j: T) -> DeriveJunction { let j = j.as_ref(); let (code, hard) = if let Some(stripped) = j.strip_prefix('/') { (stripped, true) } else { (j, false) }; let res = if let Ok(n) = str::parse::(code) { // number DeriveJunction::soft(n) } else { // something else DeriveJunction::soft(code) }; if hard { res.harden() } else { res } } }