bhwi/ledger/
store.rs

1use core::convert::TryFrom;
2use core::fmt::Debug;
3
4use bitcoin::{
5    consensus::encode::{self, VarInt},
6    hashes::{sha256, Hash, HashEngine},
7};
8
9use super::{apdu::ClientCommandCode, merkle::MerkleTree};
10
11/// This struct keeps has methods to keep track of:
12///   - known preimages
13///   - known Merkle trees from lists of elements
14/// Moreover, it containes the state that is relevant for the interpreted client side commands:
15///   - a queue of bytes that contains any bytes that could not fit in a response from the
16///     GET_PREIMAGE client command (when a preimage is too long to fit in a single message) or the
17///     GET_MERKLE_LEAF_PROOF command (which returns a Merkle proof, which might be too long to fit
18///     in a single message). The data in the queue is returned in one (or more) successive
19///     GET_MORE_ELEMENTS commands from the hardware wallet.
20/// Finally, it keeps track of the yielded values (that is, the values sent from the hardware
21/// wallet with a YIELD client command).
22pub struct DelegatedStore {
23    yielded: Vec<Vec<u8>>,
24    queue: Vec<Vec<u8>>,
25    known_preimages: Vec<([u8; 32], Vec<u8>)>,
26    trees: Vec<MerkleTree>,
27}
28
29impl DelegatedStore {
30    pub fn new() -> Self {
31        Self {
32            yielded: Vec::new(),
33            queue: Vec::new(),
34            known_preimages: Vec::new(),
35            trees: Vec::new(),
36        }
37    }
38
39    /// Adds a preimage to the list of known preimages.
40    /// The client must respond with `element` when a GET_PREIMAGE command is sent with
41    /// `sha256(element)` in its request.
42    pub fn add_known_preimage(&mut self, element: Vec<u8>) {
43        let mut engine = sha256::Hash::engine();
44        engine.input(&element);
45        let hash = sha256::Hash::from_engine(engine).to_byte_array();
46        self.known_preimages.push((hash, element));
47    }
48
49    /// Adds a known Merkleized list.
50    /// Builds the Merkle tree of `elements`, and adds it to the Merkle trees known to the client
51    /// (mapped by Merkle root `mt_root`).
52    /// Moreover, adds all the leafs (after adding the b'\0' prefix) to the list of known preimages.
53    /// If `el` is one of `elements`, the client must respond with b'\0' + `el` when a GET_PREIMAGE
54    /// client command is sent with `sha256(b'\0' + el)`.
55    /// Moreover, the commands GET_MERKLE_LEAF_INDEX and GET_MERKLE_LEAF_PROOF must correctly answer
56    /// queries relative to the Merkle whose root is `mt_root`.
57    pub fn add_known_list(&mut self, elements: &[impl AsRef<[u8]>]) -> [u8; 32] {
58        let mut leaves = Vec::with_capacity(elements.len());
59        for element in elements {
60            let mut preimage = vec![0x00];
61            preimage.extend_from_slice(element.as_ref());
62            let mut engine = sha256::Hash::engine();
63            engine.input(&preimage);
64            let hash = sha256::Hash::from_engine(engine).to_byte_array();
65            self.known_preimages.push((hash, preimage));
66            leaves.push(hash);
67        }
68        let tree = MerkleTree::new(leaves);
69        let root_hash = *tree.root_hash();
70        self.trees.push(tree);
71        root_hash
72    }
73
74    /// Adds the Merkle trees of keys, and the Merkle tree of values (ordered by key)
75    /// of a mapping of bytes to bytes.
76    /// Adds the Merkle tree of the list of keys, and the Merkle tree of the list of corresponding
77    /// values, with the same semantics as the `add_known_list` applied separately to the two lists.
78    pub fn add_known_mapping(&mut self, mapping: &[(Vec<u8>, Vec<u8>)]) {
79        let mut sorted: Vec<&(Vec<u8>, Vec<u8>)> = mapping.iter().collect();
80        sorted.sort_by(|(k1, _), (k2, _)| k1.as_slice().cmp(k2));
81
82        let mut keys = Vec::with_capacity(sorted.len());
83        let mut values = Vec::with_capacity(sorted.len());
84        for (key, value) in sorted {
85            keys.push(key.as_slice());
86            values.push(value.as_slice());
87        }
88        self.add_known_list(&keys);
89        self.add_known_list(&values);
90    }
91
92    // Interprets the client command requested by the hardware wallet, returns the appropriate
93    // response to transmit back and updates interpreter internal states.
94    pub fn execute(&mut self, command: Vec<u8>) -> Result<Vec<u8>, StoreError> {
95        if command.is_empty() {
96            return Err(StoreError::EmptyInput);
97        }
98        match ClientCommandCode::try_from(command[0]) {
99            Ok(ClientCommandCode::Yield) => {
100                self.yielded.push(command[1..].to_vec());
101                Ok(Vec::new())
102            }
103            Ok(ClientCommandCode::GetPreimage) => {
104                get_preimage_command(&mut self.queue, &self.known_preimages, &command[1..])
105            }
106            Ok(ClientCommandCode::GetMerkleLeafProof) => {
107                get_merkle_leaf_proof(&mut self.queue, &self.trees, &command[1..])
108            }
109            Ok(ClientCommandCode::GetMerkleLeafIndex) => {
110                get_merkle_leaf_index(&self.trees, &command[1..])
111            }
112            Ok(ClientCommandCode::GetMoreElements) => get_more_elements(&mut self.queue),
113            Err(()) => Err(StoreError::UnknownCommand(command[0])),
114        }
115    }
116
117    /// Consumes the interpreter and returns the yielded results.
118    pub fn yielded(self) -> Vec<Vec<u8>> {
119        self.yielded
120    }
121}
122
123fn get_preimage_command(
124    queue: &mut Vec<Vec<u8>>,
125    known_preimages: &[([u8; 32], Vec<u8>)],
126    request: &[u8],
127) -> Result<Vec<u8>, StoreError> {
128    if request.len() != 33 || request[0] != b'\0' {
129        return Err(StoreError::UnsupportedRequest(
130            ClientCommandCode::GetPreimage as u8,
131        ));
132    };
133
134    let (_, preimage) = known_preimages
135        .iter()
136        .find(|(hash, _)| hash == &request[1..])
137        .ok_or(StoreError::UnknownHash)?;
138
139    let preimage_len_out = encode::serialize(&VarInt(preimage.len() as u64));
140
141    // We can send at most 255 - len(preimage_len_out) - 1 bytes in a single message;
142    //the rest will be stored for GET_MORE_ELEMENTS
143    let max_payload_size = 255 - preimage_len_out.len() - 1;
144
145    let payload_size = if preimage.len() > max_payload_size {
146        max_payload_size
147    } else {
148        preimage.len()
149    };
150
151    if payload_size < preimage.len() {
152        for byte in &preimage[payload_size..] {
153            queue.push(vec![*byte]);
154        }
155    }
156
157    let mut response = preimage_len_out;
158    response.extend_from_slice(&(payload_size as u8).to_be_bytes());
159    response.extend_from_slice(&preimage[..payload_size]);
160    Ok(response)
161}
162
163fn get_merkle_leaf_proof(
164    queue: &mut Vec<Vec<u8>>,
165    trees: &[MerkleTree],
166    request: &[u8],
167) -> Result<Vec<u8>, StoreError> {
168    if !queue.is_empty() {
169        return Err(StoreError::UnexpectedQueue);
170    } else if request.len() < 34 {
171        return Err(StoreError::UnsupportedRequest(
172            ClientCommandCode::GetMerkleLeafProof as u8,
173        ));
174    };
175
176    let root = &request[0..32];
177    let (tree_size, read): (VarInt, usize) = encode::deserialize_partial(&request[32..])
178        .map_err(|_| StoreError::UnsupportedRequest(ClientCommandCode::GetMerkleLeafProof as u8))?;
179
180    // deserialize consumes the entire vector.
181    let leaf_index: VarInt = encode::deserialize(&request[32 + read..])
182        .map_err(|_| StoreError::UnsupportedRequest(ClientCommandCode::GetMerkleLeafProof as u8))?;
183
184    let tree = trees
185        .iter()
186        .find(|tree| tree.root_hash() == root)
187        .ok_or(StoreError::UnknownHash)?;
188
189    if leaf_index >= tree_size || tree_size.0 != tree.size() as u64 {
190        return Err(StoreError::InvalidIndexOrSize);
191    }
192
193    let proof = tree
194        .get_leaf_proof(leaf_index.0 as usize)
195        .ok_or(StoreError::InvalidIndexOrSize)?;
196
197    let len_proof = proof.len();
198    let mut first_part_proof = Vec::new();
199    let mut n_response_elements = 0;
200    for (i, p) in proof.into_iter().enumerate() {
201        // how many elements we can fit in 255 - 32 - 1 - 1 = 221 bytes ?
202        // response: 6 array of 32 bytes.
203        if i < 6 {
204            first_part_proof.extend(p);
205            n_response_elements += 1;
206        } else {
207            // Add to the queue any proof elements that do not fit the response
208            queue.push(p);
209        }
210    }
211
212    let mut response = tree.get_leaf(leaf_index.0 as usize).unwrap().to_vec();
213    response.extend_from_slice(&(len_proof as u8).to_be_bytes());
214    response.extend_from_slice(&(n_response_elements as u8).to_be_bytes());
215    response.extend_from_slice(&first_part_proof);
216    Ok(response)
217}
218
219fn get_merkle_leaf_index(trees: &[MerkleTree], request: &[u8]) -> Result<Vec<u8>, StoreError> {
220    if request.len() < 64 {
221        return Err(StoreError::UnsupportedRequest(
222            ClientCommandCode::GetMerkleLeafIndex as u8,
223        ));
224    }
225    let root = &request[0..32];
226    let hash = &request[32..64];
227
228    let tree = trees
229        .iter()
230        .find(|tree| tree.root_hash() == root)
231        .ok_or(StoreError::UnknownHash)?;
232
233    let leaf_index = tree.get_leaf_index(hash).ok_or(StoreError::UnknownHash)?;
234
235    let mut response = 1_u8.to_be_bytes().to_vec();
236    response.extend(encode::serialize(&VarInt(leaf_index as u64)));
237    Ok(response)
238}
239
240fn get_more_elements(queue: &mut Vec<Vec<u8>>) -> Result<Vec<u8>, StoreError> {
241    if queue.is_empty() {
242        return Err(StoreError::UnexpectedQueue);
243    }
244
245    // The queue must contain only element of the same length.
246    let element_length = queue[0].len();
247    if queue.iter().any(|e| e.len() != element_length) {
248        return Err(StoreError::UnexpectedQueue);
249    }
250
251    let mut response_elements = Vec::new();
252    let mut n_added_elements = 0;
253    for element in queue.iter() {
254        if response_elements.len() + element_length <= 253 {
255            response_elements.extend_from_slice(element);
256            n_added_elements += 1;
257        }
258    }
259    *queue = queue[n_added_elements..].to_vec();
260
261    let mut response = (n_added_elements as u8).to_be_bytes().to_vec();
262    response.extend((element_length as u8).to_be_bytes());
263    response.extend(response_elements);
264    Ok(response)
265}
266
267/// Returns a serialized Merkleized map commitment, encoded as the concatenation of:
268///     - the number of key/value pairs, as a Bitcoin-style varint;
269///     - the root of the Merkle tree of the keys
270///     - the root of the Merkle tree of the values.
271pub fn get_merkleized_map_commitment(mapping: &[(Vec<u8>, Vec<u8>)]) -> Vec<u8> {
272    let mut sorted: Vec<&(Vec<u8>, Vec<u8>)> = mapping.iter().collect();
273    sorted.sort_by(|(k1, _), (k2, _)| k1.as_slice().cmp(k2));
274
275    let mut keys_hashes: Vec<[u8; 32]> = Vec::with_capacity(sorted.len());
276    let mut values_hashes: Vec<[u8; 32]> = Vec::with_capacity(sorted.len());
277    for (key, value) in &sorted {
278        let mut preimage = vec![0x00];
279        preimage.extend_from_slice(key);
280        let mut engine = sha256::Hash::engine();
281        engine.input(&preimage);
282        keys_hashes.push(sha256::Hash::from_engine(engine).to_byte_array());
283
284        let mut preimage = vec![0x00];
285        preimage.extend_from_slice(value);
286        let mut engine = sha256::Hash::engine();
287        engine.input(&preimage);
288        values_hashes.push(sha256::Hash::from_engine(engine).to_byte_array());
289    }
290
291    let mut commitment = encode::serialize(&VarInt(sorted.len() as u64));
292    commitment.extend(MerkleTree::new(keys_hashes).root_hash());
293    commitment.extend(MerkleTree::new(values_hashes).root_hash());
294    commitment
295}
296
297#[derive(Debug)]
298pub enum StoreError {
299    EmptyInput,
300    UnknownCommand(u8),
301    UnsupportedRequest(u8),
302    InvalidIndexOrSize,
303    UnknownHash,
304    UnknownMerkleRoot,
305    UnexpectedQueue,
306}