use crate::error::{Error, Result};
use crate::identity::{Identity, NodeId};
use core::ptr;
use nwep_sys as sys;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EntryType {
KeyBinding,
KeyRotation,
Revocation,
AnchorChange,
}
impl EntryType {
pub fn of(bytes: &[u8]) -> Result<EntryType> {
let rc = unsafe { sys::nwep_log_entry_type(bytes.as_ptr(), bytes.len()) };
match rc {
sys::NWEP_ENTRY_KEY_BINDING => Ok(EntryType::KeyBinding),
sys::NWEP_ENTRY_KEY_ROTATION => Ok(EntryType::KeyRotation),
sys::NWEP_ENTRY_REVOCATION => Ok(EntryType::Revocation),
sys::NWEP_ENTRY_ANCHOR_CHANGE => Ok(EntryType::AnchorChange),
other => Err(Error::from_code(other)),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RevocationReason {
Compromised,
Rotation,
Decommission,
}
impl RevocationReason {
fn code(self) -> u8 {
match self {
RevocationReason::Compromised => 1,
RevocationReason::Rotation => 2,
RevocationReason::Decommission => 3,
}
}
fn from_code(code: u8) -> Option<RevocationReason> {
match code {
1 => Some(RevocationReason::Compromised),
2 => Some(RevocationReason::Rotation),
3 => Some(RevocationReason::Decommission),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct KeyBinding {
pub node_id: NodeId,
pub pubkey: [u8; 32],
pub recovery_commitment: [u8; 32],
pub timestamp: u64,
}
impl KeyBinding {
pub fn decode(bytes: &[u8]) -> Result<KeyBinding> {
let mut out = core::mem::MaybeUninit::<sys::nwep_keybinding>::zeroed();
Error::check(unsafe {
sys::nwep_keybinding_decode(bytes.as_ptr(), bytes.len(), out.as_mut_ptr())
})?;
let kb = unsafe { out.assume_init() };
Ok(KeyBinding {
node_id: NodeId::from_bytes(kb.node_id),
pubkey: kb.pubkey,
recovery_commitment: kb.recovery_commitment,
timestamp: kb.timestamp,
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct KeyRotation {
pub node_id: NodeId,
pub old_pubkey: [u8; 32],
pub new_pubkey: [u8; 32],
pub timestamp: u64,
pub overlap_expiry: u64,
}
impl KeyRotation {
pub fn decode(bytes: &[u8]) -> Result<KeyRotation> {
let mut out = core::mem::MaybeUninit::<sys::nwep_keyrotation>::zeroed();
Error::check(unsafe {
sys::nwep_keyrotation_decode(bytes.as_ptr(), bytes.len(), out.as_mut_ptr())
})?;
let kr = unsafe { out.assume_init() };
Ok(KeyRotation {
node_id: NodeId::from_bytes(kr.node_id),
old_pubkey: kr.old_pubkey,
new_pubkey: kr.new_pubkey,
timestamp: kr.timestamp,
overlap_expiry: kr.overlap_expiry,
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct Revocation {
pub node_id: NodeId,
pub revoked_pubkey: [u8; 32],
pub recovery_pubkey: [u8; 32],
pub reason: Option<RevocationReason>,
pub timestamp: u64,
}
impl Revocation {
pub fn decode(bytes: &[u8]) -> Result<Revocation> {
let mut out = core::mem::MaybeUninit::<sys::nwep_revocation>::zeroed();
Error::check(unsafe {
sys::nwep_revocation_decode(bytes.as_ptr(), bytes.len(), out.as_mut_ptr())
})?;
let r = unsafe { out.assume_init() };
Ok(Revocation {
node_id: NodeId::from_bytes(r.node_id),
revoked_pubkey: r.revoked_pubkey,
recovery_pubkey: r.recovery_pubkey,
reason: RevocationReason::from_code(r.reason),
timestamp: r.timestamp,
})
}
}
fn produce(mut call: impl FnMut(*mut u8, *mut usize) -> i32) -> Result<Vec<u8>> {
let mut len = 0usize;
Error::check(call(ptr::null_mut(), &mut len))?;
let mut out = vec![0u8; len];
Error::check(call(out.as_mut_ptr(), &mut len))?;
out.truncate(len);
Ok(out)
}
pub fn key_binding(
identity: &Identity,
recovery_commitment: &[u8; 32],
timestamp: u64,
) -> Result<Vec<u8>> {
identity.with_raw_keys(|pk, sk| {
produce(|out, len| unsafe {
sys::nwep_keybinding_create(pk, recovery_commitment.as_ptr(), timestamp, sk, out, len)
})
})
}
pub fn key_rotation(
node_id: &NodeId,
old: &Identity,
new: &Identity,
timestamp: u64,
overlap_expiry: u64,
) -> Result<Vec<u8>> {
let nid = node_id.raw();
old.with_raw_keys(|old_pk, old_sk| {
new.with_raw_keys(|new_pk, new_sk| {
produce(|out, len| unsafe {
sys::nwep_keyrotation_create(
nid.bytes.as_ptr(),
old_pk,
new_pk,
timestamp,
overlap_expiry,
old_sk,
new_sk,
out,
len,
)
})
})
})
}
pub fn revocation(
node_id: &NodeId,
revoked_pubkey: &[u8; 32],
recovery: &Identity,
reason: RevocationReason,
timestamp: u64,
) -> Result<Vec<u8>> {
let nid = node_id.raw();
recovery.with_raw_keys(|rec_pk, rec_sk| {
produce(|out, len| unsafe {
sys::nwep_revocation_create(
nid.bytes.as_ptr(),
revoked_pubkey.as_ptr(),
rec_pk,
reason.code(),
timestamp,
rec_sk,
out,
len,
)
})
})
}
pub struct Log {
raw: *mut sys::nwep_log,
}
impl Log {
pub fn new() -> Result<Log> {
let raw = unsafe { sys::nwep_log_create() };
if raw.is_null() {
return Err(Error::InternalAlloc);
}
Ok(Log { raw })
}
pub fn append(&mut self, entry: &[u8]) -> Result<u64> {
let rc = unsafe { sys::nwep_log_append(self.raw, entry.as_ptr(), entry.len()) };
if rc < 0 {
return Err(Error::from_code(rc as core::ffi::c_int));
}
Ok(rc as u64)
}
pub fn len(&self) -> u64 {
unsafe { sys::nwep_log_size(self.raw) }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn root(&self) -> Result<[u8; 32]> {
let mut root = [0u8; 32];
Error::check(unsafe { sys::nwep_log_root(self.raw, root.as_mut_ptr()) })?;
Ok(root)
}
pub fn as_ptr(&self) -> *mut sys::nwep_log {
self.raw
}
}
impl Drop for Log {
fn drop(&mut self) {
unsafe { sys::nwep_log_free(self.raw) };
}
}