Wallet: added checks for FCMP++ compatibility
This commit is contained in:
+13
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2020, The Monero Project
|
||||
// Copyright (c) 2014-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -42,6 +42,13 @@ const fe fe_d = {-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -627
|
||||
const fe fe_sqrtm1 = {-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482}; /* sqrt(-1) */
|
||||
const fe fe_d2 = {-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199}; /* 2 * d */
|
||||
|
||||
/* a = -1 */
|
||||
// TODO: double check these consts
|
||||
const fe fe_a_sub_d = {10913609, -13857413, 15372611, -6949391, -114729, 8787816, 6275908, 3247719, 18696448, 12055116}; /* a - d */
|
||||
const fe fe_a0 = {-21827241, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199}; /* A0 = 2 * (a + d) */
|
||||
const fe fe_ap = {-23454401, 11679213, -5618422, 5756869, -458917, 1596832, 25103633, 12990876, 7676928, 14666033}; /* Ap = -2 * A0 */
|
||||
const fe fe_msqrt2b = {-1359796, -3165658, 8463188, -8916281, -9242332, 8801166, -2887120, 14417306, 28934311, 6371549};
|
||||
|
||||
/* base[i][j] = (j+1)*256^i*B */
|
||||
const ge_precomp ge_base[32][8] = {
|
||||
{
|
||||
@@ -874,6 +881,11 @@ const fe fe_fffb1 = {-31702527, -2466483, -26106795, -12203692, -12169197, -3210
|
||||
const fe fe_fffb2 = {8166131, -6741800, -17040804, 3154616, 21461005, 1466302, -30876704, -6368709, 10503587, -13363080}; /* sqrt(2 * A * (A + 2)) */
|
||||
const fe fe_fffb3 = {-13620103, 14639558, 4532995, 7679154, 16815101, -15883539, -22863840, -14813421, 13716513, -6477756}; /* sqrt(-sqrt(-1) * A * (A + 2)) */
|
||||
const fe fe_fffb4 = {-21786234, -12173074, 21573800, 4524538, -4645904, 16204591, 8012863, -8444712, 3212926, 6885324}; /* sqrt(sqrt(-1) * A * (A + 2)) */
|
||||
const fe fe_a_inv_3 = {-22207407, 11184811, 22369621, -11184811, -22369621, 11184811, 22369621, -11184811, -22369621, 11184811}; /* A / 3*/
|
||||
const fe fe_c = {-12222970, -8312128, -11511410, 9067497, -15300785, -241793, 25456130, 14121551, -12187136, 3972024}; /* sqrt(-(A + 2))*/
|
||||
const fe fe_one = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
const fe fe_m1 = {-1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
const fe fe_inv2 = {10, 0, 0, 0, 0, 0, 0, 0, 0, -16777216}; /* 1 / 2 */
|
||||
const ge_p3 ge_p3_identity = { {0}, {1, 0}, {1, 0}, {0} };
|
||||
const ge_p3 ge_p3_H = {
|
||||
{7329926, -15101362, 31411471, 7614783, 27996851, -3197071, -11157635, -6878293, 466949, -7986503},
|
||||
|
||||
Vendored
+255
-54
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2020, The Monero Project
|
||||
// Copyright (c) 2014-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -34,13 +34,13 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "crypto-ops.h"
|
||||
|
||||
/* Predeclarations */
|
||||
|
||||
static void fe_mul(fe, const fe, const fe);
|
||||
static void fe_sq(fe, const fe);
|
||||
static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
|
||||
static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
|
||||
static void ge_p2_0(ge_p2 *);
|
||||
@@ -73,7 +73,7 @@ uint64_t load_4(const unsigned char *in)
|
||||
h = 0
|
||||
*/
|
||||
|
||||
static void fe_0(fe h) {
|
||||
void fe_0(fe h) {
|
||||
h[0] = 0;
|
||||
h[1] = 0;
|
||||
h[2] = 0;
|
||||
@@ -92,7 +92,7 @@ static void fe_0(fe h) {
|
||||
h = 1
|
||||
*/
|
||||
|
||||
static void fe_1(fe h) {
|
||||
void fe_1(fe h) {
|
||||
h[0] = 1;
|
||||
h[1] = 0;
|
||||
h[2] = 0;
|
||||
@@ -232,7 +232,7 @@ static void fe_cmov(fe f, const fe g, unsigned int b) {
|
||||
h = f
|
||||
*/
|
||||
|
||||
static void fe_copy(fe h, const fe f) {
|
||||
void fe_copy(fe h, const fe f) {
|
||||
int32_t f0 = f[0];
|
||||
int32_t f1 = f[1];
|
||||
int32_t f2 = f[2];
|
||||
@@ -315,6 +315,39 @@ void fe_invert(fe out, const fe z) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Montgomery's trick
|
||||
// https://iacr.org/archive/pkc2004/29470042/29470042.pdf 2.2
|
||||
int fe_batch_invert(fe *out, const fe *in, const int n) {
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Step 1: collect initial muls
|
||||
fe *init_muls = (fe *) malloc(n * sizeof(fe));
|
||||
if (!init_muls) {
|
||||
return 1;
|
||||
}
|
||||
memcpy(&init_muls[0], &in[0], sizeof(fe));
|
||||
for (int i = 1; i < n; ++i) {
|
||||
fe_mul(init_muls[i], init_muls[i-1], in[i]);
|
||||
}
|
||||
|
||||
// Step 2: get the inverse of all elems multiplied together
|
||||
fe a;
|
||||
fe_invert(a, init_muls[n-1]);
|
||||
|
||||
// Step 3: get each inverse
|
||||
for (int i = n; i > 1; --i) {
|
||||
fe_mul(out[i-1], a, init_muls[i-2]);
|
||||
fe_mul(a, a, in[i-1]);
|
||||
}
|
||||
memcpy(&out[0], &a, sizeof(fe));
|
||||
|
||||
free(init_muls);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* From fe_isnegative.c */
|
||||
|
||||
/*
|
||||
@@ -325,7 +358,7 @@ Preconditions:
|
||||
|f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
*/
|
||||
|
||||
static int fe_isnegative(const fe f) {
|
||||
int fe_isnegative(const fe f) {
|
||||
unsigned char s[32];
|
||||
fe_tobytes(s, f);
|
||||
return s[0] & 1;
|
||||
@@ -376,7 +409,7 @@ Can get away with 11 carries, but then data flow is much deeper.
|
||||
With tighter constraints on inputs can squeeze carries into int32.
|
||||
*/
|
||||
|
||||
static void fe_mul(fe h, const fe f, const fe g) {
|
||||
void fe_mul(fe h, const fe f, const fe g) {
|
||||
int32_t f0 = f[0];
|
||||
int32_t f1 = f[1];
|
||||
int32_t f2 = f[2];
|
||||
@@ -606,7 +639,7 @@ Postconditions:
|
||||
|h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
*/
|
||||
|
||||
static void fe_neg(fe h, const fe f) {
|
||||
void fe_neg(fe h, const fe f) {
|
||||
int32_t f0 = f[0];
|
||||
int32_t f1 = f[1];
|
||||
int32_t f2 = f[2];
|
||||
@@ -656,7 +689,7 @@ Postconditions:
|
||||
See fe_mul.c for discussion of implementation strategy.
|
||||
*/
|
||||
|
||||
static void fe_sq(fe h, const fe f) {
|
||||
void fe_sq(fe h, const fe f) {
|
||||
int32_t f0 = f[0];
|
||||
int32_t f1 = f[1];
|
||||
int32_t f2 = f[2];
|
||||
@@ -960,7 +993,7 @@ Postconditions:
|
||||
|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
*/
|
||||
|
||||
static void fe_sub(fe h, const fe f, const fe g) {
|
||||
void fe_sub(fe h, const fe f, const fe g) {
|
||||
int32_t f0 = f[0];
|
||||
int32_t f1 = f[1];
|
||||
int32_t f2 = f[2];
|
||||
@@ -1330,16 +1363,9 @@ void ge_double_scalarmult_base_vartime_p3(ge_p3 *r3, const unsigned char *a, con
|
||||
}
|
||||
}
|
||||
|
||||
/* From ge_frombytes.c, modified */
|
||||
|
||||
int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
|
||||
fe u;
|
||||
fe v;
|
||||
fe vxx;
|
||||
fe check;
|
||||
|
||||
/* From fe_frombytes.c */
|
||||
/* From fe_frombytes.c */
|
||||
|
||||
int fe_frombytes_vartime(fe y, const unsigned char *s) {
|
||||
int64_t h0 = load_4(s);
|
||||
int64_t h1 = load_3(s + 4) << 6;
|
||||
int64_t h2 = load_3(s + 7) << 5;
|
||||
@@ -1380,18 +1406,31 @@ int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
|
||||
carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
|
||||
carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
|
||||
|
||||
h->Y[0] = h0;
|
||||
h->Y[1] = h1;
|
||||
h->Y[2] = h2;
|
||||
h->Y[3] = h3;
|
||||
h->Y[4] = h4;
|
||||
h->Y[5] = h5;
|
||||
h->Y[6] = h6;
|
||||
h->Y[7] = h7;
|
||||
h->Y[8] = h8;
|
||||
h->Y[9] = h9;
|
||||
y[0] = h0;
|
||||
y[1] = h1;
|
||||
y[2] = h2;
|
||||
y[3] = h3;
|
||||
y[4] = h4;
|
||||
y[5] = h5;
|
||||
y[6] = h6;
|
||||
y[7] = h7;
|
||||
y[8] = h8;
|
||||
y[9] = h9;
|
||||
|
||||
/* End fe_frombytes.c */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* From ge_frombytes.c, modified */
|
||||
|
||||
int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
|
||||
fe u;
|
||||
fe v;
|
||||
fe vxx;
|
||||
fe check;
|
||||
|
||||
if (fe_frombytes_vartime(h->Y, s) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fe_1(h->Z);
|
||||
fe_sq(u, h->Y);
|
||||
@@ -1608,7 +1647,7 @@ static void ge_precomp_cmov(ge_precomp *t, const ge_precomp *u, unsigned char b)
|
||||
fe_cmov(t->xy2d, u->xy2d, b);
|
||||
}
|
||||
|
||||
static void select(ge_precomp *t, int pos, signed char b) {
|
||||
static void _select(ge_precomp *t, int pos, signed char b) {
|
||||
ge_precomp minust;
|
||||
unsigned char bnegative = negative(b);
|
||||
unsigned char babs = b - (((-bnegative) & b) << 1);
|
||||
@@ -1690,7 +1729,7 @@ void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
||||
|
||||
ge_p3_0(h);
|
||||
for (i = 1; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
_select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
|
||||
@@ -1700,7 +1739,7 @@ void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
||||
ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r);
|
||||
|
||||
for (i = 0; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
_select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
}
|
||||
@@ -2023,26 +2062,18 @@ void sc_reduce(unsigned char *s) {
|
||||
s[31] = s11 >> 17;
|
||||
}
|
||||
|
||||
/* New code */
|
||||
/* From fe_pow22523.c */
|
||||
|
||||
static void fe_divpowm1(fe r, const fe u, const fe v) {
|
||||
fe v3, uv7, t0, t1, t2;
|
||||
void fe_pow22523(fe out, const fe z) {
|
||||
fe t0;
|
||||
fe t1;
|
||||
fe t2;
|
||||
int i;
|
||||
|
||||
fe_sq(v3, v);
|
||||
fe_mul(v3, v3, v); /* v3 = v^3 */
|
||||
fe_sq(uv7, v3);
|
||||
fe_mul(uv7, uv7, v);
|
||||
fe_mul(uv7, uv7, u); /* uv7 = uv^7 */
|
||||
|
||||
/*fe_pow22523(uv7, uv7);*/
|
||||
|
||||
/* From fe_pow22523.c */
|
||||
|
||||
fe_sq(t0, uv7);
|
||||
fe_sq(t0, z);
|
||||
fe_sq(t1, t0);
|
||||
fe_sq(t1, t1);
|
||||
fe_mul(t1, uv7, t1);
|
||||
fe_mul(t1, z, t1);
|
||||
fe_mul(t0, t0, t1);
|
||||
fe_sq(t0, t0);
|
||||
fe_mul(t0, t1, t0);
|
||||
@@ -2081,12 +2112,24 @@ static void fe_divpowm1(fe r, const fe u, const fe v) {
|
||||
fe_mul(t0, t1, t0);
|
||||
fe_sq(t0, t0);
|
||||
fe_sq(t0, t0);
|
||||
fe_mul(t0, t0, uv7);
|
||||
fe_mul(out, t0, z);
|
||||
}
|
||||
|
||||
/* End fe_pow22523.c */
|
||||
/* t0 = (uv^7)^((q-5)/8) */
|
||||
fe_mul(t0, t0, v3);
|
||||
fe_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */
|
||||
/* New code */
|
||||
|
||||
static void fe_divpowm1(fe r, const fe u, const fe v) {
|
||||
fe v3, uv7;
|
||||
|
||||
fe_sq(v3, v);
|
||||
fe_mul(v3, v3, v); /* v3 = v^3 */
|
||||
fe_sq(uv7, v3);
|
||||
fe_mul(uv7, uv7, v);
|
||||
fe_mul(uv7, uv7, u); /* uv7 = uv^7 */
|
||||
|
||||
fe_pow22523(r, uv7); /* (uv^7)^((q-5)/8) */
|
||||
|
||||
fe_mul(r, r, v3);
|
||||
fe_mul(r, r, u); /* u^(m+1)v^(-(m+1)) */
|
||||
}
|
||||
|
||||
static void ge_cached_0(ge_cached *r) {
|
||||
@@ -2536,6 +2579,14 @@ void sc_0(unsigned char *s) {
|
||||
}
|
||||
}
|
||||
|
||||
void sc_1(unsigned char *s) {
|
||||
int i;
|
||||
s[0] = 1;
|
||||
for (i = 1; i < 32; i++) {
|
||||
s[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void sc_reduce32(unsigned char *s) {
|
||||
int64_t s0 = 2097151 & load_3(s);
|
||||
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
||||
@@ -3936,6 +3987,92 @@ int sc_isnonzero(const unsigned char *s) {
|
||||
s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1;
|
||||
}
|
||||
|
||||
static void edwardsYZ_to_x25519(unsigned char *xbytes, const fe Y, const fe Z) {
|
||||
// y = Y/Z
|
||||
// x_mont = (1 + y) / (1 - y)
|
||||
// = (1 + Y/Z) / (1 - Y/Z)
|
||||
// = (Z + Y) / (Z - Y)
|
||||
|
||||
fe tmp0;
|
||||
fe tmp1;
|
||||
fe_add(tmp0, Z, Y); // Z + Y
|
||||
fe_sub(tmp1, Z, Y); // Z - Y
|
||||
fe_invert(tmp1, tmp1); // 1/(Z - Y)
|
||||
fe_mul(tmp0, tmp0, tmp1); // (Z + Y) / (Z - Y)
|
||||
fe_tobytes(xbytes, tmp0); // tobytes((Z + Y) / (Z - Y))
|
||||
}
|
||||
|
||||
void ge_p3_to_x25519(unsigned char *xbytes, const ge_p3 *h)
|
||||
{
|
||||
edwardsYZ_to_x25519(xbytes, h->Y, h->Z);
|
||||
}
|
||||
|
||||
int edwards_bytes_to_x25519_vartime(unsigned char *xbytes, const unsigned char *s)
|
||||
{
|
||||
/* From fe_frombytes.c */
|
||||
|
||||
int64_t h0 = load_4(s);
|
||||
int64_t h1 = load_3(s + 4) << 6;
|
||||
int64_t h2 = load_3(s + 7) << 5;
|
||||
int64_t h3 = load_3(s + 10) << 3;
|
||||
int64_t h4 = load_3(s + 13) << 2;
|
||||
int64_t h5 = load_4(s + 16);
|
||||
int64_t h6 = load_3(s + 20) << 7;
|
||||
int64_t h7 = load_3(s + 23) << 5;
|
||||
int64_t h8 = load_3(s + 26) << 4;
|
||||
int64_t h9 = (load_3(s + 29) & 8388607) << 2;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
|
||||
/* Validate the number to be canonical */
|
||||
if (h9 == 33554428 && h8 == 268435440 && h7 == 536870880 && h6 == 2147483520 &&
|
||||
h5 == 4294967295 && h4 == 67108860 && h3 == 134217720 && h2 == 536870880 &&
|
||||
h1 == 1073741760 && h0 >= 4294967277) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
|
||||
carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
|
||||
carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
|
||||
carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
|
||||
carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
|
||||
|
||||
carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
|
||||
carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
|
||||
carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
|
||||
carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
|
||||
carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
|
||||
|
||||
fe Y;
|
||||
Y[0] = h0;
|
||||
Y[1] = h1;
|
||||
Y[2] = h2;
|
||||
Y[3] = h3;
|
||||
Y[4] = h4;
|
||||
Y[5] = h5;
|
||||
Y[6] = h6;
|
||||
Y[7] = h7;
|
||||
Y[8] = h8;
|
||||
Y[9] = h9;
|
||||
|
||||
/* End fe_frombytes.c */
|
||||
|
||||
fe Z;
|
||||
fe_1(Z);
|
||||
|
||||
edwardsYZ_to_x25519(xbytes, Y, Z);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p) {
|
||||
// https://eprint.iacr.org/2008/522
|
||||
// X == T == 0 and Y/Z == 1
|
||||
@@ -3984,3 +4121,67 @@ int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p) {
|
||||
// Y/Z = 0/0
|
||||
return 0;
|
||||
}
|
||||
|
||||
// https://www.ietf.org/archive/id/draft-ietf-lwig-curve-representations-02.pdf E.2
|
||||
static void fe_ed_derivatives_to_wei_x(unsigned char *wei_x, const fe inv_one_minus_y, const fe one_plus_y)
|
||||
{
|
||||
// (1/(1-y))*(1+y)
|
||||
fe inv_one_minus_y_mul_one_plus_y;
|
||||
fe_mul(inv_one_minus_y_mul_one_plus_y, inv_one_minus_y, one_plus_y);
|
||||
|
||||
// wei x = (1/(1-y))*(1+y) + (A/3)
|
||||
fe wei_x_fe;
|
||||
fe_add(wei_x_fe, inv_one_minus_y_mul_one_plus_y, fe_a_inv_3);
|
||||
fe_tobytes(wei_x, wei_x_fe);
|
||||
}
|
||||
|
||||
// https://www.ietf.org/archive/id/draft-ietf-lwig-curve-representations-02.pdf E.2
|
||||
void fe_ed_derivatives_to_wei_x_y(unsigned char *wei_x, unsigned char *wei_y, const fe inv_one_minus_y, const fe one_plus_y, const fe inv_one_minus_y_mul_x)
|
||||
{
|
||||
fe_ed_derivatives_to_wei_x(wei_x, inv_one_minus_y, one_plus_y);
|
||||
|
||||
// c*(1+y)
|
||||
fe fe_c_mul_one_plus_y;
|
||||
fe_mul(fe_c_mul_one_plus_y, fe_c, one_plus_y);
|
||||
|
||||
// wei y = c * (1+y) * (1/((1-y)*x))
|
||||
fe wei_y_fe;
|
||||
fe_mul(wei_y_fe, fe_c_mul_one_plus_y, inv_one_minus_y_mul_x);
|
||||
fe_tobytes(wei_y, wei_y_fe);
|
||||
}
|
||||
|
||||
/*
|
||||
Since fe_add and fe_sub enforce the following conditions:
|
||||
|
||||
Preconditions:
|
||||
|f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
|g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
|
||||
Postconditions:
|
||||
|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
|
||||
We sometimes need to "reduce" field elems when they are in the poscondition's
|
||||
larger domain to match the precondition domain. This way we can take the output
|
||||
of fe_add or fe_sub and use it as input to another call to fe_add or fe_sub.
|
||||
|
||||
We reduce by converting the field elem to its byte repr, then re-deriving the
|
||||
field elem from the byte repr.
|
||||
*/
|
||||
void fe_reduce(fe reduced_f, const fe f)
|
||||
{
|
||||
unsigned char f_bytes[32];
|
||||
fe_tobytes(f_bytes, f);
|
||||
fe_frombytes_vartime(reduced_f, f_bytes);
|
||||
}
|
||||
|
||||
void fe_dbl(fe h, const fe f)
|
||||
{
|
||||
// Reduce the input for safety to ensure we meet the preconditions for fe_add
|
||||
fe f_reduced;
|
||||
fe_reduce(f_reduced, f);
|
||||
fe h_res;
|
||||
fe_add(h_res, f_reduced, f_reduced);
|
||||
// Reduce the output for safety to ensure the result can be used as input to
|
||||
// fe_add or fe_sub without an extra call to fe_reduce
|
||||
fe_reduce(h, h_res);
|
||||
}
|
||||
|
||||
Vendored
+38
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2020, The Monero Project
|
||||
// Copyright (c) 2014-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* From fe.h */
|
||||
|
||||
typedef int32_t fe[10];
|
||||
@@ -86,6 +88,7 @@ void ge_double_scalarmult_base_vartime_p3(ge_p3 *, const unsigned char *, const
|
||||
|
||||
extern const fe fe_sqrtm1;
|
||||
extern const fe fe_d;
|
||||
int fe_frombytes_vartime(fe, const unsigned char *);
|
||||
int ge_frombytes_vartime(ge_p3 *, const unsigned char *);
|
||||
|
||||
/* From ge_p1p1_to_p2.c */
|
||||
@@ -128,6 +131,10 @@ void ge_tobytes(unsigned char *, const ge_p2 *);
|
||||
|
||||
void sc_reduce(unsigned char *);
|
||||
|
||||
/* From fe_pow22523.c */
|
||||
|
||||
void fe_pow22523(fe, const fe);
|
||||
|
||||
/* New code */
|
||||
|
||||
void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *);
|
||||
@@ -138,16 +145,26 @@ void ge_triple_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const
|
||||
void ge_double_scalarmult_precomp_vartime2(ge_p2 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp);
|
||||
void ge_double_scalarmult_precomp_vartime2_p3(ge_p3 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp);
|
||||
void ge_mul8(ge_p1p1 *, const ge_p2 *);
|
||||
extern const fe fe_a_sub_d;
|
||||
extern const fe fe_a0;
|
||||
extern const fe fe_ap;
|
||||
extern const fe fe_msqrt2b;
|
||||
extern const fe fe_ma2;
|
||||
extern const fe fe_ma;
|
||||
extern const fe fe_fffb1;
|
||||
extern const fe fe_fffb2;
|
||||
extern const fe fe_fffb3;
|
||||
extern const fe fe_fffb4;
|
||||
extern const fe fe_a_inv_3;
|
||||
extern const fe fe_c;
|
||||
extern const fe fe_one;
|
||||
extern const fe fe_m1;
|
||||
extern const fe fe_inv2;
|
||||
extern const ge_p3 ge_p3_identity;
|
||||
extern const ge_p3 ge_p3_H;
|
||||
void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
|
||||
void sc_0(unsigned char *);
|
||||
void sc_1(unsigned char *);
|
||||
void sc_reduce32(unsigned char *);
|
||||
void sc_add(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_sub(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
@@ -157,12 +174,32 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
|
||||
int sc_check(const unsigned char *);
|
||||
int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
|
||||
|
||||
/**
|
||||
* brief: Convert Ed25519 y-coord to X25519 x-coord, AKA "ConvertPointE()" in the Carrot spec
|
||||
*/
|
||||
void ge_p3_to_x25519(unsigned char *xbytes, const ge_p3 *h);
|
||||
int edwards_bytes_to_x25519_vartime(unsigned char *xbytes, const unsigned char *s);
|
||||
|
||||
// internal
|
||||
uint64_t load_3(const unsigned char *in);
|
||||
uint64_t load_4(const unsigned char *in);
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void fe_add(fe h, const fe f, const fe g);
|
||||
void fe_neg(fe h, const fe f);
|
||||
void fe_tobytes(unsigned char *, const fe);
|
||||
void fe_copy(fe h, const fe f);
|
||||
int fe_isnegative(const fe f);
|
||||
void fe_invert(fe out, const fe z);
|
||||
int fe_batch_invert(fe *out, const fe *in, const int n);
|
||||
void fe_mul(fe out, const fe, const fe);
|
||||
void fe_sq(fe h, const fe f);
|
||||
void fe_sub(fe h, const fe f, const fe g);
|
||||
void fe_0(fe h);
|
||||
void fe_1(fe h);
|
||||
|
||||
int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p);
|
||||
|
||||
void fe_ed_derivatives_to_wei_x_y(unsigned char *wei_x, unsigned char *wei_y, const fe inv_one_minus_y, const fe one_plus_y, const fe inv_one_minus_y_mul_x);
|
||||
|
||||
void fe_reduce(fe reduced_f, const fe f);
|
||||
void fe_dbl(fe h, const fe f);
|
||||
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
// Copyright (c) 2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4800)
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include "crypto-ops.h"
|
||||
}
|
||||
|
||||
#include "fcmp_pp_crypto.h"
|
||||
#include <cstring>
|
||||
|
||||
static bool fe_compare(const fe a, const fe b)
|
||||
{
|
||||
unsigned char a_bytes[32];
|
||||
unsigned char b_bytes[32];
|
||||
|
||||
fe_tobytes(a_bytes, a);
|
||||
fe_tobytes(b_bytes, b);
|
||||
|
||||
return memcmp(a_bytes, b_bytes, sizeof(a_bytes)) == 0;
|
||||
}
|
||||
|
||||
static bool sqrt_ext(fe y, const fe x)
|
||||
{
|
||||
fe y_res;
|
||||
|
||||
fe x2;
|
||||
fe_dbl(x2, x);
|
||||
|
||||
fe b;
|
||||
fe_pow22523(b, x2);
|
||||
|
||||
fe b_sq;
|
||||
fe_sq(b_sq, b);
|
||||
|
||||
fe c;
|
||||
fe_mul(c, x2, b_sq);
|
||||
|
||||
if (fe_compare(c, fe_one) || fe_compare(c, fe_m1))
|
||||
{
|
||||
fe_0(c);
|
||||
c[0] = 3;
|
||||
}
|
||||
|
||||
fe c_sub_1;
|
||||
fe_sub(c_sub_1, c, fe_one);
|
||||
|
||||
fe_mul(y_res, x, b);
|
||||
fe_mul(y_res, y_res, c_sub_1);
|
||||
|
||||
if (fe_isnegative(y_res)) {
|
||||
fe_neg(y_res, y_res);
|
||||
}
|
||||
|
||||
fe y_sq;
|
||||
fe_sq(y_sq, y_res);
|
||||
bool r = fe_compare(x, y_sq);
|
||||
|
||||
fe_copy(y, y_res);
|
||||
return r;
|
||||
};
|
||||
|
||||
namespace fcmp_pp
|
||||
{
|
||||
// TODO: impl faster sqrt
|
||||
bool sqrt(fe y, const fe x)
|
||||
{
|
||||
return sqrt_ext(y, x);
|
||||
};
|
||||
} // namespace fcmp_pp
|
||||
|
||||
static void inv_iso(fe u_out, fe w_out, const fe u, const fe w)
|
||||
{
|
||||
// 4u
|
||||
fe_dbl(u_out, u);
|
||||
fe_dbl(u_out, u_out);
|
||||
// 2w
|
||||
fe_dbl(w_out, w);
|
||||
};
|
||||
|
||||
static void inv_psi1(fe e_out, fe u_out, fe w_out, const fe e, const fe u, const fe w)
|
||||
{
|
||||
fe e_res, u_res, w_res;
|
||||
|
||||
fe tt;
|
||||
bool cc = sqrt_ext(tt, u);
|
||||
fe_copy(w_res, tt);
|
||||
fe w_;
|
||||
fe_copy(w_, w);
|
||||
fe_copy(e_res, e);
|
||||
|
||||
if (!cc)
|
||||
{
|
||||
fe tt_sq;
|
||||
fe_sq(tt_sq, tt);
|
||||
fe neg_u_dbl;
|
||||
fe_dbl(neg_u_dbl, u);
|
||||
fe_neg(neg_u_dbl, neg_u_dbl);
|
||||
if (fe_compare(tt_sq, neg_u_dbl)) {
|
||||
fe_mul(tt, tt, fe_sqrtm1);
|
||||
}
|
||||
|
||||
fe_mul(w_, w, tt);
|
||||
|
||||
fe e_sq;
|
||||
fe_sq(e_sq, e);
|
||||
fe_mul(w_res, fe_msqrt2b, e_sq);
|
||||
|
||||
fe_mul(e_res, e_res, tt);
|
||||
}
|
||||
|
||||
fe w_res_sq;
|
||||
fe_sq(w_res_sq, w_res);
|
||||
|
||||
fe e_res_sq;
|
||||
fe_sq(e_res_sq, e_res);
|
||||
|
||||
fe A_e_sq;
|
||||
fe_mul(A_e_sq, fe_a0, e_res_sq);
|
||||
|
||||
fe w_res_w;
|
||||
fe_mul(w_res_w, w_res, w_);
|
||||
|
||||
fe_sub(u_res, w_res_sq, A_e_sq);
|
||||
fe_reduce(u_res, u_res);
|
||||
fe_sub(u_res, u_res, w_res_w);
|
||||
fe_mul(u_res, u_res, fe_inv2);
|
||||
|
||||
fe_copy(e_out, e_res);
|
||||
fe_copy(u_out, u_res);
|
||||
fe_copy(w_out, w_res);
|
||||
};
|
||||
|
||||
static bool inv_psi2(fe u_out, fe w_out, const fe e, const fe u, const fe w)
|
||||
{
|
||||
fe u_res, w_res;
|
||||
|
||||
if (!fcmp_pp::sqrt(w_res, u))
|
||||
return false;
|
||||
fe e_sq;
|
||||
fe_sq(e_sq, e);
|
||||
fe Ap_e_sq;
|
||||
fe_mul(Ap_e_sq, fe_ap, e_sq);
|
||||
|
||||
fe w_res_w;
|
||||
fe_mul(w_res_w, w_res, w);
|
||||
|
||||
fe_sub(u_res, u, Ap_e_sq);
|
||||
fe_reduce(u_res, u_res);
|
||||
fe_sub(u_res, u_res, w_res_w);
|
||||
fe_mul(u_res, u_res, fe_inv2);
|
||||
|
||||
fe_copy(u_out, u_res);
|
||||
fe_copy(w_out, w_res);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
namespace fcmp_pp
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
bool mul8_is_identity(const ge_p3 &point) {
|
||||
ge_p2 point_ge_p2;
|
||||
ge_p3_to_p2(&point_ge_p2, &point);
|
||||
ge_p1p1 point_mul8;
|
||||
ge_mul8(&point_mul8, &point_ge_p2);
|
||||
ge_p3 point_mul8_p3;
|
||||
ge_p1p1_to_p3(&point_mul8_p3, &point_mul8);
|
||||
return ge_p3_is_point_at_infinity_vartime(&point_mul8_p3);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// https://github.com/kayabaNerve/fcmp-plus-plus/blob/94744c5324e869a9483bbbd93a864e108304bf76/crypto/divisors/src/tests/torsion_check.rs
|
||||
// Returns true if point is torsion free
|
||||
// Pre-condition: point is a valid point and point*8 not equal to identity
|
||||
// WARNING1: this approach needs to be carefully vetted academically and audited
|
||||
// before it can be used in production.
|
||||
// WARNING2: since fe_add and fe_sub expect the input fe's to be within a
|
||||
// smaller domain than the output fe, we sometimes need to "reduce" a field elem
|
||||
// to chain calls to fe_add and fe_sub. Notice all calls to fe_reduce.
|
||||
bool torsion_check_vartime(const ge_p3 &point) {
|
||||
//assert(!mul8_is_identity(point));
|
||||
|
||||
// ed to wei
|
||||
fe e, u, w;
|
||||
{
|
||||
fe z_plus_ed_y, z_minus_ed_y;
|
||||
fe_add(z_plus_ed_y, fe_one, point.Y);
|
||||
fe_sub(z_minus_ed_y, fe_one, point.Y);
|
||||
|
||||
// e
|
||||
fe_mul(e, z_minus_ed_y, point.X);
|
||||
// u
|
||||
fe_mul(u, fe_a_sub_d, z_plus_ed_y);
|
||||
fe_mul(u, u, point.X);
|
||||
fe_mul(u, u, e);
|
||||
// w
|
||||
fe_dbl(w, z_minus_ed_y);
|
||||
}
|
||||
|
||||
//assert(check_e_u_w(e, u, w));
|
||||
|
||||
// Torsion check
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
inv_iso(u, w, u, w);
|
||||
if (!inv_psi2(u, w, e, u, w)) {
|
||||
return false;
|
||||
}
|
||||
inv_psi1(e, u, w, e, u, w);
|
||||
//assert(check_e_u_w(e, u, w));
|
||||
}
|
||||
|
||||
fe _;
|
||||
inv_iso(u, _, u, w);
|
||||
|
||||
if (!sqrt(u, u)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
}//namespace fcmp_pp
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace fcmp_pp
|
||||
{
|
||||
bool sqrt(fe y, const fe x);
|
||||
bool mul8_is_identity(const ge_p3 &point);
|
||||
bool torsion_check_vartime(const ge_p3 &point);
|
||||
} //namespace fcmp_pp
|
||||
Reference in New Issue
Block a user