2022-02-16 00:53:01 -05:00
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
void randombytes_buf(std::span<byte> in) { randombytes_buf(&in[0], in.size_bytes()); }
|
|
|
|
|
void randombytes_buf(std::span< char> in) { randombytes_buf(&in[0], in.size_bytes()); }
|
|
|
|
|
namespace ristretto255 {
|
|
|
|
|
bool scalar::constant_time_required{ true };
|
|
|
|
|
bool point::constant_time_required{ true };
|
|
|
|
|
|
|
|
|
|
point point::operator*(const scalar &sclr) const& noexcept {
|
|
|
|
|
point me;
|
|
|
|
|
auto i{ crypto_scalarmult_ristretto255(&me.blob[0], &sclr.blob[0], &blob[0]) };
|
|
|
|
|
assert(i == 0);
|
|
|
|
|
return me;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
point point::operator*(int i) const& noexcept {
|
|
|
|
|
return scalar(i) * (*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
point point::ptZero({
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
|
|
|
|
point point::ptBase({
|
|
|
|
|
0xe2, 0xf2, 0xae, 0x0a, 0x6a, 0xbc, 0x4e, 0x71, 0xa8, 0x84, 0xa9, 0x61, 0xc5, 0x00, 0x51, 0x5f, 0x58, 0xe3, 0x0b, 0x6a, 0xa5, 0x82, 0xdd, 0x8d, 0xb6, 0xa6, 0x59, 0x45, 0xe0, 0x8d, 0x2d, 0x76});
|
|
|
|
|
|
2024-08-02 01:36:07 -04:00
|
|
|
|
static const scalar curveOrder({ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
|
2022-03-07 23:46:14 -05:00
|
|
|
|
0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 });
|
|
|
|
|
const scalar& scalar::scOrder{ curveOrder };
|
|
|
|
|
|
|
|
|
|
std::strong_ordering scalar::operator<=>(const scalar& sclr) const& noexcept {
|
|
|
|
|
static_assert(std::endian::native == std::endian::little);
|
|
|
|
|
// Instead of a static assert, we really should have an if constexpr()
|
|
|
|
|
// that defines reverse iterators for little endian order
|
|
|
|
|
// and defines forward iterators for big endian order.
|
|
|
|
|
// but we will fix that when the time comes.
|
|
|
|
|
// as it depends on how the libsodium library will implement
|
|
|
|
|
// scalars on big endian order.
|
|
|
|
|
std::strong_ordering retval{ std::strong_ordering::equal };
|
|
|
|
|
constexpr auto bg = sizeof(scalar::blob);
|
|
|
|
|
typedef const std::array<uint64_t, sizeof(scalar::blob)/sizeof(uint64_t) >as_uint64_t;
|
|
|
|
|
auto lh{ reinterpret_cast<as_uint64_t&>(this->blob)};
|
|
|
|
|
auto rh{ reinterpret_cast<as_uint64_t&>(sclr.blob) };
|
|
|
|
|
static_assert(sizeof(as_uint64_t) == sizeof(sclr.blob));
|
|
|
|
|
auto p{ lh.end() };
|
|
|
|
|
auto q{ rh.end() };
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
auto vp{ *--p };
|
|
|
|
|
auto vq{ *--q };
|
|
|
|
|
retval = vp <=> vq;
|
|
|
|
|
}
|
|
|
|
|
while (std::is_eq(retval) &&
|
|
|
|
|
bool(p > lh.begin()));
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
2022-02-16 00:53:01 -05:00
|
|
|
|
|
|
|
|
|
signed_text::signed_text(
|
|
|
|
|
const scalar &k, // Signer's secret key
|
|
|
|
|
const point &Kin, // Signer's public key
|
|
|
|
|
std::span<char> txtin // Text to be signed.
|
|
|
|
|
)
|
|
|
|
|
: txt(txtin), K(Kin)
|
|
|
|
|
{
|
|
|
|
|
assert(k.valid());
|
|
|
|
|
assert(K.valid());
|
|
|
|
|
|
|
|
|
|
/* • Compute r = H(k|M), a per message private key. Or r can be an unpredictable secret scalar.
|
|
|
|
|
• Compute R = r*B, a per message public key<br/>
|
|
|
|
|
• Compute c = H(R|M).<br/>
|
|
|
|
|
• Compute s = r+c*k. (Note that sB = r*B+c*k*B = R+c*K.)*/
|
|
|
|
|
scalar r(hash<512>(k, txtin));
|
|
|
|
|
point R(r.timesBase());
|
|
|
|
|
c = scalar (hash<512>(R, txtin));
|
|
|
|
|
s = r + c * k;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool signed_text::verify() {
|
|
|
|
|
/* • Check that c, s are valid scalars
|
|
|
|
|
• Check that K, the signing public key, is a valid member of the prime order group
|
|
|
|
|
• Compute R = sB − cK
|
|
|
|
|
• Check that c = H(R | M) */
|
|
|
|
|
if (!c.valid() || !s.valid() || !K.valid())return false;
|
|
|
|
|
else {
|
|
|
|
|
point R = s.timesBase() - c * K;
|
|
|
|
|
return c==scalar(hash<512>(R, txt));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} //end ristretto255 namespace
|
|
|
|
|
using ristretto255::scalar, ro::CompileSizedString, ro::bin2hex, ro::to_base64_string;
|
|
|
|
|
|
|
|
|
|
auto reverse_byte_order(std::array < uint8_t, sizeof(scalar)>const& ac) {
|
|
|
|
|
std::array <uint8_t, sizeof(scalar)> ar;
|
|
|
|
|
auto p = ar.rbegin();
|
|
|
|
|
for (auto x : ac) {
|
|
|
|
|
*p++ = x;
|
|
|
|
|
}
|
|
|
|
|
return ar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> CompileSizedString < 2 * sizeof(scalar)>
|
|
|
|
|
bin2hex<scalar>(const scalar& sc) {
|
|
|
|
|
CompileSizedString <2 * sizeof(scalar)>sz;
|
|
|
|
|
auto bigendian = reverse_byte_order(sc.blob);
|
|
|
|
|
sodium_bin2hex(&sz[0], sizeof(sc.blob) * 2 + 1, &bigendian[0], bigendian.size());
|
|
|
|
|
return sz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> scalar ro::hex2bin<scalar>(const CompileSizedString< (2 * sizeof(scalar))>& sz) {
|
|
|
|
|
scalar sc;
|
|
|
|
|
sc.blob = reverse_byte_order(ro::hex2bin<decltype(sc.blob)>(sz));
|
|
|
|
|
return sc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> CompileSizedString < (sizeof(scalar) * 8 + 5) / 6>
|
|
|
|
|
to_base64_string<scalar>(const scalar& sc) {
|
|
|
|
|
CompileSizedString < (sizeof(sc.blob) * 8 + 4) / 6> sz;
|
|
|
|
|
auto bigendian = reverse_byte_order(sc.blob);
|
|
|
|
|
bits2base64(
|
|
|
|
|
&(bigendian[0]), 4, sizeof(bigendian)*8-4,
|
|
|
|
|
std::span<char>(sz)
|
|
|
|
|
);
|
|
|
|
|
return sz;
|
|
|
|
|
}
|