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
use crate::{InternalError, PublicKey, PUBLIC_KEY_LENGTH};
use arrayref::{array_mut_ref, array_ref};
use failure::Error;
use serde::*;
use std::{convert::TryFrom, mem};
use salsa20::stream_cipher::generic_array::GenericArray;
use salsa20::stream_cipher::{NewStreamCipher, SyncStreamCipher};
use salsa20::Salsa20;
use sha2::{Digest, Sha512};
pub const ADDRESS_LENGTH: usize = 5;
const BLOCK_SIZE: usize = 64;
const MEMORY_SIZE: usize = 1 << 21;
const U64_SIZE: usize = mem::size_of::<u64>();
#[derive(Clone, Debug, PartialEq)]
pub struct Address([u8; ADDRESS_LENGTH]);
impl Serialize for Address {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&hex::encode(self.0))
}
}
fn memory_hard_hash(public_key: &PublicKey) -> Result<[u8; BLOCK_SIZE], Error> {
let mut buf = [0u8; BLOCK_SIZE];
let mut mem = [0u8; MEMORY_SIZE];
let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.into();
buf.copy_from_slice(&Sha512::digest(&public_key_bytes));
let mut cipher = Salsa20::new(
GenericArray::from_slice(&buf[0..32]),
GenericArray::from_slice(&buf[32..40]),
);
cipher.apply_keystream(&mut mem[..BLOCK_SIZE]);
for i in (BLOCK_SIZE..MEMORY_SIZE).step_by(BLOCK_SIZE) {
let (src, dst) = mem.split_at_mut(i);
dst[..BLOCK_SIZE].copy_from_slice(&src[i - BLOCK_SIZE..]);
cipher.apply_keystream(&mut dst[..BLOCK_SIZE]);
}
for i in (0..MEMORY_SIZE).step_by(2 * U64_SIZE) {
let n1 = u64::from_be_bytes(*array_ref!(mem, i, U64_SIZE));
let n2 = u64::from_be_bytes(*array_ref!(mem, i + U64_SIZE, U64_SIZE));
let i1 = usize::try_from(n1)? % (BLOCK_SIZE / U64_SIZE) * U64_SIZE;
let i2 = usize::try_from(n2)? % (MEMORY_SIZE / U64_SIZE) * U64_SIZE;
mem::swap(
array_mut_ref!(buf, i1, U64_SIZE),
array_mut_ref!(mem, i2, U64_SIZE),
);
cipher.apply_keystream(&mut buf[..]);
}
if buf[0] >= 17 {
Err(InternalError::InvalidHashcash.into())
} else {
Ok(buf)
}
}
impl TryFrom<&PublicKey> for Address {
type Error = Error;
fn try_from(public_key: &PublicKey) -> Result<Self, Error> {
let hash = memory_hard_hash(public_key)?;
let addr = array_ref!(hash, BLOCK_SIZE - ADDRESS_LENGTH, ADDRESS_LENGTH).clone();
if addr[0] == 0xff || addr[..] == [0, 0, 0, 0, 0] {
Err(InternalError::ReservedAddress.into())
} else {
Ok(Address(addr))
}
}
}
impl TryFrom<&[u8]> for Address {
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() != ADDRESS_LENGTH {
Err(InternalError::BytesLengthError.into())
} else {
Ok(Self(*array_ref!(bytes, 0, ADDRESS_LENGTH)))
}
}
}