Skip to content

Commit

Permalink
[GH-4080] Add wildcard AENS delegation signatures (#4105)
Browse files Browse the repository at this point in the history
* [GH-4080] Add wildcard AENS delegation signatures

fixup

* fix: release-note spelling
  • Loading branch information
hanssv committed Mar 22, 2023
1 parent 8eed528 commit 4b45955
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 7 deletions.
56 changes: 55 additions & 1 deletion apps/aecontract/test/aecontract_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
, sophia_signatures_oracles/1
, sophia_signature_check_gas_cost/1
, sophia_signatures_aens/1
, sophia_all_signatures_aens/1
, sophia_fate_signatures_aens/1
, sophia_maps/1
, sophia_map_benchmark/1
Expand Down Expand Up @@ -294,7 +295,7 @@
?VM_AEVM_SOPHIA_4 -> ok;
?VM_FATE_SOPHIA_1 -> ?assertMatch(__ExpVm1, __Res);
?VM_FATE_SOPHIA_2 -> ?assertMatch(__ExpVm2, __Res);
?VM_FATE_SOPHIA_3 -> ?assertMatch(__ExpVm3, __Res) %% For now :-)
?VM_FATE_SOPHIA_3 -> ?assertMatch(__ExpVm3, __Res)
end).

-define(assertMatchVM(AEVM, FATE, Res),
Expand Down Expand Up @@ -438,6 +439,7 @@ groups() ->
sophia_signatures_oracles,
sophia_signature_check_gas_cost,
sophia_signatures_aens,
sophia_all_signatures_aens,
sophia_fate_signatures_aens,
sophia_maps,
sophia_map_benchmark,
Expand Down Expand Up @@ -689,6 +691,7 @@ init_per_testcase(fate_environment, Config) ->
init_per_testcase_common(fate_environment, Config);
init_per_testcase(TC, Config) when TC == sophia_aens_resolve;
TC == sophia_signatures_aens;
TC == sophia_all_signatures_aens;
TC == sophia_fate_signatures_aens;
TC == sophia_aens_transactions ->
%% Disable name auction
Expand Down Expand Up @@ -769,6 +772,7 @@ end_per_testcase(fate_environment, _Config) ->
end_per_testcase(TC, _Config) when TC == sophia_aens_resolve;
TC == sophia_aens_lookup;
TC == sophia_signatures_aens;
TC == sophia_all_signatures_aens;
TC == sophia_fate_signatures_aens;
TC == sophia_aens_transactions;
TC == sophia_aens_update_transaction;
Expand Down Expand Up @@ -4362,6 +4366,56 @@ sophia_signatures_aens(Cfg) ->
?assertMatchProtocol(NonceAfterRevoke, ExpectedNonceAfterRevokeRoma, NonceBeforeRevoke),
ok.

sophia_all_signatures_aens(Cfg) ->
case ?config(vm_version, Cfg) of
VMVersion when VMVersion < ?VM_FATE_SOPHIA_2 -> ok;
_ -> sophia_all_signatures_aens_(Cfg)
end.

sophia_all_signatures_aens_(Cfg) ->
init_new_state(),
Acc = ?call(new_account, 40000000000000 * aec_test_utils:min_gas_price()),
NameAcc = ?call(new_account, 40000000000000 * aec_test_utils:min_gas_price()),
Ct = ?call(create_contract, NameAcc, aens, {}, #{ amount => 100000 }),
Name1 = aens_test_utils:fullname(<<"bla">>),
Salt1 = rand:uniform(10000),
{ok, NameAscii} = aens_utils:to_ascii(Name1),
CHash = ?hsh(aens_hash:commitment_hash(NameAscii, Salt1)),
NHash = aens_hash:name_hash(NameAscii),
NameArg = Name1,
NameAccSigAll = sign(<<NameAcc/binary, "AENS"/utf8, Ct/binary>>, NameAcc),
AccSigAll = sign(<<Acc/binary, "AENS"/utf8, Ct/binary>>, Acc),
APubkey = 1,
OPubkey = 2,

%% PreClaim
Res1 = ?call(call_contract, Acc, Ct, signedPreclaim, {tuple, []}, {NameAcc, CHash, NameAccSigAll}, #{ height => 10 }),
?assertMatchFATE(unused, {error, <<"Error in aens_preclaim: bad_signature">>}, {}, Res1),

%% Claim
Res2 = ?call(call_contract, Acc, Ct, signedClaim, {tuple, []}, {NameAcc, Name1, Salt1, NameAccSigAll}, #{ height => 11 }),
?assertMatchFATE(unused, {error, <<"Error in aens_claim: bad_signature">>}, {}, Res2),

Pointers = #{},
None = none,
Some = fun (X) -> {some, X} end,

Res3 = ?call(call_contract, Acc, Ct, signedUpdate, {tuple, []}, {NameAcc, NameArg, None, None, Some(Pointers), NameAccSigAll}, #{height => 12}),
?assertMatchFATE(unused, {error, <<"Error in aens_update: bad_signature">>}, {}, Res3),

%% Transfer
Res4 = ?call(call_contract, Acc, Ct, signedTransfer, {tuple, []}, {NameAcc, Acc, NameArg, NameAccSigAll}, #{ height => 12 }),
?assertMatchFATE(unused, {error, <<"Error in aens_transfer: bad_signature">>}, {}, Res4),

%% Revoke
BadRevoke = ?call(call_contract, Acc, Ct, signedRevoke, {tuple, []}, {NameAcc, NameArg, NameAccSigAll}, #{ height => 13 }),
?assertMatchFATE(unused, {error, <<"Error in aens_revoke: bad_signature">>}, {error,<<"Error in aens_revoke: name_not_owned">>}, BadRevoke),

Res5 = ?call(call_contract, NameAcc, Ct, signedRevoke, {tuple, []}, {Acc, NameArg, AccSigAll}, #{ height => 13 }),
?assertMatchFATE(unused, {error, <<"Error in aens_revoke: bad_signature">>}, {}, Res5),

ok.

%% Delegated signatures did not work for non-existing accounts pre-CERES, this test checks that this
%% continues to be true :-)
%% Note that Claim can't be done by a non-existing account since it require funds!
Expand Down
16 changes: 13 additions & 3 deletions apps/aefate/src/aefa_chain_api.erl
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ next_nonce(Pubkey, #state{primop_state = PState0,
end
end.

-spec check_delegation_signature(pubkey(), binary(), binary(), aect_contracts:vm_version(), state()) ->
-spec check_delegation_signature(pubkey(), binary() | {binary(), binary()}, binary(), aect_contracts:vm_version(), state()) ->
{'ok', state()} | 'error'.
check_delegation_signature(Pubkey, Binary, Signature, VmVersion,
#state{ primop_state = PState} = State) ->
Expand All @@ -365,14 +365,24 @@ check_delegation_signature(Pubkey, Binary, Signature, VmVersion,
error;
basic ->
State1 = State#state{primop_state = PState1},
verify_delegation_signature(Pubkey, Binary, Signature, State1)
verify_delegation_signature_(Pubkey, Binary, Signature, VmVersion, State1)
end;
none when VmVersion >= ?VM_FATE_SOPHIA_3 ->
verify_delegation_signature(Pubkey, Binary, Signature, State);
verify_delegation_signature_(Pubkey, Binary, Signature, VmVersion, State);
none ->
error
end.

verify_delegation_signature_(Pubkey, {Binary1, _}, Signature, VmVersion, State) when VmVersion < ?VM_FATE_SOPHIA_3 ->
verify_delegation_signature(Pubkey, Binary1, Signature, State);
verify_delegation_signature_(Pubkey, {Binary1, Binary2}, Signature, _VmVersion, State) ->
case verify_delegation_signature(Pubkey, Binary1, Signature, State) of
{ok, State} -> {ok, State};
error -> verify_delegation_signature(Pubkey, Binary2, Signature, State)
end;
verify_delegation_signature_(Pubkey, Binary, Signature, _VmVersion, State) ->
verify_delegation_signature(Pubkey, Binary, Signature, State).

verify_delegation_signature(Pubkey, Binary, Signature, State) ->
BinaryForNetwork = aec_governance:add_network_id(Binary),
case enacl:sign_verify_detached(Signature, BinaryForNetwork, Pubkey) of
Expand Down
10 changes: 7 additions & 3 deletions apps/aefate/src/aefa_fate_op.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2261,8 +2261,9 @@ check_delegation_signature(Type, Data, SignBin, Current, ES0) ->
end
end.

delegation_signature_data(Type, Pubkey, Current) when Type =:= aens_preclaim;
Type =:= oracle_register;
delegation_signature_data(aens_preclaim, Pubkey, Current) ->
{{<<Pubkey/binary, Current/binary>>, aens_wildcard_signature_data(Pubkey, Current)}, Pubkey};
delegation_signature_data(Type, Pubkey, Current) when Type =:= oracle_register;
Type =:= oracle_extend ->
{<<Pubkey/binary, Current/binary>>, Pubkey};
delegation_signature_data(oracle_respond, {Pubkey, QueryId}, Current) ->
Expand All @@ -2271,7 +2272,10 @@ delegation_signature_data(Type, {Pubkey, Hash}, Current) when Type =:= aens_clai
Type =:= aens_update;
Type =:= aens_transfer;
Type =:= aens_revoke ->
{<<Pubkey/binary, Hash/binary, Current/binary>>, Pubkey}.
{{<<Pubkey/binary, Hash/binary, Current/binary>>, aens_wildcard_signature_data(Pubkey, Current)}, Pubkey}.

aens_wildcard_signature_data(Pubkey, ContractPubkey) ->
<<Pubkey/binary, "AENS"/utf8, ContractPubkey/binary>>.

spend_gas(Delta, ES) when is_integer(Delta), Delta > 0 ->
aefa_engine_state:spend_gas(Delta, ES).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
* Add generic/wildcard AENS delegation signatures. I.e. instead of delegating
authority for a contract to operate with a specific name (name hash), by
signing just the string `AENS` (+ network id, public key and contract address
as usual) you can delegate the authority for a contract to handle all your
names with one signature. See [Issue
#4080](https://github.com/aeternity/aeternity/issues/4080) for details.

BEWARE: This gives the contract authority to handle all current _and future_
names on your behalf, so it should be used with extreme care and only for
well-known (and well understood!!) contracts.

0 comments on commit 4b45955

Please sign in to comment.