use core::convert::TryFrom;
use core::fmt::Debug;
use bitcoin::{
consensus::encode::{self, VarInt},
hashes::{sha256, Hash, HashEngine},
};
use crate::{apdu::ClientCommandCode, merkle::MerkleTree};
pub struct ClientCommandInterpreter {
yielded: Vec<Vec<u8>>,
queue: Vec<Vec<u8>>,
known_preimages: Vec<([u8; 32], Vec<u8>)>,
trees: Vec<MerkleTree>,
}
impl ClientCommandInterpreter {
pub fn new() -> Self {
Self {
yielded: Vec::new(),
queue: Vec::new(),
known_preimages: Vec::new(),
trees: Vec::new(),
}
}
pub fn add_known_preimage(&mut self, element: Vec<u8>) {
let mut engine = sha256::Hash::engine();
engine.input(&element);
let hash = sha256::Hash::from_engine(engine).into_inner();
self.known_preimages.push((hash, element));
}
pub fn add_known_list(&mut self, elements: &[impl AsRef<[u8]>]) -> [u8; 32] {
let mut leaves = Vec::with_capacity(elements.len());
for element in elements {
let mut preimage = vec![0x00];
preimage.extend_from_slice(element.as_ref());
let mut engine = sha256::Hash::engine();
engine.input(&preimage);
let hash = sha256::Hash::from_engine(engine).into_inner();
self.known_preimages.push((hash, preimage));
leaves.push(hash);
}
let tree = MerkleTree::new(leaves);
let root_hash = *tree.root_hash();
self.trees.push(tree);
root_hash
}
pub fn add_known_mapping(&mut self, mapping: &[(Vec<u8>, Vec<u8>)]) {
let mut sorted: Vec<&(Vec<u8>, Vec<u8>)> = mapping.iter().collect();
sorted.sort_by(|(k1, _), (k2, _)| k1.as_slice().cmp(k2));
let mut keys = Vec::with_capacity(sorted.len());
let mut values = Vec::with_capacity(sorted.len());
for (key, value) in sorted {
keys.push(key.as_slice());
values.push(value.as_slice());
}
self.add_known_list(&keys);
self.add_known_list(&values);
}
pub fn execute(&mut self, command: Vec<u8>) -> Result<Vec<u8>, InterpreterError> {
if command.is_empty() {
return Err(InterpreterError::EmptyInput);
}
match ClientCommandCode::try_from(command[0]) {
Ok(ClientCommandCode::Yield) => {
self.yielded.push(command[1..].to_vec());
Ok(Vec::new())
}
Ok(ClientCommandCode::GetPreimage) => {
get_preimage_command(&mut self.queue, &self.known_preimages, &command[1..])
}
Ok(ClientCommandCode::GetMerkleLeafProof) => {
get_merkle_leaf_proof(&mut self.queue, &self.trees, &command[1..])
}
Ok(ClientCommandCode::GetMerkleLeafIndex) => {
get_merkle_leaf_index(&self.trees, &command[1..])
}
Ok(ClientCommandCode::GetMoreElements) => get_more_elements(&mut self.queue),
Err(()) => Err(InterpreterError::UnknownCommand(command[0])),
}
}
pub fn yielded(self) -> Vec<Vec<u8>> {
self.yielded
}
}
fn get_preimage_command(
queue: &mut Vec<Vec<u8>>,
known_preimages: &[([u8; 32], Vec<u8>)],
request: &[u8],
) -> Result<Vec<u8>, InterpreterError> {
if request.len() != 33 || request[0] != b'\0' {
return Err(InterpreterError::UnsupportedRequest(
ClientCommandCode::GetPreimage as u8,
));
};
let (_, preimage) = known_preimages
.iter()
.find(|(hash, _)| hash == &request[1..])
.ok_or(InterpreterError::UnknownHash)?;
let preimage_len_out = encode::serialize(&VarInt(preimage.len() as u64));
let max_payload_size = 255 - preimage_len_out.len() - 1;
let payload_size = if preimage.len() > max_payload_size {
max_payload_size
} else {
preimage.len()
};
if payload_size < preimage.len() {
for byte in &preimage[payload_size..] {
queue.push(vec![*byte]);
}
}
let mut response = preimage_len_out;
response.extend_from_slice(&(payload_size as u8).to_be_bytes());
response.extend_from_slice(&preimage[..payload_size]);
Ok(response)
}
fn get_merkle_leaf_proof(
queue: &mut Vec<Vec<u8>>,
trees: &[MerkleTree],
request: &[u8],
) -> Result<Vec<u8>, InterpreterError> {
if !queue.is_empty() {
return Err(InterpreterError::UnexpectedQueue);
} else if request.len() < 34 {
return Err(InterpreterError::UnsupportedRequest(
ClientCommandCode::GetMerkleLeafProof as u8,
));
};
let root = &request[0..32];
let (tree_size, read): (VarInt, usize) =
encode::deserialize_partial(&request[32..]).map_err(|_| {
InterpreterError::UnsupportedRequest(ClientCommandCode::GetMerkleLeafProof as u8)
})?;
let leaf_index: VarInt = encode::deserialize(&request[32 + read..]).map_err(|_| {
InterpreterError::UnsupportedRequest(ClientCommandCode::GetMerkleLeafProof as u8)
})?;
let tree = trees
.iter()
.find(|tree| tree.root_hash() == root)
.ok_or(InterpreterError::UnknownHash)?;
if leaf_index >= tree_size || tree_size.0 != tree.size() as u64 {
return Err(InterpreterError::InvalidIndexOrSize);
}
let proof = tree
.get_leaf_proof(leaf_index.0 as usize)
.ok_or(InterpreterError::InvalidIndexOrSize)?;
let len_proof = proof.len();
let mut first_part_proof = Vec::new();
let mut n_response_elements = 0;
for (i, p) in proof.into_iter().enumerate() {
if i < 6 {
first_part_proof.extend(p);
n_response_elements += 1;
} else {
queue.push(p);
}
}
let mut response = tree.get_leaf(leaf_index.0 as usize).unwrap().to_vec();
response.extend_from_slice(&(len_proof as u8).to_be_bytes());
response.extend_from_slice(&(n_response_elements as u8).to_be_bytes());
response.extend_from_slice(&first_part_proof);
Ok(response)
}
fn get_merkle_leaf_index(
trees: &[MerkleTree],
request: &[u8],
) -> Result<Vec<u8>, InterpreterError> {
if request.len() < 64 {
return Err(InterpreterError::UnsupportedRequest(
ClientCommandCode::GetMerkleLeafIndex as u8,
));
}
let root = &request[0..32];
let hash = &request[32..64];
let tree = trees
.iter()
.find(|tree| tree.root_hash() == root)
.ok_or(InterpreterError::UnknownHash)?;
let leaf_index = tree
.get_leaf_index(hash)
.ok_or(InterpreterError::UnknownHash)?;
let mut response = 1_u8.to_be_bytes().to_vec();
response.extend(encode::serialize(&VarInt(leaf_index as u64)));
Ok(response)
}
fn get_more_elements(queue: &mut Vec<Vec<u8>>) -> Result<Vec<u8>, InterpreterError> {
if queue.is_empty() {
return Err(InterpreterError::UnexpectedQueue);
}
let element_length = queue[0].len();
if queue.iter().any(|e| e.len() != element_length) {
return Err(InterpreterError::UnexpectedQueue);
}
let mut response_elements = Vec::new();
let mut n_added_elements = 0;
for element in queue.iter() {
if response_elements.len() + element_length <= 253 {
response_elements.extend_from_slice(element);
n_added_elements += 1;
}
}
*queue = queue[n_added_elements..].to_vec();
let mut response = (n_added_elements as u8).to_be_bytes().to_vec();
response.extend((element_length as u8).to_be_bytes());
response.extend(response_elements);
Ok(response)
}
pub fn get_merkleized_map_commitment(mapping: &[(Vec<u8>, Vec<u8>)]) -> Vec<u8> {
let mut sorted: Vec<&(Vec<u8>, Vec<u8>)> = mapping.iter().collect();
sorted.sort_by(|(k1, _), (k2, _)| k1.as_slice().cmp(k2));
let mut keys_hashes: Vec<[u8; 32]> = Vec::with_capacity(sorted.len());
let mut values_hashes: Vec<[u8; 32]> = Vec::with_capacity(sorted.len());
for (key, value) in &sorted {
let mut preimage = vec![0x00];
preimage.extend_from_slice(key);
let mut engine = sha256::Hash::engine();
engine.input(&preimage);
keys_hashes.push(sha256::Hash::from_engine(engine).into_inner());
let mut preimage = vec![0x00];
preimage.extend_from_slice(value);
let mut engine = sha256::Hash::engine();
engine.input(&preimage);
values_hashes.push(sha256::Hash::from_engine(engine).into_inner());
}
let mut commitment = encode::serialize(&VarInt(sorted.len() as u64));
commitment.extend(MerkleTree::new(keys_hashes).root_hash());
commitment.extend(MerkleTree::new(values_hashes).root_hash());
commitment
}
#[derive(Debug)]
pub enum InterpreterError {
EmptyInput,
UnknownCommand(u8),
UnsupportedRequest(u8),
InvalidIndexOrSize,
UnknownHash,
UnknownMerkleRoot,
UnexpectedQueue,
}