1use crate::{InternalError, VerifyingKey, PUBLIC_KEY_LENGTH};
2
3use arrayref::{array_mut_ref, array_ref};
4use failure::Error;
5use serde::*;
6use std::{convert::TryFrom, mem};
7
8use salsa20::stream_cipher::generic_array::GenericArray;
9use salsa20::stream_cipher::{NewStreamCipher, SyncStreamCipher};
10use salsa20::Salsa20;
11
12use sha2::{Digest, Sha512};
13
14pub const ADDRESS_LENGTH: usize = 5;
16
17const BLOCK_SIZE: usize = 64;
18const MEMORY_SIZE: usize = 1 << 21; const U64_SIZE: usize = mem::size_of::<u64>();
20
21#[derive(Clone, Debug, PartialEq)]
30pub struct Address([u8; ADDRESS_LENGTH]);
31
32impl Serialize for Address {
33 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
34 where
35 S: Serializer,
36 {
37 serializer.serialize_str(&hex::encode(self.0))
38 }
39}
40
41fn memory_hard_hash(public_key: &VerifyingKey) -> Result<[u8; BLOCK_SIZE], Error> {
43 let mut buf = [0u8; BLOCK_SIZE];
44 let mut mem = [0u8; MEMORY_SIZE];
45
46 let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.into();
47 buf.copy_from_slice(&Sha512::digest(&public_key_bytes));
48
49 let mut cipher = Salsa20::new(
50 GenericArray::from_slice(&buf[0..32]),
51 GenericArray::from_slice(&buf[32..40]),
52 );
53
54 cipher.apply_keystream(&mut mem[..BLOCK_SIZE]);
55
56 for i in (BLOCK_SIZE..MEMORY_SIZE).step_by(BLOCK_SIZE) {
57 let (src, dst) = mem.split_at_mut(i);
58
59 dst[..BLOCK_SIZE].copy_from_slice(&src[i - BLOCK_SIZE..]);
60 cipher.apply_keystream(&mut dst[..BLOCK_SIZE]);
61 }
62
63 for i in (0..MEMORY_SIZE).step_by(2 * U64_SIZE) {
64 let n1 = u64::from_be_bytes(*array_ref!(mem, i, U64_SIZE));
65 let n2 = u64::from_be_bytes(*array_ref!(mem, i + U64_SIZE, U64_SIZE));
66
67 let i1 = usize::try_from(n1)? % (BLOCK_SIZE / U64_SIZE) * U64_SIZE;
68 let i2 = usize::try_from(n2)? % (MEMORY_SIZE / U64_SIZE) * U64_SIZE;
69
70 mem::swap(
71 array_mut_ref!(buf, i1, U64_SIZE),
72 array_mut_ref!(mem, i2, U64_SIZE),
73 );
74
75 cipher.apply_keystream(&mut buf[..]);
76 }
77
78 if buf[0] >= 17 {
79 Err(InternalError::InvalidHashcash.into())
80 } else {
81 Ok(buf)
82 }
83}
84
85impl TryFrom<&VerifyingKey> for Address {
88 type Error = Error;
89
90 fn try_from(public_key: &VerifyingKey) -> Result<Self, Error> {
91 let hash = memory_hard_hash(public_key)?;
92 let addr = array_ref!(hash, BLOCK_SIZE - ADDRESS_LENGTH, ADDRESS_LENGTH).clone();
93
94 if addr[0] == 0xff || addr[..] == [0, 0, 0, 0, 0] {
95 Err(InternalError::ReservedAddress.into())
96 } else {
97 Ok(Address(addr))
98 }
99 }
100}
101
102impl TryFrom<&[u8]> for Address {
104 type Error = Error;
105
106 fn try_from(bytes: &[u8]) -> Result<Self, Error> {
107 if bytes.len() != ADDRESS_LENGTH {
108 Err(InternalError::BytesLengthError.into())
109 } else {
110 Ok(Self(*array_ref!(bytes, 0, ADDRESS_LENGTH)))
111 }
112 }
113}