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
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright 2019 Conflux Foundation. All rights reserved.
// Conflux is free software and distributed under GNU General Public License.
// See http://www.gnu.org/licenses/

pub type ChildrenMerkleTable = [MerkleHash; CHILDREN_COUNT];
pub type MaybeMerkleTable = Option<ChildrenMerkleTable>;
pub type MaybeMerkleTableRef<'a> = Option<&'a ChildrenMerkleTable>;

const LEAF_CHILDREN_MERKLE: [MerkleHash; CHILDREN_COUNT] =
    [MERKLE_NULL_NODE; CHILDREN_COUNT];

/// Node merkle for a subtree is defined as keccak(buffer), where buffer
/// contains the relevant trie node representation.
///
/// buffer := 'n' children_merkles maybe_value;
/// children_merkles := path_merkle_of_child_0 ... path_merkle_of_child_15;
/// maybe_value :=   ""     (empty bytes) when maybe_value is None,
///                | 'v' value            when maybe_value is Some(value).
///
/// value can be empty string (to represent TOMBSTONE), therefore we use
/// 'v' to prefix the value.
pub fn compute_node_merkle(
    children_merkles: MaybeMerkleTableRef, maybe_value: Option<&[u8]>,
) -> MerkleHash {
    let mut buffer = Vec::with_capacity(
        1 + std::mem::size_of::<ChildrenMerkleTable>()
            + maybe_value.map_or(0, |v| 1 + v.len()),
    );
    buffer.push('n' as u8);
    let merkles = match children_merkles {
        Some(merkles) => merkles,
        _ => &LEAF_CHILDREN_MERKLE,
    };
    for i in 0..CHILDREN_COUNT {
        buffer.extend_from_slice(merkles[i].as_bytes())
    }

    match maybe_value {
        Some(value) => {
            buffer.push('v' as u8);
            buffer.extend_from_slice(value);
        }
        _ => {}
    }

    keccak(&buffer)
}

/// Path merkle is stored as one of a children merkles in its parent node.
/// It is the merkle of the compressed path combined with a child node.
///
/// path_merkle :=   keccak(buffer) when compressed_path has at least one nibble
///                | node_merkle;
/// buffer := compressed_path_info_byte compressed_path node_merkle;
///
/// compressed_path may exclude half-byte at the beginning or at the end. In
/// these cases, excluded half-byte will be cleared for the merkle computation.
///
/// compressed_path_info_byte := 128 + 64 * (no_first_nibble as bool as int) +
/// compressed_path.path_steps() % 63
///
/// % 63 as we try to avoid power of two which are commonly used in block
/// cipher.
///
/// It's impossible for compressed_path_info_byte to be 'n' used in node merkle
/// calculation.
fn compute_path_merkle(
    compressed_path: CompressedPathRef, without_first_nibble: bool,
    node_merkle: &MerkleHash,
) -> MerkleHash {
    assert_eq!(
        without_first_nibble,
        CompressedPathRaw::second_nibble(compressed_path.path_mask())
            != CompressedPathRaw::NO_MISSING_NIBBLE,
        "without_first_nibble: {}, path_mask: {}",
        without_first_nibble,
        compressed_path.path_mask(),
    );

    // compressed_path is non-empty.
    if compressed_path.path_steps() > 0 {
        let mut buffer = Vec::with_capacity(
            1 + compressed_path.path_size() as usize
                + std::mem::size_of::<MerkleHash>(),
        );
        // The path_info_byte is defined as:
        // Most significant bit = 1
        // 2nd most significant bit = if the first nibble of the first byte
        // does not belong to the compressed path;
        // least significant 6 bits = number of nibbles in the compressed path %
        // 64.
        let path_info_byte = 128u8
            + 64u8 * (without_first_nibble as u8)
            + (compressed_path.path_steps() as u8) % 63u8;
        buffer.push(path_info_byte);

        buffer.extend_from_slice(compressed_path.path_slice());
        if without_first_nibble {
            // Clear out the first nibble.
            buffer[1] = CompressedPathRaw::second_nibble(buffer[1]);
        }
        buffer.extend_from_slice(node_merkle.as_bytes());

        keccak(buffer)
    } else {
        *node_merkle
    }
}

pub fn compute_merkle(
    compressed_path: CompressedPathRef, path_without_first_nibble: bool,
    children_merkles: MaybeMerkleTableRef, maybe_value: Option<&[u8]>,
) -> MerkleHash {
    let node_merkle = compute_node_merkle(children_merkles, maybe_value);
    let path_merkle = compute_path_merkle(
        compressed_path,
        path_without_first_nibble,
        &node_merkle,
    );

    path_merkle
}

use super::*;
use keccak_hash::keccak;
use primitives::{MerkleHash, MERKLE_NULL_NODE};