1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::alloc::{alloc, Layout};
use blake_hash::Blake256;
pub use digest::{BlockInput, Digest, FixedOutput, Input, Reset};
use digest::generic_array::GenericArray;
use digest::generic_array::typenum::{U200, U32};
use groestl::Groestl256;
use jh_x86_64::Jh256;
use skein_hash::Skein512;
mod aes;
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), feature = "aesni"))]
mod aesni;
const SCRATCH_PAD_SIZE: usize = 1 << 21;
const ROUNDS: usize = 524_288;
#[repr(align(16))]
struct A16<T>(pub T);
#[derive(Debug, Default, Clone)]
pub struct CryptoNight {
internal_hasher: sha3::Keccak256Full,
}
impl CryptoNight {
fn digest_main(keccac: &mut [u8], scratchpad: &mut [u8]) {
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), feature = "aesni"))]
{
if is_x86_feature_detected!("aes") && is_x86_feature_detected!("sse4.1") {
return unsafe { aesni::digest_main(keccac, scratchpad) };
}
}
aes::digest_main(keccac, scratchpad);
}
fn hash_final_state(state: &[u8]) -> GenericArray<u8, <Self as FixedOutput>::OutputSize> {
match state[0] & 3 {
0 => Blake256::digest(&state),
1 => Groestl256::digest(&state),
2 => Jh256::digest(&state),
3 => Skein512::digest(&state),
x => unreachable!("Invalid output option {}", x)
}
}
}
impl Input for CryptoNight {
fn input<B: AsRef<[u8]>>(&mut self, data: B) {
Input::input(&mut self.internal_hasher, data);
}
}
impl Reset for CryptoNight {
fn reset(&mut self) {
Reset::reset(&mut self.internal_hasher);
}
}
impl BlockInput for CryptoNight {
type BlockSize = <sha3::Keccak256Full as BlockInput>::BlockSize;
}
impl FixedOutput for CryptoNight {
type OutputSize = U32;
fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> {
let mut keccac = A16(self.internal_hasher.fixed_result());
let keccac = &mut keccac.0;
let mut scratch_pad = unsafe {
let buffer = alloc(Layout::from_size_align_unchecked(SCRATCH_PAD_SIZE, 16));
Vec::from_raw_parts(buffer, SCRATCH_PAD_SIZE, SCRATCH_PAD_SIZE)
};
Self::digest_main(keccac, &mut scratch_pad);
#[allow(clippy::cast_ptr_alignment)]
tiny_keccak::keccakf(unsafe { &mut *(keccac as *mut GenericArray<u8, U200> as *mut [u64; 25]) });
Self::hash_final_state(&keccac)
}
}