1use std::fmt;
2use std::io;
3
4use blake2b_simd::Params as Blake2Params;
5use byteorder::{ByteOrder, LittleEndian};
6
7use crate::{node_data, NodeData, MAX_NODE_DATA_SIZE};
8
9fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] {
10 let hash_result = Blake2Params::new()
11 .hash_length(32)
12 .personal(personalization)
13 .to_state()
14 .update(input)
15 .finalize();
16 let mut result = [0u8; 32];
17 result.copy_from_slice(hash_result.as_bytes());
18 result
19}
20
21fn personalization(branch_id: u32) -> [u8; 16] {
22 let mut result = [0u8; 16];
23 result[..12].copy_from_slice(b"ZcashHistory");
24 LittleEndian::write_u32(&mut result[12..], branch_id);
25 result
26}
27
28pub trait Version {
30 type NodeData: fmt::Debug;
32
33 fn consensus_branch_id(data: &Self::NodeData) -> u32;
35
36 fn start_height(data: &Self::NodeData) -> u64;
38
39 fn end_height(data: &Self::NodeData) -> u64;
41
42 fn combine(left: &Self::NodeData, right: &Self::NodeData) -> Self::NodeData {
44 assert_eq!(
45 Self::consensus_branch_id(left),
46 Self::consensus_branch_id(right)
47 );
48
49 let mut hash_buf = [0u8; MAX_NODE_DATA_SIZE * 2];
50 let size = {
51 let mut cursor = ::std::io::Cursor::new(&mut hash_buf[..]);
52 Self::write(left, &mut cursor)
53 .expect("Writing to memory buf with enough length cannot fail; qed");
54 Self::write(right, &mut cursor)
55 .expect("Writing to memory buf with enough length cannot fail; qed");
56 cursor.position() as usize
57 };
58
59 let hash = blake2b_personal(
60 &personalization(Self::consensus_branch_id(left)),
61 &hash_buf[..size],
62 );
63
64 Self::combine_inner(hash, left, right)
65 }
66
67 fn combine_inner(
71 subtree_commitment: [u8; 32],
72 left: &Self::NodeData,
73 right: &Self::NodeData,
74 ) -> Self::NodeData;
75
76 fn read<R: io::Read>(consensus_branch_id: u32, r: &mut R) -> io::Result<Self::NodeData>;
78
79 fn write<W: io::Write>(data: &Self::NodeData, w: &mut W) -> io::Result<()>;
81
82 #[allow(clippy::wrong_self_convention)]
84 fn to_bytes(data: &Self::NodeData) -> Vec<u8> {
85 let mut buf = [0u8; MAX_NODE_DATA_SIZE];
86 let pos = {
87 let mut cursor = std::io::Cursor::new(&mut buf[..]);
88 Self::write(data, &mut cursor).expect("Cursor cannot fail");
89 cursor.position() as usize
90 };
91
92 buf[0..pos].to_vec()
93 }
94
95 fn from_bytes<T: AsRef<[u8]>>(consensus_branch_id: u32, buf: T) -> io::Result<Self::NodeData> {
97 let mut cursor = std::io::Cursor::new(buf);
98 Self::read(consensus_branch_id, &mut cursor)
99 }
100
101 fn hash(data: &Self::NodeData) -> [u8; 32] {
103 let bytes = Self::to_bytes(data);
104
105 blake2b_personal(&personalization(Self::consensus_branch_id(data)), &bytes)
106 }
107}
108
109pub enum V1 {}
113
114impl Version for V1 {
115 type NodeData = NodeData;
116
117 fn consensus_branch_id(data: &Self::NodeData) -> u32 {
118 data.consensus_branch_id
119 }
120
121 fn start_height(data: &Self::NodeData) -> u64 {
122 data.start_height
123 }
124
125 fn end_height(data: &Self::NodeData) -> u64 {
126 data.end_height
127 }
128
129 fn combine_inner(
130 subtree_commitment: [u8; 32],
131 left: &Self::NodeData,
132 right: &Self::NodeData,
133 ) -> Self::NodeData {
134 NodeData::combine_inner(subtree_commitment, left, right)
135 }
136
137 fn read<R: io::Read>(consensus_branch_id: u32, r: &mut R) -> io::Result<Self::NodeData> {
138 NodeData::read(consensus_branch_id, r)
139 }
140
141 fn write<W: io::Write>(data: &Self::NodeData, w: &mut W) -> io::Result<()> {
142 data.write(w)
143 }
144}
145
146pub enum V2 {}
150
151impl Version for V2 {
152 type NodeData = node_data::V2;
153
154 fn consensus_branch_id(data: &Self::NodeData) -> u32 {
155 data.v1.consensus_branch_id
156 }
157
158 fn start_height(data: &Self::NodeData) -> u64 {
159 data.v1.start_height
160 }
161
162 fn end_height(data: &Self::NodeData) -> u64 {
163 data.v1.end_height
164 }
165
166 fn combine_inner(
167 subtree_commitment: [u8; 32],
168 left: &Self::NodeData,
169 right: &Self::NodeData,
170 ) -> Self::NodeData {
171 node_data::V2::combine_inner(subtree_commitment, left, right)
172 }
173
174 fn read<R: io::Read>(consensus_branch_id: u32, r: &mut R) -> io::Result<Self::NodeData> {
175 node_data::V2::read(consensus_branch_id, r)
176 }
177
178 fn write<W: io::Write>(data: &Self::NodeData, w: &mut W) -> io::Result<()> {
179 data.write(w)
180 }
181}