| package org.bouncycastle.pqc.crypto.sphincs; |
| |
| class Tree |
| { |
| static class leafaddr |
| { |
| int level; |
| long subtree; |
| long subleaf; |
| |
| public leafaddr() |
| { |
| |
| } |
| |
| public leafaddr(leafaddr leafaddr) |
| { |
| this.level = leafaddr.level; |
| this.subtree = leafaddr.subtree; |
| this.subleaf = leafaddr.subleaf; |
| } |
| } |
| |
| static void l_tree(HashFunctions hs, byte[] leaf, int leafOff, byte[] wots_pk, int pkOff, byte[] masks, int masksOff) |
| { |
| int l = Wots.WOTS_L; |
| int i, j = 0; |
| for (i = 0; i < Wots.WOTS_LOG_L; i++) |
| { |
| for (j = 0; j < (l >>> 1); j++) |
| { |
| hs.hash_2n_n_mask(wots_pk, pkOff + j * SPHINCS256Config.HASH_BYTES, wots_pk, pkOff + j * 2 * SPHINCS256Config.HASH_BYTES, masks, masksOff + i * 2 * SPHINCS256Config.HASH_BYTES); |
| } |
| |
| if ((l & 1) != 0) |
| { |
| System.arraycopy(wots_pk, pkOff + (l - 1) * SPHINCS256Config.HASH_BYTES, wots_pk, pkOff + (l >>> 1) * SPHINCS256Config.HASH_BYTES, SPHINCS256Config.HASH_BYTES); |
| l = (l >>> 1) + 1; |
| } |
| else |
| { |
| l = (l >>> 1); |
| } |
| } |
| System.arraycopy(wots_pk, pkOff, leaf, leafOff, SPHINCS256Config.HASH_BYTES); |
| } |
| |
| static void treehash(HashFunctions hs, byte[] node, int nodeOff, int height, byte[] sk, leafaddr leaf, byte[] masks, int masksOff) |
| { |
| leafaddr a = new leafaddr(leaf); |
| int lastnode, i; |
| byte[] stack = new byte[(height + 1) * SPHINCS256Config.HASH_BYTES]; |
| int[] stacklevels = new int[height + 1]; |
| int stackoffset = 0; |
| |
| lastnode = (int)(a.subleaf + (1 << height)); |
| |
| for (; a.subleaf < lastnode; a.subleaf++) |
| { |
| gen_leaf_wots(hs, stack, stackoffset * SPHINCS256Config.HASH_BYTES, masks, masksOff, sk, a); |
| stacklevels[stackoffset] = 0; |
| stackoffset++; |
| while (stackoffset > 1 && stacklevels[stackoffset - 1] == stacklevels[stackoffset - 2]) |
| { |
| //MASKS |
| int maskoffset = 2 * (stacklevels[stackoffset - 1] + Wots.WOTS_LOG_L) * SPHINCS256Config.HASH_BYTES; |
| |
| hs.hash_2n_n_mask(stack, (stackoffset - 2) * SPHINCS256Config.HASH_BYTES, stack, (stackoffset - 2) * SPHINCS256Config.HASH_BYTES, |
| masks, masksOff + maskoffset); |
| stacklevels[stackoffset - 2]++; |
| stackoffset--; |
| } |
| } |
| for (i = 0; i < SPHINCS256Config.HASH_BYTES; i++) |
| { |
| node[nodeOff + i] = stack[i]; |
| } |
| } |
| |
| static void gen_leaf_wots(HashFunctions hs, byte[] leaf, int leafOff, byte[] masks, int masksOff, byte[] sk, leafaddr a) |
| { |
| byte[] seed = new byte[SPHINCS256Config.SEED_BYTES]; |
| byte[] pk = new byte[Wots.WOTS_L * SPHINCS256Config.HASH_BYTES]; |
| |
| Wots w = new Wots(); |
| |
| Seed.get_seed(hs, seed, 0, sk, a); |
| |
| w.wots_pkgen(hs, pk, 0, seed, 0, masks, masksOff); |
| |
| l_tree(hs, leaf, leafOff, pk, 0, masks, masksOff); |
| } |
| } |