mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	* getactorstats query for validator-engine-console * celldb in-memory mode (--celldb-in-memory option) * rldp2: bugfix - do not estimate speed while nothing is sent * add simple ed25519 benchmark * fix compilation errors of different platforms and move to c++20 * fix some warnings * turn on TON_USE_ABSEIL for glibc 2.27 nix build --------- Co-authored-by: birydrad <>
		
			
				
	
	
		
			256 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|     This file is part of TON Blockchain Library.
 | |
| 
 | |
|     TON Blockchain Library is free software: you can redistribute it and/or modify
 | |
|     it under the terms of the GNU Lesser General Public License as published by
 | |
|     the Free Software Foundation, either version 2 of the License, or
 | |
|     (at your option) any later version.
 | |
| 
 | |
|     TON Blockchain Library is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU Lesser General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU Lesser General Public License
 | |
|     along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
|     Copyright 2017-2020 Telegram Systems LLP
 | |
| */
 | |
| #include "crypto/Ed25519.h"
 | |
| #include "ellcurve/Ed25519.h"
 | |
| 
 | |
| #include "td/utils/logging.h"
 | |
| #include "td/utils/misc.h"
 | |
| #include "td/utils/Slice.h"
 | |
| #include "td/utils/tests.h"
 | |
| #include "td/utils/JsonBuilder.h"
 | |
| 
 | |
| #include "wycheproof.h"
 | |
| #include "keys/keys.hpp"
 | |
| #include "td/utils/benchmark.h"
 | |
| 
 | |
| #include <string>
 | |
| #include <utility>
 | |
| 
 | |
| unsigned char fixed_privkey[32] = "abacabadabacabaeabacabadabacaba";
 | |
| unsigned char fixed_pubkey[32] = {0x6f, 0x9e, 0x5b, 0xde, 0xce, 0x87, 0x21, 0xeb, 0x57, 0x37, 0xfb,
 | |
|                                   0xb5, 0x92, 0x28, 0xba, 0x07, 0xf7, 0x88, 0x0f, 0x73, 0xce, 0x5b,
 | |
|                                   0xfa, 0xa1, 0xb7, 0x15, 0x73, 0x03, 0xd4, 0x20, 0x1e, 0x74};
 | |
| 
 | |
| unsigned char rfc8032_secret_key1[32] = {0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60, 0xba, 0x84, 0x4a,
 | |
|                                          0xf4, 0x92, 0xec, 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32,
 | |
|                                          0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60};
 | |
| 
 | |
| unsigned char rfc8032_public_key1[32] = {0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe,
 | |
|                                          0xd3, 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6,
 | |
|                                          0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a};
 | |
| 
 | |
| unsigned char rfc8032_signature1[64] = {
 | |
|     0xe5, 0x56, 0x43, 0x00, 0xc3, 0x60, 0xac, 0x72, 0x90, 0x86, 0xe2, 0xcc, 0x80, 0x6e, 0x82, 0x8a,
 | |
|     0x84, 0x87, 0x7f, 0x1e, 0xb8, 0xe5, 0xd9, 0x74, 0xd8, 0x73, 0xe0, 0x65, 0x22, 0x49, 0x01, 0x55,
 | |
|     0x5f, 0xb8, 0x82, 0x15, 0x90, 0xa3, 0x3b, 0xac, 0xc6, 0x1e, 0x39, 0x70, 0x1c, 0xf9, 0xb4, 0x6b,
 | |
|     0xd2, 0x5b, 0xf5, 0xf0, 0x59, 0x5b, 0xbe, 0x24, 0x65, 0x51, 0x41, 0x43, 0x8e, 0x7a, 0x10, 0x0b,
 | |
| };
 | |
| 
 | |
| unsigned char rfc8032_secret_key2[32] = {
 | |
|     0xc5, 0xaa, 0x8d, 0xf4, 0x3f, 0x9f, 0x83, 0x7b, 0xed, 0xb7, 0x44, 0x2f, 0x31, 0xdc, 0xb7, 0xb1,
 | |
|     0x66, 0xd3, 0x85, 0x35, 0x07, 0x6f, 0x09, 0x4b, 0x85, 0xce, 0x3a, 0x2e, 0x0b, 0x44, 0x58, 0xf7,
 | |
| };
 | |
| 
 | |
| unsigned char rfc8032_public_key2[32] = {
 | |
|     0xfc, 0x51, 0xcd, 0x8e, 0x62, 0x18, 0xa1, 0xa3, 0x8d, 0xa4, 0x7e, 0xd0, 0x02, 0x30, 0xf0, 0x58,
 | |
|     0x08, 0x16, 0xed, 0x13, 0xba, 0x33, 0x03, 0xac, 0x5d, 0xeb, 0x91, 0x15, 0x48, 0x90, 0x80, 0x25,
 | |
| };
 | |
