2020-02-23 14:51:32 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
|
|
* version 2, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#include <vapours/common.hpp>
|
|
|
|
#include <vapours/assert.hpp>
|
|
|
|
#include <vapours/util.hpp>
|
|
|
|
#include <vapours/crypto/crypto_memory_compare.hpp>
|
|
|
|
#include <vapours/crypto/crypto_memory_clear.hpp>
|
|
|
|
|
|
|
|
namespace ams::crypto::impl {
|
|
|
|
|
|
|
|
class BigNum {
|
|
|
|
NON_COPYABLE(BigNum);
|
|
|
|
NON_MOVEABLE(BigNum);
|
|
|
|
public:
|
|
|
|
using HalfWord = u16;
|
|
|
|
using Word = u32;
|
|
|
|
using DoubleWord = u64;
|
|
|
|
|
|
|
|
static constexpr size_t MaxBits = 4096;
|
|
|
|
static constexpr size_t BitsPerWord = sizeof(Word) * CHAR_BIT;
|
|
|
|
static constexpr Word MaxWord = std::numeric_limits<Word>::max();
|
|
|
|
static constexpr Word MaxHalfWord = std::numeric_limits<HalfWord>::max();
|
|
|
|
|
|
|
|
class WordAllocator {
|
|
|
|
NON_COPYABLE(WordAllocator);
|
|
|
|
NON_MOVEABLE(WordAllocator);
|
|
|
|
public:
|
|
|
|
class Allocation {
|
|
|
|
NON_COPYABLE(Allocation);
|
|
|
|
NON_MOVEABLE(Allocation);
|
|
|
|
private:
|
|
|
|
friend class WordAllocator;
|
|
|
|
private:
|
|
|
|
WordAllocator *allocator;
|
|
|
|
Word *buffer;
|
|
|
|
size_t count;
|
|
|
|
private:
|
|
|
|
constexpr ALWAYS_INLINE Allocation(WordAllocator *a, Word *w, size_t c) : allocator(a), buffer(w), count(c) { /* ... */ }
|
|
|
|
public:
|
|
|
|
ALWAYS_INLINE ~Allocation() { if (allocator) { allocator->Free(this->buffer, this->count); } }
|
|
|
|
|
|
|
|
constexpr ALWAYS_INLINE Word *GetBuffer() const { return this->buffer; }
|
|
|
|
constexpr ALWAYS_INLINE size_t GetCount() const { return this->count; }
|
|
|
|
constexpr ALWAYS_INLINE bool IsValid() const { return this->buffer != nullptr; }
|
|
|
|
};
|
|
|
|
|
|
|
|
friend class Allocation;
|
|
|
|
private:
|
|
|
|
Word *buffer;
|
|
|
|
size_t count;
|
|
|
|
size_t max_count;
|
|
|
|
size_t min_count;
|
|
|
|
private:
|
|
|
|
ALWAYS_INLINE void Free(void *words, size_t num) {
|
|
|
|
this->buffer -= num;
|
|
|
|
this->count += num;
|
|
|
|
|
|
|
|
AMS_ASSERT(words == this->buffer);
|
2021-09-30 04:32:40 +00:00
|
|
|
AMS_UNUSED(words);
|
2020-02-23 14:51:32 +00:00
|
|
|
}
|
|
|
|
public:
|
|
|
|
constexpr ALWAYS_INLINE WordAllocator(Word *buf, size_t c) : buffer(buf), count(c), max_count(c), min_count(c) { /* ... */ }
|
|
|
|
|
|
|
|
ALWAYS_INLINE Allocation Allocate(size_t num) {
|
|
|
|
if (num <= this->count) {
|
|
|
|
Word *allocated = this->buffer;
|
|
|
|
|
|
|
|
this->buffer += num;
|
|
|
|
this->count -= num;
|
|
|
|
this->min_count = std::min(this->count, this->min_count);
|
|
|
|
|
|
|
|
return Allocation(this, allocated, num);
|
|
|
|
} else {
|
|
|
|
return Allocation(nullptr, nullptr, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr ALWAYS_INLINE size_t GetMaxUsedSize() const {
|
|
|
|
return (this->max_count - this->min_count) * sizeof(Word);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
private:
|
|
|
|
Word *words;
|
|
|
|
size_t num_words;
|
|
|
|
size_t max_words;
|
|
|
|
private:
|
|
|
|
static void ImportImpl(Word *out, size_t out_size, const u8 *src, size_t src_size);
|
|
|
|
static void ExportImpl(u8 *out, size_t out_size, const Word *src, size_t src_size);
|
|
|
|
public:
|
|
|
|
constexpr BigNum() : words(), num_words(), max_words() { /* ... */ }
|
|
|
|
~BigNum() { /* ... */ }
|
|
|
|
|
|
|
|
constexpr void ReserveStatic(Word *buf, size_t capacity) {
|
|
|
|
this->words = buf;
|
|
|
|
this->max_words = capacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Import(const void *src, size_t src_size);
|
|
|
|
void Export(void *dst, size_t dst_size);
|
|
|
|
|
|
|
|
size_t GetSize() const;
|
|
|
|
|
|
|
|
bool IsZero() const {
|
|
|
|
return this->num_words == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ExpMod(void *dst, const void *src, size_t size, const BigNum &exp, u32 *work_buf, size_t work_buf_size) const;
|
|
|
|
void ClearToZero();
|
|
|
|
void UpdateCount();
|
|
|
|
public:
|
|
|
|
/* Utility. */
|
|
|
|
static bool IsZero(const Word *w, size_t num_words);
|
|
|
|
static int Compare(const Word *lhs, const Word *rhs, size_t num_words);
|
|
|
|
static size_t CountWords(const Word *w, size_t num_words);
|
|
|
|
static size_t CountSignificantBits(Word w);
|
|
|
|
static void ClearToZero(Word *w, size_t num_words);
|
|
|
|
static void SetToWord(Word *w, size_t num_words, Word v);
|
|
|
|
static void Copy(Word *dst, const Word *src, size_t num_words);
|
|
|
|
|
|
|
|
/* Arithmetic. */
|
|
|
|
static bool ExpMod(Word *dst, const Word *src, const Word *exp, size_t exp_num_words, const Word *mod, size_t mod_num_words, WordAllocator *allocator);
|
|
|
|
static bool MultMod(Word *dst, const Word *src, const Word *mult, const Word *mod, size_t num_words, WordAllocator *allocator);
|
|
|
|
static bool Mod(Word *dst, const Word *src, size_t src_words, const Word *mod, size_t mod_words, WordAllocator *allocator);
|
|
|
|
static bool DivMod(Word *quot, Word *rem, const Word *top, size_t top_words, const Word *bot, size_t bot_words, WordAllocator *allocator);
|
|
|
|
static bool Mult(Word *dst, const Word *lhs, const Word *rhs, size_t num_words, WordAllocator *allocator);
|
|
|
|
|
|
|
|
static Word LeftShift(Word *dst, const Word *w, size_t num_words, const size_t shift);
|
|
|
|
static Word RightShift(Word *dst, const Word *w, size_t num_words, const size_t shift);
|
|
|
|
static Word Add(Word *dst, const Word *lhs, const Word *rhs, size_t num_words);
|
|
|
|
static Word Sub(Word *dst, const Word *lhs, const Word *rhs, size_t num_words);
|
|
|
|
static Word MultAdd(Word *dst, const Word *w, size_t num_words, Word mult);
|
|
|
|
static Word MultSub(Word *dst, const Word *w, const Word *v, size_t num_words, Word mult);
|
|
|
|
};
|
|
|
|
|
|
|
|
template<size_t Bits>
|
2020-02-24 01:34:30 +00:00
|
|
|
class StaticBigNum : public BigNum {
|
2020-02-23 14:51:32 +00:00
|
|
|
public:
|
|
|
|
static constexpr size_t NumBits = Bits;
|
|
|
|
static constexpr size_t NumWords = util::AlignUp(NumBits, BitsPerWord) / BitsPerWord;
|
|
|
|
static constexpr size_t NumBytes = NumWords * sizeof(Word);
|
|
|
|
private:
|
|
|
|
Word word_buf[NumWords];
|
|
|
|
public:
|
2020-02-24 01:34:30 +00:00
|
|
|
constexpr StaticBigNum() : word_buf() {
|
2020-02-23 14:51:32 +00:00
|
|
|
this->ReserveStatic(word_buf, NumWords);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|