mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-02 05:32:59 +02:00
Update to v106r65 release.
byuu says: This synchronizes bsnes/higan with many recent internal nall changes. This will be the last WIP until I am situated in Japan. Apologies for the bugfixes that didn't get applied yet, I ran out of time.
This commit is contained in:
@@ -4,64 +4,42 @@
|
||||
#if defined(EC_REFERENCE)
|
||||
#include <nall/elliptic-curve/modulo25519-reference.hpp>
|
||||
#else
|
||||
#include <nall/elliptic-curve/modulo25519.hpp>
|
||||
#include <nall/elliptic-curve/modulo25519-optimized.hpp>
|
||||
#endif
|
||||
|
||||
namespace nall { namespace EllipticCurve {
|
||||
|
||||
static const uint256_t L = (1_u256 << 252) + 27742317777372353535851937790883648493_u256;
|
||||
|
||||
struct Ed25519 {
|
||||
Ed25519() {
|
||||
field y = field(4) * field(5).reciprocal();
|
||||
field x = recoverX(y);
|
||||
point B{x, y, 1, x * y};
|
||||
for(uint n : range(253)) {
|
||||
Bscalar[n] = B;
|
||||
B = edwardsDouble(B);
|
||||
}
|
||||
}
|
||||
|
||||
auto publicKey(uint256_t privateKey) const -> uint256_t {
|
||||
auto H = uint512_t{Hash::SHA512(to_vector(privateKey)).output()};
|
||||
auto a = clamp(H);
|
||||
auto A = compress(scalarMultiplyB(modL(a)));
|
||||
return A;
|
||||
return compress(scalarMultiply(B, clamp(hash(privateKey)) % L));
|
||||
}
|
||||
|
||||
auto sign(const vector<uint8_t>& message, uint256_t privateKey) const -> uint512_t {
|
||||
auto H = uint512_t{Hash::SHA512(to_vector(privateKey)).output()};
|
||||
auto a = clamp(H);
|
||||
auto A = compress(scalarMultiplyB(modL(a)));
|
||||
auto sign(array_view<uint8_t> message, uint256_t privateKey) const -> uint512_t {
|
||||
uint512_t H = hash(privateKey);
|
||||
uint256_t a = clamp(H) % L;
|
||||
uint256_t A = compress(scalarMultiply(B, a));
|
||||
|
||||
Hash::SHA512 hash1;
|
||||
hash1.input(to_vector(upper(H)));
|
||||
hash1.input(message);
|
||||
auto r = uint512_t{hash1.output()};
|
||||
auto R = compress(scalarMultiplyB(modL(r)));
|
||||
uint512_t r = hash(upper(H), message) % L;
|
||||
uint256_t R = compress(scalarMultiply(B, r));
|
||||
|
||||
Hash::SHA512 hash2;
|
||||
hash2.input(to_vector(R));
|
||||
hash2.input(to_vector(A));
|
||||
hash2.input(message);
|
||||
uint512_t k = modL(uint512_t{hash2.output()});
|
||||
uint256_t S = modL(k * a + r);
|
||||
uint512_t k = hash(R, A, message) % L;
|
||||
uint256_t S = (k * a + r) % L;
|
||||
|
||||
return uint512_t(S) << 256 | R;
|
||||
}
|
||||
|
||||
auto verify(const vector<uint8_t>& message, uint512_t signature, uint256_t publicKey) const -> bool {
|
||||
auto verify(array_view<uint8_t> message, uint512_t signature, uint256_t publicKey) const -> bool {
|
||||
auto R = decompress(lower(signature));
|
||||
auto A = decompress(publicKey);
|
||||
if(!R || !A) return false;
|
||||
uint256_t S = upper(signature);
|
||||
|
||||
Hash::SHA512 hash;
|
||||
hash.input(to_vector(lower(signature)));
|
||||
hash.input(to_vector(publicKey));
|
||||
hash.input(message);
|
||||
auto r = uint512_t{hash.output()};
|
||||
uint256_t S = upper(signature) % L;
|
||||
uint512_t r = hash(lower(signature), publicKey, message) % L;
|
||||
|
||||
auto p = scalarMultiplyB(modL(S));
|
||||
auto q = edwardsAdd(R(), scalarMultiply(modL(r), A()));
|
||||
auto p = scalarMultiply(B, S);
|
||||
auto q = edwardsAdd(R(), scalarMultiply(A(), r));
|
||||
if(!onCurve(p) || !onCurve(q)) return false;
|
||||
if(p.x * q.z - q.x * p.z) return false;
|
||||
if(p.y * q.z - q.y * p.z) return false;
|
||||
@@ -71,31 +49,46 @@ struct Ed25519 {
|
||||
private:
|
||||
using field = Modulo25519;
|
||||
struct point { field x, y, z, t; };
|
||||
point Bscalar[253];
|
||||
const field D = -field(121665) * field(121666).reciprocal();
|
||||
const field D = -field(121665) * reciprocal(field(121666));
|
||||
const point B = *decompress((field(4) * reciprocal(field(5)))());
|
||||
const BarrettReduction<256> L = BarrettReduction<256>{EllipticCurve::L};
|
||||
|
||||
inline auto clamp(uint256_t p) const -> uint256_t {
|
||||
p &= ((0_u256 - 1) >> 2) - 7;
|
||||
p |= 1_u256 << 254;
|
||||
return p;
|
||||
inline auto input(Hash::SHA512&) const -> void {}
|
||||
|
||||
template<typename... P> inline auto input(Hash::SHA512& hash, uint256_t value, P&&... p) const -> void {
|
||||
for(uint byte : range(32)) hash.input(uint8_t(value >> byte * 8));
|
||||
input(hash, forward<P>(p)...);
|
||||
}
|
||||
|
||||
inline auto recoverX(field y) const -> field {
|
||||
field y2 = y.square();
|
||||
field x = ((y2 - 1) * (D * y2 + 1).reciprocal()).squareRoot();
|
||||
return x() & 1 ? -x : x;
|
||||
template<typename... P> inline auto input(Hash::SHA512& hash, array_view<uint8_t> value, P&&... p) const -> void {
|
||||
hash.input(value);
|
||||
input(hash, forward<P>(p)...);
|
||||
}
|
||||
|
||||
template<typename... P> inline auto hash(P&&... p) const -> uint512_t {
|
||||
Hash::SHA512 hash;
|
||||
input(hash, forward<P>(p)...);
|
||||
uint512_t result;
|
||||
for(auto byte : reverse(hash.output())) result = result << 8 | byte;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline auto clamp(uint256_t p) const -> uint256_t {
|
||||
p &= (1_u256 << 254) - 8;
|
||||
p |= (1_u256 << 254);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline auto onCurve(point p) const -> bool {
|
||||
if(!p.z) return false;
|
||||
if(p.x * p.y != p.z * p.t) return false;
|
||||
if(p.y.square() - p.x.square() - p.z.square() - p.t.square() * D) return false;
|
||||
if(p.x * p.y - p.z * p.t) return false;
|
||||
if(square(p.y) - square(p.x) - square(p.z) - square(p.t) * D) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline auto decompress(uint256_t c) const -> maybe<point> {
|
||||
field y = c & (1_u256 << 255) - 1;
|
||||
field x = recoverX(y);
|
||||
field y = c & ~0_u256 >> 1;
|
||||
field x = squareRoot((square(y) - 1) * reciprocal(D * square(y) + 1));
|
||||
if(c >> 255) x = -x;
|
||||
point p{x, y, 1, x * y};
|
||||
if(!onCurve(p)) return nothing;
|
||||
@@ -103,18 +96,18 @@ private:
|
||||
}
|
||||
|
||||
inline auto compress(point p) const -> uint256_t {
|
||||
field r = p.z.reciprocal();
|
||||
field r = reciprocal(p.z);
|
||||
field x = p.x * r;
|
||||
field y = p.y * r;
|
||||
return (x() & 1) << 255 | (y() & ((0_u256 - 1) >> 1));
|
||||
return (x & 1) << 255 | (y & ~0_u256 >> 1);
|
||||
}
|
||||
|
||||
inline auto edwardsDouble(point p) const -> point {
|
||||
field a = p.x.square();
|
||||
field b = p.y.square();
|
||||
field c = p.z.square();
|
||||
field a = square(p.x);
|
||||
field b = square(p.y);
|
||||
field c = square(p.z);
|
||||
field d = -a;
|
||||
field e = (p.x + p.y).square() - a - b;
|
||||
field e = square(p.x + p.y) - a - b;
|
||||
field g = d + b;
|
||||
field f = g - (c + c);
|
||||
field h = d - b;
|
||||
@@ -133,29 +126,16 @@ private:
|
||||
return {e * f, g * h, f * g, e * h};
|
||||
}
|
||||
|
||||
inline auto scalarMultiply(uint512_t e, point q) const -> point {
|
||||
inline auto scalarMultiply(point q, uint256_t exponent) const -> point {
|
||||
point p{0, 1, 1, 0}, c;
|
||||
for(uint n : reverse(range(253))) {
|
||||
for(uint bit : reverse(range(253))) {
|
||||
p = edwardsDouble(p);
|
||||
c = edwardsAdd(p, q);
|
||||
bool bit = e >> n & 1;
|
||||
cmove(bit, p.x, c.x);
|
||||
cmove(bit, p.y, c.y);
|
||||
cmove(bit, p.z, c.z);
|
||||
cmove(bit, p.t, c.t);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
inline auto scalarMultiplyB(uint512_t e) const -> point {
|
||||
point p{0, 1, 1, 0}, c;
|
||||
for(uint n : reverse(range(253))) {
|
||||
bool bit = e >> n & 1;
|
||||
c = edwardsAdd(p, Bscalar[n]);
|
||||
cmove(bit, p.x, c.x);
|
||||
cmove(bit, p.y, c.y);
|
||||
cmove(bit, p.z, c.z);
|
||||
cmove(bit, p.t, c.t);
|
||||
bool condition = exponent >> bit & 1;
|
||||
cmove(condition, p.x, c.x);
|
||||
cmove(condition, p.y, c.y);
|
||||
cmove(condition, p.z, c.z);
|
||||
cmove(condition, p.t, c.t);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
Reference in New Issue
Block a user