use heapless::{String, Vec};
use byteorder::{ByteOrder, LittleEndian};
use mc_core::slip10::Slip10Key;
use sha2::{Digest, Sha256};
use strum::{EnumIter, EnumString};
use super::{Error, Output};
#[derive(Copy, Clone, Debug, PartialEq, Default, EnumString, EnumIter)]
pub enum IdentState {
#[default]
Pending,
Approved,
Denied,
}
pub struct Ident {
pub identity_index: u32,
pub identity_uri: String<64>,
pub challenge: Vec<u8, 64>,
}
impl Ident {
pub fn new(identity_index: u32, uri: &str, challenge: &[u8]) -> Result<Self, Error> {
let identity_uri = String::try_from(uri).map_err(|_| Error::InvalidLength)?;
let challenge = Vec::try_from(challenge).map_err(|_| Error::InvalidLength)?;
Ok(Self {
identity_index,
identity_uri,
challenge,
})
}
pub fn uri(&self) -> &str {
&self.identity_uri
}
pub fn challenge(&self) -> &[u8] {
&self.challenge
}
pub fn path(&self) -> [u32; 5] {
derive_bip32(&self.identity_uri, self.identity_index)
}
pub fn compute(&self, private_key: &Slip10Key) -> Output {
#[cfg(feature = "log")]
log::debug!("computing identity proof");
let keys = ed25519_dalek::SigningKey::try_from(private_key.as_ref()).unwrap();
let signature = ed25519_dalek::Signer::sign(&keys, &self.challenge);
let verifying_key = keys.verifying_key();
drop(keys);
Output::Identity {
public_key: verifying_key.to_bytes(),
signature: signature.to_bytes(),
}
}
}
pub(crate) fn derive_bip32(uri: &str, index: u32) -> [u32; 5] {
let mut hasher = Sha256::new();
hasher.update(index.to_le_bytes());
hasher.update(uri.as_bytes());
let r = hasher.finalize();
let b = r.as_slice();
let mut p = [0u32; 5];
p[0] = 13 | (1 << 31);
for i in 0..4 {
p[i + 1] = LittleEndian::read_u32(&b[i * 4..]) | (1 << 31);
}
p
}
#[cfg(test)]
mod test {
use ed25519_dalek::{SigningKey, VerifyingKey};
use super::derive_bip32;
use ledger_mob_tests::ident::{Vector, VECTORS};
#[test]
fn slip0013_derive_path() {
for Vector {
uri, index, path, ..
} in VECTORS
{
let p = derive_bip32(uri, *index);
assert_eq!(&p, path, "derivation path mismatch");
}
}
#[test]
fn slip0013_derive_full() {
for v in VECTORS {
let seed = v.seed();
let p = derive_bip32(v.uri, v.index);
assert_eq!(&p, &v.path, "derivation path mismatch");
let secret_key = slip10_ed25519::derive_ed25519_private_key(&seed, &p);
let secret_key = SigningKey::from_bytes(&secret_key);
let public_key = VerifyingKey::from(&secret_key);
assert_eq!(public_key.as_bytes(), &v.public_key_bytes());
}
}
}