Formatting, build fixes, tests.

This commit is contained in:
Adam Ierymenko 2021-09-29 12:48:36 -04:00
parent c5ed599ef3
commit a23bd89202
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
13 changed files with 124 additions and 89 deletions

View file

@ -55,9 +55,7 @@ impl Write for SHA512 {
}
#[inline(always)]
fn flush(&mut self) -> std::io::Result<()> {
self.0.flush()
}
fn flush(&mut self) -> std::io::Result<()> { self.0.flush() }
}
pub struct SHA384(gcrypt::digest::MessageDigest);
@ -110,7 +108,5 @@ impl Write for SHA384 {
}
#[inline(always)]
fn flush(&mut self) -> std::io::Result<()> {
self.0.flush()
}
fn flush(&mut self) -> std::io::Result<()> { self.0.flush() }
}

View file

@ -1,3 +1,4 @@
/// The poly1305 message authentication function.
pub struct Poly1305(gcrypt::mac::Mac);
pub const POLY1305_ONE_TIME_KEY_SIZE: usize = 32;

View file

@ -2,13 +2,12 @@ use rand_core::{RngCore, Error};
use rand_core::CryptoRng;
use gcrypt::rand::{Level, randomize};
/// Secure random source based on the desired third party library (gcrypt).
pub struct SecureRandom;
impl SecureRandom {
#[inline(always)]
pub fn get() -> Self {
Self
}
pub fn get() -> Self { Self }
}
impl RngCore for SecureRandom {
@ -27,9 +26,7 @@ impl RngCore for SecureRandom {
}
#[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) {
randomize(Level::Strong, dest);
}
fn fill_bytes(&mut self, dest: &mut [u8]) { randomize(Level::Strong, dest); }
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
@ -41,20 +38,18 @@ impl RngCore for SecureRandom {
impl CryptoRng for SecureRandom {}
#[inline(always)]
pub(crate) fn next_u32_secure() -> u32 {
pub fn next_u32_secure() -> u32 {
let mut tmp = 0_u32;
randomize(Level::Strong, unsafe { &mut *(&mut tmp as *mut u32).cast::<[u8; 4]>() });
tmp
}
#[inline(always)]
pub(crate) fn next_u64_secure() -> u64 {
pub fn next_u64_secure() -> u64 {
let mut tmp = 0_u64;
randomize(Level::Strong, unsafe { &mut *(&mut tmp as *mut u64).cast::<[u8; 8]>() });
tmp
}
#[inline(always)]
pub(crate) fn fill_bytes_secure(dest: &mut [u8]) {
randomize(Level::Strong, dest);
}
pub fn fill_bytes_secure(dest: &mut [u8]) { randomize(Level::Strong, dest); }

View file

@ -1,3 +1,4 @@
/// The classic Salsa20 stream cipher supporting 20-round and 12-round variants.
pub struct Salsa(gcrypt::cipher::Cipher);
impl Salsa {

View file

@ -11,14 +11,10 @@ impl<const FREQ: i64> Default for IntervalGate<FREQ> {
impl<const FREQ: i64> IntervalGate<FREQ> {
#[inline(always)]
pub fn new(initial_ts: i64) -> Self {
Self(initial_ts)
}
pub fn new(initial_ts: i64) -> Self { Self(initial_ts) }
#[inline(always)]
pub fn reset(&mut self) {
self.0 = 0;
}
pub fn reset(&mut self) { self.0 = 0; }
#[inline(always)]
pub fn gate(&mut self, time: i64) -> bool {
@ -35,33 +31,31 @@ impl<const FREQ: i64> IntervalGate<FREQ> {
pub struct AtomicIntervalGate<const FREQ: i64>(AtomicI64);
impl<const FREQ: i64> Default for AtomicIntervalGate<FREQ> {
fn default() -> Self {
Self(AtomicI64::new(0))
}
fn default() -> Self { Self(AtomicI64::new(0)) }
}
impl<const FREQ: i64> AtomicIntervalGate<FREQ> {
#[inline(always)]
pub fn new(initial_ts: i64) -> Self {
Self(AtomicI64::new(initial_ts))
}
pub fn new(initial_ts: i64) -> Self { Self(AtomicI64::new(initial_ts)) }
#[inline(always)]
pub fn reset(&self) {
self.0.store(0, Ordering::Relaxed);
}
pub fn reset(&self) { self.0.store(0, Ordering::Relaxed); }
#[inline(always)]
pub fn gate(&self, time: i64) -> bool {
// Note that if two or more threads are using this at once, any thread's time might
// end up being the one stored. This is okay since these times should either be the
// same or very close, and slight differences won't cause issues with the use cases
// for this. This is primarily used to rate gate operations to prevent DOS attacks.
if (time - self.0.load(Ordering::Relaxed)) >= FREQ {
self.0.store(time, Ordering::Relaxed);
true
} else {
pub fn gate(&self, mut time: i64) -> bool {
let prev_time = self.0.load(Ordering::Relaxed);
if (time - prev_time) < FREQ {
false
} else {
loop {
let pt = self.0.swap(time, Ordering::Relaxed);
if pt <= time {
break;
} else {
time = pt;
}
}
true
}
}
}

View file

@ -1,6 +1,7 @@
pub mod hex;
pub mod pool;
pub mod gate;
pub mod varint;
pub(crate) const ZEROES: [u8; 64] = [0_u8; 64];

View file

@ -0,0 +1,53 @@
use std::io::{Read, Write};
pub fn write<W: Write>(w: &mut W, mut v: u64) -> std::io::Result<()> {
let mut b = [0_u8; 10];
let mut i = 10;
loop {
if v > 0x7f {
i -= 1;
b[i] = (v as u8) & 0x7f;
v >>= 7;
} else {
i -= 1;
b[i] = (v as u8) | 0x80;
break;
}
}
w.write_all(&b[i..])
}
pub fn read<R: Read>(r: &mut R) -> std::io::Result<u64> {
let mut v = 0_u64;
let mut buf = [0_u8; 1];
loop {
v <<= 7;
let _ = r.read_exact(&mut buf)?;
let b = buf[0];
if b <= 0x7f {
v |= b as u64;
} else {
v |= (b & 0x7f) as u64;
return Ok(v);
}
}
}
pub(crate) fn read_from_bytes(r: &[u8], cursor: &mut usize) -> std::io::Result<u64> {
let mut v = 0_u64;
let mut c = *cursor;
while c < r.len() {
v <<= 7;
let b = unsafe { *r.get_unchecked(c) };
c += 1;
if b <= 0x7f {
v |= b as u64;
} else {
v |= (b & 0x7f) as u64;
*cursor = c;
return Ok(v);
}
}
*cursor = c;
return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "incomplete varint"));
}

View file

@ -23,7 +23,6 @@ impl Address {
}
}
/// Get an address from a byte slice or return None if it is zero or reserved.
#[inline(always)]
pub fn from_bytes(b: &[u8]) -> Option<Address> {
if b.len() >= ADDRESS_SIZE {
@ -38,6 +37,16 @@ impl Address {
}
}
#[inline(always)]
pub fn from_bytes_fixed(b: &[u8; ADDRESS_SIZE]) -> Option<Address> {
let i = (b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64;
if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 {
Some(Address(unsafe { NonZeroU64::new_unchecked(i) }))
} else {
None
}
}
#[inline(always)]
pub fn to_bytes(&self) -> [u8; ADDRESS_SIZE] {
let i = self.0.get();
@ -61,7 +70,7 @@ impl Address {
#[inline(always)]
pub(crate) fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Option<Self>> {
buf.read_bytes_fixed::<{ ADDRESS_SIZE }>(cursor).map(|b| Self::from_bytes(b))
buf.read_bytes_fixed::<{ ADDRESS_SIZE }>(cursor).map(|b| Self::from_bytes_fixed(b))
}
}

View file

@ -28,7 +28,6 @@ impl<const L: usize> Buffer<L> {
pub fn new() -> Self { Self(0, [0_u8; L]) }
/// Get a Buffer initialized with a copy of a byte slice.
#[inline(always)]
pub fn from_bytes(b: &[u8]) -> std::io::Result<Self> {
let l = b.len();
if l <= L {
@ -165,19 +164,9 @@ impl<const L: usize> Buffer<L> {
}
/// Append a variable length integer to this buffer.
///
/// Varints are encoded as a series of 7-bit bytes terminated by a final 7-bit byte whose
/// most significant bit is set. Unlike fixed size integers varints are written in little
/// endian order (in 7-bit chunks).
///
/// They are slower than fixed size values so they should not be used in formats that are
/// created or parsed in very speed-critical paths.
#[inline(always)]
pub fn append_varint(&mut self, mut i: u64) -> std::io::Result<()> {
while i >= 0x80 {
self.append_u8((i as u8) & 0x7f)?;
i >>= 7;
}
self.append_u8((i as u8) | 0x80)
crate::util::varint::write(self, i)
}
/// Append a byte
@ -317,20 +306,9 @@ impl<const L: usize> Buffer<L> {
}
/// Get the next variable length integer and advance the cursor by its length in bytes.
#[inline(always)]
pub fn read_varint(&self, cursor: &mut usize) -> std::io::Result<u64> {
let mut i = 0_u64;
let mut p = 0;
loop {
let b = self.read_u8(cursor)?;
if (b & 0x80) == 0 {
i |= (b as u64).wrapping_shl(p);
p += 7;
} else {
i |= ((b & 0x7f) as u64) << p;
break;
}
}
Ok(i)
crate::util::varint::read_from_bytes(&(self.1[self.0..]), cursor)
}
/// Get the next u8 and advance the cursor.

View file

@ -71,16 +71,7 @@ impl Dictionary {
}
pub fn get_bool(&self, k: &str) -> Option<bool> {
self.0.get(k).map_or(None, |v| {
if v.is_empty() {
Some(false)
} else {
Some(match v[0] {
b'1' | b't' | b'T' | b'y' | b'Y' => true,
_ => false
})
}
})
self.0.get(k).map_or(None, |v| v.first().map_or(Some(false), |c| Some("1tTyY".contains(*c as char))))
}
pub fn set_str(&mut self, k: &str, v: &str) {
@ -96,7 +87,7 @@ impl Dictionary {
}
pub fn set_bool(&mut self, k: &str, v: bool) {
let _ = self.0.insert(String::from(k), (if v { [b'1'] } else { [b'0'] }).to_vec());
let _ = self.0.insert(String::from(k), vec![if v { b'1' } else { b'0' }]);
}
/// Write a dictionary in transport format to a writer.

View file

@ -1,7 +1,7 @@
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use crate::vl1::{Address, Endpoint, Identity};
use crate::vl1::{Address, Endpoint, Identity, Dictionary};
use crate::vl1::buffer::Buffer;
use crate::vl1::protocol::PACKET_SIZE_MAX;
@ -15,6 +15,7 @@ pub struct Locator {
pub subject: Address,
pub signer: Address,
pub timestamp: i64,
pub metadata: Option<Dictionary>,
pub endpoints: Vec<Endpoint>,
pub signature: Vec<u8>,
}
@ -34,6 +35,7 @@ impl Locator {
subject,
signer: signer_identity.address(),
timestamp: ts,
metadata: None,
endpoints: endpoints.to_vec(),
signature: Vec::new()
};
@ -81,12 +83,16 @@ impl Locator {
fn marshal_internal<const BL: usize>(&self, buf: &mut Buffer<BL>, exclude_signature: bool) -> std::io::Result<()> {
self.subject.marshal(buf)?;
self.signer.marshal(buf)?;
buf.append_u64(self.timestamp as u64)?;
buf.append_varint(self.timestamp as u64)?;
self.metadata.map_or_else(|| buf.append_varint(0), |d| {
let db = d.to_bytes();
buf.append_varint(db.len() as u64)?;
buf.append_bytes(db.as_slice())
})?;
buf.append_varint(self.endpoints.len() as u64)?;
for e in self.endpoints.iter() {
e.marshal(buf)?;
}
buf.append_varint(0)?; // length of any additional fields
if !exclude_signature {
buf.append_varint(self.signature.len() as u64)?;
buf.append_bytes(self.signature.as_slice())?;
@ -104,18 +110,26 @@ impl Locator {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid subject or signer address"));
}
let timestamp = buf.read_u64(cursor)? as i64;
let metadata_size = buf.read_varint(cursor)? as usize;
let metadata = if metadata_size > 0 {
let md = Dictionary::from_bytes(buf.read_bytes(metadata_size, cursor)?);
if md.is_none() {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid meta-data"));
}
md
} else { None };
let endpoint_count = buf.read_varint(cursor)? as usize;
let mut endpoints: Vec<Endpoint> = Vec::new();
for _ in 0..endpoint_count {
endpoints.push(Endpoint::unmarshal(buf, cursor)?);
}
*cursor += buf.read_varint(cursor)? as usize;
let signature_len = buf.read_varint(cursor)? as usize;
let signature = buf.read_bytes(signature_len, cursor)?;
Ok(Locator {
subject: subject.unwrap(),
signer: signer.unwrap(),
timestamp,
metadata,
endpoints,
signature: signature.to_vec(),
})

View file

@ -16,12 +16,17 @@ impl MAC {
#[inline(always)]
pub fn from_bytes(b: &[u8]) -> Option<MAC> {
if b.len() >= 6 {
NonZeroU64::new((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64).map_or(None, |i| Some(MAC(i)))
NonZeroU64::new((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64).map(|i| MAC(i))
} else {
None
}
}
#[inline(always)]
pub fn from_bytes_fixed(b: &[u8; 6]) -> Option<MAC> {
NonZeroU64::new((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64).map(|i| MAC(i))
}
#[inline(always)]
pub fn to_bytes(&self) -> [u8; 6] {
let i = self.0.get();
@ -31,7 +36,6 @@ impl MAC {
#[inline(always)]
pub fn to_u64(&self) -> u64 { self.0.get() }
#[inline(always)]
pub(crate) fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> std::io::Result<()> {
buf.append_and_init_bytes_fixed(|b: &mut [u8; 6]| {
let i = self.0.get();
@ -46,7 +50,7 @@ impl MAC {
#[inline(always)]
pub(crate) fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Option<Self>> {
buf.read_bytes_fixed::<6>(cursor).map(|b| Self::from_bytes(b))
buf.read_bytes_fixed::<6>(cursor).map(|b| Self::from_bytes_fixed(b))
}
}

View file

@ -296,13 +296,11 @@ mod tests {
#[test]
fn default_root_set() {
let rs = RootSet::from_bytes(&crate::defaults::ROOT_SET).unwrap();
/*
rs.roots.iter().for_each(|r| {
println!("{}", r.identity.to_string());
r.endpoints.iter().for_each(|ep| {
println!(" {}", ep.to_string());
});
});
*/
}
}