#pragma once // Copyright (c) 2018-2019 David Burkett // Distributed under the MIT software license, see the accompanying // file LICENSE or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include class SecretKey : public Traits::ISerializable { public: static constexpr size_t SIZE = 32; // // Constructor // SecretKey() = default; explicit SecretKey(BigInt&& value) : m_value(std::move(value)) { } explicit SecretKey(const BigInt& value) : m_value(value) { } explicit SecretKey(std::vector&& bytes) : m_value(BigInt(std::move(bytes))) { } explicit SecretKey(const std::vector& bytes) : m_value(BigInt(bytes)) { } explicit SecretKey(const std::array& bytes) : m_value(BigInt(bytes)) {} explicit SecretKey(std::array&& bytes) : m_value(BigInt(std::move(bytes))) { } explicit SecretKey(const uint8_t* bytes) : m_value(BigInt(bytes)) { } static SecretKey Null() { return SecretKey(); } static SecretKey Random() { SecretKey key; do { GetStrongRandBytes(key.data(), SIZE); } while (!key.IsValid()); return key; } static SecretKey FromHash(const mw::Hash& hash) { SecretKey key(hash); if (key.IsValid()) { return key; } uint32_t counter = 0; do { blake3_hasher hasher; blake3_hasher_init(&hasher); static constexpr char tag[] = "MWEB hash-to-scalar"; blake3_hasher_update(&hasher, tag, sizeof(tag) - 1); blake3_hasher_update(&hasher, hash.data(), hash.size()); std::array counter_bytes{ static_cast(counter), static_cast(counter >> 8), static_cast(counter >> 16), static_cast(counter >> 24) }; blake3_hasher_update(&hasher, counter_bytes.data(), counter_bytes.size()); blake3_hasher_finalize(&hasher, key.data(), key.size()); counter++; } while (!key.IsValid()); return key; } // // Destructor // virtual ~SecretKey() = default; // // Operators // bool operator==(const SecretKey& rhs) const noexcept { return m_value == rhs.m_value; } bool operator!=(const SecretKey& rhs) const noexcept { return !(*this == rhs); } // // Getters // const BigInt& GetBigInt() const { return m_value; } std::string ToHex() const noexcept { return m_value.ToHex(); } bool IsNull() const noexcept { return m_value.IsZero(); } bool IsValid() const noexcept { return IsValidBytes(data()); } const std::vector& vec() const { return m_value.vec(); } std::array array() const noexcept { return m_value.ToArray(); } uint8_t* data() { return m_value.data(); } const uint8_t* data() const { return m_value.data(); } uint8_t& operator[] (const size_t x) { return m_value[x]; } const uint8_t& operator[] (const size_t x) const { return m_value[x]; } size_t size() const { return m_value.size(); } // // Serialization/Deserialization // IMPL_SERIALIZABLE(SecretKey, obj) { READWRITE(obj.m_value); } private: static bool IsValidBytes(const uint8_t* bytes) noexcept { static constexpr std::array SECP256K1_ORDER{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 }}; bool nonzero = false; for (size_t i = 0; i < SIZE; i++) { if (bytes[i] != 0) { nonzero = true; break; } } if (!nonzero) { return false; } for (size_t i = 0; i < SIZE; i++) { if (bytes[i] != SECP256K1_ORDER[i]) { return bytes[i] < SECP256K1_ORDER[i]; } } return false; } BigInt m_value; };