use super::MeshId;
use crate::workload_pkg::codec::hex_decode_exact;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum MeshIdConfigError {
#[error("kernel.mesh.genesis_hash must be 64 hex characters")]
BadGenesis,
#[error("kernel.mesh.mesh_nonce must be 64 hex characters (32 random bytes)")]
BadNonce,
}
pub fn mesh_id_from_config(
genesis_hash: Option<&str>,
mesh_nonce: Option<&str>,
) -> Result<Option<MeshId>, MeshIdConfigError> {
let nonce = match mesh_nonce {
Some(n) => Some(hex_decode_exact::<32>(n).ok_or(MeshIdConfigError::BadNonce)?),
None => None,
};
let pin = match genesis_hash {
Some(g) => Some(hex_decode_exact::<32>(g).ok_or(MeshIdConfigError::BadGenesis)?),
None => None,
};
Ok(match (pin, nonce) {
(Some(p), Some(n)) => Some(MeshId::derive(&p, &n)),
_ => None,
})
}
#[cfg(test)]
mod tests {
use super::*;
const PIN: &str = "aa00000000000000000000000000000000000000000000000000000000000001";
const NONCE: &str = "bb00000000000000000000000000000000000000000000000000000000000002";
#[test]
fn needs_both_and_matches_derive() {
assert_eq!(mesh_id_from_config(Some(PIN), None), Ok(None));
assert_eq!(mesh_id_from_config(None, Some(NONCE)), Ok(None));
let id = mesh_id_from_config(Some(PIN), Some(NONCE)).unwrap().unwrap();
assert_eq!(id, MeshId::derive(&[0xaa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], &[0xbb, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]));
let other = "cc00000000000000000000000000000000000000000000000000000000000002";
assert_ne!(Some(id), mesh_id_from_config(Some(PIN), Some(other)).unwrap());
}
#[test]
fn malformed_values_are_errors() {
assert_eq!(mesh_id_from_config(Some(PIN), Some("zz")), Err(MeshIdConfigError::BadNonce));
assert_eq!(mesh_id_from_config(Some("12"), Some(NONCE)), Err(MeshIdConfigError::BadGenesis));
assert_eq!(mesh_id_from_config(None, Some("zz")), Err(MeshIdConfigError::BadNonce));
}
}