aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2019-01-08 16:05:18 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2019-01-22 23:17:39 +0000
commit7d375981584e5ddac4ea6ad8879e2211d465b79d (patch)
tree82341e77219309514ab8bc12d6c3bd65b60a2293
parentringct: encode 8 byte amount, saving 24 bytes per output (diff)
downloadmonero-7d375981584e5ddac4ea6ad8879e2211d465b79d.tar.xz
ringct: the commitment mask is now deterministic
saves space in the tx and is safe Found by knaccc
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h5
-rw-r--r--src/ringct/rctOps.cpp56
-rw-r--r--src/ringct/rctOps.h5
-rw-r--r--src/ringct/rctSigs.cpp13
-rw-r--r--src/ringct/rctTypes.h3
-rw-r--r--tests/unit_tests/device.cpp15
-rw-r--r--tests/unit_tests/ringct.cpp21
7 files changed, 55 insertions, 63 deletions
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h
index 6f26d8756..8a527b898 100644
--- a/src/cryptonote_basic/cryptonote_boost_serialization.h
+++ b/src/cryptonote_basic/cryptonote_boost_serialization.h
@@ -249,15 +249,18 @@ namespace boost
template <class Archive>
inline void serialize(Archive &a, rct::ecdhTuple &x, const boost::serialization::version_type ver)
{
- a & x.mask;
if (ver < 1)
{
+ a & x.mask;
a & x.amount;
return;
}
crypto::hash8 &amount = (crypto::hash8&)x.amount;
if (!Archive::is_saving::value)
+ {
+ memset(&x.mask, 0, sizeof(x.mask));
memset(&x.amount, 0, sizeof(x.amount));
+ }
a & amount;
// a & x.senderPk; // not serialized, as we do not use it in monero currently
}
diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp
index b28aa4fe6..e39ba16fd 100644
--- a/src/ringct/rctOps.cpp
+++ b/src/ringct/rctOps.cpp
@@ -672,36 +672,56 @@ namespace rct {
// where C= aG + bH
static key ecdhHash(const key &k)
{
- char data[38];
- rct::key hash;
- memcpy(data, "amount", 6);
- memcpy(data + 6, &k, sizeof(k));
- cn_fast_hash(hash, data, sizeof(data));
- return hash;
+ char data[38];
+ rct::key hash;
+ memcpy(data, "amount", 6);
+ memcpy(data + 6, &k, sizeof(k));
+ cn_fast_hash(hash, data, sizeof(data));
+ return hash;
}
static void xor8(key &v, const key &k)
{
- for (int i = 0; i < 8; ++i)
- v.bytes[i] ^= k.bytes[i];
+ for (int i = 0; i < 8; ++i)
+ v.bytes[i] ^= k.bytes[i];
+ }
+ key genCommitmentMask(const key &sk)
+ {
+ char data[15 + sizeof(key)];
+ memcpy(data, "commitment_mask", 15);
+ memcpy(data + 15, &sk, sizeof(sk));
+ key scalar;
+ hash_to_scalar(scalar, data, sizeof(data));
+ return scalar;
}
- void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, bool short_amount) {
- key sharedSec1 = hash_to_scalar(sharedSec);
- key sharedSec2 = hash_to_scalar(sharedSec1);
+
+ void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, bool v2) {
//encode
- sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes);
- if (short_amount)
+ if (v2)
+ {
+ unmasked.mask = zero();
xor8(unmasked.amount, ecdhHash(sharedSec));
+ }
else
+ {
+ key sharedSec1 = hash_to_scalar(sharedSec);
+ key sharedSec2 = hash_to_scalar(sharedSec1);
+ sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes);
sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes);
+ }
}
- void ecdhDecode(ecdhTuple & masked, const key & sharedSec, bool short_amount) {
- key sharedSec1 = hash_to_scalar(sharedSec);
- key sharedSec2 = hash_to_scalar(sharedSec1);
+ void ecdhDecode(ecdhTuple & masked, const key & sharedSec, bool v2) {
//decode
- sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes);
- if (short_amount)
+ if (v2)
+ {
+ masked.mask = genCommitmentMask(sharedSec);
xor8(masked.amount, ecdhHash(sharedSec));
+ }
else
+ {
+ key sharedSec1 = hash_to_scalar(sharedSec);
+ key sharedSec2 = hash_to_scalar(sharedSec1);
+ sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes);
sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.bytes);
+ }
}
}
diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h
index 01cdd6fd7..dd6d87593 100644
--- a/src/ringct/rctOps.h
+++ b/src/ringct/rctOps.h
@@ -182,7 +182,8 @@ namespace rct {
//Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
// where C= aG + bH
- void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, bool short_amount);
- void ecdhDecode(ecdhTuple & masked, const key & sharedSec, bool short_amount);
+ key genCommitmentMask(const key &sk);
+ void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, bool v2);
+ void ecdhDecode(ecdhTuple & masked, const key & sharedSec, bool v2);
}
#endif /* RCTOPS_H */
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 6687c91cd..81bec487c 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -79,9 +79,12 @@ namespace
}
namespace rct {
- Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts)
+ Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts, epee::span<const key> sk)
{
- masks = rct::skvGen(amounts.size());
+ CHECK_AND_ASSERT_THROW_MES(amounts.size() == sk.size(), "Invalid amounts/sk sizes");
+ masks.resize(amounts.size());
+ for (size_t i = 0; i < masks.size(); ++i)
+ masks[i] = genCommitmentMask(sk[i]);
Bulletproof proof = bulletproof_PROVE(amounts, masks);
CHECK_AND_ASSERT_THROW_MES(proof.V.size() == amounts.size(), "V does not have the expected size");
C = proof.V;
@@ -803,7 +806,8 @@ namespace rct {
}
else
{
- rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts));
+ const epee::span<const key> keys{&amount_keys[0], amount_keys.size()};
+ rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts, keys));
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
#endif
@@ -831,7 +835,8 @@ namespace rct {
}
else
{
- rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, batch_amounts));
+ const epee::span<const key> keys{&amount_keys[amounts_proved], batch_size};
+ rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, batch_amounts, keys));
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
#endif
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index 54fca1d05..a02c338e9 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -128,7 +128,7 @@ namespace rct {
key senderPk;
BEGIN_SERIALIZE_OBJECT()
- FIELD(mask)
+ FIELD(mask) // not saved from v2 BPs
FIELD(amount)
// FIELD(senderPk) // not serialized, as we do not use it in monero currently
END_SERIALIZE()
@@ -286,7 +286,6 @@ namespace rct {
if (type == RCTTypeBulletproof2)
{
ar.begin_object();
- FIELD_N("mask", ecdhInfo[i].mask);
if (!typename Archive<W>::is_saving())
memset(ecdhInfo[i].amount.bytes, 0, sizeof(ecdhInfo[i].amount.bytes));
crypto::hash8 &amount = (crypto::hash8&)ecdhInfo[i].amount;
diff --git a/tests/unit_tests/device.cpp b/tests/unit_tests/device.cpp
index 3ae748145..064a7028e 100644
--- a/tests/unit_tests/device.cpp
+++ b/tests/unit_tests/device.cpp
@@ -130,18 +130,3 @@ TEST(device, ecdh32)
ASSERT_EQ(tuple2.senderPk, tuple.senderPk);
}
-TEST(device, ecdh8)
-{
- hw::core::device_default dev;
- rct::ecdhTuple tuple, tuple2;
- rct::key key = rct::skGen();
- tuple.mask = rct::skGen();
- tuple.amount = rct::skGen();
- tuple.senderPk = rct::pkGen();
- tuple2 = tuple;
- dev.ecdhEncode(tuple, key, true);
- dev.ecdhDecode(tuple, key, true);
- ASSERT_EQ(tuple2.mask, tuple.mask);
- ASSERT_EQ(tuple2.amount, tuple.amount);
- ASSERT_EQ(tuple2.senderPk, tuple.senderPk);
-}
diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp
index 905b8471a..3f302cb83 100644
--- a/tests/unit_tests/ringct.cpp
+++ b/tests/unit_tests/ringct.cpp
@@ -831,27 +831,6 @@ TEST(ringct, HPow2)
static const xmr_amount test_amounts[]={0, 1, 2, 3, 4, 5, 10000, 10000000000000000000ull, 10203040506070809000ull, 123456789123456789};
-TEST(ringct, ecdh_roundtrip)
-{
- key k;
- ecdhTuple t0, t1;
-
- for (auto amount: test_amounts) {
- skGen(k);
-
- t0.mask = skGen();
- t0.amount = d2h(amount);
-
- t1 = t0;
- ecdhEncode(t1, k, true);
- ecdhDecode(t1, k, true);
- ASSERT_TRUE(t0.mask == t1.mask);
- ASSERT_TRUE(equalKeys(t0.mask, t1.mask));
- ASSERT_TRUE(t0.amount == t1.amount);
- ASSERT_TRUE(equalKeys(t0.amount, t1.amount));
- }
-}
-
TEST(ringct, d2h)
{
key k, P1;