4 Hash Tree Mode
4.1 Specification
Tree processing varies according to the following input pa-
rameters:
Y
l
The leaf size encoding. The size of each leaf of the
tree is N
l
= N
b
2
Y
l
bytes with Y
l
≥ 1 (where N
b
is
the size of the internal state of Skein).
Y
f
The fan-out encoding. The fan-out of a tree node is
2
Y
f
with Y
f
≥ 1. The size of each node is N
n
=
N
b
2
Y
f
.
Y
m
The maximum tree height; Y
m
≥ 2. If the hieght of
the tree is not limited this parameter is set to 255.
G
0
The input chaining value and the output of the previ-
ous UBI function.
M The message data.
UBI UBI UBI UBI UBI
UBI
UBIUBI
UBI UBI
UBI
message
N
b
-sized
Figure 1: Tree hashing with Y
l
= Y
f
= 1
We define the leaf size N
l
= N
b
2
Y
l
and the node size
N
n
= N
b
2
Y
f
.
We first split the message M into one or more mes-
sage blocks M
0,0
, M
0,1
, ..., M
0,k−1
, each of size N
l
bytes
except the last, which may be smaller. We now define the
first level of tree hashing by:
M
1
=
k−1
n
i=0
UBI(G
0
, M
0,i
, iN
l
+ 1 · 2
112
+ T
msg
· 2
120
)
The rest of the tree is defined iteratively. For any level l =
1, 2, ... we use the following rules:
1. If M
l
has length N
b
, then the result G
0
is defined by
G
1
= M
l
.
2. If M
l
is longer than N
b
bytes and l = Y
m
−1, then we
have almost reached the maximum tree height. The
result is then defined by:
G
1
= UBI(G
0
, M
l
, Y
m
· 2
112
+ T
msg
· 2
120
)
3. If neither of these conditions holds, we create
the next tree level. We split M
l
into blocks
M
l,0
, M
l,1
, ..., M
l,k−1
, where all blocks are of size
N
n
, except the last which may be smaller. We then
define:
M
l+1
=
k−1
n
i=0
UBI(G
0
, M
l,i
, iN
n
+(l+1)·2
112
+T
msg
·2
120
)
and apply the above rules to M
l+1
again.
The result G
1
is then the chaining input to the output
transformation.
4.2 Sequential implementation
The straightforward method would consist of implement-
ing this algorithm as it is described in its specifications.
This implementation constitutes a scheduling method for
the node processing that we call Lower level and leftmost
node first (or Lower level node first for short). Such an
implementation has the disadvantage of consuming a lot
of memory. For instance if we take Y
l
= 1, we need an
amount of avalaible memory space of up to half of the
message size, which may be impossible for long messages.
There is an effective algorithm (see [13]) which computes
a value of a node of height h, while storing only up to h + 1
hash values. The idea is to compute a new parent hash
value as soon as possible before continuing to compute
the lower level node hash values; we call this method
heigher level node first. The interest of this method,
which maintains a stack in which the intermediate values
are stored, is to rapidly discard those that are no longer
needed. This stack, which is initially empty, is used as
follows: we use (push) leaf values one by one from left to
right and we check at each step whether or not the last two
values on the stack are of the same height. If such is the
case, these last two values are popped and the parent hash
value is computed and pushed onto the stack, otherwise we
continue to push a leaf value and so on. Note that we could
use a two hash-sized buffer at each level (from 1 to h)
instead of a unique stack, even though it is useless in such a
sequential implementation. This algorithm can be applyed
to Skein trees, in which case the memory consumption
does not exceed (h − 1)(2
Y
f
− 1) + 2
Y
l
blocks of size N
b
for the computation of a node of height h, on the condition
that we include a special termination round since they are
not necessarily full trees (as we can see in Figure 1).
We assume the existence of the following elements:
• oracles:
– S(n) which returns the node value.
– LEAF CALC(l) which returns a pair of ele-
ments (S(n
l
), t) where S(n
l
) is the leaf value
(a N
b
-sized block of the message) and t a binary
variable indicating whether it is the last leaf (1)
or not (0).