diff options
author | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2019-01-08 16:05:18 +0000 |
---|---|---|
committer | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2019-01-22 23:17:39 +0000 |
commit | 7d375981584e5ddac4ea6ad8879e2211d465b79d (patch) | |
tree | 82341e77219309514ab8bc12d6c3bd65b60a2293 | |
parent | ringct: encode 8 byte amount, saving 24 bytes per output (diff) | |
download | monero-7d375981584e5ddac4ea6ad8879e2211d465b79d.tar.xz |
ringct: the commitment mask is now deterministic
saves space in the tx and is safe
Found by knaccc
Diffstat (limited to '')
-rw-r--r-- | src/cryptonote_basic/cryptonote_boost_serialization.h | 5 | ||||
-rw-r--r-- | src/ringct/rctOps.cpp | 56 | ||||
-rw-r--r-- | src/ringct/rctOps.h | 5 | ||||
-rw-r--r-- | src/ringct/rctSigs.cpp | 13 | ||||
-rw-r--r-- | src/ringct/rctTypes.h | 3 | ||||
-rw-r--r-- | tests/unit_tests/device.cpp | 15 | ||||
-rw-r--r-- | tests/unit_tests/ringct.cpp | 21 |
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; |