def ht_sign(self, m, secret_seed, public_seed, idx_tree, idx_leaf): adrs = ADRS() adrs.set_layer_address(0) adrs.set_tree_address(idx_tree) sig_tmp = self.xmss_sign(m, secret_seed, idx_leaf, public_seed, adrs.copy()) sig_ht = sig_tmp root = self.xmss_pk_from_sig(idx_leaf, sig_tmp, m, public_seed, adrs.copy()) for j in range(1, self._d): idx_leaf = idx_tree % 2**self._h_prime idx_tree = idx_tree >> self._h_prime adrs.set_layer_address(j) adrs.set_tree_address(idx_tree) sig_tmp = self.xmss_sign(root, secret_seed, idx_leaf, public_seed, adrs.copy()) sig_ht = sig_ht + sig_tmp if j < self._d - 1: root = self.xmss_pk_from_sig(idx_leaf, sig_tmp, root, public_seed, adrs.copy()) return sig_ht
def treehash(self, secret_seed, s, z, public_seed, adrs: ADRS): if s % (1 << z) != 0: return -1 stack = [] for i in range(0, 2 ** z): adrs.set_type(ADRS.WOTS_HASH) adrs.set_key_pair_address(s + i) node = self.wots_pk_gen(secret_seed, public_seed, adrs.copy()) adrs.set_type(ADRS.TREE) adrs.set_tree_height(1) adrs.set_tree_index(s + i) if len(stack) > 0: while stack[len(stack) - 1]['height'] == adrs.get_tree_height(): adrs.set_tree_index((adrs.get_tree_index() - 1) // 2) node = hash(public_seed, adrs.copy(), stack.pop()['node'] + node, self._n) adrs.set_tree_height(adrs.get_tree_height() + 1) if len(stack) <= 0: break stack.append({'node': node, 'height': adrs.get_tree_height()}) return stack.pop()['node']
def wots_pk_from_sig(self, sig, m, public_seed, adrs: ADRS): csum = 0 wots_pk_adrs = adrs.copy() msg = base_w(m, self._w, self._len_1) for i in range(0, self._len_1): csum += self._w - 1 - msg[i] padding = (self._len_2 * math.floor(math.log(self._w, 2))) % 8 if ( self._len_2 * math.floor(math.log(self._w, 2))) % 8 != 0 else 8 csum = csum << (8 - padding) csumb = csum.to_bytes(math.ceil( (self._len_2 * math.floor(math.log(self._w, 2))) / 8), byteorder='big') csumw = base_w(csumb, self._w, self._len_2) msg += csumw tmp = bytes() for i in range(0, self._len_0): adrs.set_chain_address(i) tmp += self.chain(sig[i], msg[i], self._w - 1 - msg[i], public_seed, adrs.copy()) wots_pk_adrs.set_type(ADRS.WOTS_PK) wots_pk_adrs.set_key_pair_address(adrs.get_key_pair_address()) pk_sig = hash(public_seed, wots_pk_adrs, tmp, self._n) return pk_sig
def spx_sign(self, m, secret_key): adrs = ADRS() secret_seed = secret_key[0] secret_prf = secret_key[1] public_seed = secret_key[2] public_root = secret_key[3] opt = bytes(self._n) if self._randomize: opt = os.urandom(self._n) r = prf_msg(secret_prf, opt, m, self._n) sig = [r] size_md = math.floor((self._k * self._a + 7) / 8) size_idx_tree = math.floor((self._h - self._h // self._d + 7) / 8) size_idx_leaf = math.floor((self._h // self._d + 7) / 8) digest = hash_msg(r, public_seed, public_root, m, size_md + size_idx_tree + size_idx_leaf) tmp_md = digest[:size_md] tmp_idx_tree = digest[size_md:(size_md + size_idx_tree)] tmp_idx_leaf = digest[(size_md + size_idx_tree):len(digest)] md_int = int.from_bytes(tmp_md, 'big') >> (len(tmp_md) * 8 - self._k * self._a) md = md_int.to_bytes(math.ceil(self._k * self._a / 8), 'big') idx_tree = int.from_bytes(tmp_idx_tree, 'big') >> (len(tmp_idx_tree) * 8 - (self._h - self._h // self._d)) idx_leaf = int.from_bytes(tmp_idx_leaf, 'big') >> (len(tmp_idx_leaf) * 8 - (self._h // self._d)) adrs.set_layer_address(0) adrs.set_tree_address(idx_tree) adrs.set_type(ADRS.FORS_TREE) adrs.set_key_pair_address(idx_leaf) sig_fors = self.fors_sign(md, secret_seed, public_seed, adrs.copy()) sig += [sig_fors] pk_fors = self.fors_pk_from_sig(sig_fors, md, public_seed, adrs.copy()) adrs.set_type(ADRS.TREE) sig_ht = self.ht_sign(pk_fors, secret_seed, public_seed, idx_tree, idx_leaf) sig += [sig_ht] return sig
def wots_pk_gen(self, secret_seed, public_seed, adrs: ADRS): wots_pk_adrs = adrs.copy() tmp = bytes() for i in range(0, self._len_0): adrs.set_chain_address(i) adrs.set_hash_address(0) sk = prf(secret_seed, adrs.copy(), self._n) tmp += bytes(self.chain(sk, 0, self._w - 1, public_seed, adrs.copy())) wots_pk_adrs.set_type(ADRS.WOTS_PK) wots_pk_adrs.set_key_pair_address(adrs.get_key_pair_address()) pk = hash(public_seed, wots_pk_adrs, tmp, self._n) return pk
def wots_sk_gen(self, secret_seed, adrs: ADRS): # Not necessary sk = [] for i in range(0, self._len_0): adrs.set_chain_address(i) adrs.set_hash_address(0) sk.append(prf(secret_seed, adrs.copy(), self._n)) return sk
def fors_pk_gen(self, secret_seed, public_seed, adrs: ADRS): fors_pk_adrs = adrs.copy() root = bytes() for i in range(0, self._k): root += self.fors_treehash(secret_seed, i * self._t, self._a, public_seed, adrs) fors_pk_adrs.set_type(ADRS.FORS_ROOTS) fors_pk_adrs.set_key_pair_address(adrs.get_key_pair_address()) pk = hash(public_seed, fors_pk_adrs, root, self._n) return pk
def fors_pk_from_sig(self, sig_fors, m, public_seed, adrs: ADRS): m_int = int.from_bytes(m, 'big') sigs = self.auths_from_sig_fors(sig_fors) root = bytes() for i in range(0, self._k): idx = (m_int >> (self._k - 1 - i) * self._a) % self._t sk = sigs[i][0] adrs.set_tree_height(0) adrs.set_tree_index(i * self._t + idx) node_0 = hash(public_seed, adrs.copy(), sk, self._n) node_1 = 0 auth = sigs[i][1] adrs.set_tree_index(i * self._t + idx) # Really Useful? for j in range(0, self._a): adrs.set_tree_height(j + 1) if math.floor(idx / 2**j) % 2 == 0: adrs.set_tree_index(adrs.get_tree_index() // 2) node_1 = hash(public_seed, adrs.copy(), node_0 + auth[j], self._n) else: adrs.set_tree_index((adrs.get_tree_index() - 1) // 2) node_1 = hash(public_seed, adrs.copy(), auth[j] + node_0, self._n) node_0 = node_1 root += node_0 fors_pk_adrs = adrs.copy() fors_pk_adrs.set_type(ADRS.FORS_ROOTS) fors_pk_adrs.set_key_pair_address(adrs.get_key_pair_address()) pk = hash(public_seed, fors_pk_adrs, root, self._n) return pk
def fors_sk_gen(self, secret_seed, adrs: ADRS, idx): adrs.set_tree_height(0) adrs.set_tree_index(idx) sk = prf(secret_seed, adrs.copy(), self._n) return sk
def ht_pk_gen(self, secret_seed, public_seed): adrs = ADRS() adrs.set_layer_address(self._d - 1) adrs.set_tree_address(0) root = self.xmss_pk_gen(secret_seed, public_seed, adrs.copy()) return root
def xmss_pk_gen(self, secret_seed, public_key, adrs: ADRS): pk = self.treehash(secret_seed, 0, self._h_prime, public_key, adrs.copy()) return pk