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

132 lines
3.9 KiB
C++
Raw Normal View History

#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 };
scalar::scalar(int i) {
if (i >= 0) {
auto k{ unsigned int(i) };
for (auto& j : blob) { j = k; k = k >> 8; }
}
else{
std::array<uint8_t, crypto_core_ristretto255_BYTES> absdata;
auto k{ unsigned int(-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});
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;
}
namespace mpir {
mpz ristretto25519_curve_order("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16);
}