diff options
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/functional_tests/proofs.py | 39 | ||||
-rw-r--r-- | tests/unit_tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/unit_tests/tx_proof.cpp | 130 |
3 files changed, 165 insertions, 5 deletions
diff --git a/tests/functional_tests/proofs.py b/tests/functional_tests/proofs.py index 5f23f7ea4..e58d29f94 100755 --- a/tests/functional_tests/proofs.py +++ b/tests/functional_tests/proofs.py @@ -130,13 +130,13 @@ class ProofsTest(): sending_address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' receiving_address = '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW' res = self.wallet[0].get_tx_proof(txid, sending_address, 'foo'); - assert res.signature.startswith('InProof'); + assert res.signature.startswith('InProofV2'); signature0i = res.signature res = self.wallet[0].get_tx_proof(txid, receiving_address, 'bar'); - assert res.signature.startswith('OutProof'); + assert res.signature.startswith('OutProofV2'); signature0o = res.signature res = self.wallet[1].get_tx_proof(txid, receiving_address, 'baz'); - assert res.signature.startswith('InProof'); + assert res.signature.startswith('InProofV2'); signature1 = res.signature res = self.wallet[0].check_tx_proof(txid, sending_address, 'foo', signature0i); @@ -219,6 +219,23 @@ class ProofsTest(): except: ok = True assert ok or not res.good + + # Test bad cross-version verification + ok = False + try: res = self.wallet[0].check_tx_proof(txid, sending_address, 'foo', signature0i.replace('ProofV2','ProofV1')); + except: ok = True + assert ok or not res.good + + ok = False + try: res = self.wallet[0].check_tx_proof(txid, receiving_address, 'bar', signature0o.replace('ProofV2','ProofV1')); + except: ok = True + assert ok or not res.good + + ok = False + try: res = self.wallet[1].check_tx_proof(txid, receiving_address, 'baz', signature1.replace('ProofV2','ProofV1')); + except: ok = True + assert ok or not res.good + def check_spend_proof(self, txid): daemon = Daemon() @@ -270,7 +287,7 @@ class ProofsTest(): balance1 = res.balance res = self.wallet[0].get_reserve_proof(all_ = True, message = 'foo') - assert res.signature.startswith('ReserveProof') + assert res.signature.startswith('ReserveProofV2') signature = res.signature for i in range(2): res = self.wallet[i].check_reserve_proof(address = address0, message = 'foo', signature = signature) @@ -287,9 +304,15 @@ class ProofsTest(): except: ok = True assert ok or not res.good + # Test bad cross-version verification + ok = False + try: res = self.wallet[i].check_reserve_proof(address = address0, message = 'foo', signature = signature.replace('ProofV2','ProofV1')) + except: ok = True + assert ok or not res.good + amount = int(balance0 / 10) res = self.wallet[0].get_reserve_proof(all_ = False, amount = amount, message = 'foo') - assert res.signature.startswith('ReserveProof') + assert res.signature.startswith('ReserveProofV2') signature = res.signature for i in range(2): res = self.wallet[i].check_reserve_proof(address = address0, message = 'foo', signature = signature) @@ -306,6 +329,12 @@ class ProofsTest(): except: ok = True assert ok or not res.good + # Test bad cross-version verification + ok = False + try: res = self.wallet[i].check_reserve_proof(address = address0, message = 'foo', signature = signature.replace('ProofV2','ProofV1')) + except: ok = True + assert ok or not res.good + ok = False try: self.wallet[0].get_reserve_proof(all_ = False, amount = balance0 + 1, message = 'foo') except: ok = True diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 4f1b0c22a..a5984b2c9 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -83,6 +83,7 @@ set(unit_tests_sources test_peerlist.cpp test_protocol_pack.cpp threadpool.cpp + tx_proof.cpp hardfork.cpp unbound.cpp uri.cpp diff --git a/tests/unit_tests/tx_proof.cpp b/tests/unit_tests/tx_proof.cpp new file mode 100644 index 000000000..c5d06bc68 --- /dev/null +++ b/tests/unit_tests/tx_proof.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2018, 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. + +#include "gtest/gtest.h" + +#include "crypto/crypto.h" +extern "C" { +#include "crypto/crypto-ops.h" +} +#include "crypto/hash.h" +#include <boost/algorithm/string.hpp> + +static inline unsigned char *operator &(crypto::ec_point &point) { + return &reinterpret_cast<unsigned char &>(point); + } + +static inline unsigned char *operator &(crypto::ec_scalar &scalar) { + return &reinterpret_cast<unsigned char &>(scalar); + } + +TEST(tx_proof, prove_verify_v2) +{ + crypto::secret_key r; + crypto::random32_unbiased(&r); + + // A = aG + // B = bG + crypto::secret_key a,b; + crypto::public_key A,B; + crypto::generate_keys(A, a, a, false); + crypto::generate_keys(B, b, b, false); + + // R_B = rB + crypto::public_key R_B; + ge_p3 B_p3; + ge_frombytes_vartime(&B_p3,&B); + ge_p2 R_B_p2; + ge_scalarmult(&R_B_p2, &unwrap(r), &B_p3); + ge_tobytes(&R_B, &R_B_p2); + + // R_G = rG + crypto::public_key R_G; + ge_frombytes_vartime(&B_p3,&B); + ge_p3 R_G_p3; + ge_scalarmult_base(&R_G_p3, &unwrap(r)); + ge_p3_tobytes(&R_G, &R_G_p3); + + // D = rA + crypto::public_key D; + ge_p3 A_p3; + ge_frombytes_vartime(&A_p3,&A); + ge_p2 D_p2; + ge_scalarmult(&D_p2, &unwrap(r), &A_p3); + ge_tobytes(&D, &D_p2); + + crypto::signature sig; + + // Message data + crypto::hash prefix_hash; + char data[] = "hash input"; + crypto::cn_fast_hash(data,sizeof(data)-1,prefix_hash); + + // Generate/verify valid v1 proof with standard address + crypto::generate_tx_proof_v1(prefix_hash, R_G, A, boost::none, D, r, sig); + ASSERT_TRUE(crypto::check_tx_proof(prefix_hash, R_G, A, boost::none, D, sig, 1)); + + // Generate/verify valid v1 proof with subaddress + crypto::generate_tx_proof_v1(prefix_hash, R_B, A, B, D, r, sig); + ASSERT_TRUE(crypto::check_tx_proof(prefix_hash, R_B, A, B, D, sig, 1)); + + // Generate/verify valid v2 proof with standard address + crypto::generate_tx_proof(prefix_hash, R_G, A, boost::none, D, r, sig); + ASSERT_TRUE(crypto::check_tx_proof(prefix_hash, R_G, A, boost::none, D, sig, 2)); + + // Generate/verify valid v2 proof with subaddress + crypto::generate_tx_proof(prefix_hash, R_B, A, B, D, r, sig); + ASSERT_TRUE(crypto::check_tx_proof(prefix_hash, R_B, A, B, D, sig, 2)); + + // Try to verify valid v2 proofs as v1 proof (bad) + crypto::generate_tx_proof(prefix_hash, R_G, A, boost::none, D, r, sig); + ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_G, A, boost::none, D, sig, 1)); + crypto::generate_tx_proof(prefix_hash, R_B, A, B, D, r, sig); + ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, A, B, D, sig, 1)); + + // Randomly-distributed test points + crypto::secret_key evil_a, evil_b, evil_d, evil_r; + crypto::public_key evil_A, evil_B, evil_D, evil_R; + crypto::generate_keys(evil_A, evil_a, evil_a, false); + crypto::generate_keys(evil_B, evil_b, evil_b, false); + crypto::generate_keys(evil_D, evil_d, evil_d, false); + crypto::generate_keys(evil_R, evil_r, evil_r, false); + + // Selectively choose bad point in v2 proof (bad) + crypto::generate_tx_proof(prefix_hash, R_B, A, B, D, r, sig); + ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, evil_R, A, B, D, sig, 2)); + ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, evil_A, B, D, sig, 2)); + ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, A, evil_B, D, sig, 2)); + ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, A, B, evil_D, sig, 2)); + + // Try to verify valid v1 proofs as v2 proof (bad) + crypto::generate_tx_proof_v1(prefix_hash, R_G, A, boost::none, D, r, sig); + ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_G, A, boost::none, D, sig, 2)); + crypto::generate_tx_proof_v1(prefix_hash, R_B, A, B, D, r, sig); + ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, A, B, D, sig, 2)); +} |