| 
 | |
| unsigned char rfc8032_message2[2] = {0xaf, 0x82};
 | |
| 
 | |
| unsigned char rfc8032_signature2[64] = {
 | |
|     0x62, 0x91, 0xd6, 0x57, 0xde, 0xec, 0x24, 0x02, 0x48, 0x27, 0xe6, 0x9c, 0x3a, 0xbe, 0x01, 0xa3,
 | |
|     0x0c, 0xe5, 0x48, 0xa2, 0x84, 0x74, 0x3a, 0x44, 0x5e, 0x36, 0x80, 0xd7, 0xdb, 0x5a, 0xc3, 0xac,
 | |
|     0x18, 0xff, 0x9b, 0x53, 0x8d, 0x16, 0xf2, 0x90, 0xae, 0x67, 0xf7, 0x60, 0x98, 0x4d, 0xc6, 0x59,
 | |
|     0x4a, 0x7c, 0x15, 0xe9, 0x71, 0x6e, 0xd2, 0x8d, 0xc0, 0x27, 0xbe, 0xce, 0xea, 0x1e, 0xc4, 0x0a,
 | |
| };
 | |
| 
 | |
| TEST(Crypto, ed25519) {
 | |
|   td::Ed25519::generate_private_key().ensure();
 | |
| 
 | |
|   auto PK1 = td::Ed25519::generate_private_key().move_as_ok();
 | |
|   auto PK2 = td::Ed25519::PrivateKey(td::SecureString(td::Slice(fixed_privkey, 32)));
 | |
|   LOG(ERROR) << "PK1 = " << td::buffer_to_hex(PK1.as_octet_string());
 | |
|   auto priv2_export = PK2.as_octet_string();
 | |
|   LOG(ERROR) << "PK2 = " << td::buffer_to_hex(priv2_export);
 | |
|   auto PK3 = td::Ed25519::PrivateKey(std::move(priv2_export));
 | |
| 
 | |
|   auto PubK1 = PK1.get_public_key().move_as_ok();
 | |
|   LOG(ERROR) << "PubK1 = " << td::buffer_to_hex(PubK1.as_octet_string());
 | |
|   auto PubK2 = PK2.get_public_key().move_as_ok();
 | |
|   LOG(ERROR) << "PubK2 = " << td::buffer_to_hex(PubK2.as_octet_string());
 | |
|   CHECK(td::Slice(fixed_pubkey, 32) == PubK2.as_octet_string());
 | |
|   auto PubK3 = PK3.get_public_key().move_as_ok();
 | |
|   LOG(ERROR) << "PubK3 = " << td::buffer_to_hex(PubK3.as_octet_string());
 | |
|   CHECK(td::Slice(fixed_pubkey, 32) == PubK3.as_octet_string());
 | |
|   LOG(ERROR) << "PubK1 = " << td::buffer_to_hex(PubK1.as_octet_string());
 | |
| 
 | |
|   auto secret22 = td::Ed25519::compute_shared_secret(PubK3, PK2).move_as_ok();
 | |
|   LOG(ERROR) << "secret(PK2, PubK2)=" << td::buffer_to_hex(secret22);
 | |
| 
 | |
|   auto secret12 = td::Ed25519::compute_shared_secret(PubK3, PK1).move_as_ok();
 | |
|   LOG(ERROR) << "secret(PK1, PubK2)=" << td::buffer_to_hex(secret12);
 | |
|   auto secret21 = td::Ed25519::compute_shared_secret(PubK1, PK2).move_as_ok();
 | |
|   LOG(ERROR) << "secret(PK2, PubK1)=" << td::buffer_to_hex(secret21);
 | |
|   CHECK(secret12 == secret21);
 | |
| 
 | |
|   //  for (int i = 0; i < 1000; i++) {
 | |
|   //    td::Ed25519::compute_shared_secret(PubK2, PK1).ensure();
 | |
|   //    td::Ed25519::compute_shared_secret(PubK1, PK2).ensure();
 | |
|   //  }
 | |
| 
 | |
|   auto signature = PK1.sign("abc").move_as_ok();
 | |
|   LOG(ERROR) << "PK1.signature=" << td::buffer_to_hex(signature);
 | |
| 
 | |
|   // signature[63] ^= 1;
 | |
|   auto ok = PubK1.verify_signature("abc", signature);
 | |
|   LOG(ERROR) << "PubK1.check_signature=" << ok;
 | |
|   ok.ensure();
 | |
| 
 | |
|   td::Ed25519::PrivateKey PK4(td::SecureString(td::Slice(rfc8032_secret_key1, 32)));
 | |
|   auto PubK4 = PK4.get_public_key().move_as_ok();
 | |
|   LOG(ERROR) << "PK4.private_key = " << td::buffer_to_hex(PK4.as_octet_string());
 | |
|   LOG(ERROR) << "PK4.public_key = " << td::buffer_to_hex(PubK4.as_octet_string());
 | |
|   CHECK(td::Slice(rfc8032_public_key1, 32) == PubK4.as_octet_string());
 | |
|   signature = PK4.sign("").move_as_ok();
 | |
|   LOG(ERROR) << "PK4.signature('') = " << td::buffer_to_hex(signature);
 | |
|   CHECK(signature == td::Slice(rfc8032_signature1, 64));
 | |
| 
 | |
|   td::Ed25519::PrivateKey PK5(td::SecureString(td::Slice(rfc8032_secret_key2, 32)));
 | |
|   auto PubK5 = PK5.get_public_key().move_as_ok();
 | |
|   LOG(ERROR) << "PK5.private_key = " << td::buffer_to_hex(PK5.as_octet_string());
 | |
|   LOG(ERROR) << "PK5.public_key = " << td::buffer_to_hex(PubK5.as_octet_string());
 | |
|   CHECK(td::Slice(rfc8032_public_key2, 32) == PubK5.as_octet_string());
 | |
|   signature = PK5.sign(td::Slice(rfc8032_message2, 2)).move_as_ok();
 | |
|   LOG(ERROR) << "PK5.signature('') = " << td::buffer_to_hex(signature);
 | |
|   CHECK(signature == td::Slice(rfc8032_signature2, 64));
 | |
| 
 | |
|   //  for (int i = 0; i < 100000; i++) {
 | |
|   //    PK5.sign(td::Slice(rfc8032_message2, 2));
 | |
|   //  }
 | |
|   //  for (int i = 0; i < 1000; i++) {
 | |
|   //    PubK5.verify_signature(td::Slice(rfc8032_message2, 2), signature).ensure();
 | |
|   //  }
 | |
| 
 | |
|   /*
 | |
|   unsigned char temp_pubkey[32];
 | |
|   crypto::Ed25519::TempKeyGenerator TKG; // use one generator a lot of times
 | |
| 
 | |
|   TKG.create_temp_shared_secret(temp_pubkey, secret12, PubK1, (const unsigned char*)"abc", 3);
 | |
|   LOG(ERROR) << "secret12=" << td::buffer_to_hex(secret12) << "; temp_pubkey=" << td::buffer_to_hex(temp_pubkey);
 | |
| 
 | |
|   PK1.compute_temp_shared_secret(secret21, temp_pubkey);
 | |
|   LOG(ERROR) << "secret21=" << td::buffer_to_hex(secret21);
 | |
|   assert(!std::memcmp(secret12, secret21, 32));
 | |
| */
 | |
| }
 | |
