refactor(bytecode/pointer): use [u8; 16] instead of (u64, u64)
API BREAK: this changes the computed HMAC
This commit is contained in:
parent
724531eae9
commit
6256336a5c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue