/* * XMSS Address * (C) 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ #ifndef BOTAN_XMSS_ADDRESS_H__ #define BOTAN_XMSS_ADDRESS_H__ #include #include #include namespace Botan { /** * Generic XMSS Address type holding 256 Bits of data. Properties * of all three address formats L-Tree-Address, Hash-Tree-Address, * OTS-Hash-Address can be called depending on the type currently * assigned to the XMSS address using set_type(). **/ class XMSS_Address { public: /** * Distinct types an XMSS_Address can represent. The available types * are specified in [1] - 2.5 Hash Function Address Scheme. **/ enum class Type : uint8_t { None = 255, OTS_Hash_Address = 0, LTree_Address = 1, Hash_Tree_Address = 2 }; /** * The available modes for an XMSS Address: * - Key_Mode: Used to generate the key. * - Mask_Mode: Sets the n-byte bitmask (OTS-Hash-Address) * - Mask_MSB_Mode: Used to generate the b most significant bytes of * the 2n-byte bitmask (LTree Address and Hash Tree Address). * - Mask_LSB_Mode: Used to generated the b least significant bytes * of the 2n-byte bitmask. (LTree Address and Hash Tree Address). **/ enum class Key_Mask : uint8_t { Key_Mode = 0, Mask_Mode = 1, Mask_MSB_Mode = 1, Mask_LSB_Mode = 2 }; /** * Layer Address for XMSS is constantly zero and can not be changed this * property is only of relevance to XMSS_MT. * * @return Layer address, which is constant 0 for XMSS. **/ uint8_t get_layer_addr() const { return 0; } /** * Layer Address for XMSS is constantly zero and can not be changed this * property is only of relevance to XMSS_MT. Calling this method for * XMSS will result in an error. **/ void set_layer_addr() { BOTAN_ASSERT(false, "Only available in XMSS_MT."); } /** * Tree Address for XMSS is constantly zero and can not be changed this * property is only of relevance to XMSS_MT. * * @return Tree address, which is constant 0 for XMSS. **/ uint64_t get_tree_addr() const { return 0; } /** * Tree Address for XMSS is constantly zero and can not be changed this * property is only of relevance to XMSS_MT. Calling this method for * XMSS will result in an error. **/ void set_tree_addr() { BOTAN_ASSERT(false, "Only available in XMSS_MT."); } /** * retrieves the logical type currently assigned to the XMSS Address * instance. * * @return Type of the address (OTS_Hash_Address, LTree_Address or * Hash_Tree_Address) **/ Type get_type() const { return static_cast(m_data[15]); } /** * Changes the logical type currently assigned to the XMSS Address * instance. Please note that changing the type will automatically * reset the 128 LSBs of the Address to zero. This affects the * key_mask_mode property as well as all properties identified by * XMSS_Address::Property. * * @param type Type that shall be assigned to the address * (OTS_Hash_Address, LTree_Address or Hash_Tree_Address) **/ void set_type(Type type) { m_data[15] = static_cast(type); std::fill(m_data.begin() + 16, m_data.end(), 0); } /** * Retrieves the mode the address os currently set to. (See * XMSS_Address::Key_Mask for details.) * * @return currently active mode **/ Key_Mask get_key_mask_mode() const { return Key_Mask(m_data[31]); } /** * Changes the mode the address currently used address mode. * (XMSS_Address::Key_Mask for details.) * * @param value Target mode. **/ void set_key_mask_mode(Key_Mask value) { BOTAN_ASSERT(value != Key_Mask::Mask_LSB_Mode || get_type() != Type::OTS_Hash_Address, "Invalid Key_Mask for current XMSS_Address::Type."); m_data[31] = static_cast(value); } /** * Retrieve the index of the OTS key pair within the tree. A call to * this method is only valid, if the address type is set to * Type::OTS_Hash_Address. * * @return index of OTS key pair. **/ uint32_t get_ots_address() const { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "get_ots_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); return get_hi32(2); } /** * Sets the index of the OTS key pair within the tree. A call to this * method is only valid, if the address type is set to * Type::OTS_Hash_Address. * * @param value index of OTS key pair. **/ void set_ots_address(uint32_t value) { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "set_ots_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); set_hi32(2, value); } /** * Retrieves the index of the leaf computed with this LTree. A call to * this method is only valid, if the address type is set to * Type::LTree_Address. * * @return index of the leaf. **/ uint32_t get_ltree_address() const { BOTAN_ASSERT(get_type() == Type::LTree_Address, "set_ltree_address() requires XMSS_Address::Type::" "LTree_Address."); return get_hi32(2); } /** * Sets the index of the leaf computed with this LTree. A call to this * method is only valid, if the address type is set to * Type::LTree_Address. * * @param value index of the leaf. **/ void set_ltree_address(uint32_t value) { BOTAN_ASSERT(get_type() == Type::LTree_Address, "set_ltree_address() requires XMSS_Address::Type::" "LTree_Address."); set_hi32(2, value); } /** * Retrieve the chain address. A call to this method is only valid, if * the address type is set to Type::OTS_Hash_Address. * * @return chain address. **/ uint32_t get_chain_address() const { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "get_chain_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); return get_lo32(2); } /** * Set the chain address. A call to this method is only valid, if * the address type is set to Type::OTS_Hash_Address. * * @return chain address. **/ void set_chain_address(uint32_t value) { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "set_chain_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); set_lo32(2, value); } /** * Retrieves the height of the tree node to be computed within the * tree. A call to this method is only valid, if the address type is * set to Type::LTree_Address or Type::Hash_Tree_Address. * * @return height of the tree node. **/ uint32_t get_tree_height() const { BOTAN_ASSERT(get_type() == Type::LTree_Address || get_type() == Type::Hash_Tree_Address, "get_tree_height() requires XMSS_Address::Type::" "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); return get_lo32(2); } /** * Sets the height of the tree node to be computed within the * tree. A call to this method is only valid, if the address type is * set to Type::LTree_Address or Type::Hash_Tree_Address. * * @param value height of the tree node. **/ void set_tree_height(uint32_t value) { BOTAN_ASSERT(get_type() == Type::LTree_Address || get_type() == Type::Hash_Tree_Address, "set_tree_height() requires XMSS_Address::Type::" "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); set_lo32(2, value); } /** * Retrieves the address of the hash function call within the chain. * A call to this method is only valid, if the address type is * set to Type::OTS_Hash_Address. * * @return address of the hash function call within chain. **/ uint32_t get_hash_address() const { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "get_hash_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); return get_hi32(3); } /** * Sets the address of the hash function call within the chain. * A call to this method is only valid, if the address type is * set to Type::OTS_Hash_Address. * * @param value address of the hash function call within chain. **/ void set_hash_address(uint32_t value) { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "set_hash_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); set_hi32(3, value); } /** * Retrieves the index of the tree node at current tree height in the * tree. A call to this method is only valid, if the address type is * set to Type::LTree_Address or Type::Hash_Tree_Address. * * @return index of the tree node at current height. **/ uint32_t get_tree_index() const { BOTAN_ASSERT(get_type() == Type::LTree_Address || get_type() == Type::Hash_Tree_Address, "get_tree_index() requires XMSS_Address::Type::" "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); return get_hi32(3); } /** * Sets the index of the tree node at current tree height in the * tree. A call to this method is only valid, if the address type is * set to Type::LTree_Address or Type::Hash_Tree_Address. * * @param value index of the tree node at current height. **/ void set_tree_index(uint32_t value) { BOTAN_ASSERT(get_type() == Type::LTree_Address || get_type() == Type::Hash_Tree_Address, "set_tree_index() requires XMSS_Address::Type::" "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); set_hi32(3, value); } const secure_vector& bytes() const { return m_data; } secure_vector& bytes() { return m_data; } /** * @return the size of an XMSS_Address **/ size_t size() const { return m_data.size(); } XMSS_Address() : m_data(m_address_size) { set_type(Type::None); } XMSS_Address(Type type) : m_data(m_address_size) { set_type(type); } XMSS_Address(const secure_vector& data) : m_data(data) { BOTAN_ASSERT(m_data.size() == m_address_size, "XMSS_Address must be of 256 bits size."); } XMSS_Address(secure_vector&& data) : m_data(std::move(data)) { BOTAN_ASSERT(m_data.size() == m_address_size, "XMSS_Address must be of 256 bits size."); } protected: secure_vector m_data; private: static const size_t m_address_size = 32; inline uint32_t get_hi32(size_t offset) const { return ((0x000000FF & m_data[8 * offset + 3]) | (0x000000FF & m_data[8 * offset + 2]) << 8 | (0x000000FF & m_data[8 * offset + 1]) << 16 | (0x000000FF & m_data[8 * offset ]) << 24); } inline void set_hi32(size_t offset, uint32_t value) { m_data[offset * 8 ] = ((value >> 24) & 0xFF); m_data[offset * 8 + 1] = ((value >> 16) & 0xFF); m_data[offset * 8 + 2] = ((value >> 8) & 0xFF); m_data[offset * 8 + 3] = ((value ) & 0xFF); } inline uint32_t get_lo32(size_t offset) const { return ((0x000000FF & m_data[8 * offset + 7]) | (0x000000FF & m_data[8 * offset + 6]) << 8 | (0x000000FF & m_data[8 * offset + 5]) << 16 | (0x000000FF & m_data[8 * offset + 4]) << 24); } inline void set_lo32(size_t offset, uint32_t value) { m_data[offset * 8 + 4] = ((value >> 24) & 0xFF); m_data[offset * 8 + 5] = ((value >> 16) & 0xFF); m_data[offset * 8 + 6] = ((value >> 8) & 0xFF); m_data[offset * 8 + 7] = ((value ) & 0xFF); } }; } #endif