| 
 | |
| TEST(Crypto, wycheproof) {
 | |
|   std::vector<std::pair<std::string, std::string>> bad_tests;
 | |
|   auto json_str = wycheproof_ed25519();
 | |
|   auto value = td::json_decode(json_str).move_as_ok();
 | |
|   auto &root = value.get_object();
 | |
|   auto test_groups_o = get_json_object_field(root, "testGroups", td::JsonValue::Type::Array, false).move_as_ok();
 | |
|   auto &test_groups = test_groups_o.get_array();
 | |
|   auto from_hexc = [](char c) {
 | |
|     if (c >= '0' && c <= '9') {
 | |
|       return c - '0';
 | |
|     }
 | |
|     return c - 'a' + 10;
 | |
|   };
 | |
|   auto from_hex = [&](td::Slice s) {
 | |
|     CHECK(s.size() % 2 == 0);
 | |
|     std::string res(s.size() / 2, 0);
 | |
|     for (size_t i = 0; i < s.size(); i += 2) {
 | |
|       res[i / 2] = char(from_hexc(s[i]) * 16 + from_hexc(s[i + 1]));
 | |
|     }
 | |
|     return res;
 | |
|   };
 | |
|   for (auto &test_o : test_groups) {
 | |
|     auto &test = test_o.get_object();
 | |
|     auto key_o = get_json_object_field(test, "key", td::JsonValue::Type::Object, false).move_as_ok();
 | |
|     auto sk_str = td::get_json_object_string_field(key_o.get_object(), "sk", false).move_as_ok();
 | |
|     auto pk_str = td::get_json_object_string_field(key_o.get_object(), "pk", false).move_as_ok();
 | |
|     auto pk = td::Ed25519::PublicKey(td::SecureString(from_hex(pk_str)));
 | |
|     auto sk = td::Ed25519::PrivateKey(td::SecureString(from_hex(sk_str)));
 | |
|     CHECK(sk.get_public_key().move_as_ok().as_octet_string().as_slice() == pk.as_octet_string().as_slice());
 | |
| 
 | |
|     //auto key =
 | |
|     //td::Ed25519::PrivateKey::from_pem(
 | |
|     //td::SecureString(td::get_json_object_string_field(test, "keyPem", false).move_as_ok()), td::SecureString())
 | |
|     //.move_as_ok();
 | |
| 
 | |
|     auto tests_o = get_json_object_field(test, "tests", td::JsonValue::Type::Array, false).move_as_ok();
 | |
|     auto &tests = tests_o.get_array();
 | |
|     for (auto &test_o : tests) {
 | |
|       auto &test = test_o.get_object();
 | |
|       auto id = td::get_json_object_string_field(test, "tcId", false).move_as_ok();
 | |
|       auto comment = td::get_json_object_string_field(test, "comment", false).move_as_ok();
 | |
|       auto sig = from_hex(td::get_json_object_string_field(test, "sig", false).move_as_ok());
 | |
|       auto msg = from_hex(td::get_json_object_string_field(test, "msg", false).move_as_ok());
 | |
|       auto result = td::get_json_object_string_field(test, "result", false).move_as_ok();
 | |
|       auto has_result = pk.verify_signature(msg, sig).is_ok() ? "valid" : "invalid";
 | |
|       if (result != has_result) {
 | |
|         bad_tests.push_back({id, comment});
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (bad_tests.empty()) {
 | |
|     return;
 | |
|   }
 | |
|   LOG(ERROR) << "FAILED: " << td::format::as_array(bad_tests);
 | |
| }
 | |
| 
 | |
| TEST(Crypto, almost_zero) {
 | |
|   td::SecureString pub(32);
 | |
|   td::SecureString sig(64);
 | |
|   td::SecureString msg(1);
 | |
| 
 | |
|   pub.as_mutable_slice().ubegin()[31] = static_cast<unsigned char>(128);
 | |
|   for (td::int32 j = 0; j < 256; j++) {
 | |
|     msg.as_mutable_slice()[0] = (char)j;
 | |
|     if (td::Ed25519::PublicKey(pub.copy()).verify_signature(msg, sig).is_ok()) {
 | |
|       LOG(ERROR) << "FAILED: " << j;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| BENCH(ed25519_sign, "ed25519_sign") {
 | |
|   auto private_key = td::Ed25519::generate_private_key().move_as_ok();
 | |
|   std::string hash_to_sign(32, 'a');
 | |
|   for (int i = 0; i < n; i++) {
 | |
|     private_key.sign(hash_to_sign).ensure();
 | |
|   }
 | |
| }
 | |
| 
 | |
| BENCH(ed25519_shared_secret, "ed25519_shared_secret") {
 | |
|   auto private_key_a = td::Ed25519::generate_private_key().move_as_ok();
 | |
|   auto private_key_b = td::Ed25519::generate_private_key().move_as_ok();
 | |
|   auto public_key_b = private_key_a.get_public_key().move_as_ok();
 | |
|   for (int i = 0; i < n; i++) {
 | |
|     td::Ed25519::compute_shared_secret(public_key_b, private_key_a).ensure();
 | |
|   }
 | |
| }
 | |
| 
 | |
| BENCH(ed25519_verify, "ed25519_verify") {
 | |
|   auto private_key = td::Ed25519::generate_private_key().move_as_ok();
 | |
|   std::string hash_to_sign(32, 'a');
 | |
|   auto public_key = private_key.get_public_key().move_as_ok();
 | |
|   auto signature = private_key.sign(hash_to_sign).move_as_ok();
 | |
|   for (int i = 0; i < n; i++) {
 | |
|     public_key.verify_signature(hash_to_sign, signature).ensure();
 | |
|   }
 | |
| }
 | |
| 
 | |
| TEST(Crypto, ed25519_benchmark) {
 | |
|   bench(ed25519_signBench());
 | |
|   bench(ed25519_shared_secretBench());
 | |
|   bench(ed25519_verifyBench());
 | |
| } |