What changed, and why it matters
This commit renames and rewrites a Monero function used to compute a 'zero-commitment' Pedersen commitment (a cryptographic value that hides transaction amounts). The new implementation uses a precomputed table and a vartime (variable-time) bit-by-bit addition to make the calculation about six times faster. The commit does not claim to fix any security bug, and the diff itself shows no signs of a vulnerability. The main risk is that the new code must produce exactly the same results as the old code, otherwise consensus between nodes could break.
No immediate security action required. Treat as a routine performance optimization. Verify that the unit tests comparing zeroCommitVartime output against the uncached reference pass, and consider running the new performance benchmark. If deploying, ensure the consensus-critical output has not changed compared to the old implementation.
Security signals we found
No security-relevant signal in commit title or message
No CVE, advisory, or bug-fix language present
Change is a pure performance optimization with test coverage
Potential concern: vartime algorithm is acceptable here because amount is public in the pre-RingCT paths where this is used
Consensus-critical: zeroCommit output must remain bit-identical to previous implementation
Evidence from the diff
The change renames rct::zeroCommit to rct::zeroCommitVartime and replaces its body. The old implementation converted the amount to a scalar, multiplied it by the curve point H, and added the base point G. The new implementation builds a static 64-entry table of cached doublings of H (H, 2H, 4H, …) and then adds only the table entries corresponding to set bits of the 64-bit amount to G. This is a standard fixed-base scalar-multiplication optimization. ge_p3_dbl is exposed in crypto-ops.h so it can be used during table construction. All call sites and tests are updated to use the new name. A new performance test compares the new path against the old path.
Changed components
src/ringct/rctOps.cppsrc/ringct/rctOps.hsrc/crypto/crypto-ops.csrc/crypto/crypto-ops.hsrc/blockchain_db/blockchain_db.cppsrc/blockchain_db/lmdb/db_lmdb.cppsrc/cryptonote_core/cryptonote_tx_utils.hsrc/wallet/wallet2.cpptests/performance_tests/zero_commit.htests/unit_tests/ringct.cppInspect captured patch +146 / −33
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index 72492f9..294a1b3 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -233,7 +233,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
if (miner_tx && tx.version == 2)
{
cryptonote::tx_out vout = tx.vout[i];
- rct::key commitment = rct::zeroCommit(vout.amount);
+ rct::key commitment = rct::zeroCommitVartime(vout.amount);
vout.amount = 0;
amount_output_indices[i] = add_output(tx_hash, vout, i, tx.unlock_time,
&commitment);
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 82de0a8..b5b1825 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -3457,7 +3457,7 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint6
const pre_rct_outkey *okp = (const pre_rct_outkey *)v.mv_data;
memcpy(&ret, &okp->data, sizeof(pre_rct_output_data_t));
if (include_commitmemt)
- ret.commitment = rct::zeroCommit(amount);
+ ret.commitment = rct::zeroCommitVartime(amount);
}
TXN_POSTFIX_RDONLY();
return ret;
@@ -4203,7 +4203,7 @@ void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, c
outputs.resize(outputs.size() + 1);
output_data_t &data = outputs.back();
memcpy(&data, &okp->data, sizeof(pre_rct_output_data_t));
- data.commitment = rct::zeroCommit(amount);
+ data.commitment = rct::zeroCommitVartime(amount);
}
}
diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c
index 314fe44..ec73098 100644
--- a/src/crypto/crypto-ops.c
+++ b/src/crypto/crypto-ops.c
@@ -42,7 +42,6 @@ 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 *);
-static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *);
static void fe_divpowm1(fe, const fe, const fe);
/* Common functions */
@@ -1529,7 +1528,7 @@ static void ge_p3_0(ge_p3 *h) {
r = 2 * p
*/
-static void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
+void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
ge_p2 q;
ge_p3_to_p2(&q, p);
ge_p2_dbl(r, &q);
diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h
index c103f1f..2bf82c9 100644
--- a/src/crypto/crypto-ops.h
+++ b/src/crypto/crypto-ops.h
@@ -102,6 +102,10 @@ void ge_p1p1_to_p3(ge_p3 *, const ge_p1p1 *);
void ge_p2_dbl(ge_p1p1 *, const ge_p2 *);
+/* From ge_p3_dbl.c */
+
+void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
+
/* From ge_p3_to_cached.c */
extern const fe fe_d2;
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index d3b8bfe..deffee9 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -53,7 +53,7 @@ namespace cryptonote
rct::key mask; //ringct amount mask
rct::multisig_kLRki multisig_kLRki; //multisig info
- void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); }
+ void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommitVartime(amount)}))); }
BEGIN_SERIALIZE_OBJECT()
FIELD(outputs)
diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp
index 3860a7e..3c11e6b 100644
--- a/src/ringct/rctOps.cpp
+++ b/src/ringct/rctOps.cpp
@@ -29,6 +29,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/lexical_cast.hpp>
+#include "crypto/generators.h"
#include "misc_log_ex.h"
#include "rctOps.h"
using namespace crypto;
@@ -216,6 +217,33 @@ static const zero_commitment zero_commitments[] = {
{ (uint64_t)10000000000000000000ull, {{0x65, 0x8d, 0x1, 0x37, 0x6d, 0x18, 0x63, 0xe7, 0x7b, 0x9, 0x6f, 0x98, 0xe6, 0xe5, 0x13, 0xc2, 0x4, 0x10, 0xf5, 0xc7, 0xfb, 0x18, 0xa6, 0xe5, 0x9a, 0x52, 0x66, 0x84, 0x5c, 0xd9, 0xb1, 0xe3}} },
};
+static constexpr std::size_t H_TABLE_SIZE = 64;
+const std::vector<ge_cached>& H_TABLE()
+{
+ struct static_h_table
+ {
+ std::vector<ge_cached> h_table;
+ static_h_table()
+ : h_table()
+ {
+ h_table.resize(H_TABLE_SIZE);
+
+ ge_p3_to_cached(&h_table.at(0), &ge_p3_H);
+ ge_p3 H_bit_p3 = ge_p3_H;
+
+ for (std::size_t i = 1; i < H_TABLE_SIZE; ++i)
+ {
+ ge_p1p1 H_bit_p1p1;
+ ge_p3_dbl(&H_bit_p1p1, &H_bit_p3);
+ ge_p1p1_to_p3(&H_bit_p3, &H_bit_p1p1);
+ ge_p3_to_cached(&h_table.at(i), &H_bit_p3);
+ }
+ }
+ };
+ static const static_h_table out;
+ return out.h_table;
+}
+
namespace rct {
//Various key initialization functions
@@ -318,7 +346,7 @@ namespace rct {
return make_tuple(sk, pk);
}
- key zeroCommit(xmr_amount amount) {
+ key zeroCommitVartime(xmr_amount amount) {
const zero_commitment *begin = zero_commitments;
const zero_commitment *end = zero_commitments + sizeof(zero_commitments) / sizeof(zero_commitments[0]);
const zero_commitment value{amount, rct::zero()};
@@ -327,9 +355,20 @@ namespace rct {
{
return it->commitment;
}
- key am = d2h(amount);
- key bH = scalarmultH(am);
- return addKeys(G, bH);
+ ge_p3 res_ge_p3 = get_G_p3();
+ static_assert(sizeof(xmr_amount) * 8 == H_TABLE_SIZE, "unexpected size of h table");
+ for (size_t i = 0; i < H_TABLE_SIZE; ++i)
+ {
+ if (amount & (xmr_amount(1) << i))
+ {
+ ge_p1p1 p1p1;
+ ge_add(&p1p1, &res_ge_p3, &H_TABLE()[i]);
+ ge_p1p1_to_p3(&res_ge_p3, &p1p1);
+ }
+ }
+ rct::key res;
+ ge_p3_tobytes(res.bytes, &res_ge_p3);
+ return res;
}
key commit(xmr_amount amount, const key &mask) {
diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h
index 0edd030..e4110c6 100644
--- a/src/ringct/rctOps.h
+++ b/src/ringct/rctOps.h
@@ -108,7 +108,7 @@ namespace rct {
// make a pedersen commitment with given key
key commit(xmr_amount amount, const key &mask);
// make a pedersen commitment with zero key
- key zeroCommit(xmr_amount amount);
+ key zeroCommitVartime(xmr_amount amount);
//generates a random uint long long
xmr_amount randXmrAmount(xmr_amount upperlimit);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index b7ec6d2..5d7e530 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -9550,7 +9550,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0);
outs.push_back(std::vector<get_outs_entry>());
outs.back().reserve(fake_outputs_count + 1);
- const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommit(td.amount());
+ const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommitVartime(td.amount());
uint64_t num_outs = 0;
const uint64_t amount = td.is_rct() ? 0 : td.amount();
@@ -9659,7 +9659,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{
const transfer_details &td = m_transfers[idx];
std::vector<get_outs_entry> v;
- const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommit(td.amount());
+ const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommitVartime(td.amount());
v.push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), mask));
outs.push_back(v);
}
diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp
index 05a6ce1..a5ebb30 100644
--- a/tests/core_tests/chaingen.cpp
+++ b/tests/core_tests/chaingen.cpp
@@ -594,7 +594,7 @@ bool fill_tx_sources(std::vector<tx_source_entry>& sources, const std::vector<te
ts.rct = false;
ts.mask = rct::identity(); // non-rct has identity mask by definition
- rct::key comm = rct::zeroCommit(ts.amount);
+ rct::key comm = rct::zeroCommitVartime(ts.amount);
for(auto & ot : ts.outputs)
ot.second.mask = comm;
diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp
index 0252c48..6810b1f 100644
--- a/tests/core_tests/rct.cpp
+++ b/tests/core_tests/rct.cpp
@@ -296,7 +296,7 @@ bool gen_rct_tx_pre_rct_bad_real_mask::generate(std::vector<test_event_entry>& e
const int out_idx[] = {0, -1};
const uint64_t amount_paid = 10000;
return generate_with(events, out_idx, mixin, amount_paid, false,
- [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);},
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommitVartime(99999);},
NULL);
}
@@ -316,7 +316,7 @@ bool gen_rct_tx_pre_rct_bad_fake_mask::generate(std::vector<test_event_entry>& e
const int out_idx[] = {0, -1};
const uint64_t amount_paid = 10000;
return generate_with(events, out_idx, mixin, amount_paid, false,
- [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);},
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommitVartime(99999);},
NULL);
}
@@ -339,7 +339,7 @@ bool gen_rct_tx_rct_bad_real_mask::generate(std::vector<test_event_entry>& event
const int out_idx[] = {1, -1};
const uint64_t amount_paid = 10000;
return generate_with(events, out_idx, mixin, amount_paid, false,
- [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);},
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommitVartime(99999);},
NULL);
}
@@ -359,7 +359,7 @@ bool gen_rct_tx_rct_bad_fake_mask::generate(std::vector<test_event_entry>& event
const int out_idx[] = {1, -1};
const uint64_t amount_paid = 10000;
return generate_with(events, out_idx, mixin, amount_paid, false,
- [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);},
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommitVartime(99999);},
NULL);
}
@@ -369,7 +369,7 @@ bool gen_rct_tx_rct_spend_with_zero_commit::generate(std::vector<test_event_entr
const int out_idx[] = {1, -1};
const uint64_t amount_paid = 10000;
return generate_with(events, out_idx, mixin, amount_paid, false,
- [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(sources[0].amount); sources[0].mask = rct::identity();},
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommitVartime(sources[0].amount); sources[0].mask = rct::identity();},
[](transaction &tx){boost::get<txin_to_key>(tx.vin[0]).amount = 0;});
}
diff --git a/tests/performance_tests/CMakeLists.txt b/tests/performance_tests/CMakeLists.txt
index a1158fc..3c18d67 100644
--- a/tests/performance_tests/CMakeLists.txt
+++ b/tests/performance_tests/CMakeLists.txt
@@ -55,7 +55,8 @@ set(performance_tests_headers
multi_tx_test_base.h
performance_tests.h
performance_utils.h
- single_tx_test_base.h)
+ single_tx_test_base.h
+ zero_commit.h)
monero_add_minimal_executable(performance_tests
${performance_tests_sources}
diff --git a/tests/performance_tests/crypto_ops.h b/tests/performance_tests/crypto_ops.h
index b8ebc85..334beca 100644
--- a/tests/performance_tests/crypto_ops.h
+++ b/tests/performance_tests/crypto_ops.h
@@ -128,8 +128,8 @@ public:
case op_addKeys_aGbBcC: rct::addKeys_aGbBcC(key, scalar0, scalar1, precomp1, scalar2, precomp2); break;
case op_addKeys_aAbBcC: rct::addKeys_aAbBcC(key, scalar0, precomp0, scalar1, precomp1, scalar2, precomp2); break;
case op_isInMainSubgroup: rct::isInMainSubgroup(point0); break;
- case op_zeroCommitUncached: rct::zeroCommit(9001); break;
- case op_zeroCommitCached: rct::zeroCommit(9000); break;
+ case op_zeroCommitUncached: rct::zeroCommitVartime(9001); break;
+ case op_zeroCommitCached: rct::zeroCommitVartime(9000); break;
default: return false;
}
return true;
diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp
index c40656e..da151d2 100644
--- a/tests/performance_tests/main.cpp
+++ b/tests/performance_tests/main.cpp
@@ -66,6 +66,7 @@
#include "multiexp.h"
#include "sig_mlsag.h"
#include "sig_clsag.h"
+#include "zero_commit.h"
namespace po = boost::program_options;
@@ -594,6 +595,9 @@ int main(int argc, char** argv)
TEST_PERFORMANCE3(filter, p, test_multiexp, multiexp_pippenger, 4096, 9);
#endif
+ TEST_PERFORMANCE1(filter, p, test_zero_commit, true); // fast
+ TEST_PERFORMANCE1(filter, p, test_zero_commit, false);
+
std::cout << "Tests finished. Elapsed time: " << timer.elapsed_ms() / 1000 << " sec" << std::endl;
return 0;
diff --git a/tests/performance_tests/multi_tx_test_base.h b/tests/performance_tests/multi_tx_test_base.h
index 75e0120..64413fb 100644
--- a/tests/performance_tests/multi_tx_test_base.h
+++ b/tests/performance_tests/multi_tx_test_base.h
@@ -59,7 +59,7 @@ public:
return false;
txout_to_key tx_out = boost::get<txout_to_key>(m_miner_txs[i].vout[0].target);
- output_entries.push_back(std::make_pair(i, rct::ctkey({rct::pk2rct(tx_out.key), rct::zeroCommit(m_miner_txs[i].vout[0].amount)})));
+ output_entries.push_back(std::make_pair(i, rct::ctkey({rct::pk2rct(tx_out.key), rct::zeroCommitVartime(m_miner_txs[i].vout[0].amount)})));
m_public_keys[i] = tx_out.key;
m_public_key_ptrs[i] = &m_public_keys[i];
}
diff --git a/tests/performance_tests/zero_commit.h b/tests/performance_tests/zero_commit.h
new file mode 100644
index 0000000..188d31e
--- /dev/null
+++ b/tests/performance_tests/zero_commit.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2025, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include "crypto/random.h"
+#include "ringct/rctOps.h"
+
+template<bool fast>
+class test_zero_commit
+{
+public:
+ static const size_t loop_count = 1000;
+
+ bool init()
+ {
+ m_amount = crypto::rand<uint64_t>();
+ return true;
+ }
+
+ bool test()
+ {
+ if constexpr (fast)
+ {
+ rct::zeroCommitVartime(m_amount);
+ }
+ else
+ {
+ // Old way of doing it
+ rct::key am = rct::d2h(m_amount);
+ rct::key bH = rct::scalarmultH(am);
+ rct::addKeys(rct::G, bH);
+ }
+ return true;
+ }
+
+private:
+ uint64_t m_amount;
+};
diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp
index 9979fad..090b021 100644
--- a/tests/unit_tests/ringct.cpp
+++ b/tests/unit_tests/ringct.cpp
@@ -1204,14 +1204,14 @@ TEST(ringct, key_ostream)
TEST(ringct, zeroCommmit)
{
static const uint64_t amount = crypto::rand<uint64_t>();
- const rct::key z = rct::zeroCommit(amount);
+ const rct::key z = rct::zeroCommitVartime(amount);
const rct::key a = rct::scalarmultBase(rct::identity());
const rct::key b = rct::scalarmultH(rct::d2h(amount));
const rct::key manual = rct::addKeys(a, b);
ASSERT_EQ(z, manual);
}
-static rct::key uncachedZeroCommit(uint64_t amount)
+static rct::key uncachedZeroCommitVartime(uint64_t amount)
{
const rct::key am = rct::d2h(amount);
const rct::key bH = rct::scalarmultH(am);
@@ -1220,14 +1220,14 @@ static rct::key uncachedZeroCommit(uint64_t amount)
TEST(ringct, zeroCommitCache)
{
- ASSERT_EQ(rct::zeroCommit(0), uncachedZeroCommit(0));
- ASSERT_EQ(rct::zeroCommit(1), uncachedZeroCommit(1));
- ASSERT_EQ(rct::zeroCommit(2), uncachedZeroCommit(2));
- ASSERT_EQ(rct::zeroCommit(10), uncachedZeroCommit(10));
- ASSERT_EQ(rct::zeroCommit(200), uncachedZeroCommit(200));
- ASSERT_EQ(rct::zeroCommit(1000000000), uncachedZeroCommit(1000000000));
- ASSERT_EQ(rct::zeroCommit(3000000000000), uncachedZeroCommit(3000000000000));
- ASSERT_EQ(rct::zeroCommit(900000000000000), uncachedZeroCommit(900000000000000));
+ ASSERT_EQ(rct::zeroCommitVartime(0), uncachedZeroCommitVartime(0));
+ ASSERT_EQ(rct::zeroCommitVartime(1), uncachedZeroCommitVartime(1));
+ ASSERT_EQ(rct::zeroCommitVartime(2), uncachedZeroCommitVartime(2));
+ ASSERT_EQ(rct::zeroCommitVartime(10), uncachedZeroCommitVartime(10));
+ ASSERT_EQ(rct::zeroCommitVartime(200), uncachedZeroCommitVartime(200));
+ ASSERT_EQ(rct::zeroCommitVartime(1000000000), uncachedZeroCommitVartime(1000000000));
+ ASSERT_EQ(rct::zeroCommitVartime(3000000000000), uncachedZeroCommitVartime(3000000000000));
+ ASSERT_EQ(rct::zeroCommitVartime(900000000000000), uncachedZeroCommitVartime(900000000000000));
}
TEST(ringct, H)
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.