refactor(bytecode/pointer): use [u8; 16] instead of (u64, u64)

API BREAK: this changes the computed HMAC
This commit is contained in:
Alain Zscheile 2022-09-27 15:19:25 +02:00
parent 724531eae9
commit 6256336a5c
2 changed files with 74 additions and 37 deletions

View file

@ -2,30 +2,49 @@ use siphasher::sip::SipHasher24 as SipHasher;
/// An atomic value (128bit),
/// can also be used to sign a pointer
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, align(16))]
pub struct Atom(pub u64, pub u64);
pub struct Atom(pub [u8; 16]);
impl Atom {
#[inline(always)]
#[inline]
fn build_hasher(&self) -> SipHasher {
SipHasher::new_with_keys(self.0, self.1)
SipHasher::new_with_key(&self.0)
}
}
const M64: u128 = u64::MAX as u128;
impl From<u128> for Atom {
#[inline]
fn from(x: u128) -> Atom {
Atom((x >> 64) as u64, (x & M64) as u64)
Atom(x.to_be_bytes())
}
}
impl From<(u64, u64)> for Atom {
#[inline]
fn from((a, b): (u64, u64)) -> Atom {
let mut this = Atom([0; 16]);
{
let (a_, b_) = this.0.split_at_mut(8);
a_.copy_from_slice(&a.to_be_bytes());
b_.copy_from_slice(&b.to_be_bytes());
}
this
}
}
impl From<Atom> for u128 {
#[inline]
fn from(Atom(a, b): Atom) -> u128 {
(u128::from(a) << 64) + u128::from(b)
fn from(Atom(x): Atom) -> u128 {
u128::from_be_bytes(x)
}
}
impl From<Atom> for (u64, u64) {
#[inline]
fn from(Atom(x): Atom) -> (u64, u64) {
let (a, b) = x.split_at(8);
(u64::from_be_bytes(a.try_into().unwrap()), u64::from_be_bytes(b.try_into().unwrap()))
}
}
@ -33,16 +52,21 @@ impl From<Atom> for u128 {
/// without verifying the pointer first
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, align(16))]
pub struct Pointer {
pub hmac: u64,
pub payload: u64,
}
pub struct Pointer(pub [u8; 16]);
impl From<Pointer> for Atom {
#[inline(always)]
/// allows to derive a atom/pointer key from a pointer
fn from(x: Pointer) -> Self {
Self(x.hmac, x.payload)
fn from(Pointer(x): Pointer) -> Self {
Self(x)
}
}
impl From<Atom> for Pointer {
#[inline(always)]
/// allows to derive a atom/pointer key from a pointer
fn from(Atom(x): Atom) -> Self {
Self(x)
}
}
@ -54,22 +78,25 @@ impl Pointer {
h.finish()
}
#[inline]
pub fn new_with_key(payload: u64, key: &Atom) -> Pointer {
Pointer {
hmac: Self::calculate_hmac(payload, key),
payload,
}
let hmac = Self::calculate_hmac(payload, key);
Atom::from((hmac, payload)).into()
}
#[inline]
pub fn verify(&self, key: &Atom) -> Option<u64> {
if self.hmac == Self::calculate_hmac(self.payload, key) {
Some(self.payload)
let (hmac, payload) = Atom(self.0).into();
if hmac == Self::calculate_hmac(payload, key) {
Some(payload)
} else {
None
}
}
#[inline]
pub fn origin(&self) -> u16 {
u16::from_be_bytes(self.0[8..10].try_into().unwrap())
}
}
impl crate::Parse<'_> for Pointer {
@ -77,17 +104,17 @@ impl crate::Parse<'_> for Pointer {
fn parse(inp: &[u8]) -> Result<(&[u8], Self), ()> {
if inp.len() < 16 {
return Err(());
} else {
let (this, next) = inp.split_at(16);
Ok((next, Self(this.try_into().unwrap())))
}
let hmac = u64::from_be_bytes(inp[0..8].try_into().unwrap());
let payload = u64::from_be_bytes(inp[8..16].try_into().unwrap());
Ok((&inp[16..], Self { hmac, payload }))
}
}
#[cfg(any(test, feature = "std"))]
impl Pointer {
#[inline]
pub fn write_to<W: std::io::Write>(&self, writer: W) -> std::io::Result<()> {
Atom::from(*self).write_to(writer)
pub fn write_to<W: std::io::Write>(&self, mut writer: W) -> std::io::Result<()> {
writer.write_all(&self.0)
}
}
@ -95,16 +122,14 @@ impl crate::Parse<'_> for Atom {
type Err = ();
#[inline]
fn parse(inp: &[u8]) -> Result<(&[u8], Self), ()> {
let (inp, p) = Pointer::parse(inp)?;
Ok((inp, p.into()))
Pointer::parse(inp).map(|(inp, p)| (inp, p.into()))
}
}
#[cfg(any(test, feature = "std"))]
impl Atom {
#[inline]
pub fn write_to<W: std::io::Write>(&self, mut writer: W) -> std::io::Result<()> {
writer.write_all(&self.0.to_be_bytes())?;
writer.write_all(&self.1.to_be_bytes())?;
Ok(())
writer.write_all(&self.0)
}
}
@ -131,10 +156,21 @@ mod tests {
#[test]
fn pointer_usage() {
let k = Atom(0xdead, 0xbeef);
let k = Atom([0, 0, 0, 0, 0, 0, 0xde, 0xad, 0, 0, 0, 0, 0, 0, 0xbe, 0xef]);
let p = Pointer::new_with_key(0xfefe, &k);
// verify that this is the same value on all systems
assert_eq!(p.hmac, 0xf5779875fe3ef8e);
assert_eq!(p.0[0..8], [42, 115, 131, 215, 127, 235, 147, 241]);
assert_eq!(p.verify(&k), Some(0xfefe));
assert_eq!(p.origin(), 0);
}
#[test]
fn pointer_usage2() {
let k = Atom([0, 0, 0, 0, 0, 0, 0xde, 0xad, 0, 0, 0, 0, 0, 0, 0xbe, 0xef]);
let p = Pointer::new_with_key(0x0508deadbeeffefe, &k);
// verify that this is the same value on all systems
assert_eq!(p.0[0..8], [98, 122, 191, 167, 34, 251, 28, 171]);
assert_eq!(p.verify(&k), Some(0x0508deadbeeffefe));
assert_eq!(p.origin(), 0x0508);
}
}

View file

@ -219,7 +219,7 @@ impl Process {
break;
}
Some(StackEntValue::Int(i)) => i != 0,
Some(StackEntValue::Atom(a)) => a != Atom(0, 0),
Some(StackEntValue::Atom(a)) => a != Atom([0; 16]),
Some(z) => {
tracing::error!(
"encountered invalid condition value {:?} @ {}",
@ -294,7 +294,7 @@ impl Process {
let b = self.stack.pop();
match (a, b) {
(Some(StackEntValue::Int(a)), Some(StackEntValue::Int(b))) => {
self.stack.push(StackEntValue::Atom(Atom(b, a)));
self.stack.push(StackEntValue::Atom((b, a).into()));
}
x => {
tracing::error!("BIF atom:build @ {} called with {:?}", previptr, x);
@ -303,7 +303,8 @@ impl Process {
}
}
Instr::ADecon => match self.stack.pop() {
Some(StackEntValue::Atom(Atom(b, a))) => {
Some(StackEntValue::Atom(atom)) => {
let (b, a) = atom.into();
self.stack.push(StackEntValue::Int(b));
self.stack.push(StackEntValue::Int(a));
}