aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkoe <ukoe@protonmail.com>2021-11-08 18:14:17 -0600
committerkoe <ukoe@protonmail.com>2022-01-25 07:14:46 -0600
commitc36ea26e5c6b94f107cc1aeb02a45cfc5a7c38ef (patch)
tree06ead3fb8c9b88df1084d475d0673b88811a7183 /src
parentMerge pull request #8021 (diff)
downloadmonero-c36ea26e5c6b94f107cc1aeb02a45cfc5a7c38ef.tar.xz
fix ge_p3_is_point_at_infinity(), which is evaluating field elements that haven't been reduced by the field order
Diffstat (limited to 'src')
-rw-r--r--src/crypto/crypto-ops.c50
-rw-r--r--src/crypto/crypto-ops.h2
-rw-r--r--src/ringct/multiexp.cc4
3 files changed, 46 insertions, 10 deletions
diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c
index 508709280..54ca39775 100644
--- a/src/crypto/crypto-ops.c
+++ b/src/crypto/crypto-ops.c
@@ -3830,15 +3830,51 @@ int sc_isnonzero(const unsigned char *s) {
s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1;
}
-int ge_p3_is_point_at_infinity(const ge_p3 *p) {
- // X = 0 and Y == Z
- int n;
- for (n = 0; n < 10; ++n)
+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
+ // note: convert all pieces to canonical bytes in case rounding is required (i.e. an element is > q)
+ // note2: even though T = XY/Z is true for valid point representations (implying it isn't necessary to
+ // test T == 0), the input to this function might NOT be valid, so we must test T == 0
+ char result_X_bytes[32];
+ fe_tobytes((unsigned char*)&result_X_bytes, p->X);
+
+ // X != 0
+ for (int i = 0; i < 32; ++i)
{
- if (p->X[n] | p->T[n])
+ if (result_X_bytes[i])
return 0;
- if (p->Y[n] != p->Z[n])
+ }
+
+ char result_T_bytes[32];
+ fe_tobytes((unsigned char*)&result_T_bytes, p->T);
+
+ // T != 0
+ for (int i = 0; i < 32; ++i)
+ {
+ if (result_T_bytes[i])
+ return 0;
+ }
+
+ char result_Y_bytes[32];
+ char result_Z_bytes[32];
+ fe_tobytes((unsigned char*)&result_Y_bytes, p->Y);
+ fe_tobytes((unsigned char*)&result_Z_bytes, p->Z);
+
+ // Y != Z
+ for (int i = 0; i < 32; ++i)
+ {
+ if (result_Y_bytes[i] != result_Z_bytes[i])
return 0;
}
- return 1;
+
+ // is Y nonzero? then Y/Z == 1
+ for (int i = 0; i < 32; ++i)
+ {
+ if (result_Y_bytes[i] != 0)
+ return 1;
+ }
+
+ // Y/Z = 0/0
+ return 0;
}
diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h
index 22f76974b..96da16cbd 100644
--- a/src/crypto/crypto-ops.h
+++ b/src/crypto/crypto-ops.h
@@ -162,4 +162,4 @@ void fe_add(fe h, const fe f, const fe g);
void fe_tobytes(unsigned char *, const fe);
void fe_invert(fe out, const fe z);
-int ge_p3_is_point_at_infinity(const ge_p3 *p);
+int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p);
diff --git a/src/ringct/multiexp.cc b/src/ringct/multiexp.cc
index 784c90a4e..f256325a1 100644
--- a/src/ringct/multiexp.cc
+++ b/src/ringct/multiexp.cc
@@ -235,7 +235,7 @@ rct::key bos_coster_heap_conv_robust(std::vector<MultiexpData> data)
heap.reserve(points);
for (size_t n = 0; n < points; ++n)
{
- if (!(data[n].scalar == rct::zero()) && !ge_p3_is_point_at_infinity(&data[n].point))
+ if (!(data[n].scalar == rct::zero()) && !ge_p3_is_point_at_infinity_vartime(&data[n].point))
heap.push_back(n);
}
points = heap.size();
@@ -457,7 +457,7 @@ rct::key straus(const std::vector<MultiexpData> &data, const std::shared_ptr<str
MULTIEXP_PERF(PERF_TIMER_START_UNIT(skip, 1000000));
std::vector<uint8_t> skip(data.size());
for (size_t i = 0; i < data.size(); ++i)
- skip[i] = data[i].scalar == rct::zero() || ge_p3_is_point_at_infinity(&data[i].point);
+ skip[i] = data[i].scalar == rct::zero() || ge_p3_is_point_at_infinity_vartime(&data[i].point);
MULTIEXP_PERF(PERF_TIMER_STOP(skip));
#endif