From 87ee39ffb0dca7bd10d77a98042103bcfcdfed70 Mon Sep 17 00:00:00 2001 From: Juraj Hlista Date: Tue, 12 Mar 2019 12:21:29 +0700 Subject: [PATCH] Export verify_proof/4 and add get_target/2 verify_proof/4 checks that a solution is a valid solution it doesn't check it against any target. get_target/2 returns the target of a solution in integer form (not scientific). --- src/aeminer_pow.erl | 6 ----- src/aeminer_pow_cuckoo.erl | 45 +++++++++++++++++++------------ test/aeminer_pow_cuckoo_tests.erl | 27 ++++++++++++++----- 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/aeminer_pow.erl b/src/aeminer_pow.erl index c7e880b..ac8983c 100644 --- a/src/aeminer_pow.erl +++ b/src/aeminer_pow.erl @@ -136,12 +136,6 @@ test_target(Bin, Target) -> <> = Bin, Val < Threshold. -%% TODO: get target -%Bin = solution_to_binary(lists:sort(Soln), NodeSize * 8, <<>>), -%%Hash = aec_hash:hash(pow, Bin), -%%<> = Hash, -%%Val - %%%============================================================================= %%% Internal functions %%%============================================================================= diff --git a/src/aeminer_pow_cuckoo.erl b/src/aeminer_pow_cuckoo.erl index f1b1195..5c17de6 100644 --- a/src/aeminer_pow_cuckoo.erl +++ b/src/aeminer_pow_cuckoo.erl @@ -25,7 +25,9 @@ ]). -export([generate/5, - verify/5 + verify/5, + verify_proof/4, + get_target/2 ]). -export_type([hashable/0, @@ -53,6 +55,8 @@ -type nonce() :: aeminer_pow:nonce(). +-type int_target() :: aeminer_pow:int_target(). + -type sci_target() :: aeminer_pow:sci_target(). -type instance() :: aeminer_pow:instance() @@ -193,14 +197,35 @@ generate(Data, Target, Nonce, Config, Instance) when boolean(). verify(Data, Nonce, Soln, Target, EdgeBits) when is_list(Soln), Nonce >= 0, Nonce =< ?MAX_NONCE -> - Hash = aeminer_blake2b_256:hash(Data), case test_target(Soln, Target, EdgeBits) of true -> - verify_proof(Hash, Nonce, Soln, EdgeBits); + verify_proof(Data, Nonce, Soln, EdgeBits); false -> false end. +%%------------------------------------------------------------------------------ +%% @doc +%% Proof of Work verification +%% @end +%%------------------------------------------------------------------------------ +-spec verify_proof(hashable(), nonce(), solution(), edge_bits()) -> boolean(). +verify_proof(Data, Nonce, Solution, EdgeBits) -> + %% Cuckoo has an 80 byte header, we have to use that as well + %% packed Hash + Nonce = 56 bytes, add 24 bytes of 0:s + Hash = aeminer_blake2b_256:hash(Data), + Header0 = pack_header_and_nonce(Hash, Nonce), + Header = <<(list_to_binary(Header0))/binary, 0:(8*24)>>, + verify_proof_(Header, Solution, EdgeBits). + +-spec get_target(solution(), edge_bits()) -> int_target(). +get_target(Soln, EdgeBits) when is_list(Soln), length(Soln) =:= ?SOLUTION_SIZE -> + NodeSize = get_node_size(EdgeBits), + Bin = solution_to_binary(lists:sort(Soln), NodeSize * 8, <<>>), + Hash = aeminer_blake2b_256:hash(Bin), + <> = Hash, + Val. + %% Internal functions. generate_int(Hash, Nonce, Target, @@ -270,20 +295,6 @@ exec_bin_dir(#config{exec_group = ExecGroup}) -> -define(POW_DEAD_END, {error, cycle_dead_ends}). -define(POW_SHORT_CYCLE, {error, cycle_too_short}). -%%------------------------------------------------------------------------------ -%% @doc -%% Proof of Work verification (difficulty check should be done before calling -%% this function) -%% @end -%%------------------------------------------------------------------------------ - -verify_proof(Hash, Nonce, Solution, EdgeBits) -> - %% Cuckoo has an 80 byte header, we have to use that as well - %% packed Hash + Nonce = 56 bytes, add 24 bytes of 0:s - Header0 = pack_header_and_nonce(Hash, Nonce), - Header = <<(list_to_binary(Header0))/binary, 0:(8*24)>>, - verify_proof_(Header, Solution, EdgeBits). - verify_proof_(Header, Solution, EdgeBits) -> {K0, K1, K2, K3} = aeminer_siphash24:create_keys(Header), diff --git a/test/aeminer_pow_cuckoo_tests.erl b/test/aeminer_pow_cuckoo_tests.erl index 651b5d5..c9f228b 100644 --- a/test/aeminer_pow_cuckoo_tests.erl +++ b/test/aeminer_pow_cuckoo_tests.erl @@ -11,6 +11,7 @@ -include("aeminer.hrl"). -define(TEST_MODULE, aeminer_pow_cuckoo). +-define(POW_MODULE, aeminer_pow). -define(TEST_BIN, <<"wsffgujnjkqhduihsahswgdf">>). -define(TEST_HIGH_NONCE, 38). %% Nonce with solution with high target. @@ -29,14 +30,18 @@ pow_test_() -> ?assertMatch(L when length(L) == ?SOLUTION_SIZE, Soln), %% verify the nonce and the solution - Res2 = ?TEST_MODULE:verify(?TEST_BIN, Nonce, Soln, Target, ?EDGE_BITS_15), - ?assert(Res2) + ?assert(?TEST_MODULE:verify(?TEST_BIN, Nonce, Soln, Target, ?EDGE_BITS_15)), + ?assert(?TEST_MODULE:verify_proof(?TEST_BIN, Nonce, Soln, ?EDGE_BITS_15)), + + SolnTarget = ?TEST_MODULE:get_target(Soln, ?EDGE_BITS_15), + ?assert(SolnTarget =< ?HIGHEST_TARGET_INT) end} }, {"Generate with a winning nonce but low target threshold, shall fail", {timeout, 90, fun() -> Target = 16#01010000, + TargetInt = ?POW_MODULE:scientific_to_integer(Target), Nonce = ?TEST_HIGH_NONCE, Config = fast_and_deterministic_cuckoo_pow(), Res1 = spawn_worker(fun() -> @@ -56,7 +61,12 @@ pow_test_() -> ?assertMatch(L when length(L) == ?SOLUTION_SIZE, Soln2), %% ... then attempt to verify such solution (and %% nonce) with the low target threshold (shall fail). - ?assertNot(?TEST_MODULE:verify(?TEST_BIN, Nonce, Soln2, Target, ?EDGE_BITS_15)) + ?assertNot(?TEST_MODULE:verify(?TEST_BIN, Nonce, Soln2, Target, ?EDGE_BITS_15)), + %% The solution is still valid though. + ?assert(?TEST_MODULE:verify_proof(?TEST_BIN, Nonce, Soln2, ?EDGE_BITS_15)), + + %% The target of the solution shall be higher than the low target. + ?assert(?TEST_MODULE:get_target(Soln2, ?EDGE_BITS_15) > TargetInt) end} }, {"Attempt to verify wrong solution for nonce that has a solution shall fail", @@ -71,7 +81,8 @@ pow_test_() -> WrongSoln = lists:seq(0, 41), ?assertMatch(L when length(L) == ?SOLUTION_SIZE, WrongSoln), ?assertNotEqual(Soln, WrongSoln), - ?assertNot(?TEST_MODULE:verify(?TEST_BIN, Nonce, WrongSoln, Target, ?EDGE_BITS_15)) + ?assertNot(?TEST_MODULE:verify(?TEST_BIN, Nonce, WrongSoln, Target, ?EDGE_BITS_15)), + ?assertNot(?TEST_MODULE:verify_proof(?TEST_BIN, Nonce, WrongSoln, ?EDGE_BITS_15)) end}, {"Attempt to verify nonce that does not have a solution (providing a dummy solution) shall fail", fun() -> @@ -82,8 +93,9 @@ pow_test_() -> spawn_worker(fun() -> ?TEST_MODULE:generate(?TEST_BIN, Target, Nonce, Config, undefined) end)), DummySoln = lists:seq(0, 41), - ?assertMatch(L when length(L) == ?SOLUTION_SIZE, DummySoln), - ?assertNot(?TEST_MODULE:verify(?TEST_BIN, Nonce, DummySoln, Target, ?EDGE_BITS_15)) + ?assertMatch(L when length(L) =:= ?SOLUTION_SIZE, DummySoln), + ?assertNot(?TEST_MODULE:verify(?TEST_BIN, Nonce, DummySoln, Target, ?EDGE_BITS_15)), + ?assertNot(?TEST_MODULE:verify_proof(?TEST_BIN, Nonce, DummySoln, ?EDGE_BITS_15)) end}, {"Attempt to verify nonce that is too big shall fail gracefully", fun() -> @@ -99,7 +111,8 @@ pow_test_() -> 117537386,120015599,125293300,125684682,129332159], Nonce = 17654096256755765485, Target = 536940240, - ?assertNot(?TEST_MODULE:verify(Hash, Nonce, Pow, Target, ?EDGE_BITS_15)) + ?assertNot(?TEST_MODULE:verify(Hash, Nonce, Pow, Target, ?EDGE_BITS_15)), + ?assertNot(?TEST_MODULE:verify_proof(Hash, Nonce, Pow, ?EDGE_BITS_15)) end} ].