1
0
forked from cheng/wallet
wallet/ristretto255.cpp

160 lines
5.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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()); }
bool operator ==(const std::span<byte>& p, const std::span<byte>& q) {
bool breturn{ true };
for (auto xq = q.begin(); auto xp:p) {
if (xp != *xq++) {
breturn = false;
break;
}
}
return breturn;
}
bool operator !=(const std::span<byte>& p, const std::span<byte>& q) {
bool breturn{ false };
for (auto xq = q.begin(); auto xp:p) {
if (xp != *xq++) {
breturn = true;
break;
}
}
return breturn;
}
namespace ristretto255 {
bool scalar::constant_time_required{ true };
bool point::constant_time_required{ true };
/* constexpr scalar::scalar(intmax_t i) {
if (i >= 0) {
auto k{ intmax_t(i) };
for (auto& j : blob) { j = k; k = k >> 8; }
}
else {
std::array<uint8_t, crypto_core_ristretto255_BYTES> absdata;
auto k{ uintmax_t(-i) };
for (auto& j : absdata) { j = k; k = k >> 8; }
crypto_core_ristretto255_scalar_negate(&blob[0], &absdata[0]);
}
}
*/
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});
static constexpr scalar curveOrder({ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
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;
}
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;
}