use crate::error::{Error, Result};
use crate::identity::{Identity, NodeId};
use crate::trust::bls::{BlsKeypair, SIGNATURE_SIZE};
use core::ptr;
use core::time::Duration;
use nwep_sys as sys;
#[derive(Clone, Copy)]
pub struct PartialSig {
index: u8,
sig: [u8; SIGNATURE_SIZE],
}
impl PartialSig {
pub fn index(&self) -> u8 {
self.index
}
pub fn signature(&self) -> &[u8; SIGNATURE_SIZE] {
&self.sig
}
}
pub struct AnchorNode {
raw: *mut sys::nwep_anchor_node,
}
unsafe impl Send for AnchorNode {}
impl AnchorNode {
pub fn new(
identity: &Identity,
bls: &BlsKeypair,
share_index: u8,
collection_window: Duration,
) -> Result<AnchorNode> {
let window_ms = collection_window.as_millis().min(u64::MAX as u128) as u64;
let raw = identity.with_raw_keys(|pk, sk| unsafe {
sys::nwep_anchor_node_create(
pk,
sk,
bls.secret().as_ptr(),
bls.public_key().as_ptr(),
share_index as u64,
window_ms,
)
});
if raw.is_null() {
return Err(Error::ConfigInvalid);
}
Ok(AnchorNode { raw })
}
pub fn collect_log_root(
&mut self,
epoch: u64,
server_root: &[u8; 32],
server_log_size: u64,
local_root: &[u8; 32],
) -> Result<()> {
Error::check(unsafe {
sys::nwep_anchor_node_collect_log_root(
self.raw,
epoch,
server_root.as_ptr(),
server_log_size,
local_root.as_ptr(),
)
})
}
pub fn produce_partial_sig(
&mut self,
epoch: u64,
merkle_root: &[u8; 32],
log_size: u64,
) -> Result<PartialSig> {
let mut index = 0u8;
let mut sig = [0u8; SIGNATURE_SIZE];
Error::check(unsafe {
sys::nwep_anchor_node_produce_partial_sig(
self.raw,
epoch,
merkle_root.as_ptr(),
log_size,
&mut index,
sig.as_mut_ptr(),
)
})?;
Ok(PartialSig { index, sig })
}
pub fn dispatch(
&mut self,
requester: &NodeId,
anchor_ids: &[NodeId],
req: &crate::Request,
res: crate::Responder,
now_secs: i64,
) -> crate::DispatchOutcome {
let mut ids = Vec::with_capacity(anchor_ids.len() * 32);
for id in anchor_ids {
ids.extend_from_slice(id.as_bytes());
}
let rc = unsafe {
sys::nwep_anchor_node_dispatch(
self.raw,
requester.raw().bytes.as_ptr(),
ids.as_ptr(),
anchor_ids.len(),
req.raw_msg(),
res.raw_buf(),
now_secs,
)
};
if rc == 1 {
crate::DispatchOutcome::NotMine(res)
} else {
crate::DispatchOutcome::Handled(res.finish(rc))
}
}
pub fn as_ptr(&self) -> *mut sys::nwep_anchor_node {
self.raw
}
}
pub fn request_partial_sig(
client: &crate::Client,
epoch: u64,
merkle_root: &[u8; 32],
log_size: u64,
peer_bls_pubkey: &[u8; 48],
) -> Result<PartialSig> {
let mut index = 0u8;
let mut sig = [0u8; SIGNATURE_SIZE];
Error::check(unsafe {
sys::nwep_anchor_request_partial_sig(
client.as_ptr(),
epoch,
merkle_root.as_ptr(),
log_size,
peer_bls_pubkey.as_ptr(),
&mut index,
sig.as_mut_ptr(),
)
})?;
Ok(PartialSig { index, sig })
}
impl Drop for AnchorNode {
fn drop(&mut self) {
unsafe { sys::nwep_anchor_node_free(self.raw) };
}
}
pub fn finish_checkpoint(
epoch: u64,
merkle_root: &[u8; 32],
log_size: u64,
partials: &[PartialSig],
anchor_bls_pubkeys: &[[u8; 48]],
) -> Result<Vec<u8>> {
if partials.is_empty() || anchor_bls_pubkeys.is_empty() {
return Err(Error::ConfigInvalid);
}
let mut indices = Vec::with_capacity(partials.len());
let mut sigs = Vec::with_capacity(partials.len() * SIGNATURE_SIZE);
for p in partials {
indices.push(p.index);
sigs.extend_from_slice(&p.sig);
}
let mut len = 0usize;
let call = |out: *mut u8, len: *mut usize| unsafe {
sys::nwep_anchor_finish_checkpoint(
epoch,
merkle_root.as_ptr(),
log_size,
indices.as_ptr(),
sigs.as_ptr(),
partials.len(),
anchor_bls_pubkeys.as_ptr().cast::<u8>(),
anchor_bls_pubkeys.len(),
out,
len,
)
};
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)
}