add error handling to cryptonight.

Also remove the variant enum for separate functions.
This commit is contained in:
Boog900 2023-10-18 12:52:43 +01:00
parent 21f1448343
commit ac87f9998e
No known key found for this signature in database
GPG key ID: 5401367FB7302004
2 changed files with 50 additions and 47 deletions

View file

@ -8,6 +8,7 @@ authors = ["Boog900", "The Monero Project"]
repository = "https://github.com/Cuprate/cuprate/tree/main/cryptonight"
[dependencies]
thiserror = "1"
[build-dependencies]
cc = "1"

View file

@ -10,59 +10,64 @@ extern "C" {
);
}
/// CryptoNight variants used in Monero, with data needed for specific variants.
pub enum Variant {
V0,
V1,
V2,
R { height: u64 },
}
impl Variant {
/// Returns the height of the block we are hashing, if thats relevant for this variant otherwise
/// `0` is returned.
fn height(&self) -> u64 {
if let Variant::R { height } = self {
*height
} else {
0
}
}
fn identifier(&self) -> i32 {
match self {
Variant::V0 => 0,
Variant::V1 => 1,
Variant::V2 => 2,
Variant::R { .. } => 4,
}
}
}
/// Calculates the CryptoNight variant hash of buf.
pub fn cryptonight_hash(buf: &[u8], variant: &Variant) -> [u8; 32] {
/// Calculates the CryptoNight v0 hash of buf.
///
pub fn cryptonight_hash_v0(buf: &[u8]) -> [u8; 32] {
let mut hash = [0; 32];
unsafe {
cn_slow_hash(
buf.as_ptr(),
buf.len(),
hash.as_mut_ptr(),
variant.identifier(),
0,
variant.height(),
);
cn_slow_hash(buf.as_ptr(), buf.len(), hash.as_mut_ptr(), 0, 0, 0);
}
hash
}
#[derive(thiserror::Error, Debug, Copy, Clone, Eq, PartialEq)]
#[error("Data can't be hashed")]
pub struct DataCanNotBeHashed;
/// Calculates the CryptoNight v1 hash of buf.
///
/// This will return an error if buf is less than43 bytes.
///
pub fn cryptonight_hash_v1(buf: &[u8]) -> Result<[u8; 32], DataCanNotBeHashed> {
if buf.len() < 43 {
return Err(DataCanNotBeHashed);
}
let mut hash = [0; 32];
unsafe {
cn_slow_hash(buf.as_ptr(), buf.len(), hash.as_mut_ptr(), 1, 0, 0);
}
Ok(hash)
}
/// Calculates the CryptoNight v2 hash of buf.
///
pub fn cryptonight_hash_v2(buf: &[u8]) -> [u8; 32] {
let mut hash = [0; 32];
unsafe {
cn_slow_hash(buf.as_ptr(), buf.len(), hash.as_mut_ptr(), 2, 0, 0);
}
hash
}
/// Calculates the CryptoNight R hash of buf.
///
pub fn cryptonight_hash_r(buf: &[u8], height: u64) -> [u8; 32] {
let mut hash = [0; 32];
unsafe {
cn_slow_hash(buf.as_ptr(), buf.len(), hash.as_mut_ptr(), 4, 0, height);
}
hash
}
#[cfg(test)]
mod tests {
use crate::{cryptonight_hash, Variant};
use crate::*;
#[test]
fn slow_hash_0() {
let test = |inp: &str, exp: &str| {
let res = hex::encode(cryptonight_hash(&hex::decode(inp).unwrap(), &Variant::V0));
let res = hex::encode(cryptonight_hash_v0(&hex::decode(inp).unwrap()));
assert_eq!(&res, exp);
};
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/tests/hash/tests-slow.txt
@ -87,7 +92,7 @@ mod tests {
#[test]
fn slow_hash_1() {
let test = |inp: &str, exp: &str| {
let res = hex::encode(cryptonight_hash(&hex::decode(inp).unwrap(), &Variant::V1));
let res = hex::encode(cryptonight_hash_v1(&hex::decode(inp).unwrap()).unwrap());
assert_eq!(&res, exp);
};
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/tests/hash/tests-slow-1.txt
@ -116,7 +121,7 @@ mod tests {
#[test]
fn slow_hash_2() {
let test = |inp: &str, exp: &str| {
let res = hex::encode(cryptonight_hash(&hex::decode(inp).unwrap(), &Variant::V2));
let res = hex::encode(cryptonight_hash_v2(&hex::decode(inp).unwrap()));
assert_eq!(&res, exp);
};
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/tests/hash/tests-slow-2.txt
@ -165,10 +170,7 @@ mod tests {
#[test]
fn slow_hash_r() {
let test = |inp: &str, exp: &str, height: u64| {
let res = hex::encode(cryptonight_hash(
&hex::decode(inp).unwrap(),
&Variant::R { height },
));
let res = hex::encode(cryptonight_hash_r(&hex::decode(inp).unwrap(), height));
assert_eq!(&res, exp);
};