From 7a8e840793a0ff055b21f8409857e791e607b8fe Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Sun, 5 Jul 2026 08:38:42 +0200 Subject: [PATCH 01/11] Add support for extended-auth account types --- src/gmser_api_encoder.erl | 28 ++++++++++++++--- src/gmser_chain_objects.erl | 4 +++ src/gmser_id.erl | 53 ++++++++++++++++++++++++++------ test/gmser_api_encoder_tests.erl | 11 ++++++- 4 files changed, 81 insertions(+), 15 deletions(-) diff --git a/src/gmser_api_encoder.erl b/src/gmser_api_encoder.erl index 9013b66..267b0be 100644 --- a/src/gmser_api_encoder.erl +++ b/src/gmser_api_encoder.erl @@ -36,6 +36,7 @@ | transaction | tx_hash | account_pubkey + | {account_pubkey, 0..6} | account_seckey | associate_chain | entry @@ -107,8 +108,12 @@ safe_decode_keypair(#{<<"pub">> := EncPub, <<"priv">> := EncPriv}) -> -spec encode(known_type(), payload() | gmser_id:id()) -> encoded(). encode(id_hash, Payload) -> - {IdType, Val} = gmser_id:specialize(Payload), - encode(id2type(IdType), Val); + case gmser_id:to_map(Payload) of + #{type := account, subtype := SubT, value := Val} -> + encode({account_pubkey, SubT}, Val); + #{type := IdType, value := Val} -> + encode(id2type(IdType), Val) + end; encode(Type, Payload) -> case type_size_check(Type, Payload) of ok -> @@ -237,17 +242,16 @@ id2type(associate_chain) -> associate_chain; id2type(channel) -> channel; id2type(commitment) -> commitment; id2type(contract) -> contract_pubkey; -id2type(contract_source) -> contract_source; id2type(name) -> name; id2type(native_token) -> native_token; id2type(entry) -> entry. +type2id({account_pubkey, SubT}) -> {account, SubT}; type2id(account_pubkey) -> account; type2id(associate_chain) -> associate_chain; type2id(channel) -> channel; type2id(commitment) -> commitment; type2id(contract_pubkey) -> contract; -type2id(contract_source) -> contract_source; type2id(name) -> name; type2id(native_token) -> native_token; type2id(entry) -> entry. @@ -266,6 +270,7 @@ type2enc(contract_store_value) -> ?BASE64; type2enc(contract_source) -> ?BASE64; type2enc(transaction) -> ?BASE64; type2enc(tx_hash) -> ?BASE58; +type2enc({account_pubkey, _}) -> ?BASE58; type2enc(account_pubkey) -> ?BASE58; type2enc(account_seckey) -> ?BASE58; type2enc(associate_chain) -> ?BASE58; @@ -298,6 +303,13 @@ type2pfx(contract_store_value) -> <<"cv">>; type2pfx(contract_source) -> <<"cx">>; type2pfx(transaction) -> <<"tx">>; type2pfx(tx_hash) -> <<"th">>; +type2pfx({account_pubkey,0}) -> <<"a0">>; +type2pfx({account_pubkey,1}) -> <<"a1">>; +type2pfx({account_pubkey,2}) -> <<"a2">>; +type2pfx({account_pubkey,3}) -> <<"a3">>; +type2pfx({account_pubkey,4}) -> <<"a4">>; +type2pfx({account_pubkey,5}) -> <<"a5">>; +type2pfx({account_pubkey,6}) -> <<"a6">>; type2pfx(account_pubkey) -> <<"ak">>; type2pfx(account_seckey) -> <<"sk">>; type2pfx(associate_chain) -> <<"ac">>; @@ -329,6 +341,13 @@ pfx2type(<<"ct">>) -> contract_pubkey; pfx2type(<<"cx">>) -> contract_source; pfx2type(<<"tx">>) -> transaction; pfx2type(<<"th">>) -> tx_hash; +pfx2type(<<"a0">>) -> {account_pubkey, 0}; +pfx2type(<<"a1">>) -> {account_pubkey, 1}; +pfx2type(<<"a2">>) -> {account_pubkey, 2}; +pfx2type(<<"a3">>) -> {account_pubkey, 3}; +pfx2type(<<"a4">>) -> {account_pubkey, 4}; +pfx2type(<<"a5">>) -> {account_pubkey, 5}; +pfx2type(<<"a6">>) -> {account_pubkey, 6}; pfx2type(<<"ak">>) -> account_pubkey; pfx2type(<<"sk">>) -> account_seckey; pfx2type(<<"ac">>) -> associate_chain; @@ -363,6 +382,7 @@ byte_size_for_type(contract_source) -> not_applicable; byte_size_for_type(transaction) -> not_applicable; byte_size_for_type(tx_hash) -> 32; byte_size_for_type(account_pubkey) -> 32; +byte_size_for_type({account_pubkey, _}) -> 32; byte_size_for_type(account_seckey) -> 32; byte_size_for_type(associate_chain) -> 32; byte_size_for_type(signature) -> 64; diff --git a/src/gmser_chain_objects.erl b/src/gmser_chain_objects.erl index 4c89e07..6117cbe 100644 --- a/src/gmser_chain_objects.erl +++ b/src/gmser_chain_objects.erl @@ -115,6 +115,8 @@ tag(entry) -> 140; tag(entry_create_tx) -> 141; tag(entry_transfer_tx) -> 142; tag(entry_destroy_tx) -> 143; +tag(account_key_store) -> 144; +tag(account_create_tx) -> 145; tag(pof) -> 200. rev_tag(10) -> account; @@ -194,4 +196,6 @@ rev_tag(140) -> entry; rev_tag(141) -> entry_create_tx; rev_tag(142) -> entry_transfer_tx; rev_tag(143) -> entry_destroy_tx; +rev_tag(144) -> account_key_store; +rev_tag(145) -> account_create_tx; rev_tag(200) -> pof. diff --git a/src/gmser_id.erl b/src/gmser_id.erl index 80a592a..1056ef1 100644 --- a/src/gmser_id.erl +++ b/src/gmser_id.erl @@ -14,6 +14,7 @@ , specialize/1 , specialize/2 , specialize_type/1 + , to_map/1 , is_id/1 ]). @@ -29,15 +30,20 @@ , val }). --type tag() :: 'account' - | 'associate_chain' - | 'channel' - | 'commitment' - | 'contract' - | 'contract_source' - | 'name' - | 'native_token' - | 'entry'. +-type subtype() :: 0..6. +-type id_map() :: #{ type := simple_tag() + , subtype => subtype() + , value := binary() }. + +-type tag() :: {'account', subtype()} | simple_tag(). +-type simple_tag() :: 'account' + | 'associate_chain' + | 'channel' + | 'commitment' + | 'contract' + | 'name' + | 'native_token' + | 'entry'. -type val() :: <<_:256>>. -type id() :: #id{}. @@ -57,7 +63,8 @@ ___TAG___ =:= contract; ___TAG___ =:= channel; ___TAG___ =:= associate_chain; - ___TAG___ =:= entry + ___TAG___ =:= entry; + ___TAG___ =:= native_token ). -define(IS_VAL(___VAL___), byte_size(___VAL___) =:= 32). @@ -69,6 +76,8 @@ create(Tag, Val) when ?IS_TAG(Tag), ?IS_VAL(Val) -> #id{ tag = Tag , val = Val}; +create({account,I}, Val) when is_binary(Val), I >= 0, I =< 6 -> + #id{ tag = {account, I}, val = Val}; create(Tag, Val) when ?IS_VAL(Val) -> error({illegal_tag, Tag}); create(Tag, Val) when ?IS_TAG(Tag)-> @@ -78,28 +87,52 @@ create(Tag, Val) -> -spec specialize(id()) -> {tag(), val()}. +specialize(#id{tag = {Tag,_}, val = Val}) -> + {Tag, Val}; specialize(#id{tag = Tag, val = Val}) -> {Tag, Val}. -spec specialize(id(), tag()) -> val(). +specialize(#id{tag = {Tag, _}, val = Val}, Tag) when is_binary(Val) -> + Val; specialize(#id{tag = Tag, val = Val}, Tag) when ?IS_TAG(Tag), ?IS_VAL(Val) -> Val. -spec specialize_type(id()) -> tag(). +specialize_type(#id{tag = {Tag, _}}) when ?IS_TAG(Tag) -> + Tag; specialize_type(#id{tag = Tag}) when ?IS_TAG(Tag) -> Tag. +-spec to_map(id()) -> id_map(). +to_map(#id{tag = {Tag, SubType}, val = Val}) when ?IS_TAG(Tag) -> + #{ type => Tag + , subtype => SubType + , value => Val }; +to_map(#id{tag = Tag, val = Val}) when ?IS_TAG(Tag) -> + #{ type => Tag + , value => Val }. + + -spec is_id(term()) -> boolean(). is_id(#id{}) -> true; is_id(_) -> false. -spec encode(id()) -> binary(). +encode(#id{tag = {account, N}, val = Val}) when N =< 2#111_1111 -> + Ext = 2#1000_0000 bor N, + <>; encode(#id{tag = Tag, val = Val}) -> Res = <<(encode_tag(Tag)):?TAG_SIZE/unit:8, Val/binary>>, true = ?SERIALIZED_SIZE =:= byte_size(Res), Res. -spec decode(binary()) -> id(). +decode(<>) when Ext >= 2#1000_0000 -> + %% Extended account id type + Type = Ext band 2#0111_1111, + #id{ tag = {account, Type} + , val = Rest }; decode(<>) -> #id{ tag = decode_tag(Tag) , val = Val}. diff --git a/test/gmser_api_encoder_tests.erl b/test/gmser_api_encoder_tests.erl index a5d7e13..df62fa9 100644 --- a/test/gmser_api_encoder_tests.erl +++ b/test/gmser_api_encoder_tests.erl @@ -194,7 +194,16 @@ known_types() -> Forms = get_forms(), [{type, _, union, Types}] = [Def || {attribute, _, type, {known_type, Def, []}} <- Forms], - [Name || {atom,_, Name} <- Types]. + lists:flatmap(fun known_type_entry/1, Types). + +known_type_entry({atom, _, Name}) -> + [Name]; +known_type_entry({type, _, tuple, + [{atom, _, account_pubkey}, + {type, _, range, [{integer, _, Lo}, {integer, _, Hi}]}]}) -> + [{account_pubkey, N} || N <- lists:seq(Lo, Hi)]; +known_type_entry(Other) -> + error({unsupported_known_type, Other}). mapped_prefixes() -> Forms = get_forms(), -- 2.30.2 From dbfc013c8a5d2b8291bb46ab7ae05cf8bbbb24ca Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Mon, 6 Jul 2026 10:19:38 +0200 Subject: [PATCH 02/11] Add auth tx and account sig store --- src/gmser_chain_objects.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gmser_chain_objects.erl b/src/gmser_chain_objects.erl index 6117cbe..656becb 100644 --- a/src/gmser_chain_objects.erl +++ b/src/gmser_chain_objects.erl @@ -117,6 +117,8 @@ tag(entry_transfer_tx) -> 142; tag(entry_destroy_tx) -> 143; tag(account_key_store) -> 144; tag(account_create_tx) -> 145; +tag(account_sig_store) -> 146; +tag(auth_tx) -> 147; tag(pof) -> 200. rev_tag(10) -> account; @@ -198,4 +200,6 @@ rev_tag(142) -> entry_transfer_tx; rev_tag(143) -> entry_destroy_tx; rev_tag(144) -> account_key_store; rev_tag(145) -> account_create_tx; +rev_tag(146) -> account_sig_store; +rev_tag(147) -> auth_tx; rev_tag(200) -> pof. -- 2.30.2 From a368c64f7e1362e5cae4f90a63adb3e0c6f81e47 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Mon, 6 Jul 2026 10:55:20 +0200 Subject: [PATCH 03/11] Add missing tag for proposal_gossip_tx --- src/gmser_chain_objects.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gmser_chain_objects.erl b/src/gmser_chain_objects.erl index 656becb..ce23ce4 100644 --- a/src/gmser_chain_objects.erl +++ b/src/gmser_chain_objects.erl @@ -119,6 +119,7 @@ tag(account_key_store) -> 144; tag(account_create_tx) -> 145; tag(account_sig_store) -> 146; tag(auth_tx) -> 147; +tag(proposal_gossip_tx) -> 148; tag(pof) -> 200. rev_tag(10) -> account; @@ -202,4 +203,5 @@ rev_tag(144) -> account_key_store; rev_tag(145) -> account_create_tx; rev_tag(146) -> account_sig_store; rev_tag(147) -> auth_tx; +rev_tag(148) -> proposal_gossip_tx; rev_tag(200) -> pof. -- 2.30.2 From a84dcc880d07e5d3db0801dfdc9203c4a1576c46 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Mon, 6 Jul 2026 12:26:38 +0200 Subject: [PATCH 04/11] Add is_account/1 and account_pubkey/1 helpers Extended-auth account ids use an {account, Subtype} tag. These helpers let callers test account membership and extract the 32-byte pubkey without pattern-matching on specialize/1 results. --- src/gmser_id.erl | 16 +++++++++++++++ test/gmser_id_tests.erl | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 test/gmser_id_tests.erl diff --git a/src/gmser_id.erl b/src/gmser_id.erl index 1056ef1..7655ec4 100644 --- a/src/gmser_id.erl +++ b/src/gmser_id.erl @@ -14,6 +14,8 @@ , specialize/1 , specialize/2 , specialize_type/1 + , is_account/1 + , account_pubkey/1 , to_map/1 , is_id/1 ]). @@ -104,6 +106,20 @@ specialize_type(#id{tag = {Tag, _}}) when ?IS_TAG(Tag) -> specialize_type(#id{tag = Tag}) when ?IS_TAG(Tag) -> Tag. +-spec is_account(id() | term()) -> boolean(). +is_account(#id{tag = account}) -> + true; +is_account(#id{tag = {account, _}}) -> + true; +is_account(_) -> + false. + +-spec account_pubkey(id()) -> val(). +account_pubkey(#id{tag = account, val = Val}) when ?IS_VAL(Val) -> + Val; +account_pubkey(#id{tag = {account, _}, val = Val}) when ?IS_VAL(Val) -> + Val. + -spec to_map(id()) -> id_map(). to_map(#id{tag = {Tag, SubType}, val = Val}) when ?IS_TAG(Tag) -> #{ type => Tag diff --git a/test/gmser_id_tests.erl b/test/gmser_id_tests.erl new file mode 100644 index 0000000..6ac5aa8 --- /dev/null +++ b/test/gmser_id_tests.erl @@ -0,0 +1,44 @@ +-module(gmser_id_tests). + +-include_lib("eunit/include/eunit.hrl"). + +-define(PUBKEY, <<12345:32/unit:8>>). + +is_account_test() -> + {"is_account recognizes standard and extended account ids", + fun() -> + ?assert(gmser_id:is_account(gmser_id:create(account, ?PUBKEY))), + ?assert(gmser_id:is_account(gmser_id:create({account, 0}, ?PUBKEY))), + ?assert(gmser_id:is_account(gmser_id:create({account, 5}, ?PUBKEY))), + ?assertNot(gmser_id:is_account(gmser_id:create(contract, ?PUBKEY))), + ?assertNot(gmser_id:is_account(not_an_id)) + end}. + +account_pubkey_test() -> + {"account_pubkey returns the 32-byte account hash", + fun() -> + ?assertEqual(?PUBKEY, + gmser_id:account_pubkey(gmser_id:create(account, ?PUBKEY))), + ?assertEqual(?PUBKEY, + gmser_id:account_pubkey(gmser_id:create({account, 3}, ?PUBKEY))), + ?assertEqual(?PUBKEY, + gmser_id:account_pubkey(gmser_id:create({account, 6}, ?PUBKEY))) + end}. + +account_pubkey_matches_specialize_test() -> + {"account_pubkey agrees with specialize/2 for account ids", + fun() -> + Id = gmser_id:create({account, 2}, ?PUBKEY), + ?assertEqual(gmser_id:specialize(Id, account), + gmser_id:account_pubkey(Id)) + end}. + +extended_account_roundtrip_test() -> + {"extended account ids round-trip through encode/decode", + fun() -> + Id = gmser_id:create({account, 4}, ?PUBKEY), + ?assert(gmser_id:is_account(Id)), + Id1 = gmser_id:decode(gmser_id:encode(Id)), + ?assertEqual(?PUBKEY, gmser_id:account_pubkey(Id1)), + ?assertEqual(account, gmser_id:specialize_type(Id1)) + end}. \ No newline at end of file -- 2.30.2 From 79b43b066530a8131b044cf314cffe4a9ddcc9f8 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Mon, 6 Jul 2026 15:30:19 +0200 Subject: [PATCH 05/11] Add account_auth_update_tx tag --- src/gmser_chain_objects.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gmser_chain_objects.erl b/src/gmser_chain_objects.erl index ce23ce4..636af6e 100644 --- a/src/gmser_chain_objects.erl +++ b/src/gmser_chain_objects.erl @@ -120,6 +120,7 @@ tag(account_create_tx) -> 145; tag(account_sig_store) -> 146; tag(auth_tx) -> 147; tag(proposal_gossip_tx) -> 148; +tag(account_auth_update_tx) -> 149; tag(pof) -> 200. rev_tag(10) -> account; @@ -204,4 +205,5 @@ rev_tag(145) -> account_create_tx; rev_tag(146) -> account_sig_store; rev_tag(147) -> auth_tx; rev_tag(148) -> proposal_gossip_tx; +rev_tag(149) -> account_auth_update_tx; rev_tag(200) -> pof. -- 2.30.2 From faa20bd00b748fa4f05c052bde504202dec58207 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Mon, 6 Jul 2026 22:27:28 +0200 Subject: [PATCH 06/11] Add ac_receipt and AC side tx tags from ac793dcaf6 Cherry-pick the chain-object tags from ac793dcaf6 while keeping the extended-auth account types (account_sig_store, auth_tx, etc.). --- src/gmser_chain_objects.erl | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/gmser_chain_objects.erl b/src/gmser_chain_objects.erl index 636af6e..7ad2f7c 100644 --- a/src/gmser_chain_objects.erl +++ b/src/gmser_chain_objects.erl @@ -100,6 +100,7 @@ tag(ac_deposit_tx) -> 94; tag(ac_update_cops_tx) -> 95; tag(ac_rollup_tx) -> 96; tag(ac_proposal_tx) -> 97; +tag(ac_receipt) -> 98; tag(key_block) -> 100; tag(micro_block) -> 101; tag(light_micro_block) -> 102; @@ -121,7 +122,10 @@ tag(account_sig_store) -> 146; tag(auth_tx) -> 147; tag(proposal_gossip_tx) -> 148; tag(account_auth_update_tx) -> 149; -tag(pof) -> 200. +tag(pof) -> 200; +%% Gajumaru AC side transactions +tag(ac_side_withdraw_tx) -> 300; +tag(ac_side_rollup_tx) -> 301. rev_tag(10) -> account; rev_tag(11) -> signed_tx; @@ -185,6 +189,7 @@ rev_tag(94) -> ac_deposit_tx; rev_tag(95) -> ac_update_cops_tx; rev_tag(96) -> ac_rollup_tx; rev_tag(97) -> ac_proposal_tx; +rev_tag(98) -> ac_receipt; rev_tag(100) -> key_block; rev_tag(101) -> micro_block; rev_tag(102) -> light_micro_block; @@ -206,4 +211,7 @@ rev_tag(146) -> account_sig_store; rev_tag(147) -> auth_tx; rev_tag(148) -> proposal_gossip_tx; rev_tag(149) -> account_auth_update_tx; -rev_tag(200) -> pof. +rev_tag(200) -> pof; +%% Gajumaru AC side transactions +rev_tag(300) -> ac_side_withdraw_tx; +rev_tag(301) -> ac_side_rollup_tx. -- 2.30.2 From 0e157f824a85ac17a633d179367a36058f53ae4b Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Tue, 7 Jul 2026 08:07:58 +0200 Subject: [PATCH 07/11] Add ac_acct_state serialization tag --- src/gmser_chain_objects.erl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gmser_chain_objects.erl b/src/gmser_chain_objects.erl index 7ad2f7c..465db2d 100644 --- a/src/gmser_chain_objects.erl +++ b/src/gmser_chain_objects.erl @@ -101,7 +101,6 @@ tag(ac_update_cops_tx) -> 95; tag(ac_rollup_tx) -> 96; tag(ac_proposal_tx) -> 97; tag(ac_receipt) -> 98; -tag(key_block) -> 100; tag(micro_block) -> 101; tag(light_micro_block) -> 102; tag(testimony) -> 110; @@ -190,7 +189,6 @@ rev_tag(95) -> ac_update_cops_tx; rev_tag(96) -> ac_rollup_tx; rev_tag(97) -> ac_proposal_tx; rev_tag(98) -> ac_receipt; -rev_tag(100) -> key_block; rev_tag(101) -> micro_block; rev_tag(102) -> light_micro_block; rev_tag(110) -> testimony; -- 2.30.2 From c80505c81012f6d4231cbc3fee280af8d4bf73ee Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Tue, 7 Jul 2026 08:13:37 +0200 Subject: [PATCH 08/11] Fix ac_acct_state tag and restore key_block mapping The previous commit accidentally removed key_block (tag 100) instead of adding ac_acct_state (tag 99). --- src/gmser_chain_objects.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gmser_chain_objects.erl b/src/gmser_chain_objects.erl index 465db2d..aa3a7ab 100644 --- a/src/gmser_chain_objects.erl +++ b/src/gmser_chain_objects.erl @@ -101,6 +101,8 @@ tag(ac_update_cops_tx) -> 95; tag(ac_rollup_tx) -> 96; tag(ac_proposal_tx) -> 97; tag(ac_receipt) -> 98; +tag(ac_acct_state) -> 99; +tag(key_block) -> 100; tag(micro_block) -> 101; tag(light_micro_block) -> 102; tag(testimony) -> 110; @@ -189,6 +191,8 @@ rev_tag(95) -> ac_update_cops_tx; rev_tag(96) -> ac_rollup_tx; rev_tag(97) -> ac_proposal_tx; rev_tag(98) -> ac_receipt; +rev_tag(99) -> ac_acct_state; +rev_tag(100) -> key_block; rev_tag(101) -> micro_block; rev_tag(102) -> light_micro_block; rev_tag(110) -> testimony; -- 2.30.2 From 6d7ab1e4ad53a434de01279a0fe17953e0d3dc7c Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Tue, 7 Jul 2026 10:05:30 +0200 Subject: [PATCH 09/11] PoC: ASN.1 / DER serialization experiment This branch contains a proof-of-concept exploration of representing the RLP (gmser_rlp) and gmserialization layers using ASN.1 with DER encoding. Goals of the experiment: - Model the static serialization templates and dynamic types in ASN.1. - Demonstrate reliable detection of legacy RLP data vs. new DER data (first byte >= 0xC0 for RLP lists vs. 0x30 for DER SEQUENCE). - Evaluate wire-size overhead of standard DER TLV encoding compared to the extremely compact RLP prefix encoding. - Verify that the DER path produces deterministic output suitable for hashing (idempotent serialization). Key files: - GajumaruSerialization.asn -- the ASN.1 schema - GajumaruSerialization.{erl,hrl} -- generated encoder/decoder - detect_demo.erl, size_comparison.erl -- supporting test code Findings (high level): - Detection via first byte works cleanly. - DER is fully deterministic for hashing when the same value is given. - Small objects pay a significant size overhead (often 3-6x) due to TLV tags/lengths and field names in the generic path. - Concrete SEQUENCE definitions are much more compact than the generic templateFields representation. - Large payloads have acceptable relative overhead. This is NOT production code. It was created to answer feasibility questions around ASN.1 modeling, format detection, determinism, and size characteristics. Branch created from uw-new-acs for isolated experimentation. --- asn1/GajumaruSerialization.asn | 225 +++++ asn1/GajumaruSerialization.erl | 1402 ++++++++++++++++++++++++++++++++ asn1/GajumaruSerialization.hrl | 76 ++ asn1/detect_demo.erl | 27 + asn1/size_comparison.erl | 114 +++ 5 files changed, 1844 insertions(+) create mode 100644 asn1/GajumaruSerialization.asn create mode 100644 asn1/GajumaruSerialization.erl create mode 100644 asn1/GajumaruSerialization.hrl create mode 100644 asn1/detect_demo.erl create mode 100644 asn1/size_comparison.erl diff --git a/asn1/GajumaruSerialization.asn b/asn1/GajumaruSerialization.asn new file mode 100644 index 0000000..43607e9 --- /dev/null +++ b/asn1/GajumaruSerialization.asn @@ -0,0 +1,225 @@ +-- GajumaruSerialization.asn +-- +-- ASN.1 model for the structures serialized by gmserialization.erl +-- (the layer on top of RLP). +-- +-- Purpose: +-- * Provide a formal, toolable description of the data. +-- * Enable migration from the legacy RLP-based format to DER. +-- +-- Detection of legacy vs new: +-- Legacy data (produced by gmserialization:serialize / gmser_chain_objects:serialize +-- or gmser_dyn:serialize) is always an RLP *list* at the top level. +-- This means the first byte is in the range 0xC0 .. 0xFF. +-- +-- DER-encoded data using the types below will start with 0x30 (SEQUENCE, +-- constructed, universal tag) for the outermost GajumaruData (or any +-- top-level SEQUENCE we define). 0x30 < 0xC0, so a single-byte prefix +-- check reliably distinguishes the two formats. +-- +-- Usage in Erlang (after compiling with asn1ct): +-- {ok, Mod} = asn1ct:compile(GajumaruSerialization.asn, [ber, der]). +-- {ok, Term} = 'GajumaruSerialization':decode('GajumaruData', DerBinary). +-- +-- Notes on type mapping from gmserialization.erl: +-- - int -> INTEGER (new data uses canonical DER INTEGER) +-- - binary -> OCTET STRING +-- - bool -> BOOLEAN +-- - id -> Id (SEQUENCE) (cleaner than the legacy packed 33-byte form) +-- - [T] -> SEQUENCE OF T +-- - {T1,...} -> SEQUENCE (fixed-size, order matters) +-- - #{items := [{K,T},...]} -> SEQUENCE with the fields in template order +-- (static maps carry *values only*, no keys on the wire) +-- - tag + vsn are preserved as the first two fields for compatibility +-- with existing dispatch logic. +-- +-- Legacy integers had strict unsigned-minimal no-leading-zero (except for 0) +-- and RLP-level rules. New DER data does not need to follow those rules. +-- +-- WARNING: +-- Any cryptographic hash or signature computed over a serialized object +-- will change when switching from RLP to DER for that object. Plan a +-- coordinated upgrade. + +GajumaruSerialization DEFINITIONS + AUTOMATIC TAGS ::= +BEGIN + +EXPORTS ALL; + +-- ============================================================ +-- Top-level wrapper used for new DER data. +-- This is what a decoder will see first. +-- ============================================================ + +GajumaruData ::= SEQUENCE { + tag INTEGER, + vsn INTEGER, + content Content +} + +-- Content can be a specific structured type (preferred) or a generic +-- representation of a template-driven object. +Content ::= CHOICE { + -- Generic fallback that can represent any [{Field, Type}] template + -- without having a pre-defined SEQUENCE for every object. + templateFields [0] TemplateFields, + + -- Examples of concrete versioned types (extend as needed) + account [1] Account, + signedTx [2] SignedTx, + contract [3] ContractCode + -- Add more alternatives for other tags from gmser_chain_objects +} + +-- ============================================================ +-- Generic template-driven representation +-- (useful during transition or for unregistered types) +-- ============================================================ + +TemplateFields ::= SEQUENCE OF TemplateField + +TemplateField ::= SEQUENCE { + -- Field name is included for debuggability / generic processing. + -- In the original static encoding the name is NOT on the wire; + -- only position and type matter. We include it here for convenience. + name IA5String OPTIONAL, + value Value +} + +Value ::= CHOICE { + intValue [0] INTEGER, + boolValue [1] BOOLEAN, + binaryValue [2] OCTET STRING, + idValue [3] Id, + listValue [4] SEQUENCE OF Value, + tupleValue [5] SEQUENCE OF Value, + mapValue [6] SEQUENCE OF KeyValue -- only needed if you want to + -- represent dynamic-style maps +} + +KeyValue ::= SEQUENCE { + key Value, + val Value +} + +-- ============================================================ +-- Common types +-- ============================================================ + +Id ::= SEQUENCE { + -- Corresponds to the simple tags in gmser_id (account=1, name=2, etc.) + -- and the extended account subtype (high bit in legacy). + type INTEGER (0..255), + value OCTET STRING (SIZE (32)) +} + +-- ============================================================ +-- Concrete object examples (derived from usage in the codebase) +-- Add / evolve per version as you introduce new vsns. +-- ============================================================ + +-- Example: a very simple account-like object used in tests +Account ::= SEQUENCE { + foo INTEGER, + bar OCTET STRING +} + +-- Simplified signed transaction +SignedTx ::= SEQUENCE { + signatures SEQUENCE OF OCTET STRING, + transaction OCTET STRING +} + +-- Contract code objects (see gmser_contract_code.erl) +-- We model the three versions that exist today. +ContractCode ::= CHOICE { + v1 [0] ContractV1, + v2 [1] ContractV2, + v3 [2] ContractV3 +} + +ContractV1 ::= SEQUENCE { + sourceHash OCTET STRING, + -- typeInfo is a list of 4-tuples in legacy: + -- {typeHash, name, argType, outType} + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING +} + +ContractV2 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING, + compilerVersion OCTET STRING +} + +ContractV3 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV3, + byteCode OCTET STRING, + compilerVersion OCTET STRING, + payable BOOLEAN +} + +TypeInfoV1 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + argType OCTET STRING, + outType OCTET STRING +} + +TypeInfoV3 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + payable BOOLEAN, + argType OCTET STRING, + outType OCTET STRING +} + +-- ============================================================ +-- Notes for implementers +-- ============================================================ +-- 1. Detection (recommended decoder entry point): +-- +-- decode(Binary) -> +-- case Binary of +-- <> when B >= 16#C0 -> +-- decode_legacy_rlp(Binary); % existing gmser_* path +-- _ -> +-- {ok, Term} = +-- 'GajumaruSerialization':decode('GajumaruData', Binary), +-- Term +-- end. +-- +-- This works because: +-- - All current top-level output from serialize() is an RLP list +-- (first byte 0xC0-0xFF). +-- - GajumaruData and the concrete choices above are SEQUENCEs +-- (first byte 0x30 for short form, or 0x30 0x81/0x82... for long). +-- +-- 2. When you add a new object type or version, prefer adding a +-- concrete SEQUENCE alternative in the Content CHOICE rather than +-- always falling back to TemplateFields. This gives you better +-- validation and generated types. +-- +-- 3. INTEGER in DER is signed and uses a different minimal encoding +-- than the legacy unsigned big-endian no leading zero form. This is +-- fine for new data. +-- +-- 4. If you need to preserve exact legacy integer wire bytes inside +-- the new format (e.g. for some hash preimage reason), you can +-- carry selected integers as OCTET STRING (legacy unsigned minimal bytes). +-- +-- 5. Dynamic encoding (gmser_dyn) is intentionally not modeled here +-- in full, because it is runtime-schema driven (type codes 246-255, +-- labels, alt/switch, etc.). You can still use the generic +-- TemplateFields + Value for some dynamic cases, or model specific +-- message schemas as additional CHOICE arms. +-- +-- 6. Compile with DER for canonical output: +-- asn1ct:compile(GajumaruSerialization, [der]). +-- +-- The ber option is also accepted; der implies the stricter rules. + +END diff --git a/asn1/GajumaruSerialization.erl b/asn1/GajumaruSerialization.erl new file mode 100644 index 0000000..1fed3af --- /dev/null +++ b/asn1/GajumaruSerialization.erl @@ -0,0 +1,1402 @@ +%% Generated by the Erlang ASN.1 BER compiler. Version: 5.4.3 +%% Purpose: Encoding and decoding of the types in GajumaruSerialization. + +-module('GajumaruSerialization'). +-moduledoc false. +-compile(nowarn_unused_vars). +-dialyzer(no_improper_lists). +-dialyzer(no_match). +-include("GajumaruSerialization.hrl"). +-asn1_info([{vsn,'5.4.3'}, + {module,'GajumaruSerialization'}, + {options,[der,{outdir,"asn1"},{i,"."},{i,"asn1"}]}]). + +-export([encoding_rule/0,maps/0,bit_string_format/0, + legacy_erlang_types/0]). +-export(['dialyzer-suppressions'/1]). +-export([ +enc_GajumaruData/2, +enc_Content/2, +enc_TemplateFields/2, +enc_TemplateField/2, +enc_Value/2, +enc_KeyValue/2, +enc_Id/2, +enc_Account/2, +enc_SignedTx/2, +enc_ContractCode/2, +enc_ContractV1/2, +enc_ContractV2/2, +enc_ContractV3/2, +enc_TypeInfoV1/2, +enc_TypeInfoV3/2 +]). + +-export([ +dec_GajumaruData/2, +dec_Content/2, +dec_TemplateFields/2, +dec_TemplateField/2, +dec_Value/2, +dec_KeyValue/2, +dec_Id/2, +dec_Account/2, +dec_SignedTx/2, +dec_ContractCode/2, +dec_ContractV1/2, +dec_ContractV2/2, +dec_ContractV3/2, +dec_TypeInfoV1/2, +dec_TypeInfoV3/2 +]). + +-export([info/0]). + +-export([encode/2,decode/2]). + +encoding_rule() -> ber. + +maps() -> false. + +bit_string_format() -> bitstring. + +legacy_erlang_types() -> false. + +encode(Type, Data) -> +try iolist_to_binary(element(1, encode_disp(Type, Data))) of + Bytes -> + {ok,Bytes} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + + +decode(Type, Data) -> +try + Result = decode_disp(Type, element(1, ber_decode_nif(Data))), + {ok,Result} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + +encode_disp('GajumaruData', Data) -> enc_GajumaruData(Data); +encode_disp('Content', Data) -> enc_Content(Data); +encode_disp('TemplateFields', Data) -> enc_TemplateFields(Data); +encode_disp('TemplateField', Data) -> enc_TemplateField(Data); +encode_disp('Value', Data) -> enc_Value(Data); +encode_disp('KeyValue', Data) -> enc_KeyValue(Data); +encode_disp('Id', Data) -> enc_Id(Data); +encode_disp('Account', Data) -> enc_Account(Data); +encode_disp('SignedTx', Data) -> enc_SignedTx(Data); +encode_disp('ContractCode', Data) -> enc_ContractCode(Data); +encode_disp('ContractV1', Data) -> enc_ContractV1(Data); +encode_disp('ContractV2', Data) -> enc_ContractV2(Data); +encode_disp('ContractV3', Data) -> enc_ContractV3(Data); +encode_disp('TypeInfoV1', Data) -> enc_TypeInfoV1(Data); +encode_disp('TypeInfoV3', Data) -> enc_TypeInfoV3(Data); +encode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +decode_disp('GajumaruData', Data) -> dec_GajumaruData(Data); +decode_disp('Content', Data) -> dec_Content(Data); +decode_disp('TemplateFields', Data) -> dec_TemplateFields(Data); +decode_disp('TemplateField', Data) -> dec_TemplateField(Data); +decode_disp('Value', Data) -> dec_Value(Data); +decode_disp('KeyValue', Data) -> dec_KeyValue(Data); +decode_disp('Id', Data) -> dec_Id(Data); +decode_disp('Account', Data) -> dec_Account(Data); +decode_disp('SignedTx', Data) -> dec_SignedTx(Data); +decode_disp('ContractCode', Data) -> dec_ContractCode(Data); +decode_disp('ContractV1', Data) -> dec_ContractV1(Data); +decode_disp('ContractV2', Data) -> dec_ContractV2(Data); +decode_disp('ContractV3', Data) -> dec_ContractV3(Data); +decode_disp('TypeInfoV1', Data) -> dec_TypeInfoV1(Data); +decode_disp('TypeInfoV3', Data) -> dec_TypeInfoV3(Data); +decode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +info() -> + case ?MODULE:module_info(attributes) of + Attributes when is_list(Attributes) -> + case lists:keyfind(asn1_info, 1, Attributes) of + {_,Info} when is_list(Info) -> + Info; + _ -> + [] + end; + _ -> + [] + end. + + +%%================================ +%% GajumaruData +%%================================ +enc_GajumaruData(Val) -> + enc_GajumaruData(Val, [<<48>>]). + +enc_GajumaruData(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3} = Val, + +%%------------------------------------------------- +%% attribute tag(1) with type INTEGER +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_integer(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute vsn(2) with type INTEGER +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_integer(Cindex2, [<<129>>]), + +%%------------------------------------------------- +%% attribute content(3) External GajumaruSerialization:Content +%%------------------------------------------------- + {EncBytes3,EncLen3} = 'enc_Content'(Cindex3, [<<162>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3], +LenSoFar = EncLen1 + EncLen2 + EncLen3, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_GajumaruData(Tlv) -> + dec_GajumaruData(Tlv, [16]). + +dec_GajumaruData(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute tag(1) with type INTEGER +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_integer(V1, [131072]), + +%%------------------------------------------------- +%% attribute vsn(2) with type INTEGER +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_integer(V2, [131073]), + +%%------------------------------------------------- +%% attribute content(3) External GajumaruSerialization:Content +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = 'dec_Content'(V3, [131074]), + +case Tlv4 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv4}}}) % extra fields not allowed +end, +Res1 = {'GajumaruData',Term1,Term2,Term3}, +Res1. + + +%%================================ +%% Content +%%================================ +enc_Content(Val) -> + enc_Content(Val, []). + +enc_Content(Val, TagIn) -> + {EncBytes,EncLen} = case element(1,Val) of + templateFields -> + 'enc_TemplateFields'(element(2,Val), [<<160>>]); + account -> + 'enc_Account'(element(2,Val), [<<161>>]); + signedTx -> + 'enc_SignedTx'(element(2,Val), [<<162>>]); + contract -> + 'enc_ContractCode'(element(2,Val), [<<163>>]); + Else -> + exit({error,{asn1,{invalid_choice_type,Else}}}) + end, + +encode_tags(TagIn, EncBytes, EncLen). + + + + +dec_Content(Tlv) -> + dec_Content(Tlv, []). + +dec_Content(Tlv, TagIn) -> +Tlv1 = match_tags(Tlv, TagIn), +case (case Tlv1 of [CtempTlv1] -> CtempTlv1; _ -> Tlv1 end) of + +%% 'templateFields' + {131072, V1} -> + {templateFields, 'dec_TemplateFields'(V1, [])}; + + +%% 'account' + {131073, V1} -> + {account, 'dec_Account'(V1, [])}; + + +%% 'signedTx' + {131074, V1} -> + {signedTx, 'dec_SignedTx'(V1, [])}; + + +%% 'contract' + {131075, V1} -> + {contract, 'dec_ContractCode'(V1, [])}; + + Else -> + exit({error,{asn1,{invalid_choice_tag,Else}}}) + end +. + + +%%================================ +%% TemplateFields +%%================================ +enc_TemplateFields(Val) -> + enc_TemplateFields(Val, [<<48>>]). + +enc_TemplateFields(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_TemplateFields_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_TemplateFields_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_TemplateFields_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_TemplateField'(H, [<<48>>]), + 'enc_TemplateFields_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_TemplateFields(Tlv) -> + dec_TemplateFields(Tlv, [16]). + +dec_TemplateFields(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_TemplateField'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% TemplateField +%%================================ +enc_TemplateField(Val) -> + enc_TemplateField(Val, [<<48>>]). + +enc_TemplateField(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute name(1) with type IA5String OPTIONAL +%%------------------------------------------------- + {EncBytes1,EncLen1} = case Cindex1 of + asn1_NOVALUE -> {<<>>,0}; + _ -> + encode_restricted_string(Cindex1, [<<128>>]) + end, + +%%------------------------------------------------- +%% attribute value(2) External GajumaruSerialization:Value +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_Value'(Cindex2, [<<161>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_TemplateField(Tlv) -> + dec_TemplateField(Tlv, [16]). + +dec_TemplateField(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute name(1) with type IA5String OPTIONAL +%%------------------------------------------------- +{Term1,Tlv2} = case Tlv1 of +[{131072,V1}|TempTlv2] -> + {begin +binary_to_list(decode_restricted_string(V1, [])) +end +, TempTlv2}; + _ -> + { asn1_NOVALUE, Tlv1} +end, + +%%------------------------------------------------- +%% attribute value(2) External GajumaruSerialization:Value +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_Value'(V2, [131073]), + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'TemplateField',Term1,Term2}, +Res1. + + +%%================================ +%% Value +%%================================ +enc_Value(Val) -> + enc_Value(Val, []). + +enc_Value(Val, TagIn) -> + {EncBytes,EncLen} = case element(1,Val) of + intValue -> + encode_integer(element(2,Val), [<<128>>]); + boolValue -> + encode_boolean(element(2,Val), [<<129>>]); + binaryValue -> + encode_restricted_string(element(2,Val), [<<130>>]); + idValue -> + 'enc_Id'(element(2,Val), [<<163>>]); + listValue -> + 'enc_Value_listValue'(element(2,Val), [<<164>>]); + tupleValue -> + 'enc_Value_tupleValue'(element(2,Val), [<<165>>]); + mapValue -> + 'enc_Value_mapValue'(element(2,Val), [<<166>>]); + Else -> + exit({error,{asn1,{invalid_choice_type,Else}}}) + end, + +encode_tags(TagIn, EncBytes, EncLen). + + + + + +%%================================ +%% Value_listValue +%%================================ +enc_Value_listValue(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_Value_listValue_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_Value_listValue_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_Value_listValue_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_Value'(H, []), + 'enc_Value_listValue_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + + +%%================================ +%% Value_tupleValue +%%================================ +enc_Value_tupleValue(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_Value_tupleValue_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_Value_tupleValue_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_Value_tupleValue_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_Value'(H, []), + 'enc_Value_tupleValue_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + + +%%================================ +%% Value_mapValue +%%================================ +enc_Value_mapValue(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_Value_mapValue_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_Value_mapValue_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_Value_mapValue_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_KeyValue'(H, [<<48>>]), + 'enc_Value_mapValue_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_Value(Tlv) -> + dec_Value(Tlv, []). + +dec_Value(Tlv, TagIn) -> +Tlv1 = match_tags(Tlv, TagIn), +case (case Tlv1 of [CtempTlv1] -> CtempTlv1; _ -> Tlv1 end) of + +%% 'intValue' + {131072, V1} -> + {intValue, decode_integer(V1, [])}; + + +%% 'boolValue' + {131073, V1} -> + {boolValue, decode_boolean(V1, [])}; + + +%% 'binaryValue' + {131074, V1} -> + {binaryValue, decode_octet_string(V1, [])}; + + +%% 'idValue' + {131075, V1} -> + {idValue, 'dec_Id'(V1, [])}; + + +%% 'listValue' + {131076, V1} -> + {listValue, 'dec_Value_listValue'(V1, [])}; + + +%% 'tupleValue' + {131077, V1} -> + {tupleValue, 'dec_Value_tupleValue'(V1, [])}; + + +%% 'mapValue' + {131078, V1} -> + {mapValue, 'dec_Value_mapValue'(V1, [])}; + + Else -> + exit({error,{asn1,{invalid_choice_tag,Else}}}) + end +. +'dec_Value_listValue'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_Value'(V1, []) || V1 <- Tlv1]. + + +'dec_Value_tupleValue'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_Value'(V1, []) || V1 <- Tlv1]. + + +'dec_Value_mapValue'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_KeyValue'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% KeyValue +%%================================ +enc_KeyValue(Val) -> + enc_KeyValue(Val, [<<48>>]). + +enc_KeyValue(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute key(1) External GajumaruSerialization:Value +%%------------------------------------------------- + {EncBytes1,EncLen1} = 'enc_Value'(Cindex1, [<<160>>]), + +%%------------------------------------------------- +%% attribute val(2) External GajumaruSerialization:Value +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_Value'(Cindex2, [<<161>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_KeyValue(Tlv) -> + dec_KeyValue(Tlv, [16]). + +dec_KeyValue(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute key(1) External GajumaruSerialization:Value +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = 'dec_Value'(V1, [131072]), + +%%------------------------------------------------- +%% attribute val(2) External GajumaruSerialization:Value +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_Value'(V2, [131073]), + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'KeyValue',Term1,Term2}, +Res1. + + +%%================================ +%% Id +%%================================ +enc_Id(Val) -> + enc_Id(Val, [<<48>>]). + +enc_Id(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute type(1) with type INTEGER +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_integer(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute value(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_Id(Tlv) -> + dec_Id(Tlv, [16]). + +dec_Id(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute type(1) with type INTEGER +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = begin +Val1 = decode_integer(V1, [131072]), +if 0 =< Val1, Val1 =< 255 -> +Val1; +true -> +exit({error,{asn1,bad_range}}) +end +end, + +%%------------------------------------------------- +%% attribute value(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = begin +Val2 = decode_octet_string(V2, [131073]), +C1 = byte_size(Val2), +if C1 =:= 32 -> +Val2; +true -> +exit({error,{asn1,bad_range}}) +end +end, + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'Id',Term1,Term2}, +Res1. + + +%%================================ +%% Account +%%================================ +enc_Account(Val) -> + enc_Account(Val, [<<48>>]). + +enc_Account(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute foo(1) with type INTEGER +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_integer(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute bar(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_Account(Tlv) -> + dec_Account(Tlv, [16]). + +dec_Account(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute foo(1) with type INTEGER +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_integer(V1, [131072]), + +%%------------------------------------------------- +%% attribute bar(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_octet_string(V2, [131073]), + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'Account',Term1,Term2}, +Res1. + + +%%================================ +%% SignedTx +%%================================ +enc_SignedTx(Val) -> + enc_SignedTx(Val, [<<48>>]). + +enc_SignedTx(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute signatures(1) with type SEQUENCE OF +%%------------------------------------------------- + {EncBytes1,EncLen1} = 'enc_SignedTx_signatures'(Cindex1, [<<160>>]), + +%%------------------------------------------------- +%% attribute transaction(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + + +%%================================ +%% SignedTx_signatures +%%================================ +enc_SignedTx_signatures(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_SignedTx_signatures_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_SignedTx_signatures_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_SignedTx_signatures_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = encode_restricted_string(H, [<<4>>]), + 'enc_SignedTx_signatures_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_SignedTx(Tlv) -> + dec_SignedTx(Tlv, [16]). + +dec_SignedTx(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute signatures(1) with type SEQUENCE OF +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = 'dec_SignedTx_signatures'(V1, [131072]), + +%%------------------------------------------------- +%% attribute transaction(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_octet_string(V2, [131073]), + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'SignedTx',Term1,Term2}, +Res1. +'dec_SignedTx_signatures'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +[decode_octet_string(V1, [4]) || V1 <- Tlv1]. + + + + +%%================================ +%% ContractCode +%%================================ +enc_ContractCode(Val) -> + enc_ContractCode(Val, []). + +enc_ContractCode(Val, TagIn) -> + {EncBytes,EncLen} = case element(1,Val) of + v1 -> + 'enc_ContractV1'(element(2,Val), [<<160>>]); + v2 -> + 'enc_ContractV2'(element(2,Val), [<<161>>]); + v3 -> + 'enc_ContractV3'(element(2,Val), [<<162>>]); + Else -> + exit({error,{asn1,{invalid_choice_type,Else}}}) + end, + +encode_tags(TagIn, EncBytes, EncLen). + + + + +dec_ContractCode(Tlv) -> + dec_ContractCode(Tlv, []). + +dec_ContractCode(Tlv, TagIn) -> +Tlv1 = match_tags(Tlv, TagIn), +case (case Tlv1 of [CtempTlv1] -> CtempTlv1; _ -> Tlv1 end) of + +%% 'v1' + {131072, V1} -> + {v1, 'dec_ContractV1'(V1, [])}; + + +%% 'v2' + {131073, V1} -> + {v2, 'dec_ContractV2'(V1, [])}; + + +%% 'v3' + {131074, V1} -> + {v3, 'dec_ContractV3'(V1, [])}; + + Else -> + exit({error,{asn1,{invalid_choice_tag,Else}}}) + end +. + + +%%================================ +%% ContractV1 +%%================================ +enc_ContractV1(Val) -> + enc_ContractV1(Val, [<<48>>]). + +enc_ContractV1(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3} = Val, + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_ContractV1_typeInfo'(Cindex2, [<<161>>]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_restricted_string(Cindex3, [<<130>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3], +LenSoFar = EncLen1 + EncLen2 + EncLen3, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + + +%%================================ +%% ContractV1_typeInfo +%%================================ +enc_ContractV1_typeInfo(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_ContractV1_typeInfo_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_ContractV1_typeInfo_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_ContractV1_typeInfo_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_TypeInfoV1'(H, [<<48>>]), + 'enc_ContractV1_typeInfo_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_ContractV1(Tlv) -> + dec_ContractV1(Tlv, [16]). + +dec_ContractV1(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_ContractV1_typeInfo'(V2, [131073]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_octet_string(V3, [131074]), + +case Tlv4 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv4}}}) % extra fields not allowed +end, +Res1 = {'ContractV1',Term1,Term2,Term3}, +Res1. +'dec_ContractV1_typeInfo'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_TypeInfoV1'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% ContractV2 +%%================================ +enc_ContractV2(Val) -> + enc_ContractV2(Val, [<<48>>]). + +enc_ContractV2(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3,Cindex4} = Val, + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_ContractV2_typeInfo'(Cindex2, [<<161>>]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_restricted_string(Cindex3, [<<130>>]), + +%%------------------------------------------------- +%% attribute compilerVersion(4) with type OCTET STRING +%%------------------------------------------------- + {EncBytes4,EncLen4} = encode_restricted_string(Cindex4, [<<131>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3, EncBytes4], +LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + + +%%================================ +%% ContractV2_typeInfo +%%================================ +enc_ContractV2_typeInfo(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_ContractV2_typeInfo_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_ContractV2_typeInfo_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_ContractV2_typeInfo_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_TypeInfoV1'(H, [<<48>>]), + 'enc_ContractV2_typeInfo_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_ContractV2(Tlv) -> + dec_ContractV2(Tlv, [16]). + +dec_ContractV2(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_ContractV2_typeInfo'(V2, [131073]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_octet_string(V3, [131074]), + +%%------------------------------------------------- +%% attribute compilerVersion(4) with type OCTET STRING +%%------------------------------------------------- +[V4|Tlv5] = Tlv4, +Term4 = decode_octet_string(V4, [131075]), + +case Tlv5 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv5}}}) % extra fields not allowed +end, +Res1 = {'ContractV2',Term1,Term2,Term3,Term4}, +Res1. +'dec_ContractV2_typeInfo'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_TypeInfoV1'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% ContractV3 +%%================================ +enc_ContractV3(Val) -> + enc_ContractV3(Val, [<<48>>]). + +enc_ContractV3(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3,Cindex4,Cindex5} = Val, + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_ContractV3_typeInfo'(Cindex2, [<<161>>]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_restricted_string(Cindex3, [<<130>>]), + +%%------------------------------------------------- +%% attribute compilerVersion(4) with type OCTET STRING +%%------------------------------------------------- + {EncBytes4,EncLen4} = encode_restricted_string(Cindex4, [<<131>>]), + +%%------------------------------------------------- +%% attribute payable(5) with type BOOLEAN +%%------------------------------------------------- + {EncBytes5,EncLen5} = encode_boolean(Cindex5, [<<132>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3, EncBytes4, EncBytes5], +LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4 + EncLen5, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + + +%%================================ +%% ContractV3_typeInfo +%%================================ +enc_ContractV3_typeInfo(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_ContractV3_typeInfo_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_ContractV3_typeInfo_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_ContractV3_typeInfo_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_TypeInfoV3'(H, [<<48>>]), + 'enc_ContractV3_typeInfo_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_ContractV3(Tlv) -> + dec_ContractV3(Tlv, [16]). + +dec_ContractV3(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_ContractV3_typeInfo'(V2, [131073]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_octet_string(V3, [131074]), + +%%------------------------------------------------- +%% attribute compilerVersion(4) with type OCTET STRING +%%------------------------------------------------- +[V4|Tlv5] = Tlv4, +Term4 = decode_octet_string(V4, [131075]), + +%%------------------------------------------------- +%% attribute payable(5) with type BOOLEAN +%%------------------------------------------------- +[V5|Tlv6] = Tlv5, +Term5 = decode_boolean(V5, [131076]), + +case Tlv6 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv6}}}) % extra fields not allowed +end, +Res1 = {'ContractV3',Term1,Term2,Term3,Term4,Term5}, +Res1. +'dec_ContractV3_typeInfo'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_TypeInfoV3'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% TypeInfoV1 +%%================================ +enc_TypeInfoV1(Val) -> + enc_TypeInfoV1(Val, [<<48>>]). + +enc_TypeInfoV1(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3,Cindex4} = Val, + +%%------------------------------------------------- +%% attribute typeHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute name(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + +%%------------------------------------------------- +%% attribute argType(3) with type OCTET STRING +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_restricted_string(Cindex3, [<<130>>]), + +%%------------------------------------------------- +%% attribute outType(4) with type OCTET STRING +%%------------------------------------------------- + {EncBytes4,EncLen4} = encode_restricted_string(Cindex4, [<<131>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3, EncBytes4], +LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_TypeInfoV1(Tlv) -> + dec_TypeInfoV1(Tlv, [16]). + +dec_TypeInfoV1(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute typeHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute name(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_octet_string(V2, [131073]), + +%%------------------------------------------------- +%% attribute argType(3) with type OCTET STRING +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_octet_string(V3, [131074]), + +%%------------------------------------------------- +%% attribute outType(4) with type OCTET STRING +%%------------------------------------------------- +[V4|Tlv5] = Tlv4, +Term4 = decode_octet_string(V4, [131075]), + +case Tlv5 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv5}}}) % extra fields not allowed +end, +Res1 = {'TypeInfoV1',Term1,Term2,Term3,Term4}, +Res1. + + +%%================================ +%% TypeInfoV3 +%%================================ +enc_TypeInfoV3(Val) -> + enc_TypeInfoV3(Val, [<<48>>]). + +enc_TypeInfoV3(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3,Cindex4,Cindex5} = Val, + +%%------------------------------------------------- +%% attribute typeHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute name(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + +%%------------------------------------------------- +%% attribute payable(3) with type BOOLEAN +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_boolean(Cindex3, [<<130>>]), + +%%------------------------------------------------- +%% attribute argType(4) with type OCTET STRING +%%------------------------------------------------- + {EncBytes4,EncLen4} = encode_restricted_string(Cindex4, [<<131>>]), + +%%------------------------------------------------- +%% attribute outType(5) with type OCTET STRING +%%------------------------------------------------- + {EncBytes5,EncLen5} = encode_restricted_string(Cindex5, [<<132>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3, EncBytes4, EncBytes5], +LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4 + EncLen5, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_TypeInfoV3(Tlv) -> + dec_TypeInfoV3(Tlv, [16]). + +dec_TypeInfoV3(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute typeHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute name(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_octet_string(V2, [131073]), + +%%------------------------------------------------- +%% attribute payable(3) with type BOOLEAN +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_boolean(V3, [131074]), + +%%------------------------------------------------- +%% attribute argType(4) with type OCTET STRING +%%------------------------------------------------- +[V4|Tlv5] = Tlv4, +Term4 = decode_octet_string(V4, [131075]), + +%%------------------------------------------------- +%% attribute outType(5) with type OCTET STRING +%%------------------------------------------------- +[V5|Tlv6] = Tlv5, +Term5 = decode_octet_string(V5, [131076]), + +case Tlv6 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv6}}}) % extra fields not allowed +end, +Res1 = {'TypeInfoV3',Term1,Term2,Term3,Term4,Term5}, +Res1. + +%%% +%%% Run-time functions. +%%% + +'dialyzer-suppressions'(Arg) -> + ok. + +ber_decode_nif(B) -> + asn1rt_nif:decode_ber_tlv(B). + +collect_parts(TlvList) -> + collect_parts(TlvList, []). + +collect_parts([{_, L} | Rest], Acc) when is_list(L) -> + collect_parts(Rest, [collect_parts(L) | Acc]); +collect_parts([{3, <>} | Rest], _Acc) -> + collect_parts_bit(Rest, [Bits], Unused); +collect_parts([{_T, V} | Rest], Acc) -> + collect_parts(Rest, [V | Acc]); +collect_parts([], Acc) -> + list_to_binary(lists:reverse(Acc)). + +collect_parts_bit([{3, <>} | Rest], Acc, Uacc) -> + collect_parts_bit(Rest, [Bits | Acc], Unused + Uacc); +collect_parts_bit([], Acc, Uacc) -> + list_to_binary([Uacc | lists:reverse(Acc)]). + +decode_boolean(Tlv, TagIn) -> + Val = match_tags(Tlv, TagIn), + case Val of + <<0:8>> -> + false; + <<_:8>> -> + true; + _ -> + exit({error, {asn1, {decode_boolean, Val}}}) + end. + +decode_integer(Tlv, TagIn) -> + Bin = match_tags(Tlv, TagIn), + Len = byte_size(Bin), + <> = Bin, + Int. + +decode_octet_string(Tlv, TagsIn) -> + Bin = match_and_collect(Tlv, TagsIn), + binary:copy(Bin). + +decode_restricted_string(Tlv, TagsIn) -> + match_and_collect(Tlv, TagsIn). + +encode_boolean(true, TagIn) -> + encode_tags(TagIn, [255], 1); +encode_boolean(false, TagIn) -> + encode_tags(TagIn, [0], 1); +encode_boolean(X, _) -> + exit({error, {asn1, {encode_boolean, X}}}). + +encode_integer(Val) -> + Bytes = + if + Val >= 0 -> + encode_integer_pos(Val, []); + true -> + encode_integer_neg(Val, []) + end, + {Bytes, length(Bytes)}. + +encode_integer(Val, Tag) when is_integer(Val) -> + encode_tags(Tag, encode_integer(Val)); +encode_integer(Val, _Tag) -> + exit({error, {asn1, {encode_integer, Val}}}). + +encode_integer_neg(-1, [B1 | _T] = L) when B1 > 127 -> + L; +encode_integer_neg(N, Acc) -> + encode_integer_neg(N bsr 8, [N band 255 | Acc]). + +encode_integer_pos(0, [B | _Acc] = L) when B < 128 -> + L; +encode_integer_pos(N, Acc) -> + encode_integer_pos(N bsr 8, [N band 255 | Acc]). + +encode_length(L) when L =< 127 -> + {[L], 1}; +encode_length(L) -> + Oct = minimum_octets(L), + Len = length(Oct), + if + Len =< 126 -> + {[128 bor Len | Oct], Len + 1}; + true -> + exit({error, {asn1, too_long_length_oct, Len}}) + end. + +encode_restricted_string(OctetList, TagIn) when is_binary(OctetList) -> + encode_tags(TagIn, OctetList, byte_size(OctetList)); +encode_restricted_string(OctetList, TagIn) when is_list(OctetList) -> + encode_tags(TagIn, OctetList, length(OctetList)). + +encode_tags(TagIn, {BytesSoFar, LenSoFar}) -> + encode_tags(TagIn, BytesSoFar, LenSoFar). + +encode_tags([Tag | Trest], BytesSoFar, LenSoFar) -> + {Bytes2, L2} = encode_length(LenSoFar), + encode_tags(Trest, + [Tag, Bytes2 | BytesSoFar], + LenSoFar + byte_size(Tag) + L2); +encode_tags([], BytesSoFar, LenSoFar) -> + {BytesSoFar, LenSoFar}. + +match_and_collect(Tlv, TagsIn) -> + Val = match_tags(Tlv, TagsIn), + case Val of + [_ | _] = PartList -> + collect_parts(PartList); + Bin when is_binary(Bin) -> + Bin + end. + +match_tags({T, V}, [T]) -> + V; +match_tags({T, V}, [T | Tt]) -> + match_tags(V, Tt); +match_tags([{T, V}], [T | Tt]) -> + match_tags(V, Tt); +match_tags([{T, _V} | _] = Vlist, [T]) -> + Vlist; +match_tags(Tlv, []) -> + Tlv; +match_tags({Tag, _V} = Tlv, [T | _Tt]) -> + exit({error, {asn1, {wrong_tag, {{expected, T}, {got, Tag, Tlv}}}}}). + +minimum_octets(0, Acc) -> + Acc; +minimum_octets(Val, Acc) -> + minimum_octets(Val bsr 8, [Val band 255 | Acc]). + +minimum_octets(Val) -> + minimum_octets(Val, []). diff --git a/asn1/GajumaruSerialization.hrl b/asn1/GajumaruSerialization.hrl new file mode 100644 index 0000000..4c5d52e --- /dev/null +++ b/asn1/GajumaruSerialization.hrl @@ -0,0 +1,76 @@ +%% Generated by the Erlang ASN.1 compiler. Version: 5.4.3 +%% Purpose: Erlang record definitions for each named and unnamed +%% SEQUENCE and SET, and macro definitions for each value +%% definition in module GajumaruSerialization. + +-ifndef(_GAJUMARUSERIALIZATION_HRL_). +-define(_GAJUMARUSERIALIZATION_HRL_, true). + +-record('GajumaruData', { + tag, + vsn, + content +}). + +-record('TemplateField', { + name = asn1_NOVALUE, + value +}). + +-record('KeyValue', { + key, + val +}). + +-record('Id', { + type, + value +}). + +-record('Account', { + foo, + bar +}). + +-record('SignedTx', { + signatures, + transaction +}). + +-record('ContractV1', { + sourceHash, + typeInfo, + byteCode +}). + +-record('ContractV2', { + sourceHash, + typeInfo, + byteCode, + compilerVersion +}). + +-record('ContractV3', { + sourceHash, + typeInfo, + byteCode, + compilerVersion, + payable +}). + +-record('TypeInfoV1', { + typeHash, + name, + argType, + outType +}). + +-record('TypeInfoV3', { + typeHash, + name, + payable, + argType, + outType +}). + +-endif. %% _GAJUMARUSERIALIZATION_HRL_ diff --git a/asn1/detect_demo.erl b/asn1/detect_demo.erl new file mode 100644 index 0000000..c938688 --- /dev/null +++ b/asn1/detect_demo.erl @@ -0,0 +1,27 @@ +-module(detect_demo). +-export([run/0]). + +run() -> + application:ensure_all_started(gmserialization), + code:add_path("asn1"), + + Sample = {'GajumaruData', 10, 1, + {templateFields, [ + {'TemplateField', <<"foo">>, {intValue, 42}}, + {'TemplateField', <<"bar">>, {binaryValue, <<"hello">>}} + ]}}, + + {ok, Der} = 'GajumaruSerialization':encode('GajumaruData', Sample), + io:format("DER first byte: ~p (0x~2.16.0B)~n", [binary:at(Der,0), binary:at(Der,0)]), + + {ok, _Dec} = 'GajumaruSerialization':decode('GajumaruData', Der), + io:format("DER roundtrip OK~n"), + + Legacy = gmser_chain_objects:serialize(account, 1, + [{foo,int},{bar,binary}], + [{foo,42},{bar,<<"hello">>}]), + <> = binary:part(Legacy,0,1), + <> = binary:part(Der,0,1), + io:format("Legacy 0x~2.16.0B (>= 0xC0 -> legacy: ~p)~n", [L0, L0 >= 16#C0]), + io:format("DER 0x~2.16.0B (< 0xC0 -> new DER: ~p)~n", [D0, D0 < 16#C0]), + ok. diff --git a/asn1/size_comparison.erl b/asn1/size_comparison.erl new file mode 100644 index 0000000..17d3969 --- /dev/null +++ b/asn1/size_comparison.erl @@ -0,0 +1,114 @@ +-module(size_comparison). +-export([run/0]). + +run() -> + application:ensure_all_started(gmserialization), + code:add_path("asn1"), + + io:format("=== Size Comparison: Legacy RLP vs DER ===~n~n"), + + Compare = fun(Desc, LegacyBin, DerBin) -> + L = byte_size(LegacyBin), + D = byte_size(DerBin), + Overhead = D - L, + Pct = case L of 0 -> 0; _ -> round(Overhead * 100 / L) end, + io:format("~s~n", [Desc]), + io:format(" Legacy: ~p bytes ~w~n", [L, LegacyBin]), + Show = binary:part(DerBin, 0, min(18, D)), + io:format(" DER: ~p bytes ~w~n", [D, Show]), + io:format(" Overhead: +~p bytes (~p%)~n~n", [Overhead, Pct]) + end, + + %% Case 1: tag+vsn + small int + small binary + T1 = [{foo,int},{bar,binary}], + V1 = [{foo,1},{bar,<<2>>}], + Leg1 = gmser_chain_objects:serialize(account, 1, T1, V1), + DerVal1 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"foo">>, {intValue, 1}}, + {'TemplateField', <<"bar">>, {binaryValue, <<2>>}} + ]}}, + {ok, Der1} = 'GajumaruSerialization':encode('GajumaruData', DerVal1), + Compare("Case 1: tag+vsn + small int + tiny binary (2 fields)", Leg1, Der1), + + %% Case 2: zero + empty binary + V2 = [{foo,0},{bar,<<>>}], + Leg2 = gmser_chain_objects:serialize(account, 1, T1, V2), + DerVal2 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"foo">>, {intValue, 0}}, + {'TemplateField', <<"bar">>, {binaryValue, <<>>}} + ]}}, + {ok, Der2} = 'GajumaruSerialization':encode('GajumaruData', DerVal2), + Compare("Case 2: zero int + empty binary", Leg2, Der2), + + %% Case 3: list of ints + T3 = [{xs,[int]}], + V3 = [{xs,[1,2,3]}], + Leg3 = gmser_chain_objects:serialize(account, 1, T3, V3), + DerVal3 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"xs">>, {listValue, [ + {intValue,1},{intValue,2},{intValue,3} + ]}} + ]}}, + {ok, Der3} = 'GajumaruSerialization':encode('GajumaruData', DerVal3), + Compare("Case 3: list of 3 small ints", Leg3, Der3), + + %% Case 4: tuple (int, binary) + T4 = [{p,{int,binary}}], + V4 = [{p,{42,<<"hi">>}}], + Leg4 = gmser_chain_objects:serialize(account, 1, T4, V4), + DerVal4 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"p">>, {tupleValue, [ + {intValue,42}, {binaryValue,<<"hi">>} + ]}} + ]}}, + {ok, Der4} = 'GajumaruSerialization':encode('GajumaruData', DerVal4), + Compare("Case 4: fixed tuple (int + 2-byte binary)", Leg4, Der4), + + %% Case 5: 256-byte payload + Bin5 = crypto:strong_rand_bytes(256), + T5 = [{data,binary}], + V5 = [{data,Bin5}], + Leg5 = gmser_chain_objects:serialize(account, 1, T5, V5), + DerVal5 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"data">>, {binaryValue, Bin5}} + ]}}, + {ok, Der5} = 'GajumaruSerialization':encode('GajumaruData', DerVal5), + Compare("Case 5: 256-byte binary payload only", Leg5, Der5), + + %% Case 6: Concrete SignedTx style (no field names in DER) + T6 = [{signatures,[binary]},{tx,binary}], + V6 = [{signatures,[<<"sig1">>,<<"sig2">>]},{tx,<<"txbody123">>}], + Leg6 = gmser_chain_objects:serialize(signed_tx, 1, T6, V6), + DerVal6 = {'GajumaruData', 11, 1, {signedTx, {'SignedTx', + [<<"sig1">>, <<"sig2">>], <<"txbody123">>}}}, + {ok, Der6} = 'GajumaruSerialization':encode('GajumaruData', DerVal6), + Compare("Case 6: SignedTx-like (concrete DER, no names)", Leg6, Der6), + + %% Case 7: 33-byte id-like value + IdBin = <<1, 0:256>>, + T7 = [{owner,binary}], + V7 = [{owner,IdBin}], + Leg7 = gmser_chain_objects:serialize(account, 1, T7, V7), + DerVal7 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"owner">>, {binaryValue, IdBin}} + ]}}, + {ok, Der7} = 'GajumaruSerialization':encode('GajumaruData', DerVal7), + Compare("Case 7: 33-byte value (id-like)", Leg7, Der7), + + %% Case 8: Deeper nesting / more fields + T8 = [{a,int},{b,binary},{c,[int]},{d,{int,int}}], + V8 = [{a,123456},{b,<<"abcdef">>},{c,[10,20,30]},{d,{7,8}}], + Leg8 = gmser_chain_objects:serialize(account, 1, T8, V8), + DerVal8 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"a">>, {intValue, 123456}}, + {'TemplateField', <<"b">>, {binaryValue, <<"abcdef">>}}, + {'TemplateField', <<"c">>, {listValue, [{intValue,10},{intValue,20},{intValue,30}]}}, + {'TemplateField', <<"d">>, {tupleValue, [{intValue,7},{intValue,8}]}} + ]}}, + {ok, Der8} = 'GajumaruSerialization':encode('GajumaruData', DerVal8), + Compare("Case 8: 4 fields mixed (int, bin, list, tuple)", Leg8, Der8), + + io:format("=== Analysis ===~n"), + io:format("Note: Generic templateFields path includes IA5String field names.~n"), + io:format("Concrete types (e.g. SignedTx) avoid name overhead.~n"), + ok. -- 2.30.2 From 9817af8a46e740e92706d904925f20c4a53e4e64 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Tue, 7 Jul 2026 10:48:30 +0200 Subject: [PATCH 10/11] Add thin ASN.1-driven RLP production layer + equivalence tests Implements gmser_asn1_rlp:encode/1 that accepts terms shaped according to the GajumaruSerialization.asn model (e.g. GajumaruData with templateFields or concrete CHOICEs like signedTx) and emits exactly the same RLP bytes as the legacy gmserialization + gmser_rlp stack. Purpose: - Use ASN.1 as a formal, multi-language friendly schema and type model. - Provide a thin, portable "production layer" that other languages can implement (ASN.1-generated types + equivalent RLP emitter). - Preserve the existing compact RLP wire format and on-the-wire equivalence (no DER bloat for the legacy path). The implementation walks the ASN.1-shaped value and applies the same encoding rules as gmserialization:encode_field/2 (minimal unsigned integers, positional values for static maps, etc.) followed by gmser_rlp:encode/1. Includes EUnit equivalence tests covering: - Simple fields, zero/empty values - Lists and tuples - List-of-tuples (e.g. type_info) - Concrete signedTx - ContractV3 (including bool in structured data) All tests assert byte-for-byte identity with legacy serialization and that the resulting bytes are still accepted by legacy decoders. This continues the proof-of-concept on the uw-asn1 branch. --- src/gmser_asn1_rlp.erl | 305 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 src/gmser_asn1_rlp.erl diff --git a/src/gmser_asn1_rlp.erl b/src/gmser_asn1_rlp.erl new file mode 100644 index 0000000..e8cbd15 --- /dev/null +++ b/src/gmser_asn1_rlp.erl @@ -0,0 +1,305 @@ +%%%------------------------------------------------------------------- +%%% @copyright (C) 2026, QPQ AG (experiment) +%%% @doc +%%% Thin RLP production layer driven by ASN.1-shaped values. +%%% +%%% This module implements a "thin translation" from structures that +%%% mirror the ASN.1 definitions in asn1/GajumaruSerialization.asn +%%% to the exact same RLP wire format produced by the legacy +%%% gmserialization + gmser_rlp + gmser_chain_objects stack. +%%% +%%% Goal: +%%% - Use ASN.1 as a formal, multi-language-friendly schema. +%%% - Keep the compact legacy RLP on the wire (no DER bloat). +%%% - Provide a reference implementation that other languages can +%%% port (types from ASN.1 compiler + this thin RLP emitter). +%%% +%%% The layer does NOT use the ASN.1 BER/DER codec at runtime for +%%% the wire format. It walks ASN.1-like Erlang terms and emits +%%% RLP using the same rules as gmserialization:encode_field/2 +%%% and gmser_rlp:encode/1. +%%% +%%% Supported shapes (matching the ASN.1 value notation): +%%% {'GajumaruData', Tag, Vsn, Content} +%%% Content is a CHOICE: +%%% {templateFields, [ {'TemplateField', Name, Value}, ... ]} +%%% {signedTx, {'SignedTx', Sigs, Tx}} +%%% {account, {'Account', Foo, Bar}} +%%% ... +%%% Value is one of: +%%% {intValue, integer()} +%%% {binaryValue, binary()} +%%% {boolValue, boolean()} +%%% {listValue, [Value]} +%%% {tupleValue, [Value]} % or tuple, both accepted +%%% {idValue, ...} % basic support +%%% +%%% For templateFields (used for generic/static equivalence), field +%%% *names* are ignored on the wire (matching legacy static behavior +%%% where only values are sent in template order). +%%% +%%% Equivalence with legacy is the primary contract of this module. +%%% @end +%%%------------------------------------------------------------------- + +-module(gmser_asn1_rlp). +-vsn("0.1.0-experiment"). + +-export([encode/1]). + +%% For tests and other-language ports, these helpers are useful +-export([encode_basic/2, + encode_asn1_value/1]). + +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. + +%%%=================================================================== +%%% API +%%%=================================================================== + +-spec encode(term()) -> binary(). +encode({'GajumaruData', Tag, Vsn, Content}) -> + TagB = encode_basic(int, Tag), + VsnB = encode_basic(int, Vsn), + Payload = encode_content(Content), + gmser_rlp:encode([TagB, VsnB | Payload]); +encode(Other) -> + error({unsupported_asn1_top_level, Other}). + +%%%=================================================================== +%%% Internal: content (the CHOICE after tag/vsn) +%%%=================================================================== + +encode_content({templateFields, FieldList}) when is_list(FieldList) -> + %% For wire compatibility with legacy static serialization we + %% emit only the values (in order). Names are not sent on the wire. + [encode_asn1_value(Val) || {_, _Name, Val} <- FieldList]; + +encode_content({signedTx, {'SignedTx', Sigs, Tx}}) -> + SigsEnc = [encode_basic(binary, S) || S <- Sigs], + TxEnc = encode_basic(binary, Tx), + [SigsEnc, TxEnc]; + +encode_content({account, {'Account', Foo, Bar}}) -> + [encode_basic(int, Foo), encode_basic(binary, Bar)]; + +encode_content({contract, Contract}) -> + encode_contract(Contract); + +encode_content(Other) -> + error({unsupported_content_choice, Other}). + +encode_contract({v1, {'ContractV1', Hash, TypeInfo, ByteCode}}) -> + [encode_basic(binary, Hash), + [encode_type_info_v1(TI) || TI <- TypeInfo], + encode_basic(binary, ByteCode)]; + +encode_contract({v2, {'ContractV2', Hash, TypeInfo, ByteCode, CompilerVsn}}) -> + [encode_basic(binary, Hash), + [encode_type_info_v1(TI) || TI <- TypeInfo], + encode_basic(binary, ByteCode), + encode_basic(binary, CompilerVsn)]; + +encode_contract({v3, {'ContractV3', Hash, TypeInfo, ByteCode, CompilerVsn, Payable}}) -> + [encode_basic(binary, Hash), + [encode_type_info_v3(TI) || TI <- TypeInfo], + encode_basic(binary, ByteCode), + encode_basic(binary, CompilerVsn), + encode_basic(bool, Payable)]. + +encode_type_info_v1({_TypeInfoV1, H, N, A, O}) -> + [encode_basic(binary, H), + encode_basic(binary, N), + encode_basic(binary, A), + encode_basic(binary, O)]; +encode_type_info_v1(T) when is_tuple(T), tuple_size(T) =:= 4 -> + %% Accept plain 4-tuple as well for convenience + [encode_basic(binary, element(I, T)) || I <- lists:seq(1,4)]. + +encode_type_info_v3({_TypeInfoV3, H, N, P, A, O}) -> + [encode_basic(binary, H), + encode_basic(binary, N), + encode_basic(bool, P), + encode_basic(binary, A), + encode_basic(binary, O)]; +encode_type_info_v3(T) when is_tuple(T), tuple_size(T) =:= 5 -> + %% TypeInfoV3 layout: binary, binary, bool, binary, binary + [encode_basic(binary, element(1,T)), + encode_basic(binary, element(2,T)), + encode_basic(bool, element(3,T)), + encode_basic(binary, element(4,T)), + encode_basic(binary, element(5,T))]. + +%%%=================================================================== +%%% Value encoding (recursive, mirrors ASN.1 Value CHOICE) +%%%=================================================================== + +-spec encode_asn1_value(term()) -> binary() | [term()]. +encode_asn1_value({intValue, I}) -> encode_basic(int, I); +encode_asn1_value({binaryValue, B}) -> encode_basic(binary, B); +encode_asn1_value({boolValue, B}) -> encode_basic(bool, B); +encode_asn1_value({listValue, L}) when is_list(L) -> + [encode_asn1_value(E) || E <- L]; +encode_asn1_value({tupleValue, T}) when is_list(T) -> + [encode_asn1_value(E) || E <- T]; +encode_asn1_value({tupleValue, T}) when is_tuple(T) -> + [encode_asn1_value(E) || E <- tuple_to_list(T)]; +encode_asn1_value({idValue, {'Id', Type, Val}}) -> + %% Basic support: encode as the legacy 33-byte id form if possible, + %% otherwise fall back to treating the value as binary. + try + Id = gmser_id:create(decode_id_tag(Type), Val), + gmser_id:encode(Id) + catch _:_ -> + encode_basic(binary, Val) + end; +encode_asn1_value({idValue, Bin}) when is_binary(Bin) -> + %% Convenience: bare 33-byte id value + encode_basic(binary, Bin); +encode_asn1_value(Other) -> + error({unsupported_asn1_value, Other}). + +decode_id_tag(1) -> account; +decode_id_tag(2) -> name; +decode_id_tag(3) -> commitment; +decode_id_tag(5) -> contract; +decode_id_tag(6) -> channel; +decode_id_tag(7) -> associate_chain; +decode_id_tag(8) -> native_token; +decode_id_tag(9) -> entry; +decode_id_tag(T) when is_integer(T) -> error({unknown_id_tag, T}). + +%%%=================================================================== +%%% Basic encoders matching gmserialization rules +%%%=================================================================== + +-spec encode_basic(atom(), term()) -> binary(). +encode_basic(int, X) when is_integer(X), X >= 0 -> + binary:encode_unsigned(X); +encode_basic(binary, X) when is_binary(X) -> + X; +encode_basic(bool, true) -> <<1:8>>; +encode_basic(bool, false) -> <<0:8>>; +encode_basic(id, Val) -> + try gmser_id:encode(Val) + catch _:_ -> error({illegal, id, Val}) + end; +encode_basic(Type, Val) -> + error({unsupported_basic_type, Type, Val}). + +%%%=================================================================== +%%% EUnit equivalence tests +%%%=================================================================== + +-ifdef(TEST). + +%% These tests assert that encoding an ASN.1-shaped value produces +%% *exactly* the same bytes as the legacy gmserialization stack. +%% This is the key property for a thin RLP production layer. + +equivalence_simple_fields_test() -> + T = [{foo, int}, {bar, binary}], + V = [{foo, 1}, {bar, <<2>>}], + Legacy = gmser_chain_objects:serialize(account, 1, T, V), + + Asn1 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"foo">>, {intValue, 1}}, + {'TemplateField', <<"bar">>, {binaryValue, <<2>>}} + ]}}, + New = encode(Asn1), + ?assertEqual(Legacy, New), + %% Also check we can roundtrip via legacy decoder + Dec = gmser_chain_objects:deserialize(account, 1, T, New), + ?assertEqual(V, Dec). + +equivalence_zero_and_empty_test() -> + T = [{foo, int}, {bar, binary}], + V = [{foo, 0}, {bar, <<>>}], + Legacy = gmser_chain_objects:serialize(account, 1, T, V), + + Asn1 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"foo">>, {intValue, 0}}, + {'TemplateField', <<"bar">>, {binaryValue, <<>>}} + ]}}, + ?assertEqual(Legacy, encode(Asn1)). + +equivalence_list_field_test() -> + T = [{xs, [int]}], + V = [{xs, [1,2,3]}], + Legacy = gmser_chain_objects:serialize(account, 1, T, V), + + Asn1 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"xs">>, {listValue, [ + {intValue, 1}, {intValue, 2}, {intValue, 3} + ]}} + ]}}, + ?assertEqual(Legacy, encode(Asn1)). + +equivalence_tuple_field_test() -> + T = [{p, {int, binary}}], + V = [{p, {42, <<"hi">>}}], + Legacy = gmser_chain_objects:serialize(account, 1, T, V), + + Asn1 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"p">>, {tupleValue, [ + {intValue, 42}, {binaryValue, <<"hi">>} + ]}} + ]}}, + ?assertEqual(Legacy, encode(Asn1)). + +equivalence_signed_tx_concrete_test() -> + T = [{signatures, [binary]}, {tx, binary}], + V = [{signatures, [<<"sig1">>, <<"sig2">>]}, {tx, <<"txbody123">>}], + Legacy = gmser_chain_objects:serialize(signed_tx, 1, T, V), + + Asn1 = {'GajumaruData', 11, 1, {signedTx, {'SignedTx', + [<<"sig1">>, <<"sig2">>], <<"txbody123">>}}}, + ?assertEqual(Legacy, encode(Asn1)). + +equivalence_list_of_tuples_test() -> + %% Corresponds to type_info style: list of 4-tuples + T = [{type_info, [{binary, binary, binary, binary}]}], + V = [{type_info, [ + {<<"h1">>, <<"n1">>, <<"a1">>, <<"o1">>}, + {<<"h2">>, <<"n2">>, <<"a2">>, <<"o2">>} + ]}], + Legacy = gmser_chain_objects:serialize(account, 1, T, V), + + Asn1 = {'GajumaruData', 10, 1, {templateFields, [ + {'TemplateField', <<"type_info">>, {listValue, [ + {tupleValue, [{binaryValue,<<"h1">>},{binaryValue,<<"n1">>}, + {binaryValue,<<"a1">>},{binaryValue,<<"o1">>}]}, + {tupleValue, [{binaryValue,<<"h2">>},{binaryValue,<<"n2">>}, + {binaryValue,<<"a2">>},{binaryValue,<<"o2">>}]} + ]}} + ]}}, + ?assertEqual(Legacy, encode(Asn1)). + +equivalence_contract_v3_test() -> + T = [ {source_hash, binary} + , {type_info, [{binary, binary, bool, binary, binary}]} + , {byte_code, binary} + , {compiler_version, binary} + , {payable, bool} + ], + TI = [{<<"h">>, <<"n">>, true, <<"a">>, <<"o">>}], + V = [ {source_hash, <<"hash">>} + , {type_info, TI} + , {byte_code, <<"code">>} + , {compiler_version, <<"vsn">>} + , {payable, true} + ], + Legacy = gmser_chain_objects:serialize(contract, 3, T, V), + + Asn1 = {'GajumaruData', 40, 3, {contract, {v3, {'ContractV3', + <<"hash">>, + [ {<<"h">>, <<"n">>, true, <<"a">>, <<"o">>} ], + <<"code">>, + <<"vsn">>, + true + }}}}, + ?assertEqual(Legacy, encode(Asn1)). + +-endif. -- 2.30.2 From 403613347631b0b2b0b12b40ecd5692d3d4ecf83 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Wed, 8 Jul 2026 10:53:31 +0200 Subject: [PATCH 11/11] Updated asn1 experiment, now exploring PER and OER --- asn1/FINDINGS.md | 212 +++ asn1/GajumaruSerialization.asn | 102 +- asn1_compact/GajumaruSerialization.asn | 267 +++ asn1_compact/GajumaruSerialization.asn1db | Bin 0 -> 17742 bytes asn1_compact/GajumaruSerialization.erl | 1879 +++++++++++++++++++ asn1_compact/GajumaruSerialization.hrl | 82 + asn1_oer/GajumaruSerialization.asn | 247 +++ asn1_oer/GajumaruSerialization.asn1db | Bin 0 -> 16610 bytes asn1_oer/GajumaruSerialization.erl | 1540 +++++++++++++++ asn1_oer/GajumaruSerialization.hrl | 82 + asn1_optimized/GajumaruSerialization.asn | 235 +++ asn1_optimized/GajumaruSerialization.asn1db | Bin 0 -> 15985 bytes asn1_optimized/GajumaruSerialization.erl | 1684 +++++++++++++++++ asn1_optimized/GajumaruSerialization.hrl | 76 + asn1_per/GajumaruSerialization.asn | 225 +++ asn1_per/GajumaruSerialization.asn1db | Bin 0 -> 15532 bytes asn1_per/GajumaruSerialization.erl | 1750 +++++++++++++++++ asn1_per/GajumaruSerialization.hrl | 76 + asn1_uper/GajumaruSerialization.asn | 225 +++ asn1_uper/GajumaruSerialization.asn1db | Bin 0 -> 15533 bytes asn1_uper/GajumaruSerialization.erl | 1641 ++++++++++++++++ asn1_uper/GajumaruSerialization.hrl | 76 + doc/asn1_compact.md | 70 + doc/static.md | 3 +- src/gmser_asn1_rlp.erl | 24 +- src/gmserialization.erl | 42 +- 26 files changed, 10499 insertions(+), 39 deletions(-) create mode 100644 asn1/FINDINGS.md create mode 100644 asn1_compact/GajumaruSerialization.asn create mode 100644 asn1_compact/GajumaruSerialization.asn1db create mode 100644 asn1_compact/GajumaruSerialization.erl create mode 100644 asn1_compact/GajumaruSerialization.hrl create mode 100644 asn1_oer/GajumaruSerialization.asn create mode 100644 asn1_oer/GajumaruSerialization.asn1db create mode 100644 asn1_oer/GajumaruSerialization.erl create mode 100644 asn1_oer/GajumaruSerialization.hrl create mode 100644 asn1_optimized/GajumaruSerialization.asn create mode 100644 asn1_optimized/GajumaruSerialization.asn1db create mode 100644 asn1_optimized/GajumaruSerialization.erl create mode 100644 asn1_optimized/GajumaruSerialization.hrl create mode 100644 asn1_per/GajumaruSerialization.asn create mode 100644 asn1_per/GajumaruSerialization.asn1db create mode 100644 asn1_per/GajumaruSerialization.erl create mode 100644 asn1_per/GajumaruSerialization.hrl create mode 100644 asn1_uper/GajumaruSerialization.asn create mode 100644 asn1_uper/GajumaruSerialization.asn1db create mode 100644 asn1_uper/GajumaruSerialization.erl create mode 100644 asn1_uper/GajumaruSerialization.hrl create mode 100644 doc/asn1_compact.md diff --git a/asn1/FINDINGS.md b/asn1/FINDINGS.md new file mode 100644 index 0000000..2049479 --- /dev/null +++ b/asn1/FINDINGS.md @@ -0,0 +1,212 @@ +# ASN.1 for gmserialization Static Encoding - Findings Diary + +This is a living diary documenting the investigation into using ASN.1 for the **static** serialization path (based on existing `gmserialization` templates in `gmserialization.erl` and `gmser_chain_objects.erl`). Dynamic encoding is out of scope. + +Focus areas: +- Modeling static templates with ASN.1 (portability goal). +- Generating the most compact stable/deterministic wire format possible using *portable ASN.1 techniques* (UPER etc.). +- Determinism for blockchain hashing (idempotent: same logical value always produces identical bytes). +- (Deferred) Legacy RLP compatibility via a model-to-RLP translation layer (see `src/gmser_asn1_rlp.erl`). + +The single source of truth is the ASN.1 schema in `GajumaruSerialization.asn`. + +--- + +## 2026-07-08 - Setup and Initial Schema + +- Schema (`asn1/GajumaruSerialization.asn`) models: + - `GajumaruData` as top-level (tag + vsn + content). + - `Content` CHOICE with `templateFields` (generic) and concrete types (e.g. `SignedTx`, `ContractV*`). + - `StaticFields` (SEQUENCE OF Value) for name-less positional encoding (matches legacy static behavior where field names are never on the wire). + - `Value` CHOICE for primitives and compounds (`intValue`, `binaryValue`, `listValue`, `tupleValue`, etc.). + - Supports all static template types: `int`, `bool`, `binary`, `id`, `[T]`, tuples, `#{items => [...]}`. + +- Initial schema comments were DER-oriented (migration path). Updated to emphasize compact UPER + portability. + +- Generated artifacts in `asn1/` (DER/ber) and `asn1_per/`, `asn1_compact/` (PER/UPER variants). + +- Key files: + - `asn1/GajumaruSerialization.asn` (source) + - `src/gmser_asn1_rlp.erl` (reference model-to-value mapping + legacy RLP emitter; value shapes match ASN.1) + - Tests in `test/gmser_chain_objects_tests.erl` and inside `gmser_asn1_rlp` for equivalence. + +## 2026-07-08 - Compact Encoding Experiments (UPER) + +Goal: most compact *stable* wire using standard portable ASN.1 (not custom non-portable rules, not RLP). + +- Tried standard DER → too verbose (tiny case: ~36 bytes vs legacy RLP 5 bytes). +- Switched to **UPER (Unaligned PER)** — the most compact *standard* ASN.1 encoding rule with good canonical/deterministic properties. + - Compiled via `asn1ct:compile(..., [uper])`. + - Uses schema knowledge: omits redundant tags/lengths, bit-packing, constrained integers, etc. + - Deterministic for this schema (no EXTENSIBILITY markers, fixed ordering, no optional extensibility). + +- Schema optimizations for compactness: + - Added `CompactStatic` top-level type (avoids extra Content CHOICE tag overhead for common static path). + - `staticFields` (pure `SEQUENCE OF Value`) — no IA5String names on wire. + - Constrained `tag`/`vsn` (INTEGER (0..65535), (0..255)) for better packing. + - Prefer concrete SEQUENCES (e.g. `SignedTx`) or `staticFields` over generic `templateFields` (names add cost). + - Kept `TemplateFields` for debug/transition only. + +- Size results (using `CompactStatic` + `staticFields` where appropriate): + + | Case | Legacy RLP | UPER (optimized) | Delta | Notes | + |-----------------------------|------------|------------------|----------|-------| + | tiny (tag/vsn + int + 1B bin) | 5 B | 9 B | +4 B | Big improvement vs DER | + | list of 3 ints | 7 B | 13 B | +6 B | — | + | tuple (int + bin) | 8 B | 12 B | +4 B | — | + | signed_tx-like (concrete) | 7–24 B | 11–14 B | small | Concrete helps | + | 256-byte payload | 264 B | 263 B | -1 B | Matches or beats RLP | + | contract v3 (complex) | ~18–20 B | ~25–35 B (generic); better w/ concrete | — | Structural overhead on complex nested | + +- UPER is stable: encode → decode → re-encode produces identical bytes. Roundtrips work. + +- For large payloads, UPER is excellent (schema knowledge eliminates most RLP-style list prefixes). For tiny objects, RLP's prefix trick is hard to beat, but the gap is acceptable for portability. + +- OER (Octet Encoding Rules) also compiled but was larger (18 B on tiny case). + +## 2026-07-08 - Portability & Stability Takeaways + +- The schema + UPER is fully portable. Other languages can: + 1. Compile the `.asn` with their ASN.1 tool. + 2. Build a value matching `CompactStatic` / `staticFields` / concrete types. + 3. Call their UPER encoder → identical compact bytes. + +- No Erlang-specific runtime required for the new wire format. +- Determinism comes from: + - UPER canonical packing rules. + - Constrained types in schema. + - Explicit staticFields (no map iteration, names omitted). + - Same rules as legacy for ints (minimal), ordering, etc. + +- This directly models the existing static templates (see `serialization_template/1` functions and `gmserialization:encode_field/2` logic). +- Concrete types in schema give best compactness for known objects. +- Generic `staticFields` covers *any* template without defining every object. + +## Next Steps / Open Questions (Diary Entries) + +- [ ] Add more concrete types from `gmser_chain_objects` (many tags) to reduce generic overhead. +- [ ] Add more ASN.1 constraints (SIZE, value ranges) to help PER pack tighter. +- [ ] Measure on real on-chain objects (key_block, etc.). +- [ ] Decide on top-level header for the new format (keep tag/vsn?). +- [ ] (Deferred) How the same model can feed the RLP layer for legacy compat without losing compactness on new path. +- [ ] Consider if a custom "ASN.1-inspired" rule set (still schema-driven) could close the remaining gap to RLP on tiny objects while staying portable. + +## 2026-07-08 - Schema Updated for Bignums + +- Updated `GajumaruSerialization.asn`: + - Introduced `BigInt ::= INTEGER (0..MAX)` as the representation for the traditional `int` (used for Pucks amounts up to 10^30). + - `Value` CHOICE now uses `bigIntValue` for the bignum case. + - Added `uint64Value`, `uint32Value`, `uint128Value` as future template types (with corresponding ASN.1 subtypes). + - Updated header comments to document the bignum nature of `int`. + +- This change keeps the model honest about real usage while opening the door to much more compact encodings for the many fields that actually fit in 64 or 128 bits. + +- Next: We should extend the Erlang-side `type()` in `gmserialization.erl` and the encode/decode logic to recognize the new smaller integer types so that templates can start using them. + +--- + +*This file should be kept as a living diary. Append new dated sections with findings, size data, schema changes, and decisions as the investigation progresses.* + +## 2026-07-08 - Handling of `int` as Bignums (Pucks, amounts, etc.) + +Important clarification from domain: + +- In practice, the `int` type in static templates is frequently used for **large bignums**. +- Example: Amount fields (balances, transaction amounts, etc.) are denominated in "Pucks". +- Maximum value mentioned: 1 × 10^30. +- This is ~ 2^99.66, i.e., requires up to ~13 bytes in minimal unsigned encoding. + +Current legacy handling (in `gmserialization.erl`): +```erlang +encode_field(int, X) when is_integer(X), X >= 0 -> + binary:encode_unsigned(X); +``` +This produces minimal big-endian unsigned with no leading zero byte (except for the value 0). + +Implications for ASN.1 model: + +- We should **keep `int` / `intValue` modeled as an unbounded non-negative integer** (bignum): + ```asn1 + BigInt ::= INTEGER (0..MAX) + ``` + (or simply `INTEGER` with documentation that it is used for non-negative bignums). + +- Plain `INTEGER` in UPER will encode large positive values reasonably (length + content), but we must ensure the encoding rules we choose remain fully deterministic. + +- To allow more compact encodings where ranges are known, we should introduce **new template types** for smaller integers: + Suggested new `type()` variants in the Erlang template language: + - `uint64` -- 0 .. 2^64-1 + - `uint32` -- 0 .. 2^32-1 + - `uint16`, `uint8`, `uint128` etc. as needed + - Possibly signed variants if ever required (currently everything seems non-negative). + + Corresponding in ASN.1 (inside Value CHOICE or as reusable types): + ```asn1 + Uint64 ::= INTEGER (0..18446744073709551615) + Uint32 ::= INTEGER (0..4294967295) + Uint128 ::= INTEGER (0..340282366920938463463374607431768211455) + ``` + +- In the schema's Value CHOICE we can evolve to: + ```asn1 + Value ::= CHOICE { + bigIntValue [0] BigInt, -- the classic "int" for Pucks etc. + uint64Value [7] Uint64, + uint32Value [8] Uint32, + ... + -- keep backward-compatible intValue alias if needed during transition + } + ``` + +- Benefits for compactness: + - Constrained `Uint64` etc. allow UPER to use fixed-width or minimal-bit encoding (often 8 bytes for uint64 instead of length+data). + - Still fully portable and deterministic. + +- Impact on existing templates: + - Most amount-related fields should eventually be annotated as `uint128` or a `BigInt` alias rather than plain `int`. + - Small counters, versions, indices can use `uint32` / `uint64`. + - This may require extending the `type()` in `gmserialization.erl` and the encoders. + +## 2026-07-08 - Updated gmserialization source + +- Extended `type()` in `src/gmserialization.erl` with `uint128`, `uint64`, `uint32`, `uint16`, `uint8` (keeping `int` for bignums). +- Added corresponding clauses in `encode_field/2` and `decode_field/2` with range checks for the fixed-size ones. +- Updated `src/gmser_asn1_rlp.erl` (the experimental layer) to recognize the new value tags (`uint*Value`, `bigIntValue`) and updated one test case to use `uint32`. +- Updated `doc/static.md` example types. +- `int` remains fully backward compatible for bignum use. +- All existing tests + new type usage pass. + +- In the legacy RLP translation layer: + - `bigIntValue` would continue to use `binary:encode_unsigned/1`. + - Smaller uint types can use the same (or optimized fixed-length if desired for new format). + +Next action items: +- Update `GajumaruSerialization.asn` to introduce `BigInt`, `Uint*` types and adjust Value. +- Decide on naming in the Erlang template DSL (`int` remains bignum alias? or rename?). +- Add example in the schema for a balance field. +- Re-measure UPER sizes when using constrained uint types on amount fields (should improve small/medium amounts). + +This is an important modeling decision that affects both compactness and correctness for real on-chain data. + +## 2026-07-08 - Source Update Completed & Verified + +- Performed the source changes in `src/gmserialization.erl`: + - Extended `-type type()` to include `'uint128' | 'uint64' | 'uint32' | 'uint16' | 'uint8'` while retaining `'int'` for bignums. + - Implemented `encode_field/2` and `decode_field/2` handlers for the new types (range-checked for fixed-width, falling back to the same minimal unsigned encoding as `int` for RLP compatibility). +- Synced `src/gmser_asn1_rlp.erl`: + - Added support for new ASN.1 value variants (`{uint*Value, ...}`, `{bigIntValue, ...}`) in `encode_asn1_value/1`. + - Updated test data and comments to use the new types. +- Updated `doc/static.md` to reflect the extended type language. +- Verified: + - Legacy templates using `int` continue to work unchanged. + - New types (e.g. `{small, uint32}, {big, int}`) serialize/deserialize correctly via the legacy RLP path. + - All 7 equivalence tests in `gmser_asn1_rlp` still pass. + - `gmser_chain_objects_tests` (12 tests) still pass. +- The ASN.1 schema (updated earlier) now has matching `BigInt` + `Uint*` types, so the model and implementation are in sync for the compact UPER path. + +The complementary integer types are now part of the experimental static template system. This enables the ASN.1 UPER encoder to use tighter, schema-constrained encodings for smaller values while keeping full bignum support for amounts. + +Next diary items (still open): +- Extend more concrete types in the schema. +- Add actual UPER-based encode path in the library (beyond the RLP layer). +- Measure size savings on real amount-heavy objects using uint128 vs plain int. \ No newline at end of file diff --git a/asn1/GajumaruSerialization.asn b/asn1/GajumaruSerialization.asn index 43607e9..00ea8a0 100644 --- a/asn1/GajumaruSerialization.asn +++ b/asn1/GajumaruSerialization.asn @@ -4,8 +4,13 @@ -- (the layer on top of RLP). -- -- Purpose: --- * Provide a formal, toolable description of the data. --- * Enable migration from the legacy RLP-based format to DER. +-- * Provide a formal, toolable description of the data for portability +-- (other languages use ASN.1 compilers to get types/parsers). +-- * Define compact canonical wire format using standard ASN.1 techniques +-- (primarily Unaligned PER / UPER with constraints for packing). +-- * Static encoding only (templates from gmserialization). +-- * Legacy RLP compatibility is achieved via separate translation layer +-- (deferred in current focus). -- -- Detection of legacy vs new: -- Legacy data (produced by gmserialization:serialize / gmser_chain_objects:serialize @@ -17,15 +22,21 @@ -- top-level SEQUENCE we define). 0x30 < 0xC0, so a single-byte prefix -- check reliably distinguishes the two formats. -- --- Usage in Erlang (after compiling with asn1ct): --- {ok, Mod} = asn1ct:compile(GajumaruSerialization.asn, [ber, der]). --- {ok, Term} = 'GajumaruSerialization':decode('GajumaruData', DerBinary). +-- Usage in Erlang (after compiling with asn1ct for compact wire): +-- {ok, Mod} = asn1ct:compile(GajumaruSerialization.asn, [uper]). +-- {ok, Bytes} = 'GajumaruSerialization':encode('GajumaruData', Asn1Value). +-- Bytes is the compact UPER wire format (deterministic with this schema). +-- For legacy RLP, use the model-to-RLP layer instead (see gmser_asn1_rlp). -- --- Notes on type mapping from gmserialization.erl: --- - int -> INTEGER (new data uses canonical DER INTEGER) +-- Notes on type mapping from gmserialization.erl (static templates): +-- - int (bignum) -> BigInt ::= INTEGER (0..MAX) +-- In practice used for amounts/balances in Pucks (up to 1*10^30). +-- Encoded as non-negative bignum. +-- - New smaller integer types will be added to templates (uint64, uint32, ...) +-- for cases where range is known → enables tighter UPER packing. -- - binary -> OCTET STRING -- - bool -> BOOLEAN --- - id -> Id (SEQUENCE) (cleaner than the legacy packed 33-byte form) +-- - id -> Id (SEQUENCE) -- - [T] -> SEQUENCE OF T -- - {T1,...} -> SEQUENCE (fixed-size, order matters) -- - #{items := [{K,T},...]} -> SEQUENCE with the fields in template order @@ -33,9 +44,6 @@ -- - tag + vsn are preserved as the first two fields for compatibility -- with existing dispatch logic. -- --- Legacy integers had strict unsigned-minimal no-leading-zero (except for 0) --- and RLP-level rules. New DER data does not need to follow those rules. --- -- WARNING: -- Any cryptographic hash or signature computed over a serialized object -- will change when switching from RLP to DER for that object. Plan a @@ -53,11 +61,20 @@ EXPORTS ALL; -- ============================================================ GajumaruData ::= SEQUENCE { - tag INTEGER, - vsn INTEGER, + -- Constrained for better PER packing + tag INTEGER (0..65535), + vsn INTEGER (0..255), content Content } +-- Preferred top-level for the compact static wire format. +-- Avoids the extra Content CHOICE tag when the structure is known to be static. +CompactStatic ::= SEQUENCE { + tag INTEGER (0..65535), + vsn INTEGER (0..255), + fields StaticFields +} + -- Content can be a specific structured type (preferred) or a generic -- representation of a template-driven object. Content ::= CHOICE { @@ -65,6 +82,10 @@ Content ::= CHOICE { -- without having a pre-defined SEQUENCE for every object. templateFields [0] TemplateFields, + -- Static-optimized: no field names on wire (matches legacy static behavior exactly) + -- Preferred for compact wire format of known templates. + staticFields [10] StaticFields, + -- Examples of concrete versioned types (extend as needed) account [1] Account, signedTx [2] SignedTx, @@ -87,17 +108,41 @@ TemplateField ::= SEQUENCE { value Value } +-- Optimized for static wire format: just the values in order, no names. +-- This matches the legacy static encoding where maps/records are positional only. +StaticFields ::= SEQUENCE OF Value + + Value ::= CHOICE { - intValue [0] INTEGER, + -- "int" in static templates is used for bignums in practice + -- (e.g. balances and amounts in Pucks, up to 1*10^30). + -- We keep it as unbounded non-negative integer. + bigIntValue [0] BigInt, + boolValue [1] BOOLEAN, binaryValue [2] OCTET STRING, idValue [3] Id, listValue [4] SEQUENCE OF Value, tupleValue [5] SEQUENCE OF Value, - mapValue [6] SEQUENCE OF KeyValue -- only needed if you want to - -- represent dynamic-style maps + mapValue [6] SEQUENCE OF KeyValue, -- only needed if you want to + -- represent dynamic-style maps + + -- Additional integer types for smaller ranges (future use in templates + -- for better UPER packing when the range is known). + uint64Value [7] Uint64, + uint32Value [8] Uint32, + uint128Value [9] Uint128 } +-- Bignum integer (non-negative). Used for the traditional "int" in static +-- templates. Max practical value mentioned: 1*10^30 (≈ 2^100 bits). +BigInt ::= INTEGER (0..MAX) + +-- Convenience sized unsigned integer types. +Uint64 ::= INTEGER (0..18446744073709551615) +Uint32 ::= INTEGER (0..4294967295) +Uint128 ::= INTEGER (0..340282366920938463463374607431768211455) + KeyValue ::= SEQUENCE { key Value, val Value @@ -203,23 +248,20 @@ TypeInfoV3 ::= SEQUENCE { -- always falling back to TemplateFields. This gives you better -- validation and generated types. -- --- 3. INTEGER in DER is signed and uses a different minimal encoding --- than the legacy unsigned big-endian no leading zero form. This is --- fine for new data. +-- 3. For the compact wire format we use UPER (unaligned PER). +-- It is stable/deterministic for a given schema (no extensibility +-- markers on these types, fixed order). -- --- 4. If you need to preserve exact legacy integer wire bytes inside --- the new format (e.g. for some hash preimage reason), you can --- carry selected integers as OCTET STRING (legacy unsigned minimal bytes). +-- 4. INTEGER uses ASN.1 PER encoding (canonical for the constraints). +-- This may differ from legacy RLP minimal unsigned; new format +-- will have different hashes (expected when introducing new encoding). -- --- 5. Dynamic encoding (gmser_dyn) is intentionally not modeled here --- in full, because it is runtime-schema driven (type codes 246-255, --- labels, alt/switch, etc.). You can still use the generic --- TemplateFields + Value for some dynamic cases, or model specific --- message schemas as additional CHOICE arms. +-- 5. Dynamic encoding (gmser_dyn) is not in scope here. -- --- 6. Compile with DER for canonical output: --- asn1ct:compile(GajumaruSerialization, [der]). +-- 6. To generate the compact wire: +-- asn1ct:compile(GajumaruSerialization, [uper]). +-- {ok, CompactBytes} = 'GajumaruSerialization':encode('GajumaruData', Value). -- --- The ber option is also accepted; der implies the stricter rules. +-- Use staticFields (not templateFields) for best compactness on static data. END diff --git a/asn1_compact/GajumaruSerialization.asn b/asn1_compact/GajumaruSerialization.asn new file mode 100644 index 0000000..00ea8a0 --- /dev/null +++ b/asn1_compact/GajumaruSerialization.asn @@ -0,0 +1,267 @@ +-- GajumaruSerialization.asn +-- +-- ASN.1 model for the structures serialized by gmserialization.erl +-- (the layer on top of RLP). +-- +-- Purpose: +-- * Provide a formal, toolable description of the data for portability +-- (other languages use ASN.1 compilers to get types/parsers). +-- * Define compact canonical wire format using standard ASN.1 techniques +-- (primarily Unaligned PER / UPER with constraints for packing). +-- * Static encoding only (templates from gmserialization). +-- * Legacy RLP compatibility is achieved via separate translation layer +-- (deferred in current focus). +-- +-- Detection of legacy vs new: +-- Legacy data (produced by gmserialization:serialize / gmser_chain_objects:serialize +-- or gmser_dyn:serialize) is always an RLP *list* at the top level. +-- This means the first byte is in the range 0xC0 .. 0xFF. +-- +-- DER-encoded data using the types below will start with 0x30 (SEQUENCE, +-- constructed, universal tag) for the outermost GajumaruData (or any +-- top-level SEQUENCE we define). 0x30 < 0xC0, so a single-byte prefix +-- check reliably distinguishes the two formats. +-- +-- Usage in Erlang (after compiling with asn1ct for compact wire): +-- {ok, Mod} = asn1ct:compile(GajumaruSerialization.asn, [uper]). +-- {ok, Bytes} = 'GajumaruSerialization':encode('GajumaruData', Asn1Value). +-- Bytes is the compact UPER wire format (deterministic with this schema). +-- For legacy RLP, use the model-to-RLP layer instead (see gmser_asn1_rlp). +-- +-- Notes on type mapping from gmserialization.erl (static templates): +-- - int (bignum) -> BigInt ::= INTEGER (0..MAX) +-- In practice used for amounts/balances in Pucks (up to 1*10^30). +-- Encoded as non-negative bignum. +-- - New smaller integer types will be added to templates (uint64, uint32, ...) +-- for cases where range is known → enables tighter UPER packing. +-- - binary -> OCTET STRING +-- - bool -> BOOLEAN +-- - id -> Id (SEQUENCE) +-- - [T] -> SEQUENCE OF T +-- - {T1,...} -> SEQUENCE (fixed-size, order matters) +-- - #{items := [{K,T},...]} -> SEQUENCE with the fields in template order +-- (static maps carry *values only*, no keys on the wire) +-- - tag + vsn are preserved as the first two fields for compatibility +-- with existing dispatch logic. +-- +-- WARNING: +-- Any cryptographic hash or signature computed over a serialized object +-- will change when switching from RLP to DER for that object. Plan a +-- coordinated upgrade. + +GajumaruSerialization DEFINITIONS + AUTOMATIC TAGS ::= +BEGIN + +EXPORTS ALL; + +-- ============================================================ +-- Top-level wrapper used for new DER data. +-- This is what a decoder will see first. +-- ============================================================ + +GajumaruData ::= SEQUENCE { + -- Constrained for better PER packing + tag INTEGER (0..65535), + vsn INTEGER (0..255), + content Content +} + +-- Preferred top-level for the compact static wire format. +-- Avoids the extra Content CHOICE tag when the structure is known to be static. +CompactStatic ::= SEQUENCE { + tag INTEGER (0..65535), + vsn INTEGER (0..255), + fields StaticFields +} + +-- Content can be a specific structured type (preferred) or a generic +-- representation of a template-driven object. +Content ::= CHOICE { + -- Generic fallback that can represent any [{Field, Type}] template + -- without having a pre-defined SEQUENCE for every object. + templateFields [0] TemplateFields, + + -- Static-optimized: no field names on wire (matches legacy static behavior exactly) + -- Preferred for compact wire format of known templates. + staticFields [10] StaticFields, + + -- Examples of concrete versioned types (extend as needed) + account [1] Account, + signedTx [2] SignedTx, + contract [3] ContractCode + -- Add more alternatives for other tags from gmser_chain_objects +} + +-- ============================================================ +-- Generic template-driven representation +-- (useful during transition or for unregistered types) +-- ============================================================ + +TemplateFields ::= SEQUENCE OF TemplateField + +TemplateField ::= SEQUENCE { + -- Field name is included for debuggability / generic processing. + -- In the original static encoding the name is NOT on the wire; + -- only position and type matter. We include it here for convenience. + name IA5String OPTIONAL, + value Value +} + +-- Optimized for static wire format: just the values in order, no names. +-- This matches the legacy static encoding where maps/records are positional only. +StaticFields ::= SEQUENCE OF Value + + +Value ::= CHOICE { + -- "int" in static templates is used for bignums in practice + -- (e.g. balances and amounts in Pucks, up to 1*10^30). + -- We keep it as unbounded non-negative integer. + bigIntValue [0] BigInt, + + boolValue [1] BOOLEAN, + binaryValue [2] OCTET STRING, + idValue [3] Id, + listValue [4] SEQUENCE OF Value, + tupleValue [5] SEQUENCE OF Value, + mapValue [6] SEQUENCE OF KeyValue, -- only needed if you want to + -- represent dynamic-style maps + + -- Additional integer types for smaller ranges (future use in templates + -- for better UPER packing when the range is known). + uint64Value [7] Uint64, + uint32Value [8] Uint32, + uint128Value [9] Uint128 +} + +-- Bignum integer (non-negative). Used for the traditional "int" in static +-- templates. Max practical value mentioned: 1*10^30 (≈ 2^100 bits). +BigInt ::= INTEGER (0..MAX) + +-- Convenience sized unsigned integer types. +Uint64 ::= INTEGER (0..18446744073709551615) +Uint32 ::= INTEGER (0..4294967295) +Uint128 ::= INTEGER (0..340282366920938463463374607431768211455) + +KeyValue ::= SEQUENCE { + key Value, + val Value +} + +-- ============================================================ +-- Common types +-- ============================================================ + +Id ::= SEQUENCE { + -- Corresponds to the simple tags in gmser_id (account=1, name=2, etc.) + -- and the extended account subtype (high bit in legacy). + type INTEGER (0..255), + value OCTET STRING (SIZE (32)) +} + +-- ============================================================ +-- Concrete object examples (derived from usage in the codebase) +-- Add / evolve per version as you introduce new vsns. +-- ============================================================ + +-- Example: a very simple account-like object used in tests +Account ::= SEQUENCE { + foo INTEGER, + bar OCTET STRING +} + +-- Simplified signed transaction +SignedTx ::= SEQUENCE { + signatures SEQUENCE OF OCTET STRING, + transaction OCTET STRING +} + +-- Contract code objects (see gmser_contract_code.erl) +-- We model the three versions that exist today. +ContractCode ::= CHOICE { + v1 [0] ContractV1, + v2 [1] ContractV2, + v3 [2] ContractV3 +} + +ContractV1 ::= SEQUENCE { + sourceHash OCTET STRING, + -- typeInfo is a list of 4-tuples in legacy: + -- {typeHash, name, argType, outType} + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING +} + +ContractV2 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING, + compilerVersion OCTET STRING +} + +ContractV3 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV3, + byteCode OCTET STRING, + compilerVersion OCTET STRING, + payable BOOLEAN +} + +TypeInfoV1 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + argType OCTET STRING, + outType OCTET STRING +} + +TypeInfoV3 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + payable BOOLEAN, + argType OCTET STRING, + outType OCTET STRING +} + +-- ============================================================ +-- Notes for implementers +-- ============================================================ +-- 1. Detection (recommended decoder entry point): +-- +-- decode(Binary) -> +-- case Binary of +-- <> when B >= 16#C0 -> +-- decode_legacy_rlp(Binary); % existing gmser_* path +-- _ -> +-- {ok, Term} = +-- 'GajumaruSerialization':decode('GajumaruData', Binary), +-- Term +-- end. +-- +-- This works because: +-- - All current top-level output from serialize() is an RLP list +-- (first byte 0xC0-0xFF). +-- - GajumaruData and the concrete choices above are SEQUENCEs +-- (first byte 0x30 for short form, or 0x30 0x81/0x82... for long). +-- +-- 2. When you add a new object type or version, prefer adding a +-- concrete SEQUENCE alternative in the Content CHOICE rather than +-- always falling back to TemplateFields. This gives you better +-- validation and generated types. +-- +-- 3. For the compact wire format we use UPER (unaligned PER). +-- It is stable/deterministic for a given schema (no extensibility +-- markers on these types, fixed order). +-- +-- 4. INTEGER uses ASN.1 PER encoding (canonical for the constraints). +-- This may differ from legacy RLP minimal unsigned; new format +-- will have different hashes (expected when introducing new encoding). +-- +-- 5. Dynamic encoding (gmser_dyn) is not in scope here. +-- +-- 6. To generate the compact wire: +-- asn1ct:compile(GajumaruSerialization, [uper]). +-- {ok, CompactBytes} = 'GajumaruSerialization':encode('GajumaruData', Value). +-- +-- Use staticFields (not templateFields) for best compactness on static data. + +END diff --git a/asn1_compact/GajumaruSerialization.asn1db b/asn1_compact/GajumaruSerialization.asn1db new file mode 100644 index 0000000000000000000000000000000000000000..27599d33a64c98a7f25c7e58c074718cf9f605ed GIT binary patch literal 17742 zcmeHPTWlOx8Q%NNcH%Y)NC+hJisVYRQ^XUnUQd#3>|NtsJ5Ex`9Pb|6vsur$GqX8% zFNqM87bJ>k-;k(y10*glw3P}f5^X`GP^nxbu7U?%k>H6J6#g@_XXebznKQG#Mktn= zI(yE}`TqNV{{Nq(Gud2ceQ7L}O24{!eX;t*oyT`FB%^k3rm|#0(>1+|Kdb3Gx@o28 zPxk)5)Vrzl=l}ERHQ4u|F79B>GEiTA7I!x~`arX=VUqk7>YErgOd1%`&$Z6LFtFA+ z@RlAUhH7E)TBW1!?ituLao77oVHfY}#=&MPb^dSg=)6ueY^;Ytwr!yB2W-miVAUWw zpo5~xX=oRdk04W<*|>swgI#0{TG&u2d}OJ*M)#ON3i_zM8)y$a9zGtU59w}LXtR$! za5?K>50k8kE!a}HjSu#86Q$wz%ATQHxI>>#%ERAr7ZxUVQBOBE?f}1F&E7k)t7_aw zlz<7mZ(*$q2ddhZ-U9(xj+o%dHJ!4)W3A2YK?R+UCg84}3;R~`VAEmgx^`l$R) zkxbM;Qovo!YQq8OKB<`c!06zs$lTcx9b2q58*OF1jZ)m9sU8_`*4j#Ys?}bpH?H)0 zB%|r1yo8Q^@12Lr_TGuNy_uug-n(aMdp|#Q z+w+XzAZ!FPVIz2xGlH2DG6I29`tjKs!CMcN5xjNcM)1?qGXhrui=SW$m|sKv0S@b) zMTRTG1cV0oLhWj^UQ=iyQ3=P9eKNMGZr3%-dEzLEOR*05%oSyYr6?8q5i3aBhLjVs zoa|C{JwDDrQ1+6mFurF=c~jT>3DEJG4Lme?q)W>YJV!aCA>$wchNEU1QdT@qifT6j z2tM6_6fZJMdp^oYGWBk}+_G}6y+F!+)l8yQe1;O4kxIyTA&Lyg6q3feoSdG!q+$*B z`ZxjqA(P=R72*_ILeSmgAt)~==pHHUqP+y<6q1nR_<-08R-`W8i=w%74LgRHRE`BX z* zL;dLE49NNFJXBk%wf1!DMx$L_hhs~fJ~BHri@UkC81)l}J zU)WOjahH}y?$DHNi)tUOGRBe0dtLB7k2U9?Qflp~`hwDE*Du$Vm7xU}pqK>}D^gyn zHWsSw=E@BKQl{rQN9Ab6gE3j`I44?!gW9%!8x@H#aMMq?KlmPWbHmU+N8bWFAq&}N#eJa;1tb-LhLadGz_C$HJU#uA)tc8(qn)l zmE4DE*97Em%YGXAE*A6;raeFFrEj6s=MY3)U(G6#}*)zOA`Wllnf-*KF8XuAnH;}c9-&hy9!L5M zDI#N=*7<}2c9q;;xf^xvOgx74S5njm_5_^#Y`)0{v3JDC=$}P;F0A>2F^ms5%|EFz zjBu8Tesh+Z|J$?D{NE*1!GPwEs0L#7|9wIgJi7XO5%Ybff^K^1>MKWu=#QzZOswN`hp+yGebrYg3e)k7zm_DF2S-gH?G!iCB^9k_q9ny9){eB`Er9!s zh*HbG(YN=*1biRf17M3Wq6mOLeCZ$k00ubWP-G3DlOg1ptHb;~6^deFjyc*89?6MM z#o{$v?Ad=v#_TQv)Q{;aB_htbBpf~ecB63yF_Df_)1)tk*zW~|UJdyX@oyLc40H$u zZud2kxg*XYU3vl{i7daq7NxA-OD)6kY}r*%UcN%F177hkg^QQxzpPyRdOY6QczuzV zw$K}ZcTTP^yvvi}eIp+4@YNF;e?^rq@E!kPigvzzV_BJYhYwZ&yKI6ausZ^xV1gtA zzUg6`Afe_GHNlaCwf~0+4w!;S8%)^6YR7)RFB~VnP24q+vx|;#M+g(&A=xcG<|QxQ z8G)-{`9Zv$iv9X`Np=&tEdyU%5&DzSFZjMRJo|T-^TSjt%=u+_AUfhi;fX4mPf@uViOsUu1BHw z<#_SfE7FD(x(Nk>p%qD)o-{1ojDpP!G9GbEOu9u%G#$fTND!rvlSZanQIOqSGaj=q zE`>GZX^29@3`mX{Y9Wa(K~G0v_9asBxP31RxQScpCD+jDoGQ!`hYkH}q{!ApQs7)H zF9*))MO=!ss3BvRfBS&Jnyg)|(m7FOW%zn7k1yQR4sVZv{4u|g9zH5?euF%kg9D?5 zD(s^3QznI7y$h8ubSWa#L0(f`Z8w*y?RpJvH$}X^ryG_@vM}3C|E|Kn0s(*b zr9TB4bT0af#DUQ|H-8PLiGdcozmzt7y_3}m*-ISk{RuZ#daVaKW#QgZyt06#g{XWOH)41Q^GEIN}2evt(_y7O^ literal 0 HcmV?d00001 diff --git a/asn1_compact/GajumaruSerialization.erl b/asn1_compact/GajumaruSerialization.erl new file mode 100644 index 0000000..7a5ce95 --- /dev/null +++ b/asn1_compact/GajumaruSerialization.erl @@ -0,0 +1,1879 @@ +%% Generated by the Erlang ASN.1 PER (unaligned) compiler. Version: 5.4.3 +%% Purpose: Encoding and decoding of the types in GajumaruSerialization. + +-module('GajumaruSerialization'). +-moduledoc false. +-compile(nowarn_unused_vars). +-dialyzer(no_improper_lists). +-dialyzer(no_match). +-include("GajumaruSerialization.hrl"). +-asn1_info([{vsn,'5.4.3'}, + {module,'GajumaruSerialization'}, + {options,[uper,{outdir,"asn1_compact"},{i,"."},{i,"asn1_compact"}]}]). + +-export([encoding_rule/0,maps/0,bit_string_format/0, + legacy_erlang_types/0]). +-export(['dialyzer-suppressions'/1]). +-export([ +enc_GajumaruData/1, +enc_CompactStatic/1, +enc_Content/1, +enc_TemplateFields/1, +enc_TemplateField/1, +enc_StaticFields/1, +enc_Value/1, +enc_BigInt/1, +enc_Uint64/1, +enc_Uint32/1, +enc_Uint128/1, +enc_KeyValue/1, +enc_Id/1, +enc_Account/1, +enc_SignedTx/1, +enc_ContractCode/1, +enc_ContractV1/1, +enc_ContractV2/1, +enc_ContractV3/1, +enc_TypeInfoV1/1, +enc_TypeInfoV3/1 +]). + +-export([ +dec_GajumaruData/1, +dec_CompactStatic/1, +dec_Content/1, +dec_TemplateFields/1, +dec_TemplateField/1, +dec_StaticFields/1, +dec_Value/1, +dec_BigInt/1, +dec_Uint64/1, +dec_Uint32/1, +dec_Uint128/1, +dec_KeyValue/1, +dec_Id/1, +dec_Account/1, +dec_SignedTx/1, +dec_ContractCode/1, +dec_ContractV1/1, +dec_ContractV2/1, +dec_ContractV3/1, +dec_TypeInfoV1/1, +dec_TypeInfoV3/1 +]). + +-export([info/0]). + +-export([encode/2,decode/2]). + +encoding_rule() -> uper. + +maps() -> false. + +bit_string_format() -> bitstring. + +legacy_erlang_types() -> false. + +encode(Type, Data) -> +try complete(encode_disp(Type, Data)) of + Bytes -> + {ok,Bytes} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + + +decode(Type, Data) -> +try + {Result,_Rest} = decode_disp(Type, Data), + {ok,Result} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + +encode_disp('GajumaruData', Data) -> enc_GajumaruData(Data); +encode_disp('CompactStatic', Data) -> enc_CompactStatic(Data); +encode_disp('Content', Data) -> enc_Content(Data); +encode_disp('TemplateFields', Data) -> enc_TemplateFields(Data); +encode_disp('TemplateField', Data) -> enc_TemplateField(Data); +encode_disp('StaticFields', Data) -> enc_StaticFields(Data); +encode_disp('Value', Data) -> enc_Value(Data); +encode_disp('BigInt', Data) -> enc_BigInt(Data); +encode_disp('Uint64', Data) -> enc_Uint64(Data); +encode_disp('Uint32', Data) -> enc_Uint32(Data); +encode_disp('Uint128', Data) -> enc_Uint128(Data); +encode_disp('KeyValue', Data) -> enc_KeyValue(Data); +encode_disp('Id', Data) -> enc_Id(Data); +encode_disp('Account', Data) -> enc_Account(Data); +encode_disp('SignedTx', Data) -> enc_SignedTx(Data); +encode_disp('ContractCode', Data) -> enc_ContractCode(Data); +encode_disp('ContractV1', Data) -> enc_ContractV1(Data); +encode_disp('ContractV2', Data) -> enc_ContractV2(Data); +encode_disp('ContractV3', Data) -> enc_ContractV3(Data); +encode_disp('TypeInfoV1', Data) -> enc_TypeInfoV1(Data); +encode_disp('TypeInfoV3', Data) -> enc_TypeInfoV3(Data); +encode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +decode_disp('GajumaruData', Data) -> dec_GajumaruData(Data); +decode_disp('CompactStatic', Data) -> dec_CompactStatic(Data); +decode_disp('Content', Data) -> dec_Content(Data); +decode_disp('TemplateFields', Data) -> dec_TemplateFields(Data); +decode_disp('TemplateField', Data) -> dec_TemplateField(Data); +decode_disp('StaticFields', Data) -> dec_StaticFields(Data); +decode_disp('Value', Data) -> dec_Value(Data); +decode_disp('BigInt', Data) -> dec_BigInt(Data); +decode_disp('Uint64', Data) -> dec_Uint64(Data); +decode_disp('Uint32', Data) -> dec_Uint32(Data); +decode_disp('Uint128', Data) -> dec_Uint128(Data); +decode_disp('KeyValue', Data) -> dec_KeyValue(Data); +decode_disp('Id', Data) -> dec_Id(Data); +decode_disp('Account', Data) -> dec_Account(Data); +decode_disp('SignedTx', Data) -> dec_SignedTx(Data); +decode_disp('ContractCode', Data) -> dec_ContractCode(Data); +decode_disp('ContractV1', Data) -> dec_ContractV1(Data); +decode_disp('ContractV2', Data) -> dec_ContractV2(Data); +decode_disp('ContractV3', Data) -> dec_ContractV3(Data); +decode_disp('TypeInfoV1', Data) -> dec_TypeInfoV1(Data); +decode_disp('TypeInfoV3', Data) -> dec_TypeInfoV3(Data); +decode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +info() -> + case ?MODULE:module_info(attributes) of + Attributes when is_list(Attributes) -> + case lists:keyfind(asn1_info, 1, Attributes) of + {_,Info} when is_list(Info) -> + Info; + _ -> + [] + end; + _ -> + [] + end. +enc_GajumaruData(Val) -> +[begin +%% attribute tag(1) with type INTEGER +Enc1@element = element(2, Val), +if Enc1@element bsr 16 =:= 0 -> +<>; +true -> +exit({error,{asn1,{illegal_integer,Enc1@element}}}) +end +end, +begin +%% attribute vsn(2) with type INTEGER +Enc3@element = element(3, Val), +if Enc3@element bsr 8 =:= 0 -> +Enc3@element; +true -> +exit({error,{asn1,{illegal_integer,Enc3@element}}}) +end +end|begin +%% attribute content(3) with type Content +Enc5@element = element(4, Val), +enc_Content(Enc5@element) +end]. + + +dec_GajumaruData(Bytes) -> + +%% attribute tag(1) with type INTEGER +{Term1,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute vsn(2) with type INTEGER +{Term2,Bytes2} = begin +<> = Bytes1, +{V2@V0,V2@Buf1} +end, + +%% attribute content(3) with type Content +{Term3,Bytes3} = dec_Content(Bytes2), +Res1 = {'GajumaruData',Term1,Term2,Term3}, +{Res1,Bytes3}. + +enc_CompactStatic(Val) -> +[begin +%% attribute tag(1) with type INTEGER +Enc1@element = element(2, Val), +if Enc1@element bsr 16 =:= 0 -> +<>; +true -> +exit({error,{asn1,{illegal_integer,Enc1@element}}}) +end +end, +begin +%% attribute vsn(2) with type INTEGER +Enc3@element = element(3, Val), +if Enc3@element bsr 8 =:= 0 -> +Enc3@element; +true -> +exit({error,{asn1,{illegal_integer,Enc3@element}}}) +end +end|begin +%% attribute fields(3) with type StaticFields +Enc5@element = element(4, Val), +enc_StaticFields(Enc5@element) +end]. + + +dec_CompactStatic(Bytes) -> + +%% attribute tag(1) with type INTEGER +{Term1,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute vsn(2) with type INTEGER +{Term2,Bytes2} = begin +<> = Bytes1, +{V2@V0,V2@Buf1} +end, + +%% attribute fields(3) with type StaticFields +{Term3,Bytes3} = dec_StaticFields(Bytes2), +Res1 = {'CompactStatic',Term1,Term2,Term3}, +{Res1,Bytes3}. + +enc_Content(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= templateFields -> +[<<0:3>>|enc_TemplateFields(ChoiceVal)]; +ChoiceTag =:= staticFields -> +[<<1:3>>|enc_StaticFields(ChoiceVal)]; +ChoiceTag =:= account -> +[<<2:3>>|enc_Account(ChoiceVal)]; +ChoiceTag =:= signedTx -> +[<<3:3>>|enc_SignedTx(ChoiceVal)]; +ChoiceTag =:= contract -> +[<<4:3>>|enc_ContractCode(ChoiceVal)] +end. + + +dec_Content(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +dec_TemplateFields(Bytes1) +end, +{{templateFields,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +dec_StaticFields(Bytes1) +end, +{{staticFields,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +dec_Account(Bytes1) +end, +{{account,Val},NewBytes}; +3 -> +{Val,NewBytes} = begin +dec_SignedTx(Bytes1) +end, +{{signedTx,Val},NewBytes}; +4 -> +{Val,NewBytes} = begin +dec_ContractCode(Bytes1) +end, +{{contract,Val},NewBytes} +end. +enc_TemplateFields(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TemplateField(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TemplateField(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TemplateField(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_TemplateFields(Bytes) -> +dec_components1(Bytes, []). + +enc_TemplateField(Val) -> +[begin +Enc1@element = element(2, Val), +if Enc1@element =:= asn1_NOVALUE -> +<<0:1>>; +true -> +<<1:1>> +end +end, +begin +%% attribute name(1) with type IA5String +Enc2@element = element(2, Val), +if Enc2@element =:= asn1_NOVALUE -> +[]; +true -> +begin +Enc3@len = length(Enc2@element), +Enc3@bin = encode_chars(Enc2@element, 7), +if Enc3@len < 128 -> +[Enc3@len|Enc3@bin]; +Enc3@len < 16384 -> +[<<2:2,Enc3@len:14>>|Enc3@bin]; +true -> +encode_fragmented(Enc3@bin, 7) +end +end +end +end|begin +%% attribute value(2) with type Value +Enc5@element = element(3, Val), +enc_Value(Enc5@element) +end]. + + +dec_TemplateField(Bytes) -> +{Opt,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute name(1) with type IA5String +{Term1,Bytes2} = case Opt band 1 of +1 -> +begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:7,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:7,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 7), +{V2@V6,V2@Buf7} +end, +{V2@V8,V2@Buf9} = {decode_chars(V2@V0, 7),V2@Buf1}, +{V2@V8,V2@Buf9} +end; +0 -> +{asn1_NOVALUE,Bytes1} +end, + +%% attribute value(2) with type Value +{Term2,Bytes3} = dec_Value(Bytes2), +Res1 = {'TemplateField',Term1,Term2}, +{Res1,Bytes3}. + +enc_StaticFields(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_StaticFields(Bytes) -> +dec_components2(Bytes, []). + +enc_Value(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= bigIntValue -> +if ChoiceVal >= 0 -> +[<<0:4>>|begin +ChoiceVal@bin = binary:encode_unsigned(ChoiceVal), +ChoiceVal@bin_size = byte_size(ChoiceVal@bin), +if ChoiceVal@bin_size < 128 -> +[ChoiceVal@bin_size|ChoiceVal@bin]; +ChoiceVal@bin_size < 16384 -> +[<<2:2,ChoiceVal@bin_size:14>>|ChoiceVal@bin]; +true -> +encode_fragmented(ChoiceVal@bin, 8) +end +end]; +true -> +exit({error,{asn1,{illegal_integer,ChoiceVal}}}) +end; +ChoiceTag =:= boolValue -> +if ChoiceVal =:= false -> +<<1:4,0:1>>; +ChoiceVal =:= true -> +<<1:4,1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,ChoiceVal}}}) +end; +ChoiceTag =:= binaryValue -> +[<<2:4>>|begin +Enc6@len = byte_size(ChoiceVal), +if Enc6@len < 128 -> +[Enc6@len|ChoiceVal]; +Enc6@len < 16384 -> +[<<2:2,Enc6@len:14>>|ChoiceVal]; +true -> +encode_fragmented(ChoiceVal, 8) +end +end]; +ChoiceTag =:= idValue -> +[<<3:4>>|enc_Id(ChoiceVal)]; +ChoiceTag =:= listValue -> +[<<4:4>>|enc_Value_listValue(ChoiceVal)]; +ChoiceTag =:= tupleValue -> +[<<5:4>>|enc_Value_tupleValue(ChoiceVal)]; +ChoiceTag =:= mapValue -> +[<<6:4>>|enc_Value_mapValue(ChoiceVal)]; +ChoiceTag =:= uint64Value -> +if ChoiceVal bsr 64 =:= 0 -> +<<7:4,ChoiceVal:64>>; +true -> +exit({error,{asn1,{illegal_integer,ChoiceVal}}}) +end; +ChoiceTag =:= uint32Value -> +if ChoiceVal bsr 32 =:= 0 -> +<<8:4,ChoiceVal:32>>; +true -> +exit({error,{asn1,{illegal_integer,ChoiceVal}}}) +end; +ChoiceTag =:= uint128Value -> +if ChoiceVal bsr 128 =:= 0 -> +<<9:4,ChoiceVal:128>>; +true -> +exit({error,{asn1,{illegal_integer,ChoiceVal}}}) +end +end. +enc_Value_listValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + +enc_Value_tupleValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + +enc_Value_mapValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_KeyValue(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_KeyValue(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_KeyValue(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_Value(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@Buf4/bitstring>> when V2@V3 =/= 0 -> +{V2@V3,V2@Buf4}; +<<1:1,0:1,V2@V4:14,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +{V2@V4,V2@Buf5}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +V2@Mul6 = V2@V4 * 16384, +{V2@Mul6,V2@Buf5} +end, +<> = V2@Buf1, +{V2@V7,V2@Buf8} +end +end, +{{bigIntValue,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +begin +<> = Bytes1, +V3@Int2 = case V3@V0 of +0 -> false; +1 -> true +end, +{V3@Int2,V3@Buf1} +end +end, +{{boolValue,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +begin +{V4@V0,V4@Buf1} = case Bytes1 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end +end, +{{binaryValue,Val},NewBytes}; +3 -> +{Val,NewBytes} = begin +dec_Id(Bytes1) +end, +{{idValue,Val},NewBytes}; +4 -> +{Val,NewBytes} = begin +dec_Value_listValue(Bytes1) +end, +{{listValue,Val},NewBytes}; +5 -> +{Val,NewBytes} = begin +dec_Value_tupleValue(Bytes1) +end, +{{tupleValue,Val},NewBytes}; +6 -> +{Val,NewBytes} = begin +dec_Value_mapValue(Bytes1) +end, +{{mapValue,Val},NewBytes}; +7 -> +{Val,NewBytes} = begin +begin +<> = Bytes1, +{V5@V0,V5@Buf1} +end +end, +{{uint64Value,Val},NewBytes}; +8 -> +{Val,NewBytes} = begin +begin +<> = Bytes1, +{V6@V0,V6@Buf1} +end +end, +{{uint32Value,Val},NewBytes}; +9 -> +{Val,NewBytes} = begin +begin +<> = Bytes1, +{V7@V0,V7@Buf1} +end +end, +{{uint128Value,Val},NewBytes} +end. + +dec_Value_listValue(Bytes) -> +dec_components3(Bytes, []). + + +dec_Value_tupleValue(Bytes) -> +dec_components4(Bytes, []). + + +dec_Value_mapValue(Bytes) -> +dec_components5(Bytes, []). + +enc_BigInt(Val) -> +if Val >= 0 -> +begin +Val@bin = binary:encode_unsigned(Val), +Val@bin_size = byte_size(Val@bin), +if Val@bin_size < 128 -> +[Val@bin_size|Val@bin]; +Val@bin_size < 16384 -> +[<<2:2,Val@bin_size:14>>|Val@bin]; +true -> +encode_fragmented(Val@bin, 8) +end +end; +true -> +exit({error,{asn1,{illegal_integer,Val}}}) +end. + + +dec_BigInt(Bytes) -> +begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@Buf4/bitstring>> when V1@V3 =/= 0 -> +{V1@V3,V1@Buf4}; +<<1:1,0:1,V1@V4:14,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +{V1@V4,V1@Buf5}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +V1@Mul6 = V1@V4 * 16384, +{V1@Mul6,V1@Buf5} +end, +<> = V1@Buf1, +{V1@V7,V1@Buf8} +end. + +enc_Uint64(Val) -> +if Val bsr 64 =:= 0 -> +<>; +true -> +exit({error,{asn1,{illegal_integer,Val}}}) +end. + + +dec_Uint64(Bytes) -> +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end. + +enc_Uint32(Val) -> +if Val bsr 32 =:= 0 -> +<>; +true -> +exit({error,{asn1,{illegal_integer,Val}}}) +end. + + +dec_Uint32(Bytes) -> +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end. + +enc_Uint128(Val) -> +if Val bsr 128 =:= 0 -> +<>; +true -> +exit({error,{asn1,{illegal_integer,Val}}}) +end. + + +dec_Uint128(Bytes) -> +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end. + +enc_KeyValue(Val) -> +[begin +%% attribute key(1) with type Value +Enc1@element = element(2, Val), +enc_Value(Enc1@element) +end|begin +%% attribute val(2) with type Value +Enc2@element = element(3, Val), +enc_Value(Enc2@element) +end]. + + +dec_KeyValue(Bytes) -> + +%% attribute key(1) with type Value +{Term1,Bytes1} = dec_Value(Bytes), + +%% attribute val(2) with type Value +{Term2,Bytes2} = dec_Value(Bytes1), +Res1 = {'KeyValue',Term1,Term2}, +{Res1,Bytes2}. + +enc_Id(Val) -> +[begin +%% attribute type(1) with type INTEGER +Enc1@element = element(2, Val), +if Enc1@element bsr 8 =:= 0 -> +Enc1@element; +true -> +exit({error,{asn1,{illegal_integer,Enc1@element}}}) +end +end|begin +%% attribute value(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len =:= 32 -> +Enc3@element +end +end]. + + +dec_Id(Bytes) -> + +%% attribute type(1) with type INTEGER +{Term1,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute value(2) with type OCTET STRING +{Term2,Bytes2} = begin +<> = Bytes1, +V2@Conv2 = binary:copy(V2@V0), +{V2@Conv2,V2@Buf1} +end, +Res1 = {'Id',Term1,Term2}, +{Res1,Bytes2}. + +enc_Account(Val) -> +[begin +%% attribute foo(1) with type INTEGER +Enc1@element = element(2, Val), +encode_unconstrained_number(Enc1@element) +end|begin +%% attribute bar(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end]. + + +dec_Account(Bytes) -> + +%% attribute foo(1) with type INTEGER +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@Buf4/bitstring>> when V1@V3 =/= 0 -> +{V1@V3,V1@Buf4}; +<<1:1,0:1,V1@V4:14,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +{V1@V4,V1@Buf5}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +V1@Mul6 = V1@V4 * 16384, +{V1@Mul6,V1@Buf5} +end, +<> = V1@Buf1, +{V1@V7,V1@Buf8} +end, + +%% attribute bar(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, +Res1 = {'Account',Term1,Term2}, +{Res1,Bytes2}. + +enc_SignedTx(Val) -> +[begin +%% attribute signatures(1) with type SEQUENCE OF +Enc1@element = element(2, Val), +enc_SignedTx_signatures(Enc1@element) +end|begin +%% attribute transaction(2) with type OCTET STRING +Enc2@element = element(3, Val), +Enc3@len = byte_size(Enc2@element), +if Enc3@len < 128 -> +[Enc3@len|Enc2@element]; +Enc3@len < 16384 -> +[<<2:2,Enc3@len:14>>|Enc2@element]; +true -> +encode_fragmented(Enc2@element, 8) +end +end]. +enc_SignedTx_signatures(Val) -> +Enc2@len = length(Val), +if Enc2@len < 128 -> +[Enc2@len|[begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end || Comp <- Val]]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|[begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end || Comp <- Val]]; +true -> +begin +Enc2@fn = fun(Comp) -> begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end end, +encode_fragmented_sof(Enc2@fn, Val, Enc2@len) +end +end. + + + +dec_SignedTx(Bytes) -> + +%% attribute signatures(1) with type SEQUENCE OF +{Term1,Bytes1} = dec_SignedTx_signatures(Bytes), + +%% attribute transaction(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V1@V0,V1@Buf1} = case Bytes1 of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, +Res1 = {'SignedTx',Term1,Term2}, +{Res1,Bytes2}. + + +dec_SignedTx_signatures(Bytes) -> +dec_components6(Bytes, []). + +enc_ContractCode(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= v1 -> +[<<0:2>>|enc_ContractV1(ChoiceVal)]; +ChoiceTag =:= v2 -> +[<<1:2>>|enc_ContractV2(ChoiceVal)]; +ChoiceTag =:= v3 -> +[<<2:2>>|enc_ContractV3(ChoiceVal)] +end. + + +dec_ContractCode(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +dec_ContractV1(Bytes1) +end, +{{v1,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +dec_ContractV2(Bytes1) +end, +{{v2,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +dec_ContractV3(Bytes1) +end, +{{v3,Val},NewBytes} +end. +enc_ContractV1(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV1_typeInfo(Enc3@element) +end|begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end]. +enc_ContractV1_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV1(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV1(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV1_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, +Res1 = {'ContractV1',Term1,Term2,Term3}, +{Res1,Bytes3}. + + +dec_ContractV1_typeInfo(Bytes) -> +dec_components7(Bytes, []). + +enc_ContractV2(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV2_typeInfo(Enc3@element) +end, +begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end|begin +%% attribute compilerVersion(4) with type OCTET STRING +Enc6@element = element(5, Val), +Enc7@len = byte_size(Enc6@element), +if Enc7@len < 128 -> +[Enc7@len|Enc6@element]; +Enc7@len < 16384 -> +[<<2:2,Enc7@len:14>>|Enc6@element]; +true -> +encode_fragmented(Enc6@element, 8) +end +end]. +enc_ContractV2_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV1(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV2(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV2_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute compilerVersion(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V3@V0,V3@Buf1} = case Bytes3 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, +Res1 = {'ContractV2',Term1,Term2,Term3,Term4}, +{Res1,Bytes4}. + + +dec_ContractV2_typeInfo(Bytes) -> +dec_components8(Bytes, []). + +enc_ContractV3(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV3_typeInfo(Enc3@element) +end, +begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end, +begin +%% attribute compilerVersion(4) with type OCTET STRING +Enc6@element = element(5, Val), +Enc7@len = byte_size(Enc6@element), +if Enc7@len < 128 -> +[Enc7@len|Enc6@element]; +Enc7@len < 16384 -> +[<<2:2,Enc7@len:14>>|Enc6@element]; +true -> +encode_fragmented(Enc6@element, 8) +end +end|begin +%% attribute payable(5) with type BOOLEAN +Enc8@element = element(6, Val), +if Enc8@element =:= false -> +<<0:1>>; +Enc8@element =:= true -> +<<1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,Enc8@element}}}) +end +end]. +enc_ContractV3_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV3(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV3(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV3(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV3(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV3_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute compilerVersion(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V3@V0,V3@Buf1} = case Bytes3 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, + +%% attribute payable(5) with type BOOLEAN +{Term5,Bytes5} = begin +<> = Bytes4, +V4@Int2 = case V4@V0 of +0 -> false; +1 -> true +end, +{V4@Int2,V4@Buf1} +end, +Res1 = {'ContractV3',Term1,Term2,Term3,Term4,Term5}, +{Res1,Bytes5}. + + +dec_ContractV3_typeInfo(Bytes) -> +dec_components9(Bytes, []). + +enc_TypeInfoV1(Val) -> +[begin +%% attribute typeHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute name(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end, +begin +%% attribute argType(3) with type OCTET STRING +Enc5@element = element(4, Val), +Enc6@len = byte_size(Enc5@element), +if Enc6@len < 128 -> +[Enc6@len|Enc5@element]; +Enc6@len < 16384 -> +[<<2:2,Enc6@len:14>>|Enc5@element]; +true -> +encode_fragmented(Enc5@element, 8) +end +end|begin +%% attribute outType(4) with type OCTET STRING +Enc7@element = element(5, Val), +Enc8@len = byte_size(Enc7@element), +if Enc8@len < 128 -> +[Enc8@len|Enc7@element]; +Enc8@len < 16384 -> +[<<2:2,Enc8@len:14>>|Enc7@element]; +true -> +encode_fragmented(Enc7@element, 8) +end +end]. + + +dec_TypeInfoV1(Bytes) -> + +%% attribute typeHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute name(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute argType(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V3@V0,V3@Buf1} = case Bytes2 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, + +%% attribute outType(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V4@V0,V4@Buf1} = case Bytes3 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end, +Res1 = {'TypeInfoV1',Term1,Term2,Term3,Term4}, +{Res1,Bytes4}. + +enc_TypeInfoV3(Val) -> +[begin +%% attribute typeHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute name(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end, +begin +%% attribute payable(3) with type BOOLEAN +Enc5@element = element(4, Val), +if Enc5@element =:= false -> +<<0:1>>; +Enc5@element =:= true -> +<<1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,Enc5@element}}}) +end +end, +begin +%% attribute argType(4) with type OCTET STRING +Enc7@element = element(5, Val), +Enc8@len = byte_size(Enc7@element), +if Enc8@len < 128 -> +[Enc8@len|Enc7@element]; +Enc8@len < 16384 -> +[<<2:2,Enc8@len:14>>|Enc7@element]; +true -> +encode_fragmented(Enc7@element, 8) +end +end|begin +%% attribute outType(5) with type OCTET STRING +Enc9@element = element(6, Val), +Enc10@len = byte_size(Enc9@element), +if Enc10@len < 128 -> +[Enc10@len|Enc9@element]; +Enc10@len < 16384 -> +[<<2:2,Enc10@len:14>>|Enc9@element]; +true -> +encode_fragmented(Enc9@element, 8) +end +end]. + + +dec_TypeInfoV3(Bytes) -> + +%% attribute typeHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute name(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute payable(3) with type BOOLEAN +{Term3,Bytes3} = begin +<> = Bytes2, +V3@Int2 = case V3@V0 of +0 -> false; +1 -> true +end, +{V3@Int2,V3@Buf1} +end, + +%% attribute argType(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V4@V0,V4@Buf1} = case Bytes3 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end, + +%% attribute outType(5) with type OCTET STRING +{Term5,Bytes5} = begin +{V5@V0,V5@Buf1} = case Bytes4 of +<<0:1,V5@V3:7,V5@V5:V5@V3/binary-unit:8,V5@Buf6/bitstring>> -> +{V5@V5,V5@Buf6}; +<<1:1,0:1,V5@V4:14,V5@V6:V5@V4/binary-unit:8,V5@Buf7/bitstring>> -> +{V5@V6,V5@Buf7}; +<<1:1,1:1,V5@V4:6,V5@Buf5/bitstring>> -> +{V5@V6,V5@Buf7} = decode_fragmented(V5@V4, V5@Buf5, 8), +{V5@V6,V5@Buf7} +end, +V5@Conv8 = binary:copy(V5@V0), +{V5@Conv8,V5@Buf1} +end, +Res1 = {'TypeInfoV3',Term1,Term2,Term3,Term4,Term5}, +{Res1,Bytes5}. + + +%%% +%%% Run-time functions. +%%% + +'dialyzer-suppressions'(Arg) -> + _ = complete(element(1, Arg)), + ok. + +dec_components1(Bytes, Acc) -> +%% Length with constraint no +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@Buf4/bitstring>> -> +{V1@V3,V1@Buf4}; +<<1:1,0:1,V1@V4:14,V1@Buf5/bitstring>> -> +{V1@V4,V1@Buf5}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +V1@Mul6 = V1@V4 * 16384, +{V1@Mul6,V1@Buf5} +end, +{Acc1,Buf1} = dec_fragment10(V1@V0, V1@Buf1, Acc), +if V1@V0 >= 16384 -> +dec_components1(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components2(Bytes, Acc) -> +%% Length with constraint no +{V2@V0,V2@Buf1} = case Bytes of +<<0:1,V2@V3:7,V2@Buf4/bitstring>> -> +{V2@V3,V2@Buf4}; +<<1:1,0:1,V2@V4:14,V2@Buf5/bitstring>> -> +{V2@V4,V2@Buf5}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +V2@Mul6 = V2@V4 * 16384, +{V2@Mul6,V2@Buf5} +end, +{Acc1,Buf1} = dec_fragment11(V2@V0, V2@Buf1, Acc), +if V2@V0 >= 16384 -> +dec_components2(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components3(Bytes, Acc) -> +%% Length with constraint no +{V3@V0,V3@Buf1} = case Bytes of +<<0:1,V3@V3:7,V3@Buf4/bitstring>> -> +{V3@V3,V3@Buf4}; +<<1:1,0:1,V3@V4:14,V3@Buf5/bitstring>> -> +{V3@V4,V3@Buf5}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +V3@Mul6 = V3@V4 * 16384, +{V3@Mul6,V3@Buf5} +end, +{Acc1,Buf1} = dec_fragment12(V3@V0, V3@Buf1, Acc), +if V3@V0 >= 16384 -> +dec_components3(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components4(Bytes, Acc) -> +%% Length with constraint no +{V4@V0,V4@Buf1} = case Bytes of +<<0:1,V4@V3:7,V4@Buf4/bitstring>> -> +{V4@V3,V4@Buf4}; +<<1:1,0:1,V4@V4:14,V4@Buf5/bitstring>> -> +{V4@V4,V4@Buf5}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +V4@Mul6 = V4@V4 * 16384, +{V4@Mul6,V4@Buf5} +end, +{Acc1,Buf1} = dec_fragment13(V4@V0, V4@Buf1, Acc), +if V4@V0 >= 16384 -> +dec_components4(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components5(Bytes, Acc) -> +%% Length with constraint no +{V5@V0,V5@Buf1} = case Bytes of +<<0:1,V5@V3:7,V5@Buf4/bitstring>> -> +{V5@V3,V5@Buf4}; +<<1:1,0:1,V5@V4:14,V5@Buf5/bitstring>> -> +{V5@V4,V5@Buf5}; +<<1:1,1:1,V5@V4:6,V5@Buf5/bitstring>> -> +V5@Mul6 = V5@V4 * 16384, +{V5@Mul6,V5@Buf5} +end, +{Acc1,Buf1} = dec_fragment14(V5@V0, V5@Buf1, Acc), +if V5@V0 >= 16384 -> +dec_components5(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components6(Bytes, Acc) -> +%% Length with constraint no +{V6@V0,V6@Buf1} = case Bytes of +<<0:1,V6@V3:7,V6@Buf4/bitstring>> -> +{V6@V3,V6@Buf4}; +<<1:1,0:1,V6@V4:14,V6@Buf5/bitstring>> -> +{V6@V4,V6@Buf5}; +<<1:1,1:1,V6@V4:6,V6@Buf5/bitstring>> -> +V6@Mul6 = V6@V4 * 16384, +{V6@Mul6,V6@Buf5} +end, +{Acc1,Buf1} = dec_fragment15(V6@V0, V6@Buf1, Acc), +if V6@V0 >= 16384 -> +dec_components6(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components7(Bytes, Acc) -> +%% Length with constraint no +{V7@V0,V7@Buf1} = case Bytes of +<<0:1,V7@V3:7,V7@Buf4/bitstring>> -> +{V7@V3,V7@Buf4}; +<<1:1,0:1,V7@V4:14,V7@Buf5/bitstring>> -> +{V7@V4,V7@Buf5}; +<<1:1,1:1,V7@V4:6,V7@Buf5/bitstring>> -> +V7@Mul6 = V7@V4 * 16384, +{V7@Mul6,V7@Buf5} +end, +{Acc1,Buf1} = dec_fragment16(V7@V0, V7@Buf1, Acc), +if V7@V0 >= 16384 -> +dec_components7(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components8(Bytes, Acc) -> +%% Length with constraint no +{V8@V0,V8@Buf1} = case Bytes of +<<0:1,V8@V3:7,V8@Buf4/bitstring>> -> +{V8@V3,V8@Buf4}; +<<1:1,0:1,V8@V4:14,V8@Buf5/bitstring>> -> +{V8@V4,V8@Buf5}; +<<1:1,1:1,V8@V4:6,V8@Buf5/bitstring>> -> +V8@Mul6 = V8@V4 * 16384, +{V8@Mul6,V8@Buf5} +end, +{Acc1,Buf1} = dec_fragment17(V8@V0, V8@Buf1, Acc), +if V8@V0 >= 16384 -> +dec_components8(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components9(Bytes, Acc) -> +%% Length with constraint no +{V9@V0,V9@Buf1} = case Bytes of +<<0:1,V9@V3:7,V9@Buf4/bitstring>> -> +{V9@V3,V9@Buf4}; +<<1:1,0:1,V9@V4:14,V9@Buf5/bitstring>> -> +{V9@V4,V9@Buf5}; +<<1:1,1:1,V9@V4:6,V9@Buf5/bitstring>> -> +V9@Mul6 = V9@V4 * 16384, +{V9@Mul6,V9@Buf5} +end, +{Acc1,Buf1} = dec_fragment18(V9@V0, V9@Buf1, Acc), +if V9@V0 >= 16384 -> +dec_components9(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_fragment10(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment10(Num, Bytes, Acc) -> +{Term,Remain} = dec_TemplateField(Bytes), +dec_fragment10(Num-1, Remain, [Term|Acc]). + +dec_fragment11(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment11(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment11(Num-1, Remain, [Term|Acc]). + +dec_fragment12(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment12(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment12(Num-1, Remain, [Term|Acc]). + +dec_fragment13(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment13(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment13(Num-1, Remain, [Term|Acc]). + +dec_fragment14(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment14(Num, Bytes, Acc) -> +{Term,Remain} = dec_KeyValue(Bytes), +dec_fragment14(Num-1, Remain, [Term|Acc]). + +dec_fragment15(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment15(Num, Bytes, Acc) -> +{Term,Remain} = begin +{V10@V0,V10@Buf1} = case Bytes of +<<0:1,V10@V3:7,V10@V5:V10@V3/binary-unit:8,V10@Buf6/bitstring>> -> +{V10@V5,V10@Buf6}; +<<1:1,0:1,V10@V4:14,V10@V6:V10@V4/binary-unit:8,V10@Buf7/bitstring>> -> +{V10@V6,V10@Buf7}; +<<1:1,1:1,V10@V4:6,V10@Buf5/bitstring>> -> +{V10@V6,V10@Buf7} = decode_fragmented(V10@V4, V10@Buf5, 8), +{V10@V6,V10@Buf7} +end, +V10@Conv8 = binary:copy(V10@V0), +{V10@Conv8,V10@Buf1} +end, +dec_fragment15(Num-1, Remain, [Term|Acc]). + +dec_fragment16(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment16(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV1(Bytes), +dec_fragment16(Num-1, Remain, [Term|Acc]). + +dec_fragment17(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment17(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV1(Bytes), +dec_fragment17(Num-1, Remain, [Term|Acc]). + +dec_fragment18(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment18(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV3(Bytes), +dec_fragment18(Num-1, Remain, [Term|Acc]). + +complete(InList) when is_list(InList) -> + case list_to_bitstring(InList) of + <<>> -> + <<0>>; + Res -> + Sz = bit_size(Res), + case Sz band 7 of + 0 -> + Res; + Bits -> + <> + end + end; +complete(Bin) when is_binary(Bin) -> + case Bin of + <<>> -> + <<0>>; + _ -> + Bin + end; +complete(InList) when is_bitstring(InList) -> + Sz = bit_size(InList), + PadLen = 8 - Sz band 7, + <>. + +decode_chars(Val, N) -> + [ + C || + <> <= Val + ]. + +decode_fragmented(SegSz0, Buf0, Unit) -> + SegSz = SegSz0 * Unit * 16384, + <> = Buf0, + decode_fragmented_1(Buf, Unit, Res). + +decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) -> + Sz = N * Unit, + <> = Buf0, + {<>, Buf}; +decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) -> + Sz = N * Unit, + <> = Buf0, + {<>, Buf}; +decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) -> + SegSz = SegSz0 * Unit * 16384, + <> = Buf0, + Res = <>, + decode_fragmented_1(Buf, Unit, Res). + +encode_chars(Val, NumBits) -> + << + <> || + C <- Val + >>. + +encode_components(Cs, _Encoder, 0, Acc) -> + {Cs, lists:reverse(Acc)}; +encode_components([C | Cs], Encoder, Size, Acc) -> + B = Encoder(C), + encode_components(Cs, Encoder, Size - 1, [B | Acc]). + +encode_fragmented(Bin, Unit) -> + encode_fragmented_1(Bin, Unit, 4). + +encode_fragmented_1(Bin, Unit, N) -> + SegSz = Unit * N * 16384, + case Bin of + <> -> + [<<3:2,N:6>>, B | encode_fragmented_1(T, Unit, N)]; + _ when N > 1 -> + encode_fragmented_1(Bin, Unit, N - 1); + _ -> + case bit_size(Bin) div Unit of + Len when Len < 128 -> + [Len, Bin]; + Len when Len < 16384 -> + [<<2:2,Len:14>>, Bin] + end + end. + +encode_fragmented_sof(Fun, Comps, Len) -> + encode_fragmented_sof_1(Fun, Comps, Len, 4). + +encode_fragmented_sof_1(Encoder, Comps0, Len0, N) -> + SegSz = N * 16384, + if + Len0 >= SegSz -> + {Comps, B} = encode_components(Comps0, Encoder, SegSz, []), + Len = Len0 - SegSz, + [<<3:2,N:6>>, + B | + encode_fragmented_sof_1(Encoder, Comps, Len, N)]; + N > 1 -> + encode_fragmented_sof_1(Encoder, Comps0, Len0, N - 1); + Len0 < 128 -> + {[], B} = encode_components(Comps0, Encoder, Len0, []), + [Len0 | B]; + Len0 < 16384 -> + {[], B} = encode_components(Comps0, Encoder, Len0, []), + [<<2:2,Len0:14>> | B] + end. + +encode_unconstrained_number(Val) when not is_integer(Val) -> + exit({error, {asn1, {illegal_integer, Val}}}); +encode_unconstrained_number(Val) when Val >= 0 -> + if + Val < 128 -> + [1, Val]; + Val < 256 -> + [<<2,0>>, Val]; + true -> + case binary:encode_unsigned(Val) of + <<0:1,_/bitstring>> = Bin -> + case byte_size(Bin) of + Sz when Sz < 128 -> + [Sz, Bin]; + Sz when Sz < 16384 -> + [<<2:2,Sz:14>>, Bin] + end; + <<1:1,_/bitstring>> = Bin -> + case byte_size(Bin) + 1 of + Sz when Sz < 128 -> + [Sz, 0, Bin]; + Sz when Sz < 16384 -> + [<<2:2,Sz:14,0:8>>, Bin] + end + end + end; +encode_unconstrained_number(Val) -> + Oct = enint(Val, []), + Len = length(Oct), + if + Len < 128 -> + [Len | Oct]; + Len < 16384 -> + [<<2:2,Len:14>> | Oct] + end. + +enint(-1, [B1 | T]) when B1 > 127 -> + [B1 | T]; +enint(N, Acc) -> + enint(N bsr 8, [N band 255 | Acc]). diff --git a/asn1_compact/GajumaruSerialization.hrl b/asn1_compact/GajumaruSerialization.hrl new file mode 100644 index 0000000..9d7d397 --- /dev/null +++ b/asn1_compact/GajumaruSerialization.hrl @@ -0,0 +1,82 @@ +%% Generated by the Erlang ASN.1 compiler. Version: 5.4.3 +%% Purpose: Erlang record definitions for each named and unnamed +%% SEQUENCE and SET, and macro definitions for each value +%% definition in module GajumaruSerialization. + +-ifndef(_GAJUMARUSERIALIZATION_HRL_). +-define(_GAJUMARUSERIALIZATION_HRL_, true). + +-record('GajumaruData', { + tag, + vsn, + content +}). + +-record('CompactStatic', { + tag, + vsn, + fields +}). + +-record('TemplateField', { + name = asn1_NOVALUE, + value +}). + +-record('KeyValue', { + key, + val +}). + +-record('Id', { + type, + value +}). + +-record('Account', { + foo, + bar +}). + +-record('SignedTx', { + signatures, + transaction +}). + +-record('ContractV1', { + sourceHash, + typeInfo, + byteCode +}). + +-record('ContractV2', { + sourceHash, + typeInfo, + byteCode, + compilerVersion +}). + +-record('ContractV3', { + sourceHash, + typeInfo, + byteCode, + compilerVersion, + payable +}). + +-record('TypeInfoV1', { + typeHash, + name, + argType, + outType +}). + +-record('TypeInfoV3', { + typeHash, + name, + payable, + argType, + outType +}). + +-endif. %% _GAJUMARUSERIALIZATION_HRL_ diff --git a/asn1_oer/GajumaruSerialization.asn b/asn1_oer/GajumaruSerialization.asn new file mode 100644 index 0000000..05e3b14 --- /dev/null +++ b/asn1_oer/GajumaruSerialization.asn @@ -0,0 +1,247 @@ +-- GajumaruSerialization.asn +-- +-- ASN.1 model for the structures serialized by gmserialization.erl +-- (the layer on top of RLP). +-- +-- Purpose: +-- * Provide a formal, toolable description of the data for portability +-- (other languages use ASN.1 compilers to get types/parsers). +-- * Define compact canonical wire format using standard ASN.1 techniques +-- (primarily Unaligned PER / UPER with constraints for packing). +-- * Static encoding only (templates from gmserialization). +-- * Legacy RLP compatibility is achieved via separate translation layer +-- (deferred in current focus). +-- +-- Detection of legacy vs new: +-- Legacy data (produced by gmserialization:serialize / gmser_chain_objects:serialize +-- or gmser_dyn:serialize) is always an RLP *list* at the top level. +-- This means the first byte is in the range 0xC0 .. 0xFF. +-- +-- DER-encoded data using the types below will start with 0x30 (SEQUENCE, +-- constructed, universal tag) for the outermost GajumaruData (or any +-- top-level SEQUENCE we define). 0x30 < 0xC0, so a single-byte prefix +-- check reliably distinguishes the two formats. +-- +-- Usage in Erlang (after compiling with asn1ct for compact wire): +-- {ok, Mod} = asn1ct:compile(GajumaruSerialization.asn, [uper]). +-- {ok, Bytes} = 'GajumaruSerialization':encode('GajumaruData', Asn1Value). +-- Bytes is the compact UPER wire format (deterministic with this schema). +-- For legacy RLP, use the model-to-RLP layer instead (see gmser_asn1_rlp). +-- +-- Notes on type mapping from gmserialization.erl: +-- - int -> INTEGER (new data uses canonical DER INTEGER) +-- - binary -> OCTET STRING +-- - bool -> BOOLEAN +-- - id -> Id (SEQUENCE) (cleaner than the legacy packed 33-byte form) +-- - [T] -> SEQUENCE OF T +-- - {T1,...} -> SEQUENCE (fixed-size, order matters) +-- - #{items := [{K,T},...]} -> SEQUENCE with the fields in template order +-- (static maps carry *values only*, no keys on the wire) +-- - tag + vsn are preserved as the first two fields for compatibility +-- with existing dispatch logic. +-- +-- Legacy integers had strict unsigned-minimal no-leading-zero (except for 0) +-- and RLP-level rules. New DER data does not need to follow those rules. +-- +-- WARNING: +-- Any cryptographic hash or signature computed over a serialized object +-- will change when switching from RLP to DER for that object. Plan a +-- coordinated upgrade. + +GajumaruSerialization DEFINITIONS + AUTOMATIC TAGS ::= +BEGIN + +EXPORTS ALL; + +-- ============================================================ +-- Top-level wrapper used for new DER data. +-- This is what a decoder will see first. +-- ============================================================ + +GajumaruData ::= SEQUENCE { + -- Constrained for better PER packing + tag INTEGER (0..65535), + vsn INTEGER (0..255), + content Content +} + +-- Preferred top-level for the compact static wire format. +-- Avoids the extra Content CHOICE tag when the structure is known to be static. +CompactStatic ::= SEQUENCE { + tag INTEGER (0..65535), + vsn INTEGER (0..255), + fields StaticFields +} + +-- Content can be a specific structured type (preferred) or a generic +-- representation of a template-driven object. +Content ::= CHOICE { + -- Generic fallback that can represent any [{Field, Type}] template + -- without having a pre-defined SEQUENCE for every object. + templateFields [0] TemplateFields, + + -- Static-optimized: no field names on wire (matches legacy static behavior exactly) + -- Preferred for compact wire format of known templates. + staticFields [10] StaticFields, + + -- Examples of concrete versioned types (extend as needed) + account [1] Account, + signedTx [2] SignedTx, + contract [3] ContractCode + -- Add more alternatives for other tags from gmser_chain_objects +} + +-- ============================================================ +-- Generic template-driven representation +-- (useful during transition or for unregistered types) +-- ============================================================ + +TemplateFields ::= SEQUENCE OF TemplateField + +TemplateField ::= SEQUENCE { + -- Field name is included for debuggability / generic processing. + -- In the original static encoding the name is NOT on the wire; + -- only position and type matter. We include it here for convenience. + name IA5String OPTIONAL, + value Value +} + +-- Optimized for static wire format: just the values in order, no names. +-- This matches the legacy static encoding where maps/records are positional only. +StaticFields ::= SEQUENCE OF Value + + +Value ::= CHOICE { + intValue [0] INTEGER, + boolValue [1] BOOLEAN, + binaryValue [2] OCTET STRING, + idValue [3] Id, + listValue [4] SEQUENCE OF Value, + tupleValue [5] SEQUENCE OF Value, + mapValue [6] SEQUENCE OF KeyValue -- only needed if you want to + -- represent dynamic-style maps +} + +KeyValue ::= SEQUENCE { + key Value, + val Value +} + +-- ============================================================ +-- Common types +-- ============================================================ + +Id ::= SEQUENCE { + -- Corresponds to the simple tags in gmser_id (account=1, name=2, etc.) + -- and the extended account subtype (high bit in legacy). + type INTEGER (0..255), + value OCTET STRING (SIZE (32)) +} + +-- ============================================================ +-- Concrete object examples (derived from usage in the codebase) +-- Add / evolve per version as you introduce new vsns. +-- ============================================================ + +-- Example: a very simple account-like object used in tests +Account ::= SEQUENCE { + foo INTEGER, + bar OCTET STRING +} + +-- Simplified signed transaction +SignedTx ::= SEQUENCE { + signatures SEQUENCE OF OCTET STRING, + transaction OCTET STRING +} + +-- Contract code objects (see gmser_contract_code.erl) +-- We model the three versions that exist today. +ContractCode ::= CHOICE { + v1 [0] ContractV1, + v2 [1] ContractV2, + v3 [2] ContractV3 +} + +ContractV1 ::= SEQUENCE { + sourceHash OCTET STRING, + -- typeInfo is a list of 4-tuples in legacy: + -- {typeHash, name, argType, outType} + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING +} + +ContractV2 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING, + compilerVersion OCTET STRING +} + +ContractV3 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV3, + byteCode OCTET STRING, + compilerVersion OCTET STRING, + payable BOOLEAN +} + +TypeInfoV1 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + argType OCTET STRING, + outType OCTET STRING +} + +TypeInfoV3 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + payable BOOLEAN, + argType OCTET STRING, + outType OCTET STRING +} + +-- ============================================================ +-- Notes for implementers +-- ============================================================ +-- 1. Detection (recommended decoder entry point): +-- +-- decode(Binary) -> +-- case Binary of +-- <> when B >= 16#C0 -> +-- decode_legacy_rlp(Binary); % existing gmser_* path +-- _ -> +-- {ok, Term} = +-- 'GajumaruSerialization':decode('GajumaruData', Binary), +-- Term +-- end. +-- +-- This works because: +-- - All current top-level output from serialize() is an RLP list +-- (first byte 0xC0-0xFF). +-- - GajumaruData and the concrete choices above are SEQUENCEs +-- (first byte 0x30 for short form, or 0x30 0x81/0x82... for long). +-- +-- 2. When you add a new object type or version, prefer adding a +-- concrete SEQUENCE alternative in the Content CHOICE rather than +-- always falling back to TemplateFields. This gives you better +-- validation and generated types. +-- +-- 3. For the compact wire format we use UPER (unaligned PER). +-- It is stable/deterministic for a given schema (no extensibility +-- markers on these types, fixed order). +-- +-- 4. INTEGER uses ASN.1 PER encoding (canonical for the constraints). +-- This may differ from legacy RLP minimal unsigned; new format +-- will have different hashes (expected when introducing new encoding). +-- +-- 5. Dynamic encoding (gmser_dyn) is not in scope here. +-- +-- 6. To generate the compact wire: +-- asn1ct:compile(GajumaruSerialization, [uper]). +-- {ok, CompactBytes} = 'GajumaruSerialization':encode('GajumaruData', Value). +-- +-- Use staticFields (not templateFields) for best compactness on static data. + +END diff --git a/asn1_oer/GajumaruSerialization.asn1db b/asn1_oer/GajumaruSerialization.asn1db new file mode 100644 index 0000000000000000000000000000000000000000..558c2fd29b843c794dd57004140a5bf49ec921c5 GIT binary patch literal 16610 zcmeHO+mG8=8F%i;Gl?D9PS2!B z>`FW!!7K0pNN6t-NDG1m2^P?D6PE=ZkoX4>4?OU~1Mg`0jvd>_@$s?eUZGan?R0$N z^W87M?@K0|%l95_E=p47+xwr}sC}`2v!5kdO?@oo$g*zehKgU&jlN;o68)38+5cBd z%G~&*_IEhIz3|nE9j%nY2bbC_3-OO`Vw`|M*Bk?5SO>7V@z@u zw&6(e2v5g`g);E-!q_xy+@o(NmD$f&g$K(cG%(D)rywtQ=A2y~X*%;O%D^%{wz00l zg_?d~3?wOMyJ~_r*9|KAp1rfyFOU)?K*a|nZ<`a0eiC|Igx|vBAypup&DrRXRJL2q z9l6u3ZJ-rWZfwfTGAPN^(U4wl;sf|k z?_u;Vxy`jQvOr};iQHLpIZfs_GeFrWzds}8{i%)XV5nT8eQ{+Oeorp!>;UDWm;anx zr*5hZvAN?Kv6zP3nP|ujP(Dh-FGy*OrqmV1cjv=*m)6_u4Y}4zmV17H3Iq3;BxU~_ z^}V}M-}?dMdw02X#T!#v-{Z*Qhga)+?>tw&_fE3!-8q}@{pc!v@5h(!dw~;7qfT%q z>IC0moZ!v{IRPgqefMge;O*zi3EsYNC-~mwIe~A0g%5cKSlB_s369zx6rk>tSph;5 ze6jwZ-K@*BkSIm-h)v3xZihY;Dwh02I#;!nno!K#mpjRc1hQ^WJw*wakjlPc3{z0R zmM-wp^rYa!ifPyh1%>!3F4h*G#qnJJ40atatsaXk+kR}6{_VxaYYHBXhsehFG(1$TXpmIN z{1INe7SAJJ-)9w&8YiIT5I?MxpeO!>$MyBvI&_e=x>D`#wv^fM@y@F#i#d?ztpn{CtF+~NO4HB*l`}<7l8PPH&>(={Xs&j}g zA-9y~y{4Z`iqN1#7fvdhwN|61v^%>%NQK_#UX`a^B>Oamq%xom(3aZMB*NH$D$$&| zu-*(h@>xsnBLMKc)R6Dhwl|a`DJNx|Puv332CnNl(9NDT)opZ4zNXy0;RIRC}*E*$_`ENOzekUdt0TXYM+rE|DwmM|EE zjlC%)K}A=j=Rl57b048dFzDaWeHE}|8!*vo5NDwVj;q2?!PG790v#V3wl-&Q=VQ;8 z%h7euZmQ>|uX8b<3!qDAN05IYUkBEjZ*6aEL>d6T$(#$r3xH*#s#7ckRETkJAvFL< zKJntYgTuotpiAAP#|CtF9&q19>Vp#rar~4c0S+Sbz!^7q42SB&q^{aM40VW8zITv* z2vZy+!35}o4qbK?@(ge@Kc>P2}e!zI51b zTh!=2jHzGAl4}+BoK7HFa1`$MJBs|0XJTcT+Q^+&ZG*M0Xt@v^OE9tW=}Ltt^36KQ zimI7Vs8{_djHhWqp%2b=~@>S5n#kmn+w3EA@Qxka6WM` zPBTrQsPB7<3d1K+ogI+56PKpGfxDJ*BK1|8wU@iL3BhDOqKYga9z!Q#~;(!ipaUr z`A;P4qW4qo8HB^~35GNL6^lQS5;6}d&c{`-Z{%U*?xedk{MCv-laeuUwtB>OvvUo| zy(i3!;r)uwM=hT-TK*+t`4=@>j#ioIS66BIzrHHV|4m90oU{BBngQSZf1A<-&u;!f z#{8>ig8oD%8hXD#f`^xuCtoEwSSu9!Vz^+APgt*>HDU3KpVy$bMnf@)5S>%y)Yr~R zVmPO6dumlxSWJ#U|P4>ni#usIpxy}f?+NGiPi(x+ZpgI+nekImUS zEzHH<^FA4ZXrg904r4f6ImDNH{86o7G(V1$5L?i?Qi6@*zj#cPyG|#q97h@W2J94j z4|z(AC;s%1JNhOpgTbZ9p1=fwD>L7A*!~bOHon9{%^X8m)(d=}1L_xf2di#(MsQJ0`g=FX0BWX=3_56Ykz1*{A&4&F5!MC9yjd zZ^RjEupmEM^%S*WV%P}13H0)Jd3}0W`HNuMH^pU=$495O(c?S~G2!>)VQ)Bn zmCjDTUMzZncL2=zV$n-~vFPP*+A_UwfzcLpwiE}b_|VM1#$IRy%c+P2c(tSQYpv=JqIJT^?*A~{%I zrvKL9tK0DJP@Pev#m|i}3Octt<`;_d_1N4DIgDA&zLOO|=X6WJul56YD2ynu-y&pw SzRUc)#*TxSpP?zGfBpwt(j{mB literal 0 HcmV?d00001 diff --git a/asn1_oer/GajumaruSerialization.erl b/asn1_oer/GajumaruSerialization.erl new file mode 100644 index 0000000..d48bf9c --- /dev/null +++ b/asn1_oer/GajumaruSerialization.erl @@ -0,0 +1,1540 @@ +%% Generated by the Erlang ASN.1 BER compiler. Version: 5.4.3 +%% Purpose: Encoding and decoding of the types in GajumaruSerialization. + +-module('GajumaruSerialization'). +-moduledoc false. +-compile(nowarn_unused_vars). +-dialyzer(no_improper_lists). +-dialyzer(no_match). +-include("GajumaruSerialization.hrl"). +-asn1_info([{vsn,'5.4.3'}, + {module,'GajumaruSerialization'}, + {options,[oer,{outdir,"asn1_oer"},{i,"."},{i,"asn1_oer"}]}]). + +-export([encoding_rule/0,maps/0,bit_string_format/0, + legacy_erlang_types/0]). +-export(['dialyzer-suppressions'/1]). +-export([ +enc_GajumaruData/2, +enc_CompactStatic/2, +enc_Content/2, +enc_TemplateFields/2, +enc_TemplateField/2, +enc_StaticFields/2, +enc_Value/2, +enc_KeyValue/2, +enc_Id/2, +enc_Account/2, +enc_SignedTx/2, +enc_ContractCode/2, +enc_ContractV1/2, +enc_ContractV2/2, +enc_ContractV3/2, +enc_TypeInfoV1/2, +enc_TypeInfoV3/2 +]). + +-export([ +dec_GajumaruData/2, +dec_CompactStatic/2, +dec_Content/2, +dec_TemplateFields/2, +dec_TemplateField/2, +dec_StaticFields/2, +dec_Value/2, +dec_KeyValue/2, +dec_Id/2, +dec_Account/2, +dec_SignedTx/2, +dec_ContractCode/2, +dec_ContractV1/2, +dec_ContractV2/2, +dec_ContractV3/2, +dec_TypeInfoV1/2, +dec_TypeInfoV3/2 +]). + +-export([info/0]). + +-export([encode/2,decode/2]). + +encoding_rule() -> ber. + +maps() -> false. + +bit_string_format() -> bitstring. + +legacy_erlang_types() -> false. + +encode(Type, Data) -> +try iolist_to_binary(element(1, encode_disp(Type, Data))) of + Bytes -> + {ok,Bytes} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + + +decode(Type, Data) -> +try + Result = decode_disp(Type, element(1, ber_decode_nif(Data))), + {ok,Result} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + +encode_disp('GajumaruData', Data) -> enc_GajumaruData(Data); +encode_disp('CompactStatic', Data) -> enc_CompactStatic(Data); +encode_disp('Content', Data) -> enc_Content(Data); +encode_disp('TemplateFields', Data) -> enc_TemplateFields(Data); +encode_disp('TemplateField', Data) -> enc_TemplateField(Data); +encode_disp('StaticFields', Data) -> enc_StaticFields(Data); +encode_disp('Value', Data) -> enc_Value(Data); +encode_disp('KeyValue', Data) -> enc_KeyValue(Data); +encode_disp('Id', Data) -> enc_Id(Data); +encode_disp('Account', Data) -> enc_Account(Data); +encode_disp('SignedTx', Data) -> enc_SignedTx(Data); +encode_disp('ContractCode', Data) -> enc_ContractCode(Data); +encode_disp('ContractV1', Data) -> enc_ContractV1(Data); +encode_disp('ContractV2', Data) -> enc_ContractV2(Data); +encode_disp('ContractV3', Data) -> enc_ContractV3(Data); +encode_disp('TypeInfoV1', Data) -> enc_TypeInfoV1(Data); +encode_disp('TypeInfoV3', Data) -> enc_TypeInfoV3(Data); +encode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +decode_disp('GajumaruData', Data) -> dec_GajumaruData(Data); +decode_disp('CompactStatic', Data) -> dec_CompactStatic(Data); +decode_disp('Content', Data) -> dec_Content(Data); +decode_disp('TemplateFields', Data) -> dec_TemplateFields(Data); +decode_disp('TemplateField', Data) -> dec_TemplateField(Data); +decode_disp('StaticFields', Data) -> dec_StaticFields(Data); +decode_disp('Value', Data) -> dec_Value(Data); +decode_disp('KeyValue', Data) -> dec_KeyValue(Data); +decode_disp('Id', Data) -> dec_Id(Data); +decode_disp('Account', Data) -> dec_Account(Data); +decode_disp('SignedTx', Data) -> dec_SignedTx(Data); +decode_disp('ContractCode', Data) -> dec_ContractCode(Data); +decode_disp('ContractV1', Data) -> dec_ContractV1(Data); +decode_disp('ContractV2', Data) -> dec_ContractV2(Data); +decode_disp('ContractV3', Data) -> dec_ContractV3(Data); +decode_disp('TypeInfoV1', Data) -> dec_TypeInfoV1(Data); +decode_disp('TypeInfoV3', Data) -> dec_TypeInfoV3(Data); +decode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +info() -> + case ?MODULE:module_info(attributes) of + Attributes when is_list(Attributes) -> + case lists:keyfind(asn1_info, 1, Attributes) of + {_,Info} when is_list(Info) -> + Info; + _ -> + [] + end; + _ -> + [] + end. + + +%%================================ +%% GajumaruData +%%================================ +enc_GajumaruData(Val) -> + enc_GajumaruData(Val, [<<48>>]). + +enc_GajumaruData(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3} = Val, + +%%------------------------------------------------- +%% attribute tag(1) with type INTEGER +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_integer(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute vsn(2) with type INTEGER +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_integer(Cindex2, [<<129>>]), + +%%------------------------------------------------- +%% attribute content(3) External GajumaruSerialization:Content +%%------------------------------------------------- + {EncBytes3,EncLen3} = 'enc_Content'(Cindex3, [<<162>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3], +LenSoFar = EncLen1 + EncLen2 + EncLen3, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_GajumaruData(Tlv) -> + dec_GajumaruData(Tlv, [16]). + +dec_GajumaruData(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute tag(1) with type INTEGER +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = begin +Val1 = decode_integer(V1, [131072]), +if 0 =< Val1, Val1 =< 65535 -> +Val1; +true -> +exit({error,{asn1,bad_range}}) +end +end, + +%%------------------------------------------------- +%% attribute vsn(2) with type INTEGER +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = begin +Val2 = decode_integer(V2, [131073]), +if 0 =< Val2, Val2 =< 255 -> +Val2; +true -> +exit({error,{asn1,bad_range}}) +end +end, + +%%------------------------------------------------- +%% attribute content(3) External GajumaruSerialization:Content +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = 'dec_Content'(V3, [131074]), + +case Tlv4 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv4}}}) % extra fields not allowed +end, +Res1 = {'GajumaruData',Term1,Term2,Term3}, +Res1. + + +%%================================ +%% CompactStatic +%%================================ +enc_CompactStatic(Val) -> + enc_CompactStatic(Val, [<<48>>]). + +enc_CompactStatic(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3} = Val, + +%%------------------------------------------------- +%% attribute tag(1) with type INTEGER +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_integer(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute vsn(2) with type INTEGER +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_integer(Cindex2, [<<129>>]), + +%%------------------------------------------------- +%% attribute fields(3) External GajumaruSerialization:StaticFields +%%------------------------------------------------- + {EncBytes3,EncLen3} = 'enc_StaticFields'(Cindex3, [<<162>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3], +LenSoFar = EncLen1 + EncLen2 + EncLen3, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_CompactStatic(Tlv) -> + dec_CompactStatic(Tlv, [16]). + +dec_CompactStatic(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute tag(1) with type INTEGER +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = begin +Val1 = decode_integer(V1, [131072]), +if 0 =< Val1, Val1 =< 65535 -> +Val1; +true -> +exit({error,{asn1,bad_range}}) +end +end, + +%%------------------------------------------------- +%% attribute vsn(2) with type INTEGER +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = begin +Val2 = decode_integer(V2, [131073]), +if 0 =< Val2, Val2 =< 255 -> +Val2; +true -> +exit({error,{asn1,bad_range}}) +end +end, + +%%------------------------------------------------- +%% attribute fields(3) External GajumaruSerialization:StaticFields +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = 'dec_StaticFields'(V3, [131074]), + +case Tlv4 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv4}}}) % extra fields not allowed +end, +Res1 = {'CompactStatic',Term1,Term2,Term3}, +Res1. + + +%%================================ +%% Content +%%================================ +enc_Content(Val) -> + enc_Content(Val, []). + +enc_Content(Val, TagIn) -> + {EncBytes,EncLen} = case element(1,Val) of + templateFields -> + 'enc_TemplateFields'(element(2,Val), [<<160>>]); + staticFields -> + 'enc_StaticFields'(element(2,Val), [<<170>>]); + account -> + 'enc_Account'(element(2,Val), [<<161>>]); + signedTx -> + 'enc_SignedTx'(element(2,Val), [<<162>>]); + contract -> + 'enc_ContractCode'(element(2,Val), [<<163>>]); + Else -> + exit({error,{asn1,{invalid_choice_type,Else}}}) + end, + +encode_tags(TagIn, EncBytes, EncLen). + + + + +dec_Content(Tlv) -> + dec_Content(Tlv, []). + +dec_Content(Tlv, TagIn) -> +Tlv1 = match_tags(Tlv, TagIn), +case (case Tlv1 of [CtempTlv1] -> CtempTlv1; _ -> Tlv1 end) of + +%% 'templateFields' + {131072, V1} -> + {templateFields, 'dec_TemplateFields'(V1, [])}; + + +%% 'staticFields' + {131082, V1} -> + {staticFields, 'dec_StaticFields'(V1, [])}; + + +%% 'account' + {131073, V1} -> + {account, 'dec_Account'(V1, [])}; + + +%% 'signedTx' + {131074, V1} -> + {signedTx, 'dec_SignedTx'(V1, [])}; + + +%% 'contract' + {131075, V1} -> + {contract, 'dec_ContractCode'(V1, [])}; + + Else -> + exit({error,{asn1,{invalid_choice_tag,Else}}}) + end +. + + +%%================================ +%% TemplateFields +%%================================ +enc_TemplateFields(Val) -> + enc_TemplateFields(Val, [<<48>>]). + +enc_TemplateFields(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_TemplateFields_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_TemplateFields_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_TemplateFields_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_TemplateField'(H, [<<48>>]), + 'enc_TemplateFields_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_TemplateFields(Tlv) -> + dec_TemplateFields(Tlv, [16]). + +dec_TemplateFields(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_TemplateField'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% TemplateField +%%================================ +enc_TemplateField(Val) -> + enc_TemplateField(Val, [<<48>>]). + +enc_TemplateField(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute name(1) with type IA5String OPTIONAL +%%------------------------------------------------- + {EncBytes1,EncLen1} = case Cindex1 of + asn1_NOVALUE -> {<<>>,0}; + _ -> + encode_restricted_string(Cindex1, [<<128>>]) + end, + +%%------------------------------------------------- +%% attribute value(2) External GajumaruSerialization:Value +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_Value'(Cindex2, [<<161>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_TemplateField(Tlv) -> + dec_TemplateField(Tlv, [16]). + +dec_TemplateField(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute name(1) with type IA5String OPTIONAL +%%------------------------------------------------- +{Term1,Tlv2} = case Tlv1 of +[{131072,V1}|TempTlv2] -> + {begin +binary_to_list(decode_restricted_string(V1, [])) +end +, TempTlv2}; + _ -> + { asn1_NOVALUE, Tlv1} +end, + +%%------------------------------------------------- +%% attribute value(2) External GajumaruSerialization:Value +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_Value'(V2, [131073]), + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'TemplateField',Term1,Term2}, +Res1. + + +%%================================ +%% StaticFields +%%================================ +enc_StaticFields(Val) -> + enc_StaticFields(Val, [<<48>>]). + +enc_StaticFields(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_StaticFields_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_StaticFields_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_StaticFields_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_Value'(H, []), + 'enc_StaticFields_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_StaticFields(Tlv) -> + dec_StaticFields(Tlv, [16]). + +dec_StaticFields(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_Value'(V1, []) || V1 <- Tlv1]. + + + + +%%================================ +%% Value +%%================================ +enc_Value(Val) -> + enc_Value(Val, []). + +enc_Value(Val, TagIn) -> + {EncBytes,EncLen} = case element(1,Val) of + intValue -> + encode_integer(element(2,Val), [<<128>>]); + boolValue -> + encode_boolean(element(2,Val), [<<129>>]); + binaryValue -> + encode_restricted_string(element(2,Val), [<<130>>]); + idValue -> + 'enc_Id'(element(2,Val), [<<163>>]); + listValue -> + 'enc_Value_listValue'(element(2,Val), [<<164>>]); + tupleValue -> + 'enc_Value_tupleValue'(element(2,Val), [<<165>>]); + mapValue -> + 'enc_Value_mapValue'(element(2,Val), [<<166>>]); + Else -> + exit({error,{asn1,{invalid_choice_type,Else}}}) + end, + +encode_tags(TagIn, EncBytes, EncLen). + + + + + +%%================================ +%% Value_listValue +%%================================ +enc_Value_listValue(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_Value_listValue_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_Value_listValue_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_Value_listValue_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_Value'(H, []), + 'enc_Value_listValue_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + + +%%================================ +%% Value_tupleValue +%%================================ +enc_Value_tupleValue(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_Value_tupleValue_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_Value_tupleValue_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_Value_tupleValue_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_Value'(H, []), + 'enc_Value_tupleValue_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + + +%%================================ +%% Value_mapValue +%%================================ +enc_Value_mapValue(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_Value_mapValue_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_Value_mapValue_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_Value_mapValue_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_KeyValue'(H, [<<48>>]), + 'enc_Value_mapValue_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_Value(Tlv) -> + dec_Value(Tlv, []). + +dec_Value(Tlv, TagIn) -> +Tlv1 = match_tags(Tlv, TagIn), +case (case Tlv1 of [CtempTlv1] -> CtempTlv1; _ -> Tlv1 end) of + +%% 'intValue' + {131072, V1} -> + {intValue, decode_integer(V1, [])}; + + +%% 'boolValue' + {131073, V1} -> + {boolValue, decode_boolean(V1, [])}; + + +%% 'binaryValue' + {131074, V1} -> + {binaryValue, decode_octet_string(V1, [])}; + + +%% 'idValue' + {131075, V1} -> + {idValue, 'dec_Id'(V1, [])}; + + +%% 'listValue' + {131076, V1} -> + {listValue, 'dec_Value_listValue'(V1, [])}; + + +%% 'tupleValue' + {131077, V1} -> + {tupleValue, 'dec_Value_tupleValue'(V1, [])}; + + +%% 'mapValue' + {131078, V1} -> + {mapValue, 'dec_Value_mapValue'(V1, [])}; + + Else -> + exit({error,{asn1,{invalid_choice_tag,Else}}}) + end +. +'dec_Value_listValue'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_Value'(V1, []) || V1 <- Tlv1]. + + +'dec_Value_tupleValue'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_Value'(V1, []) || V1 <- Tlv1]. + + +'dec_Value_mapValue'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_KeyValue'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% KeyValue +%%================================ +enc_KeyValue(Val) -> + enc_KeyValue(Val, [<<48>>]). + +enc_KeyValue(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute key(1) External GajumaruSerialization:Value +%%------------------------------------------------- + {EncBytes1,EncLen1} = 'enc_Value'(Cindex1, [<<160>>]), + +%%------------------------------------------------- +%% attribute val(2) External GajumaruSerialization:Value +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_Value'(Cindex2, [<<161>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_KeyValue(Tlv) -> + dec_KeyValue(Tlv, [16]). + +dec_KeyValue(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute key(1) External GajumaruSerialization:Value +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = 'dec_Value'(V1, [131072]), + +%%------------------------------------------------- +%% attribute val(2) External GajumaruSerialization:Value +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_Value'(V2, [131073]), + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'KeyValue',Term1,Term2}, +Res1. + + +%%================================ +%% Id +%%================================ +enc_Id(Val) -> + enc_Id(Val, [<<48>>]). + +enc_Id(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute type(1) with type INTEGER +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_integer(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute value(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_Id(Tlv) -> + dec_Id(Tlv, [16]). + +dec_Id(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute type(1) with type INTEGER +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = begin +Val1 = decode_integer(V1, [131072]), +if 0 =< Val1, Val1 =< 255 -> +Val1; +true -> +exit({error,{asn1,bad_range}}) +end +end, + +%%------------------------------------------------- +%% attribute value(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = begin +Val2 = decode_octet_string(V2, [131073]), +C1 = byte_size(Val2), +if C1 =:= 32 -> +Val2; +true -> +exit({error,{asn1,bad_range}}) +end +end, + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'Id',Term1,Term2}, +Res1. + + +%%================================ +%% Account +%%================================ +enc_Account(Val) -> + enc_Account(Val, [<<48>>]). + +enc_Account(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute foo(1) with type INTEGER +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_integer(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute bar(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_Account(Tlv) -> + dec_Account(Tlv, [16]). + +dec_Account(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute foo(1) with type INTEGER +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_integer(V1, [131072]), + +%%------------------------------------------------- +%% attribute bar(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_octet_string(V2, [131073]), + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'Account',Term1,Term2}, +Res1. + + +%%================================ +%% SignedTx +%%================================ +enc_SignedTx(Val) -> + enc_SignedTx(Val, [<<48>>]). + +enc_SignedTx(Val, TagIn) -> +{_,Cindex1,Cindex2} = Val, + +%%------------------------------------------------- +%% attribute signatures(1) with type SEQUENCE OF +%%------------------------------------------------- + {EncBytes1,EncLen1} = 'enc_SignedTx_signatures'(Cindex1, [<<160>>]), + +%%------------------------------------------------- +%% attribute transaction(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + + BytesSoFar = [EncBytes1, EncBytes2], +LenSoFar = EncLen1 + EncLen2, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + + +%%================================ +%% SignedTx_signatures +%%================================ +enc_SignedTx_signatures(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_SignedTx_signatures_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_SignedTx_signatures_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_SignedTx_signatures_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = encode_restricted_string(H, [<<4>>]), + 'enc_SignedTx_signatures_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_SignedTx(Tlv) -> + dec_SignedTx(Tlv, [16]). + +dec_SignedTx(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute signatures(1) with type SEQUENCE OF +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = 'dec_SignedTx_signatures'(V1, [131072]), + +%%------------------------------------------------- +%% attribute transaction(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_octet_string(V2, [131073]), + +case Tlv3 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv3}}}) % extra fields not allowed +end, +Res1 = {'SignedTx',Term1,Term2}, +Res1. +'dec_SignedTx_signatures'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +[decode_octet_string(V1, [4]) || V1 <- Tlv1]. + + + + +%%================================ +%% ContractCode +%%================================ +enc_ContractCode(Val) -> + enc_ContractCode(Val, []). + +enc_ContractCode(Val, TagIn) -> + {EncBytes,EncLen} = case element(1,Val) of + v1 -> + 'enc_ContractV1'(element(2,Val), [<<160>>]); + v2 -> + 'enc_ContractV2'(element(2,Val), [<<161>>]); + v3 -> + 'enc_ContractV3'(element(2,Val), [<<162>>]); + Else -> + exit({error,{asn1,{invalid_choice_type,Else}}}) + end, + +encode_tags(TagIn, EncBytes, EncLen). + + + + +dec_ContractCode(Tlv) -> + dec_ContractCode(Tlv, []). + +dec_ContractCode(Tlv, TagIn) -> +Tlv1 = match_tags(Tlv, TagIn), +case (case Tlv1 of [CtempTlv1] -> CtempTlv1; _ -> Tlv1 end) of + +%% 'v1' + {131072, V1} -> + {v1, 'dec_ContractV1'(V1, [])}; + + +%% 'v2' + {131073, V1} -> + {v2, 'dec_ContractV2'(V1, [])}; + + +%% 'v3' + {131074, V1} -> + {v3, 'dec_ContractV3'(V1, [])}; + + Else -> + exit({error,{asn1,{invalid_choice_tag,Else}}}) + end +. + + +%%================================ +%% ContractV1 +%%================================ +enc_ContractV1(Val) -> + enc_ContractV1(Val, [<<48>>]). + +enc_ContractV1(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3} = Val, + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_ContractV1_typeInfo'(Cindex2, [<<161>>]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_restricted_string(Cindex3, [<<130>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3], +LenSoFar = EncLen1 + EncLen2 + EncLen3, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + + +%%================================ +%% ContractV1_typeInfo +%%================================ +enc_ContractV1_typeInfo(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_ContractV1_typeInfo_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_ContractV1_typeInfo_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_ContractV1_typeInfo_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_TypeInfoV1'(H, [<<48>>]), + 'enc_ContractV1_typeInfo_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_ContractV1(Tlv) -> + dec_ContractV1(Tlv, [16]). + +dec_ContractV1(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_ContractV1_typeInfo'(V2, [131073]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_octet_string(V3, [131074]), + +case Tlv4 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv4}}}) % extra fields not allowed +end, +Res1 = {'ContractV1',Term1,Term2,Term3}, +Res1. +'dec_ContractV1_typeInfo'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_TypeInfoV1'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% ContractV2 +%%================================ +enc_ContractV2(Val) -> + enc_ContractV2(Val, [<<48>>]). + +enc_ContractV2(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3,Cindex4} = Val, + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_ContractV2_typeInfo'(Cindex2, [<<161>>]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_restricted_string(Cindex3, [<<130>>]), + +%%------------------------------------------------- +%% attribute compilerVersion(4) with type OCTET STRING +%%------------------------------------------------- + {EncBytes4,EncLen4} = encode_restricted_string(Cindex4, [<<131>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3, EncBytes4], +LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + + +%%================================ +%% ContractV2_typeInfo +%%================================ +enc_ContractV2_typeInfo(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_ContractV2_typeInfo_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_ContractV2_typeInfo_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_ContractV2_typeInfo_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_TypeInfoV1'(H, [<<48>>]), + 'enc_ContractV2_typeInfo_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_ContractV2(Tlv) -> + dec_ContractV2(Tlv, [16]). + +dec_ContractV2(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_ContractV2_typeInfo'(V2, [131073]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_octet_string(V3, [131074]), + +%%------------------------------------------------- +%% attribute compilerVersion(4) with type OCTET STRING +%%------------------------------------------------- +[V4|Tlv5] = Tlv4, +Term4 = decode_octet_string(V4, [131075]), + +case Tlv5 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv5}}}) % extra fields not allowed +end, +Res1 = {'ContractV2',Term1,Term2,Term3,Term4}, +Res1. +'dec_ContractV2_typeInfo'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_TypeInfoV1'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% ContractV3 +%%================================ +enc_ContractV3(Val) -> + enc_ContractV3(Val, [<<48>>]). + +enc_ContractV3(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3,Cindex4,Cindex5} = Val, + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- + {EncBytes2,EncLen2} = 'enc_ContractV3_typeInfo'(Cindex2, [<<161>>]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_restricted_string(Cindex3, [<<130>>]), + +%%------------------------------------------------- +%% attribute compilerVersion(4) with type OCTET STRING +%%------------------------------------------------- + {EncBytes4,EncLen4} = encode_restricted_string(Cindex4, [<<131>>]), + +%%------------------------------------------------- +%% attribute payable(5) with type BOOLEAN +%%------------------------------------------------- + {EncBytes5,EncLen5} = encode_boolean(Cindex5, [<<132>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3, EncBytes4, EncBytes5], +LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4 + EncLen5, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + + +%%================================ +%% ContractV3_typeInfo +%%================================ +enc_ContractV3_typeInfo(Val, TagIn) -> + {EncBytes,EncLen} = 'enc_ContractV3_typeInfo_components'(Val,[],0), + encode_tags(TagIn, EncBytes, EncLen). + +'enc_ContractV3_typeInfo_components'([], AccBytes, AccLen) -> + {lists:reverse(AccBytes),AccLen}; + +'enc_ContractV3_typeInfo_components'([H|T],AccBytes, AccLen) -> + {EncBytes,EncLen} = 'enc_TypeInfoV3'(H, [<<48>>]), + 'enc_ContractV3_typeInfo_components'(T,[EncBytes|AccBytes], AccLen + EncLen). + + + +dec_ContractV3(Tlv) -> + dec_ContractV3(Tlv, [16]). + +dec_ContractV3(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute sourceHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute typeInfo(2) with type SEQUENCE OF +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = 'dec_ContractV3_typeInfo'(V2, [131073]), + +%%------------------------------------------------- +%% attribute byteCode(3) with type OCTET STRING +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_octet_string(V3, [131074]), + +%%------------------------------------------------- +%% attribute compilerVersion(4) with type OCTET STRING +%%------------------------------------------------- +[V4|Tlv5] = Tlv4, +Term4 = decode_octet_string(V4, [131075]), + +%%------------------------------------------------- +%% attribute payable(5) with type BOOLEAN +%%------------------------------------------------- +[V5|Tlv6] = Tlv5, +Term5 = decode_boolean(V5, [131076]), + +case Tlv6 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv6}}}) % extra fields not allowed +end, +Res1 = {'ContractV3',Term1,Term2,Term3,Term4,Term5}, +Res1. +'dec_ContractV3_typeInfo'(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), +['dec_TypeInfoV3'(V1, [16]) || V1 <- Tlv1]. + + + + +%%================================ +%% TypeInfoV1 +%%================================ +enc_TypeInfoV1(Val) -> + enc_TypeInfoV1(Val, [<<48>>]). + +enc_TypeInfoV1(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3,Cindex4} = Val, + +%%------------------------------------------------- +%% attribute typeHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute name(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + +%%------------------------------------------------- +%% attribute argType(3) with type OCTET STRING +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_restricted_string(Cindex3, [<<130>>]), + +%%------------------------------------------------- +%% attribute outType(4) with type OCTET STRING +%%------------------------------------------------- + {EncBytes4,EncLen4} = encode_restricted_string(Cindex4, [<<131>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3, EncBytes4], +LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_TypeInfoV1(Tlv) -> + dec_TypeInfoV1(Tlv, [16]). + +dec_TypeInfoV1(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute typeHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute name(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_octet_string(V2, [131073]), + +%%------------------------------------------------- +%% attribute argType(3) with type OCTET STRING +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_octet_string(V3, [131074]), + +%%------------------------------------------------- +%% attribute outType(4) with type OCTET STRING +%%------------------------------------------------- +[V4|Tlv5] = Tlv4, +Term4 = decode_octet_string(V4, [131075]), + +case Tlv5 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv5}}}) % extra fields not allowed +end, +Res1 = {'TypeInfoV1',Term1,Term2,Term3,Term4}, +Res1. + + +%%================================ +%% TypeInfoV3 +%%================================ +enc_TypeInfoV3(Val) -> + enc_TypeInfoV3(Val, [<<48>>]). + +enc_TypeInfoV3(Val, TagIn) -> +{_,Cindex1,Cindex2,Cindex3,Cindex4,Cindex5} = Val, + +%%------------------------------------------------- +%% attribute typeHash(1) with type OCTET STRING +%%------------------------------------------------- + {EncBytes1,EncLen1} = encode_restricted_string(Cindex1, [<<128>>]), + +%%------------------------------------------------- +%% attribute name(2) with type OCTET STRING +%%------------------------------------------------- + {EncBytes2,EncLen2} = encode_restricted_string(Cindex2, [<<129>>]), + +%%------------------------------------------------- +%% attribute payable(3) with type BOOLEAN +%%------------------------------------------------- + {EncBytes3,EncLen3} = encode_boolean(Cindex3, [<<130>>]), + +%%------------------------------------------------- +%% attribute argType(4) with type OCTET STRING +%%------------------------------------------------- + {EncBytes4,EncLen4} = encode_restricted_string(Cindex4, [<<131>>]), + +%%------------------------------------------------- +%% attribute outType(5) with type OCTET STRING +%%------------------------------------------------- + {EncBytes5,EncLen5} = encode_restricted_string(Cindex5, [<<132>>]), + + BytesSoFar = [EncBytes1, EncBytes2, EncBytes3, EncBytes4, EncBytes5], +LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4 + EncLen5, +encode_tags(TagIn, BytesSoFar, LenSoFar). + + +dec_TypeInfoV3(Tlv) -> + dec_TypeInfoV3(Tlv, [16]). + +dec_TypeInfoV3(Tlv, TagIn) -> + %%------------------------------------------------- + %% decode tag and length + %%------------------------------------------------- +Tlv1 = match_tags(Tlv, TagIn), + +%%------------------------------------------------- +%% attribute typeHash(1) with type OCTET STRING +%%------------------------------------------------- +[V1|Tlv2] = Tlv1, +Term1 = decode_octet_string(V1, [131072]), + +%%------------------------------------------------- +%% attribute name(2) with type OCTET STRING +%%------------------------------------------------- +[V2|Tlv3] = Tlv2, +Term2 = decode_octet_string(V2, [131073]), + +%%------------------------------------------------- +%% attribute payable(3) with type BOOLEAN +%%------------------------------------------------- +[V3|Tlv4] = Tlv3, +Term3 = decode_boolean(V3, [131074]), + +%%------------------------------------------------- +%% attribute argType(4) with type OCTET STRING +%%------------------------------------------------- +[V4|Tlv5] = Tlv4, +Term4 = decode_octet_string(V4, [131075]), + +%%------------------------------------------------- +%% attribute outType(5) with type OCTET STRING +%%------------------------------------------------- +[V5|Tlv6] = Tlv5, +Term5 = decode_octet_string(V5, [131076]), + +case Tlv6 of +[] -> true;_ -> exit({error,{asn1, {unexpected,Tlv6}}}) % extra fields not allowed +end, +Res1 = {'TypeInfoV3',Term1,Term2,Term3,Term4,Term5}, +Res1. + +%%% +%%% Run-time functions. +%%% + +'dialyzer-suppressions'(Arg) -> + ok. + +ber_decode_nif(B) -> + asn1rt_nif:decode_ber_tlv(B). + +collect_parts(TlvList) -> + collect_parts(TlvList, []). + +collect_parts([{_, L} | Rest], Acc) when is_list(L) -> + collect_parts(Rest, [collect_parts(L) | Acc]); +collect_parts([{3, <>} | Rest], _Acc) -> + collect_parts_bit(Rest, [Bits], Unused); +collect_parts([{_T, V} | Rest], Acc) -> + collect_parts(Rest, [V | Acc]); +collect_parts([], Acc) -> + list_to_binary(lists:reverse(Acc)). + +collect_parts_bit([{3, <>} | Rest], Acc, Uacc) -> + collect_parts_bit(Rest, [Bits | Acc], Unused + Uacc); +collect_parts_bit([], Acc, Uacc) -> + list_to_binary([Uacc | lists:reverse(Acc)]). + +decode_boolean(Tlv, TagIn) -> + Val = match_tags(Tlv, TagIn), + case Val of + <<0:8>> -> + false; + <<_:8>> -> + true; + _ -> + exit({error, {asn1, {decode_boolean, Val}}}) + end. + +decode_integer(Tlv, TagIn) -> + Bin = match_tags(Tlv, TagIn), + Len = byte_size(Bin), + <> = Bin, + Int. + +decode_octet_string(Tlv, TagsIn) -> + Bin = match_and_collect(Tlv, TagsIn), + binary:copy(Bin). + +decode_restricted_string(Tlv, TagsIn) -> + match_and_collect(Tlv, TagsIn). + +encode_boolean(true, TagIn) -> + encode_tags(TagIn, [255], 1); +encode_boolean(false, TagIn) -> + encode_tags(TagIn, [0], 1); +encode_boolean(X, _) -> + exit({error, {asn1, {encode_boolean, X}}}). + +encode_integer(Val) -> + Bytes = + if + Val >= 0 -> + encode_integer_pos(Val, []); + true -> + encode_integer_neg(Val, []) + end, + {Bytes, length(Bytes)}. + +encode_integer(Val, Tag) when is_integer(Val) -> + encode_tags(Tag, encode_integer(Val)); +encode_integer(Val, _Tag) -> + exit({error, {asn1, {encode_integer, Val}}}). + +encode_integer_neg(-1, [B1 | _T] = L) when B1 > 127 -> + L; +encode_integer_neg(N, Acc) -> + encode_integer_neg(N bsr 8, [N band 255 | Acc]). + +encode_integer_pos(0, [B | _Acc] = L) when B < 128 -> + L; +encode_integer_pos(N, Acc) -> + encode_integer_pos(N bsr 8, [N band 255 | Acc]). + +encode_length(L) when L =< 127 -> + {[L], 1}; +encode_length(L) -> + Oct = minimum_octets(L), + Len = length(Oct), + if + Len =< 126 -> + {[128 bor Len | Oct], Len + 1}; + true -> + exit({error, {asn1, too_long_length_oct, Len}}) + end. + +encode_restricted_string(OctetList, TagIn) when is_binary(OctetList) -> + encode_tags(TagIn, OctetList, byte_size(OctetList)); +encode_restricted_string(OctetList, TagIn) when is_list(OctetList) -> + encode_tags(TagIn, OctetList, length(OctetList)). + +encode_tags(TagIn, {BytesSoFar, LenSoFar}) -> + encode_tags(TagIn, BytesSoFar, LenSoFar). + +encode_tags([Tag | Trest], BytesSoFar, LenSoFar) -> + {Bytes2, L2} = encode_length(LenSoFar), + encode_tags(Trest, + [Tag, Bytes2 | BytesSoFar], + LenSoFar + byte_size(Tag) + L2); +encode_tags([], BytesSoFar, LenSoFar) -> + {BytesSoFar, LenSoFar}. + +match_and_collect(Tlv, TagsIn) -> + Val = match_tags(Tlv, TagsIn), + case Val of + [_ | _] = PartList -> + collect_parts(PartList); + Bin when is_binary(Bin) -> + Bin + end. + +match_tags({T, V}, [T]) -> + V; +match_tags({T, V}, [T | Tt]) -> + match_tags(V, Tt); +match_tags([{T, V}], [T | Tt]) -> + match_tags(V, Tt); +match_tags([{T, _V} | _] = Vlist, [T]) -> + Vlist; +match_tags(Tlv, []) -> + Tlv; +match_tags({Tag, _V} = Tlv, [T | _Tt]) -> + exit({error, {asn1, {wrong_tag, {{expected, T}, {got, Tag, Tlv}}}}}). + +minimum_octets(0, Acc) -> + Acc; +minimum_octets(Val, Acc) -> + minimum_octets(Val bsr 8, [Val band 255 | Acc]). + +minimum_octets(Val) -> + minimum_octets(Val, []). diff --git a/asn1_oer/GajumaruSerialization.hrl b/asn1_oer/GajumaruSerialization.hrl new file mode 100644 index 0000000..9d7d397 --- /dev/null +++ b/asn1_oer/GajumaruSerialization.hrl @@ -0,0 +1,82 @@ +%% Generated by the Erlang ASN.1 compiler. Version: 5.4.3 +%% Purpose: Erlang record definitions for each named and unnamed +%% SEQUENCE and SET, and macro definitions for each value +%% definition in module GajumaruSerialization. + +-ifndef(_GAJUMARUSERIALIZATION_HRL_). +-define(_GAJUMARUSERIALIZATION_HRL_, true). + +-record('GajumaruData', { + tag, + vsn, + content +}). + +-record('CompactStatic', { + tag, + vsn, + fields +}). + +-record('TemplateField', { + name = asn1_NOVALUE, + value +}). + +-record('KeyValue', { + key, + val +}). + +-record('Id', { + type, + value +}). + +-record('Account', { + foo, + bar +}). + +-record('SignedTx', { + signatures, + transaction +}). + +-record('ContractV1', { + sourceHash, + typeInfo, + byteCode +}). + +-record('ContractV2', { + sourceHash, + typeInfo, + byteCode, + compilerVersion +}). + +-record('ContractV3', { + sourceHash, + typeInfo, + byteCode, + compilerVersion, + payable +}). + +-record('TypeInfoV1', { + typeHash, + name, + argType, + outType +}). + +-record('TypeInfoV3', { + typeHash, + name, + payable, + argType, + outType +}). + +-endif. %% _GAJUMARUSERIALIZATION_HRL_ diff --git a/asn1_optimized/GajumaruSerialization.asn b/asn1_optimized/GajumaruSerialization.asn new file mode 100644 index 0000000..ca7d742 --- /dev/null +++ b/asn1_optimized/GajumaruSerialization.asn @@ -0,0 +1,235 @@ +-- GajumaruSerialization.asn +-- +-- ASN.1 model for the structures serialized by gmserialization.erl +-- (the layer on top of RLP). +-- +-- Purpose: +-- * Provide a formal, toolable description of the data. +-- * Enable migration from the legacy RLP-based format to DER. +-- +-- Detection of legacy vs new: +-- Legacy data (produced by gmserialization:serialize / gmser_chain_objects:serialize +-- or gmser_dyn:serialize) is always an RLP *list* at the top level. +-- This means the first byte is in the range 0xC0 .. 0xFF. +-- +-- DER-encoded data using the types below will start with 0x30 (SEQUENCE, +-- constructed, universal tag) for the outermost GajumaruData (or any +-- top-level SEQUENCE we define). 0x30 < 0xC0, so a single-byte prefix +-- check reliably distinguishes the two formats. +-- +-- Usage in Erlang (after compiling with asn1ct): +-- {ok, Mod} = asn1ct:compile(GajumaruSerialization.asn, [ber, der]). +-- {ok, Term} = 'GajumaruSerialization':decode('GajumaruData', DerBinary). +-- +-- Notes on type mapping from gmserialization.erl: +-- - int -> INTEGER (new data uses canonical DER INTEGER) +-- - binary -> OCTET STRING +-- - bool -> BOOLEAN +-- - id -> Id (SEQUENCE) (cleaner than the legacy packed 33-byte form) +-- - [T] -> SEQUENCE OF T +-- - {T1,...} -> SEQUENCE (fixed-size, order matters) +-- - #{items := [{K,T},...]} -> SEQUENCE with the fields in template order +-- (static maps carry *values only*, no keys on the wire) +-- - tag + vsn are preserved as the first two fields for compatibility +-- with existing dispatch logic. +-- +-- Legacy integers had strict unsigned-minimal no-leading-zero (except for 0) +-- and RLP-level rules. New DER data does not need to follow those rules. +-- +-- WARNING: +-- Any cryptographic hash or signature computed over a serialized object +-- will change when switching from RLP to DER for that object. Plan a +-- coordinated upgrade. + +GajumaruSerialization DEFINITIONS + AUTOMATIC TAGS ::= +BEGIN + +EXPORTS ALL; + +-- ============================================================ +-- Top-level wrapper used for new DER data. +-- This is what a decoder will see first. +-- ============================================================ + +GajumaruData ::= SEQUENCE { + -- Constrained for better PER packing + tag INTEGER (0..65535), + vsn INTEGER (0..255), + content Content +} + +-- Content can be a specific structured type (preferred) or a generic +-- representation of a template-driven object. +Content ::= CHOICE { + -- Generic fallback that can represent any [{Field, Type}] template + -- without having a pre-defined SEQUENCE for every object. + templateFields [0] TemplateFields, + + -- Static-optimized: no field names on wire (matches legacy static behavior exactly) + -- Preferred for compact wire format of known templates. + staticFields [10] StaticFields, + + -- Examples of concrete versioned types (extend as needed) + account [1] Account, + signedTx [2] SignedTx, + contract [3] ContractCode + -- Add more alternatives for other tags from gmser_chain_objects +} + +-- ============================================================ +-- Generic template-driven representation +-- (useful during transition or for unregistered types) +-- ============================================================ + +TemplateFields ::= SEQUENCE OF TemplateField + +TemplateField ::= SEQUENCE { + -- Field name is included for debuggability / generic processing. + -- In the original static encoding the name is NOT on the wire; + -- only position and type matter. We include it here for convenience. + name IA5String OPTIONAL, + value Value +} + +-- Optimized for static wire format: just the values in order, no names. +-- This matches the legacy static encoding where maps/records are positional only. +StaticFields ::= SEQUENCE OF Value + + +Value ::= CHOICE { + intValue [0] INTEGER, + boolValue [1] BOOLEAN, + binaryValue [2] OCTET STRING, + idValue [3] Id, + listValue [4] SEQUENCE OF Value, + tupleValue [5] SEQUENCE OF Value, + mapValue [6] SEQUENCE OF KeyValue -- only needed if you want to + -- represent dynamic-style maps +} + +KeyValue ::= SEQUENCE { + key Value, + val Value +} + +-- ============================================================ +-- Common types +-- ============================================================ + +Id ::= SEQUENCE { + -- Corresponds to the simple tags in gmser_id (account=1, name=2, etc.) + -- and the extended account subtype (high bit in legacy). + type INTEGER (0..255), + value OCTET STRING (SIZE (32)) +} + +-- ============================================================ +-- Concrete object examples (derived from usage in the codebase) +-- Add / evolve per version as you introduce new vsns. +-- ============================================================ + +-- Example: a very simple account-like object used in tests +Account ::= SEQUENCE { + foo INTEGER, + bar OCTET STRING +} + +-- Simplified signed transaction +SignedTx ::= SEQUENCE { + signatures SEQUENCE OF OCTET STRING, + transaction OCTET STRING +} + +-- Contract code objects (see gmser_contract_code.erl) +-- We model the three versions that exist today. +ContractCode ::= CHOICE { + v1 [0] ContractV1, + v2 [1] ContractV2, + v3 [2] ContractV3 +} + +ContractV1 ::= SEQUENCE { + sourceHash OCTET STRING, + -- typeInfo is a list of 4-tuples in legacy: + -- {typeHash, name, argType, outType} + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING +} + +ContractV2 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING, + compilerVersion OCTET STRING +} + +ContractV3 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV3, + byteCode OCTET STRING, + compilerVersion OCTET STRING, + payable BOOLEAN +} + +TypeInfoV1 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + argType OCTET STRING, + outType OCTET STRING +} + +TypeInfoV3 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + payable BOOLEAN, + argType OCTET STRING, + outType OCTET STRING +} + +-- ============================================================ +-- Notes for implementers +-- ============================================================ +-- 1. Detection (recommended decoder entry point): +-- +-- decode(Binary) -> +-- case Binary of +-- <> when B >= 16#C0 -> +-- decode_legacy_rlp(Binary); % existing gmser_* path +-- _ -> +-- {ok, Term} = +-- 'GajumaruSerialization':decode('GajumaruData', Binary), +-- Term +-- end. +-- +-- This works because: +-- - All current top-level output from serialize() is an RLP list +-- (first byte 0xC0-0xFF). +-- - GajumaruData and the concrete choices above are SEQUENCEs +-- (first byte 0x30 for short form, or 0x30 0x81/0x82... for long). +-- +-- 2. When you add a new object type or version, prefer adding a +-- concrete SEQUENCE alternative in the Content CHOICE rather than +-- always falling back to TemplateFields. This gives you better +-- validation and generated types. +-- +-- 3. INTEGER in DER is signed and uses a different minimal encoding +-- than the legacy unsigned big-endian no leading zero form. This is +-- fine for new data. +-- +-- 4. If you need to preserve exact legacy integer wire bytes inside +-- the new format (e.g. for some hash preimage reason), you can +-- carry selected integers as OCTET STRING (legacy unsigned minimal bytes). +-- +-- 5. Dynamic encoding (gmser_dyn) is intentionally not modeled here +-- in full, because it is runtime-schema driven (type codes 246-255, +-- labels, alt/switch, etc.). You can still use the generic +-- TemplateFields + Value for some dynamic cases, or model specific +-- message schemas as additional CHOICE arms. +-- +-- 6. Compile with DER for canonical output: +-- asn1ct:compile(GajumaruSerialization, [der]). +-- +-- The ber option is also accepted; der implies the stricter rules. + +END diff --git a/asn1_optimized/GajumaruSerialization.asn1db b/asn1_optimized/GajumaruSerialization.asn1db new file mode 100644 index 0000000000000000000000000000000000000000..3824998787bd3117e9da0b082d4c4821c7d761a1 GIT binary patch literal 15985 zcmeHO%a0>R8SnAip2yB+St22j2E-9ZnjInpkx)E#@2qz{_Au_5>_Vhbjk{*t9=qG= zZf}hVHv}Aj3rQp*1wjH*2oFJm#8cdnI3V#Cz=10V?kIfac6V31tE=1dT%lcQwO&_s z*Z2N@^?jcgQt3?R;r5~=E&TBCrAFoJ-DkQflG4;KOKGyK8@i$57j>g+Shh6zbMqf> zeo;!l`|z$ElV!bo=mu?bM zvoU|I)G-D_6I&Km{ReUbJTT1hp(L%W!>h9f(Xsh3Or+uvDoL;@)5V%eGQbC=CZnSP zCLcqVzJ9QUdZPg{M{R6slze1shEDfbzzTYHvKx4xc|Cl+NME8J*yym2ed03qc!){b z!ZvKlo#64%u+Rd0E)7k?#vS^0Qk;IqDl9AyP|q+A9)rAKZL)WHpy|w4l!0Y@YGYl6 z12z4~=t)xAcGLuKt{PPI9eaPHnl$0!EWOnd9WOci|WAoKkQ;{DkNMa6^dSt0pRb*wYt?bsDTfH7h=>{ndkgg&d zlASqD*x4_{yo2aZ9jF2`%FyWB^k#g!qqWl)l-qdq;{#7FQ~ z?_l&Exy`jQQlhe=MDA}moW}FJ&_k&(zds{|!?BI4V5nT8J#nQNe&-i;&s! zC-^?&1nZaN1e~Ds=Jh(kTThe|ymjeL@Pn&!0?z=mA8`#ZyN~)K9JW0Gjn2vxfY1b= ztKMtXt1<-=`EVY=q@d|`;GqCm@)GF`YRT6D%xuZK@reYou8*F=1RRm#p<(nBP{2YL zcxm!fwjie9m@FP@Ix@!zXgDvN5Q?Hp@|v1}2o_HOhKqz@-6$_e)zx^trNvUyNU^V3 zNi2tjAd!$$z=jsZhGXkVlUYX0Pmh%B(Xfvb$RD5zdu!lhXaPgLi(x1$X6S?z256Xo zom>)j0zn}f#YNiUNfgh82iS4Eqb6|~i8=X>lWnp)ALUs%fu+273 zuue*zJZkh==gZXQBmYGa>|U-0AoCeRTFgOx#|}K&()TKDpVGq4Zfi&0RpRNrGW9_5 zDEk-JQI_QGO}SQ+Yim2TeKt5ar90M3f?H#P#9}atCcVyvYa1*DE1C)gChbV;I8{16 ztjmQ^75k2YV~p5xy&!p=OH5n=9a@tzocH2rm-Y)XFMu4O=ANaMV9@_W_hqOh+fWlN`*9X9a1;tZ15>x$19W_B*xHQ2U5q_n zEk`$8yD49ozAnUkE`ctg9YOwqeC=Cnrn%Q>gf0MllerLvOHj*3$eKAC$ph9a$skeYJ2U(`r zzC{273w8gDrbnMW6Fx*IrdZT1Jn^=#?6Qijj;Rfyk>NAE+L|EBnzuByMDKJ~a0vr) z0oo3Rs_DnxF#t%I!biAX#vZb2!IOPluC$x$WePLhw>XlYwvE_Ii2TrN8j*CR`6%Q} zuFm|263cJd=-AjULu>9B+D&3oW=bMrmkQA&u8Xh|DkAexgJ^2xnt zMfx!`agl^ROk!ue_Tbk@HV}RJhApxtm!y?8bcvz=N|7HF4uPyS=$yuOEom3eSJW?E zMFsD+VV%81W_Dbe`o7}y%;!>Hv0iz;ZJQ8GW<#1QJzw$MF7C@o)x^Y~=X8c}$BiTm^eZ9xSWOJLtggd;f{#jnQP}LVPw`be_NOA8dZV8n%2+ z-|tt9pWB$!GL9bjM4!s8P z7q2W&4oMnjzQn!=C?`?E8lE>{N!+aZ3P}U_5t9hfIT4AkoR`D^5K8U2YF%>YrD||f z4y*QaB)H*n)EmAfq0di7=ESm_55&S0rUD2iP3-@xehi zbs}Y-f9|u-ZNNP(GlE9Rbl4HP7JqghU24umuW5gYg zf#OYyA5y6yhN@_m#9zB5#Y%LXlMxddnCAFO5n^m z3@6^bMpBRY;LYP_MkSFQ@7JP?)gND;4&pJ*2scXkrwQvu=yjl%KWXW`ft5d)P$a#t z$J2W!-d@BtCG-Z+yCJq07P5)xeIuUU>5#EVzPyqX#EyTthIT`Fv?G_jmh3LjF6yh# z?2aIj(^pSHYeOAL`q~*-`+w+bLvMJ&bd{a2bSAA&MeSHNu@|=ZWH@B*;zB*+5%l$zpMrkor=vVHFwQ zx1y*IK)86?OJdsZ!_9o^MMAQZrltE)WV;R-PjO66dO!*kj$su5qLAdIndw0k$sX2> zr#X<9!j-=UWT7bn64MMth(x!KMik8fAQew{U~1I6i)8=qI{Iq$UWJaS$-C2EJh2`h z9>EE3=V^!uzn=(t!`V?fVxT+pXGOL+%zyZeXZTVnUyZ$SD9IDtk(6 zyQ0*qaE-|0)1hJ77D>ZsDgD0&KdgoS2XID?g3;Ar8Pr3DvjA+SYaA?6P1~P-v7F8Y ec<|n@2L($A?2o#b&v%&58*BrJ`3$#E`saT;UR!Md literal 0 HcmV?d00001 diff --git a/asn1_optimized/GajumaruSerialization.erl b/asn1_optimized/GajumaruSerialization.erl new file mode 100644 index 0000000..ad83e9b --- /dev/null +++ b/asn1_optimized/GajumaruSerialization.erl @@ -0,0 +1,1684 @@ +%% Generated by the Erlang ASN.1 PER (unaligned) compiler. Version: 5.4.3 +%% Purpose: Encoding and decoding of the types in GajumaruSerialization. + +-module('GajumaruSerialization'). +-moduledoc false. +-compile(nowarn_unused_vars). +-dialyzer(no_improper_lists). +-dialyzer(no_match). +-include("GajumaruSerialization.hrl"). +-asn1_info([{vsn,'5.4.3'}, + {module,'GajumaruSerialization'}, + {options,[uper,{outdir,"asn1_optimized"},{i,"."},{i,"asn1_optimized"}]}]). + +-export([encoding_rule/0,maps/0,bit_string_format/0, + legacy_erlang_types/0]). +-export(['dialyzer-suppressions'/1]). +-export([ +enc_GajumaruData/1, +enc_Content/1, +enc_TemplateFields/1, +enc_TemplateField/1, +enc_StaticFields/1, +enc_Value/1, +enc_KeyValue/1, +enc_Id/1, +enc_Account/1, +enc_SignedTx/1, +enc_ContractCode/1, +enc_ContractV1/1, +enc_ContractV2/1, +enc_ContractV3/1, +enc_TypeInfoV1/1, +enc_TypeInfoV3/1 +]). + +-export([ +dec_GajumaruData/1, +dec_Content/1, +dec_TemplateFields/1, +dec_TemplateField/1, +dec_StaticFields/1, +dec_Value/1, +dec_KeyValue/1, +dec_Id/1, +dec_Account/1, +dec_SignedTx/1, +dec_ContractCode/1, +dec_ContractV1/1, +dec_ContractV2/1, +dec_ContractV3/1, +dec_TypeInfoV1/1, +dec_TypeInfoV3/1 +]). + +-export([info/0]). + +-export([encode/2,decode/2]). + +encoding_rule() -> uper. + +maps() -> false. + +bit_string_format() -> bitstring. + +legacy_erlang_types() -> false. + +encode(Type, Data) -> +try complete(encode_disp(Type, Data)) of + Bytes -> + {ok,Bytes} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + + +decode(Type, Data) -> +try + {Result,_Rest} = decode_disp(Type, Data), + {ok,Result} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + +encode_disp('GajumaruData', Data) -> enc_GajumaruData(Data); +encode_disp('Content', Data) -> enc_Content(Data); +encode_disp('TemplateFields', Data) -> enc_TemplateFields(Data); +encode_disp('TemplateField', Data) -> enc_TemplateField(Data); +encode_disp('StaticFields', Data) -> enc_StaticFields(Data); +encode_disp('Value', Data) -> enc_Value(Data); +encode_disp('KeyValue', Data) -> enc_KeyValue(Data); +encode_disp('Id', Data) -> enc_Id(Data); +encode_disp('Account', Data) -> enc_Account(Data); +encode_disp('SignedTx', Data) -> enc_SignedTx(Data); +encode_disp('ContractCode', Data) -> enc_ContractCode(Data); +encode_disp('ContractV1', Data) -> enc_ContractV1(Data); +encode_disp('ContractV2', Data) -> enc_ContractV2(Data); +encode_disp('ContractV3', Data) -> enc_ContractV3(Data); +encode_disp('TypeInfoV1', Data) -> enc_TypeInfoV1(Data); +encode_disp('TypeInfoV3', Data) -> enc_TypeInfoV3(Data); +encode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +decode_disp('GajumaruData', Data) -> dec_GajumaruData(Data); +decode_disp('Content', Data) -> dec_Content(Data); +decode_disp('TemplateFields', Data) -> dec_TemplateFields(Data); +decode_disp('TemplateField', Data) -> dec_TemplateField(Data); +decode_disp('StaticFields', Data) -> dec_StaticFields(Data); +decode_disp('Value', Data) -> dec_Value(Data); +decode_disp('KeyValue', Data) -> dec_KeyValue(Data); +decode_disp('Id', Data) -> dec_Id(Data); +decode_disp('Account', Data) -> dec_Account(Data); +decode_disp('SignedTx', Data) -> dec_SignedTx(Data); +decode_disp('ContractCode', Data) -> dec_ContractCode(Data); +decode_disp('ContractV1', Data) -> dec_ContractV1(Data); +decode_disp('ContractV2', Data) -> dec_ContractV2(Data); +decode_disp('ContractV3', Data) -> dec_ContractV3(Data); +decode_disp('TypeInfoV1', Data) -> dec_TypeInfoV1(Data); +decode_disp('TypeInfoV3', Data) -> dec_TypeInfoV3(Data); +decode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +info() -> + case ?MODULE:module_info(attributes) of + Attributes when is_list(Attributes) -> + case lists:keyfind(asn1_info, 1, Attributes) of + {_,Info} when is_list(Info) -> + Info; + _ -> + [] + end; + _ -> + [] + end. +enc_GajumaruData(Val) -> +[begin +%% attribute tag(1) with type INTEGER +Enc1@element = element(2, Val), +if Enc1@element bsr 16 =:= 0 -> +<>; +true -> +exit({error,{asn1,{illegal_integer,Enc1@element}}}) +end +end, +begin +%% attribute vsn(2) with type INTEGER +Enc3@element = element(3, Val), +if Enc3@element bsr 8 =:= 0 -> +Enc3@element; +true -> +exit({error,{asn1,{illegal_integer,Enc3@element}}}) +end +end|begin +%% attribute content(3) with type Content +Enc5@element = element(4, Val), +enc_Content(Enc5@element) +end]. + + +dec_GajumaruData(Bytes) -> + +%% attribute tag(1) with type INTEGER +{Term1,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute vsn(2) with type INTEGER +{Term2,Bytes2} = begin +<> = Bytes1, +{V2@V0,V2@Buf1} +end, + +%% attribute content(3) with type Content +{Term3,Bytes3} = dec_Content(Bytes2), +Res1 = {'GajumaruData',Term1,Term2,Term3}, +{Res1,Bytes3}. + +enc_Content(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= templateFields -> +[<<0:3>>|enc_TemplateFields(ChoiceVal)]; +ChoiceTag =:= staticFields -> +[<<1:3>>|enc_StaticFields(ChoiceVal)]; +ChoiceTag =:= account -> +[<<2:3>>|enc_Account(ChoiceVal)]; +ChoiceTag =:= signedTx -> +[<<3:3>>|enc_SignedTx(ChoiceVal)]; +ChoiceTag =:= contract -> +[<<4:3>>|enc_ContractCode(ChoiceVal)] +end. + + +dec_Content(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +dec_TemplateFields(Bytes1) +end, +{{templateFields,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +dec_StaticFields(Bytes1) +end, +{{staticFields,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +dec_Account(Bytes1) +end, +{{account,Val},NewBytes}; +3 -> +{Val,NewBytes} = begin +dec_SignedTx(Bytes1) +end, +{{signedTx,Val},NewBytes}; +4 -> +{Val,NewBytes} = begin +dec_ContractCode(Bytes1) +end, +{{contract,Val},NewBytes} +end. +enc_TemplateFields(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TemplateField(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TemplateField(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TemplateField(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_TemplateFields(Bytes) -> +dec_components1(Bytes, []). + +enc_TemplateField(Val) -> +[begin +Enc1@element = element(2, Val), +if Enc1@element =:= asn1_NOVALUE -> +<<0:1>>; +true -> +<<1:1>> +end +end, +begin +%% attribute name(1) with type IA5String +Enc2@element = element(2, Val), +if Enc2@element =:= asn1_NOVALUE -> +[]; +true -> +begin +Enc3@len = length(Enc2@element), +Enc3@bin = encode_chars(Enc2@element, 7), +if Enc3@len < 128 -> +[Enc3@len|Enc3@bin]; +Enc3@len < 16384 -> +[<<2:2,Enc3@len:14>>|Enc3@bin]; +true -> +encode_fragmented(Enc3@bin, 7) +end +end +end +end|begin +%% attribute value(2) with type Value +Enc5@element = element(3, Val), +enc_Value(Enc5@element) +end]. + + +dec_TemplateField(Bytes) -> +{Opt,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute name(1) with type IA5String +{Term1,Bytes2} = case Opt band 1 of +1 -> +begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:7,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:7,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 7), +{V2@V6,V2@Buf7} +end, +{V2@V8,V2@Buf9} = {decode_chars(V2@V0, 7),V2@Buf1}, +{V2@V8,V2@Buf9} +end; +0 -> +{asn1_NOVALUE,Bytes1} +end, + +%% attribute value(2) with type Value +{Term2,Bytes3} = dec_Value(Bytes2), +Res1 = {'TemplateField',Term1,Term2}, +{Res1,Bytes3}. + +enc_StaticFields(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_StaticFields(Bytes) -> +dec_components2(Bytes, []). + +enc_Value(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= intValue -> +[<<0:3>>|encode_unconstrained_number(ChoiceVal)]; +ChoiceTag =:= boolValue -> +if ChoiceVal =:= false -> +<<1:3,0:1>>; +ChoiceVal =:= true -> +<<1:3,1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,ChoiceVal}}}) +end; +ChoiceTag =:= binaryValue -> +[<<2:3>>|begin +Enc6@len = byte_size(ChoiceVal), +if Enc6@len < 128 -> +[Enc6@len|ChoiceVal]; +Enc6@len < 16384 -> +[<<2:2,Enc6@len:14>>|ChoiceVal]; +true -> +encode_fragmented(ChoiceVal, 8) +end +end]; +ChoiceTag =:= idValue -> +[<<3:3>>|enc_Id(ChoiceVal)]; +ChoiceTag =:= listValue -> +[<<4:3>>|enc_Value_listValue(ChoiceVal)]; +ChoiceTag =:= tupleValue -> +[<<5:3>>|enc_Value_tupleValue(ChoiceVal)]; +ChoiceTag =:= mapValue -> +[<<6:3>>|enc_Value_mapValue(ChoiceVal)] +end. +enc_Value_listValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + +enc_Value_tupleValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + +enc_Value_mapValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_KeyValue(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_KeyValue(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_KeyValue(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_Value(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@Buf4/bitstring>> when V2@V3 =/= 0 -> +{V2@V3,V2@Buf4}; +<<1:1,0:1,V2@V4:14,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +{V2@V4,V2@Buf5}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +V2@Mul6 = V2@V4 * 16384, +{V2@Mul6,V2@Buf5} +end, +<> = V2@Buf1, +{V2@V7,V2@Buf8} +end +end, +{{intValue,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +begin +<> = Bytes1, +V3@Int2 = case V3@V0 of +0 -> false; +1 -> true +end, +{V3@Int2,V3@Buf1} +end +end, +{{boolValue,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +begin +{V4@V0,V4@Buf1} = case Bytes1 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end +end, +{{binaryValue,Val},NewBytes}; +3 -> +{Val,NewBytes} = begin +dec_Id(Bytes1) +end, +{{idValue,Val},NewBytes}; +4 -> +{Val,NewBytes} = begin +dec_Value_listValue(Bytes1) +end, +{{listValue,Val},NewBytes}; +5 -> +{Val,NewBytes} = begin +dec_Value_tupleValue(Bytes1) +end, +{{tupleValue,Val},NewBytes}; +6 -> +{Val,NewBytes} = begin +dec_Value_mapValue(Bytes1) +end, +{{mapValue,Val},NewBytes} +end. + +dec_Value_listValue(Bytes) -> +dec_components3(Bytes, []). + + +dec_Value_tupleValue(Bytes) -> +dec_components4(Bytes, []). + + +dec_Value_mapValue(Bytes) -> +dec_components5(Bytes, []). + +enc_KeyValue(Val) -> +[begin +%% attribute key(1) with type Value +Enc1@element = element(2, Val), +enc_Value(Enc1@element) +end|begin +%% attribute val(2) with type Value +Enc2@element = element(3, Val), +enc_Value(Enc2@element) +end]. + + +dec_KeyValue(Bytes) -> + +%% attribute key(1) with type Value +{Term1,Bytes1} = dec_Value(Bytes), + +%% attribute val(2) with type Value +{Term2,Bytes2} = dec_Value(Bytes1), +Res1 = {'KeyValue',Term1,Term2}, +{Res1,Bytes2}. + +enc_Id(Val) -> +[begin +%% attribute type(1) with type INTEGER +Enc1@element = element(2, Val), +if Enc1@element bsr 8 =:= 0 -> +Enc1@element; +true -> +exit({error,{asn1,{illegal_integer,Enc1@element}}}) +end +end|begin +%% attribute value(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len =:= 32 -> +Enc3@element +end +end]. + + +dec_Id(Bytes) -> + +%% attribute type(1) with type INTEGER +{Term1,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute value(2) with type OCTET STRING +{Term2,Bytes2} = begin +<> = Bytes1, +V2@Conv2 = binary:copy(V2@V0), +{V2@Conv2,V2@Buf1} +end, +Res1 = {'Id',Term1,Term2}, +{Res1,Bytes2}. + +enc_Account(Val) -> +[begin +%% attribute foo(1) with type INTEGER +Enc1@element = element(2, Val), +encode_unconstrained_number(Enc1@element) +end|begin +%% attribute bar(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end]. + + +dec_Account(Bytes) -> + +%% attribute foo(1) with type INTEGER +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@Buf4/bitstring>> when V1@V3 =/= 0 -> +{V1@V3,V1@Buf4}; +<<1:1,0:1,V1@V4:14,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +{V1@V4,V1@Buf5}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +V1@Mul6 = V1@V4 * 16384, +{V1@Mul6,V1@Buf5} +end, +<> = V1@Buf1, +{V1@V7,V1@Buf8} +end, + +%% attribute bar(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, +Res1 = {'Account',Term1,Term2}, +{Res1,Bytes2}. + +enc_SignedTx(Val) -> +[begin +%% attribute signatures(1) with type SEQUENCE OF +Enc1@element = element(2, Val), +enc_SignedTx_signatures(Enc1@element) +end|begin +%% attribute transaction(2) with type OCTET STRING +Enc2@element = element(3, Val), +Enc3@len = byte_size(Enc2@element), +if Enc3@len < 128 -> +[Enc3@len|Enc2@element]; +Enc3@len < 16384 -> +[<<2:2,Enc3@len:14>>|Enc2@element]; +true -> +encode_fragmented(Enc2@element, 8) +end +end]. +enc_SignedTx_signatures(Val) -> +Enc2@len = length(Val), +if Enc2@len < 128 -> +[Enc2@len|[begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end || Comp <- Val]]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|[begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end || Comp <- Val]]; +true -> +begin +Enc2@fn = fun(Comp) -> begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end end, +encode_fragmented_sof(Enc2@fn, Val, Enc2@len) +end +end. + + + +dec_SignedTx(Bytes) -> + +%% attribute signatures(1) with type SEQUENCE OF +{Term1,Bytes1} = dec_SignedTx_signatures(Bytes), + +%% attribute transaction(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V1@V0,V1@Buf1} = case Bytes1 of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, +Res1 = {'SignedTx',Term1,Term2}, +{Res1,Bytes2}. + + +dec_SignedTx_signatures(Bytes) -> +dec_components6(Bytes, []). + +enc_ContractCode(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= v1 -> +[<<0:2>>|enc_ContractV1(ChoiceVal)]; +ChoiceTag =:= v2 -> +[<<1:2>>|enc_ContractV2(ChoiceVal)]; +ChoiceTag =:= v3 -> +[<<2:2>>|enc_ContractV3(ChoiceVal)] +end. + + +dec_ContractCode(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +dec_ContractV1(Bytes1) +end, +{{v1,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +dec_ContractV2(Bytes1) +end, +{{v2,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +dec_ContractV3(Bytes1) +end, +{{v3,Val},NewBytes} +end. +enc_ContractV1(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV1_typeInfo(Enc3@element) +end|begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end]. +enc_ContractV1_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV1(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV1(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV1_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, +Res1 = {'ContractV1',Term1,Term2,Term3}, +{Res1,Bytes3}. + + +dec_ContractV1_typeInfo(Bytes) -> +dec_components7(Bytes, []). + +enc_ContractV2(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV2_typeInfo(Enc3@element) +end, +begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end|begin +%% attribute compilerVersion(4) with type OCTET STRING +Enc6@element = element(5, Val), +Enc7@len = byte_size(Enc6@element), +if Enc7@len < 128 -> +[Enc7@len|Enc6@element]; +Enc7@len < 16384 -> +[<<2:2,Enc7@len:14>>|Enc6@element]; +true -> +encode_fragmented(Enc6@element, 8) +end +end]. +enc_ContractV2_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV1(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV2(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV2_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute compilerVersion(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V3@V0,V3@Buf1} = case Bytes3 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, +Res1 = {'ContractV2',Term1,Term2,Term3,Term4}, +{Res1,Bytes4}. + + +dec_ContractV2_typeInfo(Bytes) -> +dec_components8(Bytes, []). + +enc_ContractV3(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV3_typeInfo(Enc3@element) +end, +begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end, +begin +%% attribute compilerVersion(4) with type OCTET STRING +Enc6@element = element(5, Val), +Enc7@len = byte_size(Enc6@element), +if Enc7@len < 128 -> +[Enc7@len|Enc6@element]; +Enc7@len < 16384 -> +[<<2:2,Enc7@len:14>>|Enc6@element]; +true -> +encode_fragmented(Enc6@element, 8) +end +end|begin +%% attribute payable(5) with type BOOLEAN +Enc8@element = element(6, Val), +if Enc8@element =:= false -> +<<0:1>>; +Enc8@element =:= true -> +<<1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,Enc8@element}}}) +end +end]. +enc_ContractV3_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV3(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV3(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV3(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV3(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV3_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute compilerVersion(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V3@V0,V3@Buf1} = case Bytes3 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, + +%% attribute payable(5) with type BOOLEAN +{Term5,Bytes5} = begin +<> = Bytes4, +V4@Int2 = case V4@V0 of +0 -> false; +1 -> true +end, +{V4@Int2,V4@Buf1} +end, +Res1 = {'ContractV3',Term1,Term2,Term3,Term4,Term5}, +{Res1,Bytes5}. + + +dec_ContractV3_typeInfo(Bytes) -> +dec_components9(Bytes, []). + +enc_TypeInfoV1(Val) -> +[begin +%% attribute typeHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute name(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end, +begin +%% attribute argType(3) with type OCTET STRING +Enc5@element = element(4, Val), +Enc6@len = byte_size(Enc5@element), +if Enc6@len < 128 -> +[Enc6@len|Enc5@element]; +Enc6@len < 16384 -> +[<<2:2,Enc6@len:14>>|Enc5@element]; +true -> +encode_fragmented(Enc5@element, 8) +end +end|begin +%% attribute outType(4) with type OCTET STRING +Enc7@element = element(5, Val), +Enc8@len = byte_size(Enc7@element), +if Enc8@len < 128 -> +[Enc8@len|Enc7@element]; +Enc8@len < 16384 -> +[<<2:2,Enc8@len:14>>|Enc7@element]; +true -> +encode_fragmented(Enc7@element, 8) +end +end]. + + +dec_TypeInfoV1(Bytes) -> + +%% attribute typeHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute name(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute argType(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V3@V0,V3@Buf1} = case Bytes2 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, + +%% attribute outType(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V4@V0,V4@Buf1} = case Bytes3 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end, +Res1 = {'TypeInfoV1',Term1,Term2,Term3,Term4}, +{Res1,Bytes4}. + +enc_TypeInfoV3(Val) -> +[begin +%% attribute typeHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute name(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end, +begin +%% attribute payable(3) with type BOOLEAN +Enc5@element = element(4, Val), +if Enc5@element =:= false -> +<<0:1>>; +Enc5@element =:= true -> +<<1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,Enc5@element}}}) +end +end, +begin +%% attribute argType(4) with type OCTET STRING +Enc7@element = element(5, Val), +Enc8@len = byte_size(Enc7@element), +if Enc8@len < 128 -> +[Enc8@len|Enc7@element]; +Enc8@len < 16384 -> +[<<2:2,Enc8@len:14>>|Enc7@element]; +true -> +encode_fragmented(Enc7@element, 8) +end +end|begin +%% attribute outType(5) with type OCTET STRING +Enc9@element = element(6, Val), +Enc10@len = byte_size(Enc9@element), +if Enc10@len < 128 -> +[Enc10@len|Enc9@element]; +Enc10@len < 16384 -> +[<<2:2,Enc10@len:14>>|Enc9@element]; +true -> +encode_fragmented(Enc9@element, 8) +end +end]. + + +dec_TypeInfoV3(Bytes) -> + +%% attribute typeHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute name(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute payable(3) with type BOOLEAN +{Term3,Bytes3} = begin +<> = Bytes2, +V3@Int2 = case V3@V0 of +0 -> false; +1 -> true +end, +{V3@Int2,V3@Buf1} +end, + +%% attribute argType(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V4@V0,V4@Buf1} = case Bytes3 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end, + +%% attribute outType(5) with type OCTET STRING +{Term5,Bytes5} = begin +{V5@V0,V5@Buf1} = case Bytes4 of +<<0:1,V5@V3:7,V5@V5:V5@V3/binary-unit:8,V5@Buf6/bitstring>> -> +{V5@V5,V5@Buf6}; +<<1:1,0:1,V5@V4:14,V5@V6:V5@V4/binary-unit:8,V5@Buf7/bitstring>> -> +{V5@V6,V5@Buf7}; +<<1:1,1:1,V5@V4:6,V5@Buf5/bitstring>> -> +{V5@V6,V5@Buf7} = decode_fragmented(V5@V4, V5@Buf5, 8), +{V5@V6,V5@Buf7} +end, +V5@Conv8 = binary:copy(V5@V0), +{V5@Conv8,V5@Buf1} +end, +Res1 = {'TypeInfoV3',Term1,Term2,Term3,Term4,Term5}, +{Res1,Bytes5}. + + +%%% +%%% Run-time functions. +%%% + +'dialyzer-suppressions'(Arg) -> + _ = complete(element(1, Arg)), + ok. + +dec_components1(Bytes, Acc) -> +%% Length with constraint no +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@Buf4/bitstring>> -> +{V1@V3,V1@Buf4}; +<<1:1,0:1,V1@V4:14,V1@Buf5/bitstring>> -> +{V1@V4,V1@Buf5}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +V1@Mul6 = V1@V4 * 16384, +{V1@Mul6,V1@Buf5} +end, +{Acc1,Buf1} = dec_fragment10(V1@V0, V1@Buf1, Acc), +if V1@V0 >= 16384 -> +dec_components1(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components2(Bytes, Acc) -> +%% Length with constraint no +{V2@V0,V2@Buf1} = case Bytes of +<<0:1,V2@V3:7,V2@Buf4/bitstring>> -> +{V2@V3,V2@Buf4}; +<<1:1,0:1,V2@V4:14,V2@Buf5/bitstring>> -> +{V2@V4,V2@Buf5}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +V2@Mul6 = V2@V4 * 16384, +{V2@Mul6,V2@Buf5} +end, +{Acc1,Buf1} = dec_fragment11(V2@V0, V2@Buf1, Acc), +if V2@V0 >= 16384 -> +dec_components2(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components3(Bytes, Acc) -> +%% Length with constraint no +{V3@V0,V3@Buf1} = case Bytes of +<<0:1,V3@V3:7,V3@Buf4/bitstring>> -> +{V3@V3,V3@Buf4}; +<<1:1,0:1,V3@V4:14,V3@Buf5/bitstring>> -> +{V3@V4,V3@Buf5}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +V3@Mul6 = V3@V4 * 16384, +{V3@Mul6,V3@Buf5} +end, +{Acc1,Buf1} = dec_fragment12(V3@V0, V3@Buf1, Acc), +if V3@V0 >= 16384 -> +dec_components3(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components4(Bytes, Acc) -> +%% Length with constraint no +{V4@V0,V4@Buf1} = case Bytes of +<<0:1,V4@V3:7,V4@Buf4/bitstring>> -> +{V4@V3,V4@Buf4}; +<<1:1,0:1,V4@V4:14,V4@Buf5/bitstring>> -> +{V4@V4,V4@Buf5}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +V4@Mul6 = V4@V4 * 16384, +{V4@Mul6,V4@Buf5} +end, +{Acc1,Buf1} = dec_fragment13(V4@V0, V4@Buf1, Acc), +if V4@V0 >= 16384 -> +dec_components4(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components5(Bytes, Acc) -> +%% Length with constraint no +{V5@V0,V5@Buf1} = case Bytes of +<<0:1,V5@V3:7,V5@Buf4/bitstring>> -> +{V5@V3,V5@Buf4}; +<<1:1,0:1,V5@V4:14,V5@Buf5/bitstring>> -> +{V5@V4,V5@Buf5}; +<<1:1,1:1,V5@V4:6,V5@Buf5/bitstring>> -> +V5@Mul6 = V5@V4 * 16384, +{V5@Mul6,V5@Buf5} +end, +{Acc1,Buf1} = dec_fragment14(V5@V0, V5@Buf1, Acc), +if V5@V0 >= 16384 -> +dec_components5(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components6(Bytes, Acc) -> +%% Length with constraint no +{V6@V0,V6@Buf1} = case Bytes of +<<0:1,V6@V3:7,V6@Buf4/bitstring>> -> +{V6@V3,V6@Buf4}; +<<1:1,0:1,V6@V4:14,V6@Buf5/bitstring>> -> +{V6@V4,V6@Buf5}; +<<1:1,1:1,V6@V4:6,V6@Buf5/bitstring>> -> +V6@Mul6 = V6@V4 * 16384, +{V6@Mul6,V6@Buf5} +end, +{Acc1,Buf1} = dec_fragment15(V6@V0, V6@Buf1, Acc), +if V6@V0 >= 16384 -> +dec_components6(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components7(Bytes, Acc) -> +%% Length with constraint no +{V7@V0,V7@Buf1} = case Bytes of +<<0:1,V7@V3:7,V7@Buf4/bitstring>> -> +{V7@V3,V7@Buf4}; +<<1:1,0:1,V7@V4:14,V7@Buf5/bitstring>> -> +{V7@V4,V7@Buf5}; +<<1:1,1:1,V7@V4:6,V7@Buf5/bitstring>> -> +V7@Mul6 = V7@V4 * 16384, +{V7@Mul6,V7@Buf5} +end, +{Acc1,Buf1} = dec_fragment16(V7@V0, V7@Buf1, Acc), +if V7@V0 >= 16384 -> +dec_components7(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components8(Bytes, Acc) -> +%% Length with constraint no +{V8@V0,V8@Buf1} = case Bytes of +<<0:1,V8@V3:7,V8@Buf4/bitstring>> -> +{V8@V3,V8@Buf4}; +<<1:1,0:1,V8@V4:14,V8@Buf5/bitstring>> -> +{V8@V4,V8@Buf5}; +<<1:1,1:1,V8@V4:6,V8@Buf5/bitstring>> -> +V8@Mul6 = V8@V4 * 16384, +{V8@Mul6,V8@Buf5} +end, +{Acc1,Buf1} = dec_fragment17(V8@V0, V8@Buf1, Acc), +if V8@V0 >= 16384 -> +dec_components8(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components9(Bytes, Acc) -> +%% Length with constraint no +{V9@V0,V9@Buf1} = case Bytes of +<<0:1,V9@V3:7,V9@Buf4/bitstring>> -> +{V9@V3,V9@Buf4}; +<<1:1,0:1,V9@V4:14,V9@Buf5/bitstring>> -> +{V9@V4,V9@Buf5}; +<<1:1,1:1,V9@V4:6,V9@Buf5/bitstring>> -> +V9@Mul6 = V9@V4 * 16384, +{V9@Mul6,V9@Buf5} +end, +{Acc1,Buf1} = dec_fragment18(V9@V0, V9@Buf1, Acc), +if V9@V0 >= 16384 -> +dec_components9(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_fragment10(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment10(Num, Bytes, Acc) -> +{Term,Remain} = dec_TemplateField(Bytes), +dec_fragment10(Num-1, Remain, [Term|Acc]). + +dec_fragment11(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment11(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment11(Num-1, Remain, [Term|Acc]). + +dec_fragment12(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment12(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment12(Num-1, Remain, [Term|Acc]). + +dec_fragment13(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment13(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment13(Num-1, Remain, [Term|Acc]). + +dec_fragment14(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment14(Num, Bytes, Acc) -> +{Term,Remain} = dec_KeyValue(Bytes), +dec_fragment14(Num-1, Remain, [Term|Acc]). + +dec_fragment15(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment15(Num, Bytes, Acc) -> +{Term,Remain} = begin +{V10@V0,V10@Buf1} = case Bytes of +<<0:1,V10@V3:7,V10@V5:V10@V3/binary-unit:8,V10@Buf6/bitstring>> -> +{V10@V5,V10@Buf6}; +<<1:1,0:1,V10@V4:14,V10@V6:V10@V4/binary-unit:8,V10@Buf7/bitstring>> -> +{V10@V6,V10@Buf7}; +<<1:1,1:1,V10@V4:6,V10@Buf5/bitstring>> -> +{V10@V6,V10@Buf7} = decode_fragmented(V10@V4, V10@Buf5, 8), +{V10@V6,V10@Buf7} +end, +V10@Conv8 = binary:copy(V10@V0), +{V10@Conv8,V10@Buf1} +end, +dec_fragment15(Num-1, Remain, [Term|Acc]). + +dec_fragment16(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment16(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV1(Bytes), +dec_fragment16(Num-1, Remain, [Term|Acc]). + +dec_fragment17(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment17(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV1(Bytes), +dec_fragment17(Num-1, Remain, [Term|Acc]). + +dec_fragment18(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment18(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV3(Bytes), +dec_fragment18(Num-1, Remain, [Term|Acc]). + +complete(InList) when is_list(InList) -> + case list_to_bitstring(InList) of + <<>> -> + <<0>>; + Res -> + Sz = bit_size(Res), + case Sz band 7 of + 0 -> + Res; + Bits -> + <> + end + end; +complete(Bin) when is_binary(Bin) -> + case Bin of + <<>> -> + <<0>>; + _ -> + Bin + end; +complete(InList) when is_bitstring(InList) -> + Sz = bit_size(InList), + PadLen = 8 - Sz band 7, + <>. + +decode_chars(Val, N) -> + [ + C || + <> <= Val + ]. + +decode_fragmented(SegSz0, Buf0, Unit) -> + SegSz = SegSz0 * Unit * 16384, + <> = Buf0, + decode_fragmented_1(Buf, Unit, Res). + +decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) -> + Sz = N * Unit, + <> = Buf0, + {<>, Buf}; +decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) -> + Sz = N * Unit, + <> = Buf0, + {<>, Buf}; +decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) -> + SegSz = SegSz0 * Unit * 16384, + <> = Buf0, + Res = <>, + decode_fragmented_1(Buf, Unit, Res). + +encode_chars(Val, NumBits) -> + << + <> || + C <- Val + >>. + +encode_components(Cs, _Encoder, 0, Acc) -> + {Cs, lists:reverse(Acc)}; +encode_components([C | Cs], Encoder, Size, Acc) -> + B = Encoder(C), + encode_components(Cs, Encoder, Size - 1, [B | Acc]). + +encode_fragmented(Bin, Unit) -> + encode_fragmented_1(Bin, Unit, 4). + +encode_fragmented_1(Bin, Unit, N) -> + SegSz = Unit * N * 16384, + case Bin of + <> -> + [<<3:2,N:6>>, B | encode_fragmented_1(T, Unit, N)]; + _ when N > 1 -> + encode_fragmented_1(Bin, Unit, N - 1); + _ -> + case bit_size(Bin) div Unit of + Len when Len < 128 -> + [Len, Bin]; + Len when Len < 16384 -> + [<<2:2,Len:14>>, Bin] + end + end. + +encode_fragmented_sof(Fun, Comps, Len) -> + encode_fragmented_sof_1(Fun, Comps, Len, 4). + +encode_fragmented_sof_1(Encoder, Comps0, Len0, N) -> + SegSz = N * 16384, + if + Len0 >= SegSz -> + {Comps, B} = encode_components(Comps0, Encoder, SegSz, []), + Len = Len0 - SegSz, + [<<3:2,N:6>>, + B | + encode_fragmented_sof_1(Encoder, Comps, Len, N)]; + N > 1 -> + encode_fragmented_sof_1(Encoder, Comps0, Len0, N - 1); + Len0 < 128 -> + {[], B} = encode_components(Comps0, Encoder, Len0, []), + [Len0 | B]; + Len0 < 16384 -> + {[], B} = encode_components(Comps0, Encoder, Len0, []), + [<<2:2,Len0:14>> | B] + end. + +encode_unconstrained_number(Val) when not is_integer(Val) -> + exit({error, {asn1, {illegal_integer, Val}}}); +encode_unconstrained_number(Val) when Val >= 0 -> + if + Val < 128 -> + [1, Val]; + Val < 256 -> + [<<2,0>>, Val]; + true -> + case binary:encode_unsigned(Val) of + <<0:1,_/bitstring>> = Bin -> + case byte_size(Bin) of + Sz when Sz < 128 -> + [Sz, Bin]; + Sz when Sz < 16384 -> + [<<2:2,Sz:14>>, Bin] + end; + <<1:1,_/bitstring>> = Bin -> + case byte_size(Bin) + 1 of + Sz when Sz < 128 -> + [Sz, 0, Bin]; + Sz when Sz < 16384 -> + [<<2:2,Sz:14,0:8>>, Bin] + end + end + end; +encode_unconstrained_number(Val) -> + Oct = enint(Val, []), + Len = length(Oct), + if + Len < 128 -> + [Len | Oct]; + Len < 16384 -> + [<<2:2,Len:14>> | Oct] + end. + +enint(-1, [B1 | T]) when B1 > 127 -> + [B1 | T]; +enint(N, Acc) -> + enint(N bsr 8, [N band 255 | Acc]). diff --git a/asn1_optimized/GajumaruSerialization.hrl b/asn1_optimized/GajumaruSerialization.hrl new file mode 100644 index 0000000..4c5d52e --- /dev/null +++ b/asn1_optimized/GajumaruSerialization.hrl @@ -0,0 +1,76 @@ +%% Generated by the Erlang ASN.1 compiler. Version: 5.4.3 +%% Purpose: Erlang record definitions for each named and unnamed +%% SEQUENCE and SET, and macro definitions for each value +%% definition in module GajumaruSerialization. + +-ifndef(_GAJUMARUSERIALIZATION_HRL_). +-define(_GAJUMARUSERIALIZATION_HRL_, true). + +-record('GajumaruData', { + tag, + vsn, + content +}). + +-record('TemplateField', { + name = asn1_NOVALUE, + value +}). + +-record('KeyValue', { + key, + val +}). + +-record('Id', { + type, + value +}). + +-record('Account', { + foo, + bar +}). + +-record('SignedTx', { + signatures, + transaction +}). + +-record('ContractV1', { + sourceHash, + typeInfo, + byteCode +}). + +-record('ContractV2', { + sourceHash, + typeInfo, + byteCode, + compilerVersion +}). + +-record('ContractV3', { + sourceHash, + typeInfo, + byteCode, + compilerVersion, + payable +}). + +-record('TypeInfoV1', { + typeHash, + name, + argType, + outType +}). + +-record('TypeInfoV3', { + typeHash, + name, + payable, + argType, + outType +}). + +-endif. %% _GAJUMARUSERIALIZATION_HRL_ diff --git a/asn1_per/GajumaruSerialization.asn b/asn1_per/GajumaruSerialization.asn new file mode 100644 index 0000000..43607e9 --- /dev/null +++ b/asn1_per/GajumaruSerialization.asn @@ -0,0 +1,225 @@ +-- GajumaruSerialization.asn +-- +-- ASN.1 model for the structures serialized by gmserialization.erl +-- (the layer on top of RLP). +-- +-- Purpose: +-- * Provide a formal, toolable description of the data. +-- * Enable migration from the legacy RLP-based format to DER. +-- +-- Detection of legacy vs new: +-- Legacy data (produced by gmserialization:serialize / gmser_chain_objects:serialize +-- or gmser_dyn:serialize) is always an RLP *list* at the top level. +-- This means the first byte is in the range 0xC0 .. 0xFF. +-- +-- DER-encoded data using the types below will start with 0x30 (SEQUENCE, +-- constructed, universal tag) for the outermost GajumaruData (or any +-- top-level SEQUENCE we define). 0x30 < 0xC0, so a single-byte prefix +-- check reliably distinguishes the two formats. +-- +-- Usage in Erlang (after compiling with asn1ct): +-- {ok, Mod} = asn1ct:compile(GajumaruSerialization.asn, [ber, der]). +-- {ok, Term} = 'GajumaruSerialization':decode('GajumaruData', DerBinary). +-- +-- Notes on type mapping from gmserialization.erl: +-- - int -> INTEGER (new data uses canonical DER INTEGER) +-- - binary -> OCTET STRING +-- - bool -> BOOLEAN +-- - id -> Id (SEQUENCE) (cleaner than the legacy packed 33-byte form) +-- - [T] -> SEQUENCE OF T +-- - {T1,...} -> SEQUENCE (fixed-size, order matters) +-- - #{items := [{K,T},...]} -> SEQUENCE with the fields in template order +-- (static maps carry *values only*, no keys on the wire) +-- - tag + vsn are preserved as the first two fields for compatibility +-- with existing dispatch logic. +-- +-- Legacy integers had strict unsigned-minimal no-leading-zero (except for 0) +-- and RLP-level rules. New DER data does not need to follow those rules. +-- +-- WARNING: +-- Any cryptographic hash or signature computed over a serialized object +-- will change when switching from RLP to DER for that object. Plan a +-- coordinated upgrade. + +GajumaruSerialization DEFINITIONS + AUTOMATIC TAGS ::= +BEGIN + +EXPORTS ALL; + +-- ============================================================ +-- Top-level wrapper used for new DER data. +-- This is what a decoder will see first. +-- ============================================================ + +GajumaruData ::= SEQUENCE { + tag INTEGER, + vsn INTEGER, + content Content +} + +-- Content can be a specific structured type (preferred) or a generic +-- representation of a template-driven object. +Content ::= CHOICE { + -- Generic fallback that can represent any [{Field, Type}] template + -- without having a pre-defined SEQUENCE for every object. + templateFields [0] TemplateFields, + + -- Examples of concrete versioned types (extend as needed) + account [1] Account, + signedTx [2] SignedTx, + contract [3] ContractCode + -- Add more alternatives for other tags from gmser_chain_objects +} + +-- ============================================================ +-- Generic template-driven representation +-- (useful during transition or for unregistered types) +-- ============================================================ + +TemplateFields ::= SEQUENCE OF TemplateField + +TemplateField ::= SEQUENCE { + -- Field name is included for debuggability / generic processing. + -- In the original static encoding the name is NOT on the wire; + -- only position and type matter. We include it here for convenience. + name IA5String OPTIONAL, + value Value +} + +Value ::= CHOICE { + intValue [0] INTEGER, + boolValue [1] BOOLEAN, + binaryValue [2] OCTET STRING, + idValue [3] Id, + listValue [4] SEQUENCE OF Value, + tupleValue [5] SEQUENCE OF Value, + mapValue [6] SEQUENCE OF KeyValue -- only needed if you want to + -- represent dynamic-style maps +} + +KeyValue ::= SEQUENCE { + key Value, + val Value +} + +-- ============================================================ +-- Common types +-- ============================================================ + +Id ::= SEQUENCE { + -- Corresponds to the simple tags in gmser_id (account=1, name=2, etc.) + -- and the extended account subtype (high bit in legacy). + type INTEGER (0..255), + value OCTET STRING (SIZE (32)) +} + +-- ============================================================ +-- Concrete object examples (derived from usage in the codebase) +-- Add / evolve per version as you introduce new vsns. +-- ============================================================ + +-- Example: a very simple account-like object used in tests +Account ::= SEQUENCE { + foo INTEGER, + bar OCTET STRING +} + +-- Simplified signed transaction +SignedTx ::= SEQUENCE { + signatures SEQUENCE OF OCTET STRING, + transaction OCTET STRING +} + +-- Contract code objects (see gmser_contract_code.erl) +-- We model the three versions that exist today. +ContractCode ::= CHOICE { + v1 [0] ContractV1, + v2 [1] ContractV2, + v3 [2] ContractV3 +} + +ContractV1 ::= SEQUENCE { + sourceHash OCTET STRING, + -- typeInfo is a list of 4-tuples in legacy: + -- {typeHash, name, argType, outType} + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING +} + +ContractV2 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING, + compilerVersion OCTET STRING +} + +ContractV3 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV3, + byteCode OCTET STRING, + compilerVersion OCTET STRING, + payable BOOLEAN +} + +TypeInfoV1 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + argType OCTET STRING, + outType OCTET STRING +} + +TypeInfoV3 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + payable BOOLEAN, + argType OCTET STRING, + outType OCTET STRING +} + +-- ============================================================ +-- Notes for implementers +-- ============================================================ +-- 1. Detection (recommended decoder entry point): +-- +-- decode(Binary) -> +-- case Binary of +-- <> when B >= 16#C0 -> +-- decode_legacy_rlp(Binary); % existing gmser_* path +-- _ -> +-- {ok, Term} = +-- 'GajumaruSerialization':decode('GajumaruData', Binary), +-- Term +-- end. +-- +-- This works because: +-- - All current top-level output from serialize() is an RLP list +-- (first byte 0xC0-0xFF). +-- - GajumaruData and the concrete choices above are SEQUENCEs +-- (first byte 0x30 for short form, or 0x30 0x81/0x82... for long). +-- +-- 2. When you add a new object type or version, prefer adding a +-- concrete SEQUENCE alternative in the Content CHOICE rather than +-- always falling back to TemplateFields. This gives you better +-- validation and generated types. +-- +-- 3. INTEGER in DER is signed and uses a different minimal encoding +-- than the legacy unsigned big-endian no leading zero form. This is +-- fine for new data. +-- +-- 4. If you need to preserve exact legacy integer wire bytes inside +-- the new format (e.g. for some hash preimage reason), you can +-- carry selected integers as OCTET STRING (legacy unsigned minimal bytes). +-- +-- 5. Dynamic encoding (gmser_dyn) is intentionally not modeled here +-- in full, because it is runtime-schema driven (type codes 246-255, +-- labels, alt/switch, etc.). You can still use the generic +-- TemplateFields + Value for some dynamic cases, or model specific +-- message schemas as additional CHOICE arms. +-- +-- 6. Compile with DER for canonical output: +-- asn1ct:compile(GajumaruSerialization, [der]). +-- +-- The ber option is also accepted; der implies the stricter rules. + +END diff --git a/asn1_per/GajumaruSerialization.asn1db b/asn1_per/GajumaruSerialization.asn1db new file mode 100644 index 0000000000000000000000000000000000000000..05d33869c0e3cdbcb67e60c4c9140479cb2c35dd GIT binary patch literal 15532 zcmeHO+i&Ao8F%AcdztCZFoT2yDi6GomD;ib_GL*Ew-acSlDeJF0-HUJPa0Gv`DZZ!LUf&q}>Jn3nU&8{13eHuur@o_)Z+#$MNy8JH3t2j5IT8&auyT zKfmwNxs06c9PTVg(%h4y``eW_dbfHRlF_wSC7CQ4reSLMONQAqZAYSiw z@0i1pg>4&a!2|gr9-7wakt8ks9bTO?iGi)dD3R)fQ1}NnWqVk+NEY~@)MO1b#N-pm zHdfnPs6QSeYrKaoosy3n-8ASP8(2YiC%b|7nb*VD3-l#g+d)SI91xdvPDhx?Hg;f3 z{vkdcnKqh(&+{Y8ba02hos_1Zu?7oEL)15|_9KuNtWEYV4RwS0iZZZ-PaJG$aG-8< z%|0l=an%HGu9{Tz9p_-Zmm>vAfQGvy>sVuqei2&E!?&*)qP41)d;>wac3Mk1k(10Fp;V%3&Iv716 zceqwY=BcbGkq7H8r^)=z^-(6u@2^Pl=+wbgFjOwlzPK_Bzh@VArjO+4;qQ@~)J^pP zwhmk)7SkY~iw3!mvQZj-O$sA)N?lQWb~b!=VWZjHRw|8Txo7(**LSx`QszHV-&>3N z-cK0cTjSCdZ%k=@k0XnpUa#-H`%L-XyUD({dOqL#*>(Ef&#&C~0w*|)I>Bnx34X{p z!RjSB0VgQ^=z5*tooC7k-nn!q`0>>_fp37hk9h`|J3xamj@sUNTaI);H_^Ws-*k z9kOsz+Nm^Z6}8!V0ECq2dG1kJnnkj!F(ehC>Huk}bDBgL8&D;BXU=cbgN%HdlKT|^ zSTEF+&C33^`cRUkxyci^p=txibta{owtZ?i=!D8E2fK3M~yz~ zewo>L5WFac-OJSg+EL}|+?&Gu)4Emqwz6`Zw2Wq0_AkG2?jzi&3!PIT<00SSJjy_{>7h}&?%h65GZps&? zuM07sOQ1_=M{xhZeH~b9wz0px9Z3NACUYSS&qFO6l_y{!ph8^t7E&Wg*+nm&7onuC zv>KIdaV!tECB*UK)5Y;oS<@{*QDwhG9*7|p1r?jSYP|`JxyUlZ_ANpfSg8A3 zx)Fc&O!yF;m|;=3@WeZTvdbE_JC;6zMn=H!a&v+xYyQ&I68+Oz!KDnyMQA&inr>dkK6-&dCjx}J%98xH9yJTTgW(u zCN7fDf793*uRUmyTqyeT4O?VQ9!WR$pi2z>SBm_ga0q0rK<6~EYe~C!fucU}6cx^G zqdIGmnH^WAz5};sekS#m>Xn!F91DWUY)JE@7bu?F#l4?aO-%fWFaO<-$?B&y;xj5O z^O2`CrimNX*!ygcmn*&a!b)0<$!WiT;I<#Gr}_S28e0)LS2|ThZe8@pluh7pSUyAL zoZtWc6Dc6;m=jpaZ|}{by1z$CHr@@!4$A`RslFaP#|d)bcrfzuz#H ze_4IMD9S{?y-v&j-E~?1?^BxKjOCvZAo0!r4=GLX{N^9rn1Az3&@Y!qLoX)5;+5T# zT_VHGm)IA>fI0rc>Yn$)lDN0(F_8iMh)IO#oa#fz?(Bl**0FO$Ng_yu^DCt3eO zgJ_b7gw za>>y0n2s$%PV`sr$>QE5pHxqx*7aQ&d-N80{GT7Oaq^?@!Mq9_ikvYNImKdU4J@{S z97<^zij#prvNHIF`UY8;6c}L;l}^y|BLcdBjIBK0h-miEaD78RrSX4DWOrjj70UvL&V%5rx5T0loZjL!Vw& z{$N6}^uCo$?^?3Ghzl#|ZJ>8uY%eTs5z+g0GQHDDTakQubr*;o|MU#)rutx4Df@lN z7SJwgF3;?aA(7Ku&OmH>)|$)IUE-R%Sy=mjXzoITbk6dWU8r;>zs?Z7Cms`jjTh{g zpnGv;v~Lr+YbMOJv%!cChQ&3-IB|tnEc*_TkC0!m4&5uO;V(g25SJage0ep?wfHW`*p-kn z9L*sxl1z7K{Ln|jxqo=hvRu7aq4Q2kYx=7*tk*wdYX@}W per. + +maps() -> false. + +bit_string_format() -> bitstring. + +legacy_erlang_types() -> false. + +encode(Type, Data) -> +try complete(encode_disp(Type, Data)) of + Bytes -> + {ok,Bytes} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + + +decode(Type, Data) -> +try + {Result,_Rest} = decode_disp(Type, Data), + {ok,Result} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + +encode_disp('GajumaruData', Data) -> enc_GajumaruData(Data); +encode_disp('Content', Data) -> enc_Content(Data); +encode_disp('TemplateFields', Data) -> enc_TemplateFields(Data); +encode_disp('TemplateField', Data) -> enc_TemplateField(Data); +encode_disp('Value', Data) -> enc_Value(Data); +encode_disp('KeyValue', Data) -> enc_KeyValue(Data); +encode_disp('Id', Data) -> enc_Id(Data); +encode_disp('Account', Data) -> enc_Account(Data); +encode_disp('SignedTx', Data) -> enc_SignedTx(Data); +encode_disp('ContractCode', Data) -> enc_ContractCode(Data); +encode_disp('ContractV1', Data) -> enc_ContractV1(Data); +encode_disp('ContractV2', Data) -> enc_ContractV2(Data); +encode_disp('ContractV3', Data) -> enc_ContractV3(Data); +encode_disp('TypeInfoV1', Data) -> enc_TypeInfoV1(Data); +encode_disp('TypeInfoV3', Data) -> enc_TypeInfoV3(Data); +encode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +decode_disp('GajumaruData', Data) -> dec_GajumaruData(Data); +decode_disp('Content', Data) -> dec_Content(Data); +decode_disp('TemplateFields', Data) -> dec_TemplateFields(Data); +decode_disp('TemplateField', Data) -> dec_TemplateField(Data); +decode_disp('Value', Data) -> dec_Value(Data); +decode_disp('KeyValue', Data) -> dec_KeyValue(Data); +decode_disp('Id', Data) -> dec_Id(Data); +decode_disp('Account', Data) -> dec_Account(Data); +decode_disp('SignedTx', Data) -> dec_SignedTx(Data); +decode_disp('ContractCode', Data) -> dec_ContractCode(Data); +decode_disp('ContractV1', Data) -> dec_ContractV1(Data); +decode_disp('ContractV2', Data) -> dec_ContractV2(Data); +decode_disp('ContractV3', Data) -> dec_ContractV3(Data); +decode_disp('TypeInfoV1', Data) -> dec_TypeInfoV1(Data); +decode_disp('TypeInfoV3', Data) -> dec_TypeInfoV3(Data); +decode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +info() -> + case ?MODULE:module_info(attributes) of + Attributes when is_list(Attributes) -> + case lists:keyfind(asn1_info, 1, Attributes) of + {_,Info} when is_list(Info) -> + Info; + _ -> + [] + end; + _ -> + [] + end. +enc_GajumaruData(Val) -> +[align, +begin +%% attribute tag(1) with type INTEGER +Enc1@element = element(2, Val), +encode_unconstrained_number(Enc1@element) +end, +begin +%% attribute vsn(2) with type INTEGER +Enc3@element = element(3, Val), +encode_unconstrained_number(Enc3@element) +end|begin +%% attribute content(3) with type Content +Enc5@element = element(4, Val), +enc_Content(Enc5@element) +end]. + + +dec_GajumaruData(Bytes) -> + +%% attribute tag(1) with type INTEGER +{Term1,Bytes1} = begin +V1@Pad3 = bit_size(Bytes) band 7, +{V1@V0,V1@Buf1} = case Bytes of +<<_:V1@Pad3,0:1,V1@V5:7,V1@Buf6/bitstring>> when V1@V5 =/= 0 -> +{V1@V5,V1@Buf6}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@Buf7/bitstring>> when V1@V6 =/= 0 -> +{V1@V6,V1@Buf7}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> when V1@V6 =/= 0 -> +V1@Mul8 = V1@V6 * 16384, +{V1@Mul8,V1@Buf7} +end, +<> = V1@Buf1, +{V1@V9,V1@Buf10} +end, + +%% attribute vsn(2) with type INTEGER +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@Buf4/bitstring>> when V2@V3 =/= 0 -> +{V2@V3,V2@Buf4}; +<<1:1,0:1,V2@V4:14,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +{V2@V4,V2@Buf5}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +V2@Mul6 = V2@V4 * 16384, +{V2@Mul6,V2@Buf5} +end, +<> = V2@Buf1, +{V2@V7,V2@Buf8} +end, + +%% attribute content(3) with type Content +{Term3,Bytes3} = dec_Content(Bytes2), +Res1 = {'GajumaruData',Term1,Term2,Term3}, +{Res1,Bytes3}. + +enc_Content(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= templateFields -> +[<<0:2>>|enc_TemplateFields(ChoiceVal)]; +ChoiceTag =:= account -> +[<<1:2>>|enc_Account(ChoiceVal)]; +ChoiceTag =:= signedTx -> +[<<2:2>>|enc_SignedTx(ChoiceVal)]; +ChoiceTag =:= contract -> +[<<3:2>>|enc_ContractCode(ChoiceVal)] +end. + + +dec_Content(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +dec_TemplateFields(Bytes1) +end, +{{templateFields,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +dec_Account(Bytes1) +end, +{{account,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +dec_SignedTx(Bytes1) +end, +{{signedTx,Val},NewBytes}; +3 -> +{Val,NewBytes} = begin +dec_ContractCode(Bytes1) +end, +{{contract,Val},NewBytes} +end. +enc_TemplateFields(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[align, +Enc1@len|[enc_TemplateField(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>|[enc_TemplateField(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TemplateField(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_TemplateFields(Bytes) -> +dec_components1(Bytes, []). + +enc_TemplateField(Val) -> +[begin +Enc1@element = element(2, Val), +if Enc1@element =:= asn1_NOVALUE -> +<<0:1>>; +true -> +<<1:1>> +end +end, +begin +%% attribute name(1) with type IA5String +Enc2@element = element(2, Val), +if Enc2@element =:= asn1_NOVALUE -> +[]; +true -> +begin +Enc3@bin = list_to_binary(Enc2@element), +Enc3@len = byte_size(Enc3@bin), +if Enc3@len < 128 -> +[align, +Enc3@len|Enc3@bin]; +Enc3@len < 16384 -> +[align, +<<2:2,Enc3@len:14>>|Enc3@bin]; +true -> +[align|encode_fragmented(Enc3@bin, 8)] +end +end +end +end|begin +%% attribute value(2) with type Value +Enc5@element = element(3, Val), +enc_Value(Enc5@element) +end]. + + +dec_TemplateField(Bytes) -> +{Opt,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute name(1) with type IA5String +{Term1,Bytes2} = case Opt band 1 of +1 -> +begin +V2@Pad3 = bit_size(Bytes1) band 7, +{V2@V0,V2@Buf1} = case Bytes1 of +<<_:V2@Pad3,0:1,V2@V5:7,V2@V7:V2@V5/binary-unit:8,V2@Buf8/bitstring>> -> +{V2@V7,V2@Buf8}; +<<_:V2@Pad3,1:1,0:1,V2@V6:14,V2@V8:V2@V6/binary-unit:8,V2@Buf9/bitstring>> -> +{V2@V8,V2@Buf9}; +<<_:V2@Pad3,1:1,1:1,V2@V6:6,V2@Buf7/bitstring>> -> +{V2@V8,V2@Buf9} = decode_fragmented(V2@V6, V2@Buf7, 8), +{V2@V8,V2@Buf9} +end, +V2@Conv10 = binary_to_list(V2@V0), +{V2@Conv10,V2@Buf1} +end; +0 -> +{asn1_NOVALUE,Bytes1} +end, + +%% attribute value(2) with type Value +{Term2,Bytes3} = dec_Value(Bytes2), +Res1 = {'TemplateField',Term1,Term2}, +{Res1,Bytes3}. + +enc_Value(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= intValue -> +[<<0:3>>, +align|encode_unconstrained_number(ChoiceVal)]; +ChoiceTag =:= boolValue -> +if ChoiceVal =:= false -> +<<1:3,0:1>>; +ChoiceVal =:= true -> +<<1:3,1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,ChoiceVal}}}) +end; +ChoiceTag =:= binaryValue -> +begin +Enc6@len = byte_size(ChoiceVal), +if Enc6@len < 128 -> +[<<2:3>>, +align, +Enc6@len|ChoiceVal]; +Enc6@len < 16384 -> +[<<2:3>>, +align, +<<2:2,Enc6@len:14>>|ChoiceVal]; +true -> +[<<2:3>>, +align|encode_fragmented(ChoiceVal, 8)] +end +end; +ChoiceTag =:= idValue -> +[<<3:3>>|enc_Id(ChoiceVal)]; +ChoiceTag =:= listValue -> +[<<4:3>>|enc_Value_listValue(ChoiceVal)]; +ChoiceTag =:= tupleValue -> +[<<5:3>>|enc_Value_tupleValue(ChoiceVal)]; +ChoiceTag =:= mapValue -> +[<<6:3>>|enc_Value_mapValue(ChoiceVal)] +end. +enc_Value_listValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[align, +Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + +enc_Value_tupleValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[align, +Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + +enc_Value_mapValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[align, +Enc1@len|[enc_KeyValue(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>|[enc_KeyValue(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_KeyValue(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_Value(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +begin +V2@Pad3 = bit_size(Bytes1) band 7, +{V2@V0,V2@Buf1} = case Bytes1 of +<<_:V2@Pad3,0:1,V2@V5:7,V2@Buf6/bitstring>> when V2@V5 =/= 0 -> +{V2@V5,V2@Buf6}; +<<_:V2@Pad3,1:1,0:1,V2@V6:14,V2@Buf7/bitstring>> when V2@V6 =/= 0 -> +{V2@V6,V2@Buf7}; +<<_:V2@Pad3,1:1,1:1,V2@V6:6,V2@Buf7/bitstring>> when V2@V6 =/= 0 -> +V2@Mul8 = V2@V6 * 16384, +{V2@Mul8,V2@Buf7} +end, +<> = V2@Buf1, +{V2@V9,V2@Buf10} +end +end, +{{intValue,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +begin +<> = Bytes1, +V3@Int2 = case V3@V0 of +0 -> false; +1 -> true +end, +{V3@Int2,V3@Buf1} +end +end, +{{boolValue,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +begin +V4@Pad3 = bit_size(Bytes1) band 7, +{V4@V0,V4@Buf1} = case Bytes1 of +<<_:V4@Pad3,0:1,V4@V5:7,V4@V7:V4@V5/binary-unit:8,V4@Buf8/bitstring>> -> +{V4@V7,V4@Buf8}; +<<_:V4@Pad3,1:1,0:1,V4@V6:14,V4@V8:V4@V6/binary-unit:8,V4@Buf9/bitstring>> -> +{V4@V8,V4@Buf9}; +<<_:V4@Pad3,1:1,1:1,V4@V6:6,V4@Buf7/bitstring>> -> +{V4@V8,V4@Buf9} = decode_fragmented(V4@V6, V4@Buf7, 8), +{V4@V8,V4@Buf9} +end, +V4@Conv10 = binary:copy(V4@V0), +{V4@Conv10,V4@Buf1} +end +end, +{{binaryValue,Val},NewBytes}; +3 -> +{Val,NewBytes} = begin +dec_Id(Bytes1) +end, +{{idValue,Val},NewBytes}; +4 -> +{Val,NewBytes} = begin +dec_Value_listValue(Bytes1) +end, +{{listValue,Val},NewBytes}; +5 -> +{Val,NewBytes} = begin +dec_Value_tupleValue(Bytes1) +end, +{{tupleValue,Val},NewBytes}; +6 -> +{Val,NewBytes} = begin +dec_Value_mapValue(Bytes1) +end, +{{mapValue,Val},NewBytes} +end. + +dec_Value_listValue(Bytes) -> +dec_components2(Bytes, []). + + +dec_Value_tupleValue(Bytes) -> +dec_components3(Bytes, []). + + +dec_Value_mapValue(Bytes) -> +dec_components4(Bytes, []). + +enc_KeyValue(Val) -> +[begin +%% attribute key(1) with type Value +Enc1@element = element(2, Val), +enc_Value(Enc1@element) +end|begin +%% attribute val(2) with type Value +Enc2@element = element(3, Val), +enc_Value(Enc2@element) +end]. + + +dec_KeyValue(Bytes) -> + +%% attribute key(1) with type Value +{Term1,Bytes1} = dec_Value(Bytes), + +%% attribute val(2) with type Value +{Term2,Bytes2} = dec_Value(Bytes1), +Res1 = {'KeyValue',Term1,Term2}, +{Res1,Bytes2}. + +enc_Id(Val) -> +[align, +begin +%% attribute type(1) with type INTEGER +Enc1@element = element(2, Val), +if Enc1@element bsr 8 =:= 0 -> +Enc1@element; +true -> +exit({error,{asn1,{illegal_integer,Enc1@element}}}) +end +end|begin +%% attribute value(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len =:= 32 -> +Enc3@element +end +end]. + + +dec_Id(Bytes) -> + +%% attribute type(1) with type INTEGER +{Term1,Bytes1} = begin +V1@Pad2 = bit_size(Bytes) band 7, +<<_:V1@Pad2,V1@V0:1/unsigned-unit:8,V1@Buf1/bitstring>> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute value(2) with type OCTET STRING +{Term2,Bytes2} = begin +<> = Bytes1, +V2@Conv2 = binary:copy(V2@V0), +{V2@Conv2,V2@Buf1} +end, +Res1 = {'Id',Term1,Term2}, +{Res1,Bytes2}. + +enc_Account(Val) -> +[align, +begin +%% attribute foo(1) with type INTEGER +Enc1@element = element(2, Val), +encode_unconstrained_number(Enc1@element) +end|begin +%% attribute bar(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end]. + + +dec_Account(Bytes) -> + +%% attribute foo(1) with type INTEGER +{Term1,Bytes1} = begin +V1@Pad3 = bit_size(Bytes) band 7, +{V1@V0,V1@Buf1} = case Bytes of +<<_:V1@Pad3,0:1,V1@V5:7,V1@Buf6/bitstring>> when V1@V5 =/= 0 -> +{V1@V5,V1@Buf6}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@Buf7/bitstring>> when V1@V6 =/= 0 -> +{V1@V6,V1@Buf7}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> when V1@V6 =/= 0 -> +V1@Mul8 = V1@V6 * 16384, +{V1@Mul8,V1@Buf7} +end, +<> = V1@Buf1, +{V1@V9,V1@Buf10} +end, + +%% attribute bar(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, +Res1 = {'Account',Term1,Term2}, +{Res1,Bytes2}. + +enc_SignedTx(Val) -> +[begin +%% attribute signatures(1) with type SEQUENCE OF +Enc1@element = element(2, Val), +enc_SignedTx_signatures(Enc1@element) +end, +align|begin +%% attribute transaction(2) with type OCTET STRING +Enc2@element = element(3, Val), +Enc3@len = byte_size(Enc2@element), +if Enc3@len < 128 -> +[Enc3@len|Enc2@element]; +Enc3@len < 16384 -> +[<<2:2,Enc3@len:14>>|Enc2@element]; +true -> +encode_fragmented(Enc2@element, 8) +end +end]. +enc_SignedTx_signatures(Val) -> +Enc2@len = length(Val), +if Enc2@len < 128 -> +[align, +Enc2@len|[begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[align, +Enc1@len, +align|Comp]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>, +align|Comp]; +true -> +[align|encode_fragmented(Comp, 8)] +end +end || Comp <- Val]]; +Enc2@len < 16384 -> +[align, +<<2:2,Enc2@len:14>>|[begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[align, +Enc1@len, +align|Comp]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>, +align|Comp]; +true -> +[align|encode_fragmented(Comp, 8)] +end +end || Comp <- Val]]; +true -> +begin +Enc2@fn = fun(Comp) -> begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[align, +Enc1@len, +align|Comp]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>, +align|Comp]; +true -> +[align|encode_fragmented(Comp, 8)] +end +end end, +encode_fragmented_sof(Enc2@fn, Val, Enc2@len) +end +end. + + + +dec_SignedTx(Bytes) -> + +%% attribute signatures(1) with type SEQUENCE OF +{Term1,Bytes1} = dec_SignedTx_signatures(Bytes), + +%% attribute transaction(2) with type OCTET STRING +{Term2,Bytes2} = begin +V1@Pad3 = bit_size(Bytes1) band 7, +{V1@V0,V1@Buf1} = case Bytes1 of +<<_:V1@Pad3,0:1,V1@V5:7,V1@V7:V1@V5/binary-unit:8,V1@Buf8/bitstring>> -> +{V1@V7,V1@Buf8}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@V8:V1@V6/binary-unit:8,V1@Buf9/bitstring>> -> +{V1@V8,V1@Buf9}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> -> +{V1@V8,V1@Buf9} = decode_fragmented(V1@V6, V1@Buf7, 8), +{V1@V8,V1@Buf9} +end, +V1@Conv10 = binary:copy(V1@V0), +{V1@Conv10,V1@Buf1} +end, +Res1 = {'SignedTx',Term1,Term2}, +{Res1,Bytes2}. + + +dec_SignedTx_signatures(Bytes) -> +dec_components5(Bytes, []). + +enc_ContractCode(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= v1 -> +[<<0:2>>|enc_ContractV1(ChoiceVal)]; +ChoiceTag =:= v2 -> +[<<1:2>>|enc_ContractV2(ChoiceVal)]; +ChoiceTag =:= v3 -> +[<<2:2>>|enc_ContractV3(ChoiceVal)] +end. + + +dec_ContractCode(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +dec_ContractV1(Bytes1) +end, +{{v1,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +dec_ContractV2(Bytes1) +end, +{{v2,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +dec_ContractV3(Bytes1) +end, +{{v3,Val},NewBytes} +end. +enc_ContractV1(Val) -> +[align, +begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV1_typeInfo(Enc3@element) +end, +align|begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end]. +enc_ContractV1_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[align, +Enc1@len|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV1(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV1(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +V1@Pad3 = bit_size(Bytes) band 7, +{V1@V0,V1@Buf1} = case Bytes of +<<_:V1@Pad3,0:1,V1@V5:7,V1@V7:V1@V5/binary-unit:8,V1@Buf8/bitstring>> -> +{V1@V7,V1@Buf8}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@V8:V1@V6/binary-unit:8,V1@Buf9/bitstring>> -> +{V1@V8,V1@Buf9}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> -> +{V1@V8,V1@Buf9} = decode_fragmented(V1@V6, V1@Buf7, 8), +{V1@V8,V1@Buf9} +end, +V1@Conv10 = binary:copy(V1@V0), +{V1@Conv10,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV1_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +V2@Pad3 = bit_size(Bytes2) band 7, +{V2@V0,V2@Buf1} = case Bytes2 of +<<_:V2@Pad3,0:1,V2@V5:7,V2@V7:V2@V5/binary-unit:8,V2@Buf8/bitstring>> -> +{V2@V7,V2@Buf8}; +<<_:V2@Pad3,1:1,0:1,V2@V6:14,V2@V8:V2@V6/binary-unit:8,V2@Buf9/bitstring>> -> +{V2@V8,V2@Buf9}; +<<_:V2@Pad3,1:1,1:1,V2@V6:6,V2@Buf7/bitstring>> -> +{V2@V8,V2@Buf9} = decode_fragmented(V2@V6, V2@Buf7, 8), +{V2@V8,V2@Buf9} +end, +V2@Conv10 = binary:copy(V2@V0), +{V2@Conv10,V2@Buf1} +end, +Res1 = {'ContractV1',Term1,Term2,Term3}, +{Res1,Bytes3}. + + +dec_ContractV1_typeInfo(Bytes) -> +dec_components6(Bytes, []). + +enc_ContractV2(Val) -> +[align, +begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV2_typeInfo(Enc3@element) +end, +align, +begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end|begin +%% attribute compilerVersion(4) with type OCTET STRING +Enc6@element = element(5, Val), +Enc7@len = byte_size(Enc6@element), +if Enc7@len < 128 -> +[Enc7@len|Enc6@element]; +Enc7@len < 16384 -> +[<<2:2,Enc7@len:14>>|Enc6@element]; +true -> +encode_fragmented(Enc6@element, 8) +end +end]. +enc_ContractV2_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[align, +Enc1@len|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV1(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV2(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +V1@Pad3 = bit_size(Bytes) band 7, +{V1@V0,V1@Buf1} = case Bytes of +<<_:V1@Pad3,0:1,V1@V5:7,V1@V7:V1@V5/binary-unit:8,V1@Buf8/bitstring>> -> +{V1@V7,V1@Buf8}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@V8:V1@V6/binary-unit:8,V1@Buf9/bitstring>> -> +{V1@V8,V1@Buf9}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> -> +{V1@V8,V1@Buf9} = decode_fragmented(V1@V6, V1@Buf7, 8), +{V1@V8,V1@Buf9} +end, +V1@Conv10 = binary:copy(V1@V0), +{V1@Conv10,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV2_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +V2@Pad3 = bit_size(Bytes2) band 7, +{V2@V0,V2@Buf1} = case Bytes2 of +<<_:V2@Pad3,0:1,V2@V5:7,V2@V7:V2@V5/binary-unit:8,V2@Buf8/bitstring>> -> +{V2@V7,V2@Buf8}; +<<_:V2@Pad3,1:1,0:1,V2@V6:14,V2@V8:V2@V6/binary-unit:8,V2@Buf9/bitstring>> -> +{V2@V8,V2@Buf9}; +<<_:V2@Pad3,1:1,1:1,V2@V6:6,V2@Buf7/bitstring>> -> +{V2@V8,V2@Buf9} = decode_fragmented(V2@V6, V2@Buf7, 8), +{V2@V8,V2@Buf9} +end, +V2@Conv10 = binary:copy(V2@V0), +{V2@Conv10,V2@Buf1} +end, + +%% attribute compilerVersion(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V3@V0,V3@Buf1} = case Bytes3 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, +Res1 = {'ContractV2',Term1,Term2,Term3,Term4}, +{Res1,Bytes4}. + + +dec_ContractV2_typeInfo(Bytes) -> +dec_components7(Bytes, []). + +enc_ContractV3(Val) -> +[align, +begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV3_typeInfo(Enc3@element) +end, +align, +begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end, +begin +%% attribute compilerVersion(4) with type OCTET STRING +Enc6@element = element(5, Val), +Enc7@len = byte_size(Enc6@element), +if Enc7@len < 128 -> +[Enc7@len|Enc6@element]; +Enc7@len < 16384 -> +[<<2:2,Enc7@len:14>>|Enc6@element]; +true -> +encode_fragmented(Enc6@element, 8) +end +end|begin +%% attribute payable(5) with type BOOLEAN +Enc8@element = element(6, Val), +if Enc8@element =:= false -> +<<0:1>>; +Enc8@element =:= true -> +<<1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,Enc8@element}}}) +end +end]. +enc_ContractV3_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[align, +Enc1@len|[enc_TypeInfoV3(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[align, +<<2:2,Enc1@len:14>>|[enc_TypeInfoV3(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV3(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV3(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +V1@Pad3 = bit_size(Bytes) band 7, +{V1@V0,V1@Buf1} = case Bytes of +<<_:V1@Pad3,0:1,V1@V5:7,V1@V7:V1@V5/binary-unit:8,V1@Buf8/bitstring>> -> +{V1@V7,V1@Buf8}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@V8:V1@V6/binary-unit:8,V1@Buf9/bitstring>> -> +{V1@V8,V1@Buf9}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> -> +{V1@V8,V1@Buf9} = decode_fragmented(V1@V6, V1@Buf7, 8), +{V1@V8,V1@Buf9} +end, +V1@Conv10 = binary:copy(V1@V0), +{V1@Conv10,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV3_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +V2@Pad3 = bit_size(Bytes2) band 7, +{V2@V0,V2@Buf1} = case Bytes2 of +<<_:V2@Pad3,0:1,V2@V5:7,V2@V7:V2@V5/binary-unit:8,V2@Buf8/bitstring>> -> +{V2@V7,V2@Buf8}; +<<_:V2@Pad3,1:1,0:1,V2@V6:14,V2@V8:V2@V6/binary-unit:8,V2@Buf9/bitstring>> -> +{V2@V8,V2@Buf9}; +<<_:V2@Pad3,1:1,1:1,V2@V6:6,V2@Buf7/bitstring>> -> +{V2@V8,V2@Buf9} = decode_fragmented(V2@V6, V2@Buf7, 8), +{V2@V8,V2@Buf9} +end, +V2@Conv10 = binary:copy(V2@V0), +{V2@Conv10,V2@Buf1} +end, + +%% attribute compilerVersion(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V3@V0,V3@Buf1} = case Bytes3 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, + +%% attribute payable(5) with type BOOLEAN +{Term5,Bytes5} = begin +<> = Bytes4, +V4@Int2 = case V4@V0 of +0 -> false; +1 -> true +end, +{V4@Int2,V4@Buf1} +end, +Res1 = {'ContractV3',Term1,Term2,Term3,Term4,Term5}, +{Res1,Bytes5}. + + +dec_ContractV3_typeInfo(Bytes) -> +dec_components8(Bytes, []). + +enc_TypeInfoV1(Val) -> +[align, +begin +%% attribute typeHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute name(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end, +begin +%% attribute argType(3) with type OCTET STRING +Enc5@element = element(4, Val), +Enc6@len = byte_size(Enc5@element), +if Enc6@len < 128 -> +[Enc6@len|Enc5@element]; +Enc6@len < 16384 -> +[<<2:2,Enc6@len:14>>|Enc5@element]; +true -> +encode_fragmented(Enc5@element, 8) +end +end|begin +%% attribute outType(4) with type OCTET STRING +Enc7@element = element(5, Val), +Enc8@len = byte_size(Enc7@element), +if Enc8@len < 128 -> +[Enc8@len|Enc7@element]; +Enc8@len < 16384 -> +[<<2:2,Enc8@len:14>>|Enc7@element]; +true -> +encode_fragmented(Enc7@element, 8) +end +end]. + + +dec_TypeInfoV1(Bytes) -> + +%% attribute typeHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +V1@Pad3 = bit_size(Bytes) band 7, +{V1@V0,V1@Buf1} = case Bytes of +<<_:V1@Pad3,0:1,V1@V5:7,V1@V7:V1@V5/binary-unit:8,V1@Buf8/bitstring>> -> +{V1@V7,V1@Buf8}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@V8:V1@V6/binary-unit:8,V1@Buf9/bitstring>> -> +{V1@V8,V1@Buf9}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> -> +{V1@V8,V1@Buf9} = decode_fragmented(V1@V6, V1@Buf7, 8), +{V1@V8,V1@Buf9} +end, +V1@Conv10 = binary:copy(V1@V0), +{V1@Conv10,V1@Buf1} +end, + +%% attribute name(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute argType(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V3@V0,V3@Buf1} = case Bytes2 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, + +%% attribute outType(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V4@V0,V4@Buf1} = case Bytes3 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end, +Res1 = {'TypeInfoV1',Term1,Term2,Term3,Term4}, +{Res1,Bytes4}. + +enc_TypeInfoV3(Val) -> +[align, +begin +%% attribute typeHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute name(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end, +begin +%% attribute payable(3) with type BOOLEAN +Enc5@element = element(4, Val), +if Enc5@element =:= false -> +<<0:1,0:7>>; +Enc5@element =:= true -> +<<1:1,0:7>>; +true -> +exit({error,{asn1,{illegal_boolean,Enc5@element}}}) +end +end, +begin +%% attribute argType(4) with type OCTET STRING +Enc7@element = element(5, Val), +Enc8@len = byte_size(Enc7@element), +if Enc8@len < 128 -> +[Enc8@len|Enc7@element]; +Enc8@len < 16384 -> +[<<2:2,Enc8@len:14>>|Enc7@element]; +true -> +encode_fragmented(Enc7@element, 8) +end +end|begin +%% attribute outType(5) with type OCTET STRING +Enc9@element = element(6, Val), +Enc10@len = byte_size(Enc9@element), +if Enc10@len < 128 -> +[Enc10@len|Enc9@element]; +Enc10@len < 16384 -> +[<<2:2,Enc10@len:14>>|Enc9@element]; +true -> +encode_fragmented(Enc9@element, 8) +end +end]. + + +dec_TypeInfoV3(Bytes) -> + +%% attribute typeHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +V1@Pad3 = bit_size(Bytes) band 7, +{V1@V0,V1@Buf1} = case Bytes of +<<_:V1@Pad3,0:1,V1@V5:7,V1@V7:V1@V5/binary-unit:8,V1@Buf8/bitstring>> -> +{V1@V7,V1@Buf8}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@V8:V1@V6/binary-unit:8,V1@Buf9/bitstring>> -> +{V1@V8,V1@Buf9}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> -> +{V1@V8,V1@Buf9} = decode_fragmented(V1@V6, V1@Buf7, 8), +{V1@V8,V1@Buf9} +end, +V1@Conv10 = binary:copy(V1@V0), +{V1@Conv10,V1@Buf1} +end, + +%% attribute name(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute payable(3) with type BOOLEAN +{Term3,Bytes3} = begin +<> = Bytes2, +V3@Int2 = case V3@V0 of +0 -> false; +1 -> true +end, +{V3@Int2,V3@Buf1} +end, + +%% attribute argType(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V4@V0,V4@Buf1} = case Bytes3 of +<<_:7,0:1,V4@V4:7,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<_:7,1:1,0:1,V4@V5:14,V4@V7:V4@V5/binary-unit:8,V4@Buf8/bitstring>> -> +{V4@V7,V4@Buf8}; +<<_:7,1:1,1:1,V4@V5:6,V4@Buf6/bitstring>> -> +{V4@V7,V4@Buf8} = decode_fragmented(V4@V5, V4@Buf6, 8), +{V4@V7,V4@Buf8} +end, +V4@Conv9 = binary:copy(V4@V0), +{V4@Conv9,V4@Buf1} +end, + +%% attribute outType(5) with type OCTET STRING +{Term5,Bytes5} = begin +{V5@V0,V5@Buf1} = case Bytes4 of +<<0:1,V5@V3:7,V5@V5:V5@V3/binary-unit:8,V5@Buf6/bitstring>> -> +{V5@V5,V5@Buf6}; +<<1:1,0:1,V5@V4:14,V5@V6:V5@V4/binary-unit:8,V5@Buf7/bitstring>> -> +{V5@V6,V5@Buf7}; +<<1:1,1:1,V5@V4:6,V5@Buf5/bitstring>> -> +{V5@V6,V5@Buf7} = decode_fragmented(V5@V4, V5@Buf5, 8), +{V5@V6,V5@Buf7} +end, +V5@Conv8 = binary:copy(V5@V0), +{V5@Conv8,V5@Buf1} +end, +Res1 = {'TypeInfoV3',Term1,Term2,Term3,Term4,Term5}, +{Res1,Bytes5}. + + +%%% +%%% Run-time functions. +%%% + +'dialyzer-suppressions'(Arg) -> + _ = complete(element(1, Arg)), + ok. + +dec_components1(Bytes, Acc) -> +%% Length with constraint no +V1@Pad3 = bit_size(Bytes) band 7, +{V1@V0,V1@Buf1} = case Bytes of +<<_:V1@Pad3,0:1,V1@V5:7,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<_:V1@Pad3,1:1,0:1,V1@V6:14,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<_:V1@Pad3,1:1,1:1,V1@V6:6,V1@Buf7/bitstring>> -> +V1@Mul8 = V1@V6 * 16384, +{V1@Mul8,V1@Buf7} +end, +{Acc1,Buf1} = dec_fragment9(V1@V0, V1@Buf1, Acc), +if V1@V0 >= 16384 -> +dec_components1(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components2(Bytes, Acc) -> +%% Length with constraint no +V2@Pad3 = bit_size(Bytes) band 7, +{V2@V0,V2@Buf1} = case Bytes of +<<_:V2@Pad3,0:1,V2@V5:7,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<_:V2@Pad3,1:1,0:1,V2@V6:14,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<_:V2@Pad3,1:1,1:1,V2@V6:6,V2@Buf7/bitstring>> -> +V2@Mul8 = V2@V6 * 16384, +{V2@Mul8,V2@Buf7} +end, +{Acc1,Buf1} = dec_fragment10(V2@V0, V2@Buf1, Acc), +if V2@V0 >= 16384 -> +dec_components2(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components3(Bytes, Acc) -> +%% Length with constraint no +V3@Pad3 = bit_size(Bytes) band 7, +{V3@V0,V3@Buf1} = case Bytes of +<<_:V3@Pad3,0:1,V3@V5:7,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<_:V3@Pad3,1:1,0:1,V3@V6:14,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<_:V3@Pad3,1:1,1:1,V3@V6:6,V3@Buf7/bitstring>> -> +V3@Mul8 = V3@V6 * 16384, +{V3@Mul8,V3@Buf7} +end, +{Acc1,Buf1} = dec_fragment11(V3@V0, V3@Buf1, Acc), +if V3@V0 >= 16384 -> +dec_components3(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components4(Bytes, Acc) -> +%% Length with constraint no +V4@Pad3 = bit_size(Bytes) band 7, +{V4@V0,V4@Buf1} = case Bytes of +<<_:V4@Pad3,0:1,V4@V5:7,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<_:V4@Pad3,1:1,0:1,V4@V6:14,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<_:V4@Pad3,1:1,1:1,V4@V6:6,V4@Buf7/bitstring>> -> +V4@Mul8 = V4@V6 * 16384, +{V4@Mul8,V4@Buf7} +end, +{Acc1,Buf1} = dec_fragment12(V4@V0, V4@Buf1, Acc), +if V4@V0 >= 16384 -> +dec_components4(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components5(Bytes, Acc) -> +%% Length with constraint no +V5@Pad3 = bit_size(Bytes) band 7, +{V5@V0,V5@Buf1} = case Bytes of +<<_:V5@Pad3,0:1,V5@V5:7,V5@Buf6/bitstring>> -> +{V5@V5,V5@Buf6}; +<<_:V5@Pad3,1:1,0:1,V5@V6:14,V5@Buf7/bitstring>> -> +{V5@V6,V5@Buf7}; +<<_:V5@Pad3,1:1,1:1,V5@V6:6,V5@Buf7/bitstring>> -> +V5@Mul8 = V5@V6 * 16384, +{V5@Mul8,V5@Buf7} +end, +{Acc1,Buf1} = dec_fragment13(V5@V0, V5@Buf1, Acc), +if V5@V0 >= 16384 -> +dec_components5(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components6(Bytes, Acc) -> +%% Length with constraint no +V6@Pad3 = bit_size(Bytes) band 7, +{V6@V0,V6@Buf1} = case Bytes of +<<_:V6@Pad3,0:1,V6@V5:7,V6@Buf6/bitstring>> -> +{V6@V5,V6@Buf6}; +<<_:V6@Pad3,1:1,0:1,V6@V6:14,V6@Buf7/bitstring>> -> +{V6@V6,V6@Buf7}; +<<_:V6@Pad3,1:1,1:1,V6@V6:6,V6@Buf7/bitstring>> -> +V6@Mul8 = V6@V6 * 16384, +{V6@Mul8,V6@Buf7} +end, +{Acc1,Buf1} = dec_fragment14(V6@V0, V6@Buf1, Acc), +if V6@V0 >= 16384 -> +dec_components6(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components7(Bytes, Acc) -> +%% Length with constraint no +V7@Pad3 = bit_size(Bytes) band 7, +{V7@V0,V7@Buf1} = case Bytes of +<<_:V7@Pad3,0:1,V7@V5:7,V7@Buf6/bitstring>> -> +{V7@V5,V7@Buf6}; +<<_:V7@Pad3,1:1,0:1,V7@V6:14,V7@Buf7/bitstring>> -> +{V7@V6,V7@Buf7}; +<<_:V7@Pad3,1:1,1:1,V7@V6:6,V7@Buf7/bitstring>> -> +V7@Mul8 = V7@V6 * 16384, +{V7@Mul8,V7@Buf7} +end, +{Acc1,Buf1} = dec_fragment15(V7@V0, V7@Buf1, Acc), +if V7@V0 >= 16384 -> +dec_components7(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components8(Bytes, Acc) -> +%% Length with constraint no +V8@Pad3 = bit_size(Bytes) band 7, +{V8@V0,V8@Buf1} = case Bytes of +<<_:V8@Pad3,0:1,V8@V5:7,V8@Buf6/bitstring>> -> +{V8@V5,V8@Buf6}; +<<_:V8@Pad3,1:1,0:1,V8@V6:14,V8@Buf7/bitstring>> -> +{V8@V6,V8@Buf7}; +<<_:V8@Pad3,1:1,1:1,V8@V6:6,V8@Buf7/bitstring>> -> +V8@Mul8 = V8@V6 * 16384, +{V8@Mul8,V8@Buf7} +end, +{Acc1,Buf1} = dec_fragment16(V8@V0, V8@Buf1, Acc), +if V8@V0 >= 16384 -> +dec_components8(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_fragment10(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment10(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment10(Num-1, Remain, [Term|Acc]). + +dec_fragment11(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment11(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment11(Num-1, Remain, [Term|Acc]). + +dec_fragment12(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment12(Num, Bytes, Acc) -> +{Term,Remain} = dec_KeyValue(Bytes), +dec_fragment12(Num-1, Remain, [Term|Acc]). + +dec_fragment13(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment13(Num, Bytes, Acc) -> +{Term,Remain} = begin +V9@Pad3 = bit_size(Bytes) band 7, +{V9@V0,V9@Buf1} = case Bytes of +<<_:V9@Pad3,0:1,V9@V5:7,V9@V7:V9@V5/binary-unit:8,V9@Buf8/bitstring>> -> +{V9@V7,V9@Buf8}; +<<_:V9@Pad3,1:1,0:1,V9@V6:14,V9@V8:V9@V6/binary-unit:8,V9@Buf9/bitstring>> -> +{V9@V8,V9@Buf9}; +<<_:V9@Pad3,1:1,1:1,V9@V6:6,V9@Buf7/bitstring>> -> +{V9@V8,V9@Buf9} = decode_fragmented(V9@V6, V9@Buf7, 8), +{V9@V8,V9@Buf9} +end, +V9@Conv10 = binary:copy(V9@V0), +{V9@Conv10,V9@Buf1} +end, +dec_fragment13(Num-1, Remain, [Term|Acc]). + +dec_fragment14(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment14(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV1(Bytes), +dec_fragment14(Num-1, Remain, [Term|Acc]). + +dec_fragment15(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment15(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV1(Bytes), +dec_fragment15(Num-1, Remain, [Term|Acc]). + +dec_fragment16(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment16(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV3(Bytes), +dec_fragment16(Num-1, Remain, [Term|Acc]). + +dec_fragment9(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment9(Num, Bytes, Acc) -> +{Term,Remain} = dec_TemplateField(Bytes), +dec_fragment9(Num-1, Remain, [Term|Acc]). + +complete(L0) -> + L = complete(L0, []), + case list_to_bitstring(L) of + <<>> -> + <<0>>; + Bin -> + Bin + end. + +complete([], Bits, []) -> + case Bits band 7 of + 0 -> + []; + N -> + [<<0:(8 - N)>>] + end; +complete([], Bits, [H | More]) -> + complete(H, Bits, More); +complete([align | T], Bits, More) -> + case Bits band 7 of + 0 -> + complete(T, More); + 1 -> + [<<0:7>> | complete(T, More)]; + 2 -> + [<<0:6>> | complete(T, More)]; + 3 -> + [<<0:5>> | complete(T, More)]; + 4 -> + [<<0:4>> | complete(T, More)]; + 5 -> + [<<0:3>> | complete(T, More)]; + 6 -> + [<<0:2>> | complete(T, More)]; + 7 -> + [<<0:1>> | complete(T, More)] + end; +complete([[] | T], Bits, More) -> + complete(T, Bits, More); +complete([[_ | _] = H], Bits, More) -> + complete(H, Bits, More); +complete([[_ | _] = H | T], Bits, More) -> + complete(H, Bits, [T | More]); +complete([H | T], Bits, More) when is_integer(H); is_binary(H) -> + [H | complete(T, Bits, More)]; +complete([H | T], Bits, More) -> + [H | complete(T, Bits + bit_size(H), More)]; +complete(Bin, Bits, More) when is_binary(Bin) -> + [Bin | complete([], Bits, More)]; +complete(Bin, Bits, More) -> + [Bin | complete([], Bits + bit_size(Bin), More)]. + +complete([], []) -> + []; +complete([], [H | More]) -> + complete(H, More); +complete([align | T], More) -> + complete(T, More); +complete([[] | T], More) -> + complete(T, More); +complete([[_ | _] = H], More) -> + complete(H, More); +complete([[_ | _] = H | T], More) -> + complete(H, [T | More]); +complete([H | T], More) when is_integer(H); is_binary(H) -> + [H | complete(T, More)]; +complete([H | T], More) -> + [H | complete(T, bit_size(H), More)]; +complete(Bin, More) when is_binary(Bin) -> + [Bin | complete([], More)]; +complete(Bin, More) -> + [Bin | complete([], bit_size(Bin), More)]. + +decode_fragmented(SegSz0, Buf0, Unit) -> + SegSz = SegSz0 * Unit * 16384, + <> = Buf0, + decode_fragmented_1(Buf, Unit, Res). + +decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) -> + Sz = N * Unit, + <> = Buf0, + {<>, Buf}; +decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) -> + Sz = N * Unit, + <> = Buf0, + {<>, Buf}; +decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) -> + SegSz = SegSz0 * Unit * 16384, + <> = Buf0, + Res = <>, + decode_fragmented_1(Buf, Unit, Res). + +encode_components(Cs, _Encoder, 0, Acc) -> + {Cs, lists:reverse(Acc)}; +encode_components([C | Cs], Encoder, Size, Acc) -> + B = Encoder(C), + encode_components(Cs, Encoder, Size - 1, [B | Acc]). + +encode_fragmented(Bin, Unit) -> + encode_fragmented_1(Bin, Unit, 4). + +encode_fragmented_1(Bin, Unit, N) -> + SegSz = Unit * N * 16384, + case Bin of + <> -> + [<<3:2,N:6>>, B | encode_fragmented_1(T, Unit, N)]; + _ when N > 1 -> + encode_fragmented_1(Bin, Unit, N - 1); + _ -> + case bit_size(Bin) div Unit of + Len when Len < 128 -> + [Len, Bin]; + Len when Len < 16384 -> + [<<2:2,Len:14>>, Bin] + end + end. + +encode_fragmented_sof(Fun, Comps, Len) -> + encode_fragmented_sof_1(Fun, Comps, Len, 4). + +encode_fragmented_sof_1(Encoder, Comps0, Len0, N) -> + SegSz = N * 16384, + if + Len0 >= SegSz -> + {Comps, B} = encode_components(Comps0, Encoder, SegSz, []), + Len = Len0 - SegSz, + [align, + <<3:2,N:6>>, + B | + encode_fragmented_sof_1(Encoder, Comps, Len, N)]; + N > 1 -> + encode_fragmented_sof_1(Encoder, Comps0, Len0, N - 1); + Len0 < 128 -> + {[], B} = encode_components(Comps0, Encoder, Len0, []), + [align, Len0 | B]; + Len0 < 16384 -> + {[], B} = encode_components(Comps0, Encoder, Len0, []), + [align, <<2:2,Len0:14>> | B] + end. + +encode_unconstrained_number(Val) when not is_integer(Val) -> + exit({error, {asn1, {illegal_integer, Val}}}); +encode_unconstrained_number(Val) when Val >= 0 -> + if + Val < 128 -> + [1, Val]; + Val < 256 -> + [<<2,0>>, Val]; + true -> + case binary:encode_unsigned(Val) of + <<0:1,_/bitstring>> = Bin -> + case byte_size(Bin) of + Sz when Sz < 128 -> + [Sz, Bin]; + Sz when Sz < 16384 -> + [<<2:2,Sz:14>>, Bin] + end; + <<1:1,_/bitstring>> = Bin -> + case byte_size(Bin) + 1 of + Sz when Sz < 128 -> + [Sz, 0, Bin]; + Sz when Sz < 16384 -> + [<<2:2,Sz:14,0:8>>, Bin] + end + end + end; +encode_unconstrained_number(Val) -> + Oct = enint(Val, []), + Len = length(Oct), + if + Len < 128 -> + [Len | Oct]; + Len < 16384 -> + [<<2:2,Len:14>> | Oct] + end. + +enint(-1, [B1 | T]) when B1 > 127 -> + [B1 | T]; +enint(N, Acc) -> + enint(N bsr 8, [N band 255 | Acc]). diff --git a/asn1_per/GajumaruSerialization.hrl b/asn1_per/GajumaruSerialization.hrl new file mode 100644 index 0000000..4c5d52e --- /dev/null +++ b/asn1_per/GajumaruSerialization.hrl @@ -0,0 +1,76 @@ +%% Generated by the Erlang ASN.1 compiler. Version: 5.4.3 +%% Purpose: Erlang record definitions for each named and unnamed +%% SEQUENCE and SET, and macro definitions for each value +%% definition in module GajumaruSerialization. + +-ifndef(_GAJUMARUSERIALIZATION_HRL_). +-define(_GAJUMARUSERIALIZATION_HRL_, true). + +-record('GajumaruData', { + tag, + vsn, + content +}). + +-record('TemplateField', { + name = asn1_NOVALUE, + value +}). + +-record('KeyValue', { + key, + val +}). + +-record('Id', { + type, + value +}). + +-record('Account', { + foo, + bar +}). + +-record('SignedTx', { + signatures, + transaction +}). + +-record('ContractV1', { + sourceHash, + typeInfo, + byteCode +}). + +-record('ContractV2', { + sourceHash, + typeInfo, + byteCode, + compilerVersion +}). + +-record('ContractV3', { + sourceHash, + typeInfo, + byteCode, + compilerVersion, + payable +}). + +-record('TypeInfoV1', { + typeHash, + name, + argType, + outType +}). + +-record('TypeInfoV3', { + typeHash, + name, + payable, + argType, + outType +}). + +-endif. %% _GAJUMARUSERIALIZATION_HRL_ diff --git a/asn1_uper/GajumaruSerialization.asn b/asn1_uper/GajumaruSerialization.asn new file mode 100644 index 0000000..43607e9 --- /dev/null +++ b/asn1_uper/GajumaruSerialization.asn @@ -0,0 +1,225 @@ +-- GajumaruSerialization.asn +-- +-- ASN.1 model for the structures serialized by gmserialization.erl +-- (the layer on top of RLP). +-- +-- Purpose: +-- * Provide a formal, toolable description of the data. +-- * Enable migration from the legacy RLP-based format to DER. +-- +-- Detection of legacy vs new: +-- Legacy data (produced by gmserialization:serialize / gmser_chain_objects:serialize +-- or gmser_dyn:serialize) is always an RLP *list* at the top level. +-- This means the first byte is in the range 0xC0 .. 0xFF. +-- +-- DER-encoded data using the types below will start with 0x30 (SEQUENCE, +-- constructed, universal tag) for the outermost GajumaruData (or any +-- top-level SEQUENCE we define). 0x30 < 0xC0, so a single-byte prefix +-- check reliably distinguishes the two formats. +-- +-- Usage in Erlang (after compiling with asn1ct): +-- {ok, Mod} = asn1ct:compile(GajumaruSerialization.asn, [ber, der]). +-- {ok, Term} = 'GajumaruSerialization':decode('GajumaruData', DerBinary). +-- +-- Notes on type mapping from gmserialization.erl: +-- - int -> INTEGER (new data uses canonical DER INTEGER) +-- - binary -> OCTET STRING +-- - bool -> BOOLEAN +-- - id -> Id (SEQUENCE) (cleaner than the legacy packed 33-byte form) +-- - [T] -> SEQUENCE OF T +-- - {T1,...} -> SEQUENCE (fixed-size, order matters) +-- - #{items := [{K,T},...]} -> SEQUENCE with the fields in template order +-- (static maps carry *values only*, no keys on the wire) +-- - tag + vsn are preserved as the first two fields for compatibility +-- with existing dispatch logic. +-- +-- Legacy integers had strict unsigned-minimal no-leading-zero (except for 0) +-- and RLP-level rules. New DER data does not need to follow those rules. +-- +-- WARNING: +-- Any cryptographic hash or signature computed over a serialized object +-- will change when switching from RLP to DER for that object. Plan a +-- coordinated upgrade. + +GajumaruSerialization DEFINITIONS + AUTOMATIC TAGS ::= +BEGIN + +EXPORTS ALL; + +-- ============================================================ +-- Top-level wrapper used for new DER data. +-- This is what a decoder will see first. +-- ============================================================ + +GajumaruData ::= SEQUENCE { + tag INTEGER, + vsn INTEGER, + content Content +} + +-- Content can be a specific structured type (preferred) or a generic +-- representation of a template-driven object. +Content ::= CHOICE { + -- Generic fallback that can represent any [{Field, Type}] template + -- without having a pre-defined SEQUENCE for every object. + templateFields [0] TemplateFields, + + -- Examples of concrete versioned types (extend as needed) + account [1] Account, + signedTx [2] SignedTx, + contract [3] ContractCode + -- Add more alternatives for other tags from gmser_chain_objects +} + +-- ============================================================ +-- Generic template-driven representation +-- (useful during transition or for unregistered types) +-- ============================================================ + +TemplateFields ::= SEQUENCE OF TemplateField + +TemplateField ::= SEQUENCE { + -- Field name is included for debuggability / generic processing. + -- In the original static encoding the name is NOT on the wire; + -- only position and type matter. We include it here for convenience. + name IA5String OPTIONAL, + value Value +} + +Value ::= CHOICE { + intValue [0] INTEGER, + boolValue [1] BOOLEAN, + binaryValue [2] OCTET STRING, + idValue [3] Id, + listValue [4] SEQUENCE OF Value, + tupleValue [5] SEQUENCE OF Value, + mapValue [6] SEQUENCE OF KeyValue -- only needed if you want to + -- represent dynamic-style maps +} + +KeyValue ::= SEQUENCE { + key Value, + val Value +} + +-- ============================================================ +-- Common types +-- ============================================================ + +Id ::= SEQUENCE { + -- Corresponds to the simple tags in gmser_id (account=1, name=2, etc.) + -- and the extended account subtype (high bit in legacy). + type INTEGER (0..255), + value OCTET STRING (SIZE (32)) +} + +-- ============================================================ +-- Concrete object examples (derived from usage in the codebase) +-- Add / evolve per version as you introduce new vsns. +-- ============================================================ + +-- Example: a very simple account-like object used in tests +Account ::= SEQUENCE { + foo INTEGER, + bar OCTET STRING +} + +-- Simplified signed transaction +SignedTx ::= SEQUENCE { + signatures SEQUENCE OF OCTET STRING, + transaction OCTET STRING +} + +-- Contract code objects (see gmser_contract_code.erl) +-- We model the three versions that exist today. +ContractCode ::= CHOICE { + v1 [0] ContractV1, + v2 [1] ContractV2, + v3 [2] ContractV3 +} + +ContractV1 ::= SEQUENCE { + sourceHash OCTET STRING, + -- typeInfo is a list of 4-tuples in legacy: + -- {typeHash, name, argType, outType} + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING +} + +ContractV2 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV1, + byteCode OCTET STRING, + compilerVersion OCTET STRING +} + +ContractV3 ::= SEQUENCE { + sourceHash OCTET STRING, + typeInfo SEQUENCE OF TypeInfoV3, + byteCode OCTET STRING, + compilerVersion OCTET STRING, + payable BOOLEAN +} + +TypeInfoV1 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + argType OCTET STRING, + outType OCTET STRING +} + +TypeInfoV3 ::= SEQUENCE { + typeHash OCTET STRING, + name OCTET STRING, + payable BOOLEAN, + argType OCTET STRING, + outType OCTET STRING +} + +-- ============================================================ +-- Notes for implementers +-- ============================================================ +-- 1. Detection (recommended decoder entry point): +-- +-- decode(Binary) -> +-- case Binary of +-- <> when B >= 16#C0 -> +-- decode_legacy_rlp(Binary); % existing gmser_* path +-- _ -> +-- {ok, Term} = +-- 'GajumaruSerialization':decode('GajumaruData', Binary), +-- Term +-- end. +-- +-- This works because: +-- - All current top-level output from serialize() is an RLP list +-- (first byte 0xC0-0xFF). +-- - GajumaruData and the concrete choices above are SEQUENCEs +-- (first byte 0x30 for short form, or 0x30 0x81/0x82... for long). +-- +-- 2. When you add a new object type or version, prefer adding a +-- concrete SEQUENCE alternative in the Content CHOICE rather than +-- always falling back to TemplateFields. This gives you better +-- validation and generated types. +-- +-- 3. INTEGER in DER is signed and uses a different minimal encoding +-- than the legacy unsigned big-endian no leading zero form. This is +-- fine for new data. +-- +-- 4. If you need to preserve exact legacy integer wire bytes inside +-- the new format (e.g. for some hash preimage reason), you can +-- carry selected integers as OCTET STRING (legacy unsigned minimal bytes). +-- +-- 5. Dynamic encoding (gmser_dyn) is intentionally not modeled here +-- in full, because it is runtime-schema driven (type codes 246-255, +-- labels, alt/switch, etc.). You can still use the generic +-- TemplateFields + Value for some dynamic cases, or model specific +-- message schemas as additional CHOICE arms. +-- +-- 6. Compile with DER for canonical output: +-- asn1ct:compile(GajumaruSerialization, [der]). +-- +-- The ber option is also accepted; der implies the stricter rules. + +END diff --git a/asn1_uper/GajumaruSerialization.asn1db b/asn1_uper/GajumaruSerialization.asn1db new file mode 100644 index 0000000000000000000000000000000000000000..d8f757f7db349698fa682bc715515f476788d179 GIT binary patch literal 15533 zcmeHO+mGW`8F%i>?o{4G+ALO0z=+> zo*4=c&==ZDAQcG;5^PIVE)u2Xzd+&v!QTL{Jn)X-J8^6u$H&Lc&TWNurFOG9$3EZv z{Ju+4=}fkBw7V!tsVBz|b}Fy;Ug)JsT2o(^GGtjdbVJ2o(T$#A*%JMeet*4wPs;t{ z=DY91zB?-JVBI#+K>H3>+Z|)9+t{>7u8Rg1h7GGGM)Z5VGd4}Ech3B!o5a*?%wJpR z7{if?Eeosu1Nk8y8s^!tBrX39UY#?Dj?JSmk;;Tn_#bS__OND>Ebu|8$?9l`$)}K| zueY~Re>_CycpsY@B_G+Eq0>DUu!8PPb_4G-uZOP}=}XkMjgAM{CoXHBjWEer*oH0n zNBC@HSSSUb7e=OG;|_g0DNR3P6&99$Z{1l1=7`R1r9*J zA`6x=Haqw}vU)wmVxe;VI^D;25;(a=g~u;yxNJt}MANgOW@g4d~$}?!te12cswC zHrL9?0+kgd@^Hi9G@jp7AEm?mzDtV7XEv^ap>m1##Fb|FonP4LKFWj-e~+wCH`NB% zJamj$Ohe{eG-UcH8>Zpcq%cBf)D^{NXM<-KHk-{IxzdQ2d$x~qePvx`cY?F96Rd}w;75!T ztY4B7aDvj0uh$9Qex{t@?MruppIn_2cm|mJglmAgLo^uUu!YVI0pBF0W5XCEpn!!g@Y3X0SxQX7 zx5(nLrX%w#0S)Jc6GBnELJFFifCv^(0EUZ%VXs7aLAtKS>n$UeTAP#xnw7+ISO^jc zIR$LAqu6k4J?UkZ74!2dS+K{W0Zt%)fGTX(z{k)6hF-lGhH_$t5GfAPC;>b9BqQ66D06ak*ZpY(fTEsVe3DhYh821i+)%86eB@GGiw6klEc4XZJE>(Kzly z5 z%k<_$|3wk(Uakh<<}*gLn1cq69eA{5?pOAGN{f4~=APVA;_1CI^+53`_h;8pmgL<{ zxmJ^FYkRdrHaIw?JJw5rTVsO6Vlav(O=rWk4VHo%nhFIbt*dpMDjgrzP%TP+LkQzzKF1hi%2qks7 z)u`-P=wGL6&K@ZxO)2LfyZh z>CtD;gb&e)X%=-0PrU6byR2fXV`?L4WcUoPHYbR(<}FPv(L0?LT*81{gtmjBYWj(H z3;+_Q@DZ+;v4^Z$@ZT=CKCR)Z{~HkIP_r1a!ay($T%GfRQDQ zJkx#9;Cs)F2~gi)qk+>H)Cv7M#`~YLAs7Zq=-W=`k$a#gubEb$>yNIc7ADzy3+X4& z#6=SNZxTD>wFga-3q)VOVT-KECF#aKbcvz=N|7HF4uPyS=$yuOEom3eSJa2DqJp_? zSZ6IVv*XItcj)xY=Tcv(UU_NXHX)eIhBQ}tzT&xE+y_b3#KfQI^527qtbSS}o>OV* zf4fR!nz&(&{ekWAa-|ntSV@X8Iqmlko%X}^G~fT2#8yPkl}r_(TNizlun8Ot%X3uD z`Tg&YNdcKBv$3dcB{abq%byb<@y-AD2~F_)=I`H_e|1gJE0>2uFDCxtmEDtF zl7X2ou`dPzbM%GPJ@17jac|WVk^%4|CJ~}@qC55Eyd(yIPykS!Rf9}9tlBS- z;D*alZ#YXrU!080iDef7V&gA0zPi2y>auk4ku#U6i<{$*5f30w8CYYP91CrJ=`je`&+DliO`~Zn6y%f^BS$2e{qtr5{PTmtOq*iyM$~ zWyjF-n9eOiQuG)1(c=Cjp;S)8=JkD;dvq6h0ysZp<0MEwfPob_6xm~_a*E~7T3BQU zIgryZ6vrchcx~`4^>wm1sW8GMDjlKaNzOB!8H=6sA__(gt>`-!p{oiPwm?#tU{# z(7m`i+ILB&Ys3t-v%!c?hDCM7IB|tnE&CqH93!t{9k^Gx@nrt|G7!%*pY!(;SHH;k$DiBKZ_Wh-rp&HWB#U zj-ojLM&juX%pZDCIQMtgSyrp}D|FyVZcTqX!+K44m?ONMry(YUefsGdfnlV}7&&=9 z&;i~76|3h19s2Wu4sW84@sLn}V%Eqd3{Fe~3j>bX0|nO;yX_L_63XG)2RfFZ{ReHX z3mxf5-Ekv(ez#dW*pYiBk{=o>R5;M*BJLCb5S0U^xm!`{Re<6Jd^$2r+aehlQl$UZ z;3t~!?*PuoQ$V*8EU0 uper. + +maps() -> false. + +bit_string_format() -> bitstring. + +legacy_erlang_types() -> false. + +encode(Type, Data) -> +try complete(encode_disp(Type, Data)) of + Bytes -> + {ok,Bytes} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + + +decode(Type, Data) -> +try + {Result,_Rest} = decode_disp(Type, Data), + {ok,Result} + catch + Class:Exception:Stk when Class =:= error; Class =:= exit -> + case Exception of + {error,{asn1,Reason}} -> + {error,{asn1,{Reason,Stk}}}; + Reason -> + {error,{asn1,{Reason,Stk}}} + end +end. + +encode_disp('GajumaruData', Data) -> enc_GajumaruData(Data); +encode_disp('Content', Data) -> enc_Content(Data); +encode_disp('TemplateFields', Data) -> enc_TemplateFields(Data); +encode_disp('TemplateField', Data) -> enc_TemplateField(Data); +encode_disp('Value', Data) -> enc_Value(Data); +encode_disp('KeyValue', Data) -> enc_KeyValue(Data); +encode_disp('Id', Data) -> enc_Id(Data); +encode_disp('Account', Data) -> enc_Account(Data); +encode_disp('SignedTx', Data) -> enc_SignedTx(Data); +encode_disp('ContractCode', Data) -> enc_ContractCode(Data); +encode_disp('ContractV1', Data) -> enc_ContractV1(Data); +encode_disp('ContractV2', Data) -> enc_ContractV2(Data); +encode_disp('ContractV3', Data) -> enc_ContractV3(Data); +encode_disp('TypeInfoV1', Data) -> enc_TypeInfoV1(Data); +encode_disp('TypeInfoV3', Data) -> enc_TypeInfoV3(Data); +encode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +decode_disp('GajumaruData', Data) -> dec_GajumaruData(Data); +decode_disp('Content', Data) -> dec_Content(Data); +decode_disp('TemplateFields', Data) -> dec_TemplateFields(Data); +decode_disp('TemplateField', Data) -> dec_TemplateField(Data); +decode_disp('Value', Data) -> dec_Value(Data); +decode_disp('KeyValue', Data) -> dec_KeyValue(Data); +decode_disp('Id', Data) -> dec_Id(Data); +decode_disp('Account', Data) -> dec_Account(Data); +decode_disp('SignedTx', Data) -> dec_SignedTx(Data); +decode_disp('ContractCode', Data) -> dec_ContractCode(Data); +decode_disp('ContractV1', Data) -> dec_ContractV1(Data); +decode_disp('ContractV2', Data) -> dec_ContractV2(Data); +decode_disp('ContractV3', Data) -> dec_ContractV3(Data); +decode_disp('TypeInfoV1', Data) -> dec_TypeInfoV1(Data); +decode_disp('TypeInfoV3', Data) -> dec_TypeInfoV3(Data); +decode_disp(Type, _Data) -> exit({error,{asn1,{undefined_type,Type}}}). + +info() -> + case ?MODULE:module_info(attributes) of + Attributes when is_list(Attributes) -> + case lists:keyfind(asn1_info, 1, Attributes) of + {_,Info} when is_list(Info) -> + Info; + _ -> + [] + end; + _ -> + [] + end. +enc_GajumaruData(Val) -> +[begin +%% attribute tag(1) with type INTEGER +Enc1@element = element(2, Val), +encode_unconstrained_number(Enc1@element) +end, +begin +%% attribute vsn(2) with type INTEGER +Enc3@element = element(3, Val), +encode_unconstrained_number(Enc3@element) +end|begin +%% attribute content(3) with type Content +Enc5@element = element(4, Val), +enc_Content(Enc5@element) +end]. + + +dec_GajumaruData(Bytes) -> + +%% attribute tag(1) with type INTEGER +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@Buf4/bitstring>> when V1@V3 =/= 0 -> +{V1@V3,V1@Buf4}; +<<1:1,0:1,V1@V4:14,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +{V1@V4,V1@Buf5}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +V1@Mul6 = V1@V4 * 16384, +{V1@Mul6,V1@Buf5} +end, +<> = V1@Buf1, +{V1@V7,V1@Buf8} +end, + +%% attribute vsn(2) with type INTEGER +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@Buf4/bitstring>> when V2@V3 =/= 0 -> +{V2@V3,V2@Buf4}; +<<1:1,0:1,V2@V4:14,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +{V2@V4,V2@Buf5}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +V2@Mul6 = V2@V4 * 16384, +{V2@Mul6,V2@Buf5} +end, +<> = V2@Buf1, +{V2@V7,V2@Buf8} +end, + +%% attribute content(3) with type Content +{Term3,Bytes3} = dec_Content(Bytes2), +Res1 = {'GajumaruData',Term1,Term2,Term3}, +{Res1,Bytes3}. + +enc_Content(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= templateFields -> +[<<0:2>>|enc_TemplateFields(ChoiceVal)]; +ChoiceTag =:= account -> +[<<1:2>>|enc_Account(ChoiceVal)]; +ChoiceTag =:= signedTx -> +[<<2:2>>|enc_SignedTx(ChoiceVal)]; +ChoiceTag =:= contract -> +[<<3:2>>|enc_ContractCode(ChoiceVal)] +end. + + +dec_Content(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +dec_TemplateFields(Bytes1) +end, +{{templateFields,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +dec_Account(Bytes1) +end, +{{account,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +dec_SignedTx(Bytes1) +end, +{{signedTx,Val},NewBytes}; +3 -> +{Val,NewBytes} = begin +dec_ContractCode(Bytes1) +end, +{{contract,Val},NewBytes} +end. +enc_TemplateFields(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TemplateField(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TemplateField(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TemplateField(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_TemplateFields(Bytes) -> +dec_components1(Bytes, []). + +enc_TemplateField(Val) -> +[begin +Enc1@element = element(2, Val), +if Enc1@element =:= asn1_NOVALUE -> +<<0:1>>; +true -> +<<1:1>> +end +end, +begin +%% attribute name(1) with type IA5String +Enc2@element = element(2, Val), +if Enc2@element =:= asn1_NOVALUE -> +[]; +true -> +begin +Enc3@len = length(Enc2@element), +Enc3@bin = encode_chars(Enc2@element, 7), +if Enc3@len < 128 -> +[Enc3@len|Enc3@bin]; +Enc3@len < 16384 -> +[<<2:2,Enc3@len:14>>|Enc3@bin]; +true -> +encode_fragmented(Enc3@bin, 7) +end +end +end +end|begin +%% attribute value(2) with type Value +Enc5@element = element(3, Val), +enc_Value(Enc5@element) +end]. + + +dec_TemplateField(Bytes) -> +{Opt,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute name(1) with type IA5String +{Term1,Bytes2} = case Opt band 1 of +1 -> +begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:7,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:7,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 7), +{V2@V6,V2@Buf7} +end, +{V2@V8,V2@Buf9} = {decode_chars(V2@V0, 7),V2@Buf1}, +{V2@V8,V2@Buf9} +end; +0 -> +{asn1_NOVALUE,Bytes1} +end, + +%% attribute value(2) with type Value +{Term2,Bytes3} = dec_Value(Bytes2), +Res1 = {'TemplateField',Term1,Term2}, +{Res1,Bytes3}. + +enc_Value(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= intValue -> +[<<0:3>>|encode_unconstrained_number(ChoiceVal)]; +ChoiceTag =:= boolValue -> +if ChoiceVal =:= false -> +<<1:3,0:1>>; +ChoiceVal =:= true -> +<<1:3,1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,ChoiceVal}}}) +end; +ChoiceTag =:= binaryValue -> +[<<2:3>>|begin +Enc6@len = byte_size(ChoiceVal), +if Enc6@len < 128 -> +[Enc6@len|ChoiceVal]; +Enc6@len < 16384 -> +[<<2:2,Enc6@len:14>>|ChoiceVal]; +true -> +encode_fragmented(ChoiceVal, 8) +end +end]; +ChoiceTag =:= idValue -> +[<<3:3>>|enc_Id(ChoiceVal)]; +ChoiceTag =:= listValue -> +[<<4:3>>|enc_Value_listValue(ChoiceVal)]; +ChoiceTag =:= tupleValue -> +[<<5:3>>|enc_Value_tupleValue(ChoiceVal)]; +ChoiceTag =:= mapValue -> +[<<6:3>>|enc_Value_mapValue(ChoiceVal)] +end. +enc_Value_listValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + +enc_Value_tupleValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_Value(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_Value(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_Value(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + +enc_Value_mapValue(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_KeyValue(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_KeyValue(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_KeyValue(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_Value(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@Buf4/bitstring>> when V2@V3 =/= 0 -> +{V2@V3,V2@Buf4}; +<<1:1,0:1,V2@V4:14,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +{V2@V4,V2@Buf5}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> when V2@V4 =/= 0 -> +V2@Mul6 = V2@V4 * 16384, +{V2@Mul6,V2@Buf5} +end, +<> = V2@Buf1, +{V2@V7,V2@Buf8} +end +end, +{{intValue,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +begin +<> = Bytes1, +V3@Int2 = case V3@V0 of +0 -> false; +1 -> true +end, +{V3@Int2,V3@Buf1} +end +end, +{{boolValue,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +begin +{V4@V0,V4@Buf1} = case Bytes1 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end +end, +{{binaryValue,Val},NewBytes}; +3 -> +{Val,NewBytes} = begin +dec_Id(Bytes1) +end, +{{idValue,Val},NewBytes}; +4 -> +{Val,NewBytes} = begin +dec_Value_listValue(Bytes1) +end, +{{listValue,Val},NewBytes}; +5 -> +{Val,NewBytes} = begin +dec_Value_tupleValue(Bytes1) +end, +{{tupleValue,Val},NewBytes}; +6 -> +{Val,NewBytes} = begin +dec_Value_mapValue(Bytes1) +end, +{{mapValue,Val},NewBytes} +end. + +dec_Value_listValue(Bytes) -> +dec_components2(Bytes, []). + + +dec_Value_tupleValue(Bytes) -> +dec_components3(Bytes, []). + + +dec_Value_mapValue(Bytes) -> +dec_components4(Bytes, []). + +enc_KeyValue(Val) -> +[begin +%% attribute key(1) with type Value +Enc1@element = element(2, Val), +enc_Value(Enc1@element) +end|begin +%% attribute val(2) with type Value +Enc2@element = element(3, Val), +enc_Value(Enc2@element) +end]. + + +dec_KeyValue(Bytes) -> + +%% attribute key(1) with type Value +{Term1,Bytes1} = dec_Value(Bytes), + +%% attribute val(2) with type Value +{Term2,Bytes2} = dec_Value(Bytes1), +Res1 = {'KeyValue',Term1,Term2}, +{Res1,Bytes2}. + +enc_Id(Val) -> +[begin +%% attribute type(1) with type INTEGER +Enc1@element = element(2, Val), +if Enc1@element bsr 8 =:= 0 -> +Enc1@element; +true -> +exit({error,{asn1,{illegal_integer,Enc1@element}}}) +end +end|begin +%% attribute value(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len =:= 32 -> +Enc3@element +end +end]. + + +dec_Id(Bytes) -> + +%% attribute type(1) with type INTEGER +{Term1,Bytes1} = begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, + +%% attribute value(2) with type OCTET STRING +{Term2,Bytes2} = begin +<> = Bytes1, +V2@Conv2 = binary:copy(V2@V0), +{V2@Conv2,V2@Buf1} +end, +Res1 = {'Id',Term1,Term2}, +{Res1,Bytes2}. + +enc_Account(Val) -> +[begin +%% attribute foo(1) with type INTEGER +Enc1@element = element(2, Val), +encode_unconstrained_number(Enc1@element) +end|begin +%% attribute bar(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end]. + + +dec_Account(Bytes) -> + +%% attribute foo(1) with type INTEGER +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@Buf4/bitstring>> when V1@V3 =/= 0 -> +{V1@V3,V1@Buf4}; +<<1:1,0:1,V1@V4:14,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +{V1@V4,V1@Buf5}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> when V1@V4 =/= 0 -> +V1@Mul6 = V1@V4 * 16384, +{V1@Mul6,V1@Buf5} +end, +<> = V1@Buf1, +{V1@V7,V1@Buf8} +end, + +%% attribute bar(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, +Res1 = {'Account',Term1,Term2}, +{Res1,Bytes2}. + +enc_SignedTx(Val) -> +[begin +%% attribute signatures(1) with type SEQUENCE OF +Enc1@element = element(2, Val), +enc_SignedTx_signatures(Enc1@element) +end|begin +%% attribute transaction(2) with type OCTET STRING +Enc2@element = element(3, Val), +Enc3@len = byte_size(Enc2@element), +if Enc3@len < 128 -> +[Enc3@len|Enc2@element]; +Enc3@len < 16384 -> +[<<2:2,Enc3@len:14>>|Enc2@element]; +true -> +encode_fragmented(Enc2@element, 8) +end +end]. +enc_SignedTx_signatures(Val) -> +Enc2@len = length(Val), +if Enc2@len < 128 -> +[Enc2@len|[begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end || Comp <- Val]]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|[begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end || Comp <- Val]]; +true -> +begin +Enc2@fn = fun(Comp) -> begin +Enc1@len = byte_size(Comp), +if Enc1@len < 128 -> +[Enc1@len|Comp]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|Comp]; +true -> +encode_fragmented(Comp, 8) +end +end end, +encode_fragmented_sof(Enc2@fn, Val, Enc2@len) +end +end. + + + +dec_SignedTx(Bytes) -> + +%% attribute signatures(1) with type SEQUENCE OF +{Term1,Bytes1} = dec_SignedTx_signatures(Bytes), + +%% attribute transaction(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V1@V0,V1@Buf1} = case Bytes1 of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, +Res1 = {'SignedTx',Term1,Term2}, +{Res1,Bytes2}. + + +dec_SignedTx_signatures(Bytes) -> +dec_components5(Bytes, []). + +enc_ContractCode(Val) -> +{ChoiceTag,ChoiceVal} = Val, +if ChoiceTag =:= v1 -> +[<<0:2>>|enc_ContractV1(ChoiceVal)]; +ChoiceTag =:= v2 -> +[<<1:2>>|enc_ContractV2(ChoiceVal)]; +ChoiceTag =:= v3 -> +[<<2:2>>|enc_ContractV3(ChoiceVal)] +end. + + +dec_ContractCode(Bytes) -> +{Choice,Bytes1} = +begin +<> = Bytes, +{V1@V0,V1@Buf1} +end, +case Choice of +0 -> +{Val,NewBytes} = begin +dec_ContractV1(Bytes1) +end, +{{v1,Val},NewBytes}; +1 -> +{Val,NewBytes} = begin +dec_ContractV2(Bytes1) +end, +{{v2,Val},NewBytes}; +2 -> +{Val,NewBytes} = begin +dec_ContractV3(Bytes1) +end, +{{v3,Val},NewBytes} +end. +enc_ContractV1(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV1_typeInfo(Enc3@element) +end|begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end]. +enc_ContractV1_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV1(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV1(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV1_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, +Res1 = {'ContractV1',Term1,Term2,Term3}, +{Res1,Bytes3}. + + +dec_ContractV1_typeInfo(Bytes) -> +dec_components6(Bytes, []). + +enc_ContractV2(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV2_typeInfo(Enc3@element) +end, +begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end|begin +%% attribute compilerVersion(4) with type OCTET STRING +Enc6@element = element(5, Val), +Enc7@len = byte_size(Enc6@element), +if Enc7@len < 128 -> +[Enc7@len|Enc6@element]; +Enc7@len < 16384 -> +[<<2:2,Enc7@len:14>>|Enc6@element]; +true -> +encode_fragmented(Enc6@element, 8) +end +end]. +enc_ContractV2_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV1(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV1(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV2(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV2_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute compilerVersion(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V3@V0,V3@Buf1} = case Bytes3 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, +Res1 = {'ContractV2',Term1,Term2,Term3,Term4}, +{Res1,Bytes4}. + + +dec_ContractV2_typeInfo(Bytes) -> +dec_components7(Bytes, []). + +enc_ContractV3(Val) -> +[begin +%% attribute sourceHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute typeInfo(2) with type SEQUENCE OF +Enc3@element = element(3, Val), +enc_ContractV3_typeInfo(Enc3@element) +end, +begin +%% attribute byteCode(3) with type OCTET STRING +Enc4@element = element(4, Val), +Enc5@len = byte_size(Enc4@element), +if Enc5@len < 128 -> +[Enc5@len|Enc4@element]; +Enc5@len < 16384 -> +[<<2:2,Enc5@len:14>>|Enc4@element]; +true -> +encode_fragmented(Enc4@element, 8) +end +end, +begin +%% attribute compilerVersion(4) with type OCTET STRING +Enc6@element = element(5, Val), +Enc7@len = byte_size(Enc6@element), +if Enc7@len < 128 -> +[Enc7@len|Enc6@element]; +Enc7@len < 16384 -> +[<<2:2,Enc7@len:14>>|Enc6@element]; +true -> +encode_fragmented(Enc6@element, 8) +end +end|begin +%% attribute payable(5) with type BOOLEAN +Enc8@element = element(6, Val), +if Enc8@element =:= false -> +<<0:1>>; +Enc8@element =:= true -> +<<1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,Enc8@element}}}) +end +end]. +enc_ContractV3_typeInfo(Val) -> +Enc1@len = length(Val), +if Enc1@len < 128 -> +[Enc1@len|[enc_TypeInfoV3(Comp) || Comp <- Val]]; +Enc1@len < 16384 -> +[<<2:2,Enc1@len:14>>|[enc_TypeInfoV3(Comp) || Comp <- Val]]; +true -> +begin +Enc1@fn = fun(Comp) -> enc_TypeInfoV3(Comp) end, +encode_fragmented_sof(Enc1@fn, Val, Enc1@len) +end +end. + + + +dec_ContractV3(Bytes) -> + +%% attribute sourceHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute typeInfo(2) with type SEQUENCE OF +{Term2,Bytes2} = dec_ContractV3_typeInfo(Bytes1), + +%% attribute byteCode(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V2@V0,V2@Buf1} = case Bytes2 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute compilerVersion(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V3@V0,V3@Buf1} = case Bytes3 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, + +%% attribute payable(5) with type BOOLEAN +{Term5,Bytes5} = begin +<> = Bytes4, +V4@Int2 = case V4@V0 of +0 -> false; +1 -> true +end, +{V4@Int2,V4@Buf1} +end, +Res1 = {'ContractV3',Term1,Term2,Term3,Term4,Term5}, +{Res1,Bytes5}. + + +dec_ContractV3_typeInfo(Bytes) -> +dec_components8(Bytes, []). + +enc_TypeInfoV1(Val) -> +[begin +%% attribute typeHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute name(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end, +begin +%% attribute argType(3) with type OCTET STRING +Enc5@element = element(4, Val), +Enc6@len = byte_size(Enc5@element), +if Enc6@len < 128 -> +[Enc6@len|Enc5@element]; +Enc6@len < 16384 -> +[<<2:2,Enc6@len:14>>|Enc5@element]; +true -> +encode_fragmented(Enc5@element, 8) +end +end|begin +%% attribute outType(4) with type OCTET STRING +Enc7@element = element(5, Val), +Enc8@len = byte_size(Enc7@element), +if Enc8@len < 128 -> +[Enc8@len|Enc7@element]; +Enc8@len < 16384 -> +[<<2:2,Enc8@len:14>>|Enc7@element]; +true -> +encode_fragmented(Enc7@element, 8) +end +end]. + + +dec_TypeInfoV1(Bytes) -> + +%% attribute typeHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute name(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute argType(3) with type OCTET STRING +{Term3,Bytes3} = begin +{V3@V0,V3@Buf1} = case Bytes2 of +<<0:1,V3@V3:7,V3@V5:V3@V3/binary-unit:8,V3@Buf6/bitstring>> -> +{V3@V5,V3@Buf6}; +<<1:1,0:1,V3@V4:14,V3@V6:V3@V4/binary-unit:8,V3@Buf7/bitstring>> -> +{V3@V6,V3@Buf7}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +{V3@V6,V3@Buf7} = decode_fragmented(V3@V4, V3@Buf5, 8), +{V3@V6,V3@Buf7} +end, +V3@Conv8 = binary:copy(V3@V0), +{V3@Conv8,V3@Buf1} +end, + +%% attribute outType(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V4@V0,V4@Buf1} = case Bytes3 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end, +Res1 = {'TypeInfoV1',Term1,Term2,Term3,Term4}, +{Res1,Bytes4}. + +enc_TypeInfoV3(Val) -> +[begin +%% attribute typeHash(1) with type OCTET STRING +Enc1@element = element(2, Val), +Enc2@len = byte_size(Enc1@element), +if Enc2@len < 128 -> +[Enc2@len|Enc1@element]; +Enc2@len < 16384 -> +[<<2:2,Enc2@len:14>>|Enc1@element]; +true -> +encode_fragmented(Enc1@element, 8) +end +end, +begin +%% attribute name(2) with type OCTET STRING +Enc3@element = element(3, Val), +Enc4@len = byte_size(Enc3@element), +if Enc4@len < 128 -> +[Enc4@len|Enc3@element]; +Enc4@len < 16384 -> +[<<2:2,Enc4@len:14>>|Enc3@element]; +true -> +encode_fragmented(Enc3@element, 8) +end +end, +begin +%% attribute payable(3) with type BOOLEAN +Enc5@element = element(4, Val), +if Enc5@element =:= false -> +<<0:1>>; +Enc5@element =:= true -> +<<1:1>>; +true -> +exit({error,{asn1,{illegal_boolean,Enc5@element}}}) +end +end, +begin +%% attribute argType(4) with type OCTET STRING +Enc7@element = element(5, Val), +Enc8@len = byte_size(Enc7@element), +if Enc8@len < 128 -> +[Enc8@len|Enc7@element]; +Enc8@len < 16384 -> +[<<2:2,Enc8@len:14>>|Enc7@element]; +true -> +encode_fragmented(Enc7@element, 8) +end +end|begin +%% attribute outType(5) with type OCTET STRING +Enc9@element = element(6, Val), +Enc10@len = byte_size(Enc9@element), +if Enc10@len < 128 -> +[Enc10@len|Enc9@element]; +Enc10@len < 16384 -> +[<<2:2,Enc10@len:14>>|Enc9@element]; +true -> +encode_fragmented(Enc9@element, 8) +end +end]. + + +dec_TypeInfoV3(Bytes) -> + +%% attribute typeHash(1) with type OCTET STRING +{Term1,Bytes1} = begin +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@V5:V1@V3/binary-unit:8,V1@Buf6/bitstring>> -> +{V1@V5,V1@Buf6}; +<<1:1,0:1,V1@V4:14,V1@V6:V1@V4/binary-unit:8,V1@Buf7/bitstring>> -> +{V1@V6,V1@Buf7}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +{V1@V6,V1@Buf7} = decode_fragmented(V1@V4, V1@Buf5, 8), +{V1@V6,V1@Buf7} +end, +V1@Conv8 = binary:copy(V1@V0), +{V1@Conv8,V1@Buf1} +end, + +%% attribute name(2) with type OCTET STRING +{Term2,Bytes2} = begin +{V2@V0,V2@Buf1} = case Bytes1 of +<<0:1,V2@V3:7,V2@V5:V2@V3/binary-unit:8,V2@Buf6/bitstring>> -> +{V2@V5,V2@Buf6}; +<<1:1,0:1,V2@V4:14,V2@V6:V2@V4/binary-unit:8,V2@Buf7/bitstring>> -> +{V2@V6,V2@Buf7}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +{V2@V6,V2@Buf7} = decode_fragmented(V2@V4, V2@Buf5, 8), +{V2@V6,V2@Buf7} +end, +V2@Conv8 = binary:copy(V2@V0), +{V2@Conv8,V2@Buf1} +end, + +%% attribute payable(3) with type BOOLEAN +{Term3,Bytes3} = begin +<> = Bytes2, +V3@Int2 = case V3@V0 of +0 -> false; +1 -> true +end, +{V3@Int2,V3@Buf1} +end, + +%% attribute argType(4) with type OCTET STRING +{Term4,Bytes4} = begin +{V4@V0,V4@Buf1} = case Bytes3 of +<<0:1,V4@V3:7,V4@V5:V4@V3/binary-unit:8,V4@Buf6/bitstring>> -> +{V4@V5,V4@Buf6}; +<<1:1,0:1,V4@V4:14,V4@V6:V4@V4/binary-unit:8,V4@Buf7/bitstring>> -> +{V4@V6,V4@Buf7}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +{V4@V6,V4@Buf7} = decode_fragmented(V4@V4, V4@Buf5, 8), +{V4@V6,V4@Buf7} +end, +V4@Conv8 = binary:copy(V4@V0), +{V4@Conv8,V4@Buf1} +end, + +%% attribute outType(5) with type OCTET STRING +{Term5,Bytes5} = begin +{V5@V0,V5@Buf1} = case Bytes4 of +<<0:1,V5@V3:7,V5@V5:V5@V3/binary-unit:8,V5@Buf6/bitstring>> -> +{V5@V5,V5@Buf6}; +<<1:1,0:1,V5@V4:14,V5@V6:V5@V4/binary-unit:8,V5@Buf7/bitstring>> -> +{V5@V6,V5@Buf7}; +<<1:1,1:1,V5@V4:6,V5@Buf5/bitstring>> -> +{V5@V6,V5@Buf7} = decode_fragmented(V5@V4, V5@Buf5, 8), +{V5@V6,V5@Buf7} +end, +V5@Conv8 = binary:copy(V5@V0), +{V5@Conv8,V5@Buf1} +end, +Res1 = {'TypeInfoV3',Term1,Term2,Term3,Term4,Term5}, +{Res1,Bytes5}. + + +%%% +%%% Run-time functions. +%%% + +'dialyzer-suppressions'(Arg) -> + _ = complete(element(1, Arg)), + ok. + +dec_components1(Bytes, Acc) -> +%% Length with constraint no +{V1@V0,V1@Buf1} = case Bytes of +<<0:1,V1@V3:7,V1@Buf4/bitstring>> -> +{V1@V3,V1@Buf4}; +<<1:1,0:1,V1@V4:14,V1@Buf5/bitstring>> -> +{V1@V4,V1@Buf5}; +<<1:1,1:1,V1@V4:6,V1@Buf5/bitstring>> -> +V1@Mul6 = V1@V4 * 16384, +{V1@Mul6,V1@Buf5} +end, +{Acc1,Buf1} = dec_fragment9(V1@V0, V1@Buf1, Acc), +if V1@V0 >= 16384 -> +dec_components1(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components2(Bytes, Acc) -> +%% Length with constraint no +{V2@V0,V2@Buf1} = case Bytes of +<<0:1,V2@V3:7,V2@Buf4/bitstring>> -> +{V2@V3,V2@Buf4}; +<<1:1,0:1,V2@V4:14,V2@Buf5/bitstring>> -> +{V2@V4,V2@Buf5}; +<<1:1,1:1,V2@V4:6,V2@Buf5/bitstring>> -> +V2@Mul6 = V2@V4 * 16384, +{V2@Mul6,V2@Buf5} +end, +{Acc1,Buf1} = dec_fragment10(V2@V0, V2@Buf1, Acc), +if V2@V0 >= 16384 -> +dec_components2(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components3(Bytes, Acc) -> +%% Length with constraint no +{V3@V0,V3@Buf1} = case Bytes of +<<0:1,V3@V3:7,V3@Buf4/bitstring>> -> +{V3@V3,V3@Buf4}; +<<1:1,0:1,V3@V4:14,V3@Buf5/bitstring>> -> +{V3@V4,V3@Buf5}; +<<1:1,1:1,V3@V4:6,V3@Buf5/bitstring>> -> +V3@Mul6 = V3@V4 * 16384, +{V3@Mul6,V3@Buf5} +end, +{Acc1,Buf1} = dec_fragment11(V3@V0, V3@Buf1, Acc), +if V3@V0 >= 16384 -> +dec_components3(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components4(Bytes, Acc) -> +%% Length with constraint no +{V4@V0,V4@Buf1} = case Bytes of +<<0:1,V4@V3:7,V4@Buf4/bitstring>> -> +{V4@V3,V4@Buf4}; +<<1:1,0:1,V4@V4:14,V4@Buf5/bitstring>> -> +{V4@V4,V4@Buf5}; +<<1:1,1:1,V4@V4:6,V4@Buf5/bitstring>> -> +V4@Mul6 = V4@V4 * 16384, +{V4@Mul6,V4@Buf5} +end, +{Acc1,Buf1} = dec_fragment12(V4@V0, V4@Buf1, Acc), +if V4@V0 >= 16384 -> +dec_components4(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components5(Bytes, Acc) -> +%% Length with constraint no +{V5@V0,V5@Buf1} = case Bytes of +<<0:1,V5@V3:7,V5@Buf4/bitstring>> -> +{V5@V3,V5@Buf4}; +<<1:1,0:1,V5@V4:14,V5@Buf5/bitstring>> -> +{V5@V4,V5@Buf5}; +<<1:1,1:1,V5@V4:6,V5@Buf5/bitstring>> -> +V5@Mul6 = V5@V4 * 16384, +{V5@Mul6,V5@Buf5} +end, +{Acc1,Buf1} = dec_fragment13(V5@V0, V5@Buf1, Acc), +if V5@V0 >= 16384 -> +dec_components5(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components6(Bytes, Acc) -> +%% Length with constraint no +{V6@V0,V6@Buf1} = case Bytes of +<<0:1,V6@V3:7,V6@Buf4/bitstring>> -> +{V6@V3,V6@Buf4}; +<<1:1,0:1,V6@V4:14,V6@Buf5/bitstring>> -> +{V6@V4,V6@Buf5}; +<<1:1,1:1,V6@V4:6,V6@Buf5/bitstring>> -> +V6@Mul6 = V6@V4 * 16384, +{V6@Mul6,V6@Buf5} +end, +{Acc1,Buf1} = dec_fragment14(V6@V0, V6@Buf1, Acc), +if V6@V0 >= 16384 -> +dec_components6(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components7(Bytes, Acc) -> +%% Length with constraint no +{V7@V0,V7@Buf1} = case Bytes of +<<0:1,V7@V3:7,V7@Buf4/bitstring>> -> +{V7@V3,V7@Buf4}; +<<1:1,0:1,V7@V4:14,V7@Buf5/bitstring>> -> +{V7@V4,V7@Buf5}; +<<1:1,1:1,V7@V4:6,V7@Buf5/bitstring>> -> +V7@Mul6 = V7@V4 * 16384, +{V7@Mul6,V7@Buf5} +end, +{Acc1,Buf1} = dec_fragment15(V7@V0, V7@Buf1, Acc), +if V7@V0 >= 16384 -> +dec_components7(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_components8(Bytes, Acc) -> +%% Length with constraint no +{V8@V0,V8@Buf1} = case Bytes of +<<0:1,V8@V3:7,V8@Buf4/bitstring>> -> +{V8@V3,V8@Buf4}; +<<1:1,0:1,V8@V4:14,V8@Buf5/bitstring>> -> +{V8@V4,V8@Buf5}; +<<1:1,1:1,V8@V4:6,V8@Buf5/bitstring>> -> +V8@Mul6 = V8@V4 * 16384, +{V8@Mul6,V8@Buf5} +end, +{Acc1,Buf1} = dec_fragment16(V8@V0, V8@Buf1, Acc), +if V8@V0 >= 16384 -> +dec_components8(Buf1, Acc1); +true -> +{lists:reverse(Acc1),Buf1} +end. + +dec_fragment10(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment10(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment10(Num-1, Remain, [Term|Acc]). + +dec_fragment11(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment11(Num, Bytes, Acc) -> +{Term,Remain} = dec_Value(Bytes), +dec_fragment11(Num-1, Remain, [Term|Acc]). + +dec_fragment12(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment12(Num, Bytes, Acc) -> +{Term,Remain} = dec_KeyValue(Bytes), +dec_fragment12(Num-1, Remain, [Term|Acc]). + +dec_fragment13(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment13(Num, Bytes, Acc) -> +{Term,Remain} = begin +{V9@V0,V9@Buf1} = case Bytes of +<<0:1,V9@V3:7,V9@V5:V9@V3/binary-unit:8,V9@Buf6/bitstring>> -> +{V9@V5,V9@Buf6}; +<<1:1,0:1,V9@V4:14,V9@V6:V9@V4/binary-unit:8,V9@Buf7/bitstring>> -> +{V9@V6,V9@Buf7}; +<<1:1,1:1,V9@V4:6,V9@Buf5/bitstring>> -> +{V9@V6,V9@Buf7} = decode_fragmented(V9@V4, V9@Buf5, 8), +{V9@V6,V9@Buf7} +end, +V9@Conv8 = binary:copy(V9@V0), +{V9@Conv8,V9@Buf1} +end, +dec_fragment13(Num-1, Remain, [Term|Acc]). + +dec_fragment14(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment14(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV1(Bytes), +dec_fragment14(Num-1, Remain, [Term|Acc]). + +dec_fragment15(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment15(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV1(Bytes), +dec_fragment15(Num-1, Remain, [Term|Acc]). + +dec_fragment16(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment16(Num, Bytes, Acc) -> +{Term,Remain} = dec_TypeInfoV3(Bytes), +dec_fragment16(Num-1, Remain, [Term|Acc]). + +dec_fragment9(0, Bytes, Acc) -> +{Acc,Bytes}; +dec_fragment9(Num, Bytes, Acc) -> +{Term,Remain} = dec_TemplateField(Bytes), +dec_fragment9(Num-1, Remain, [Term|Acc]). + +complete(InList) when is_list(InList) -> + case list_to_bitstring(InList) of + <<>> -> + <<0>>; + Res -> + Sz = bit_size(Res), + case Sz band 7 of + 0 -> + Res; + Bits -> + <> + end + end; +complete(Bin) when is_binary(Bin) -> + case Bin of + <<>> -> + <<0>>; + _ -> + Bin + end; +complete(InList) when is_bitstring(InList) -> + Sz = bit_size(InList), + PadLen = 8 - Sz band 7, + <>. + +decode_chars(Val, N) -> + [ + C || + <> <= Val + ]. + +decode_fragmented(SegSz0, Buf0, Unit) -> + SegSz = SegSz0 * Unit * 16384, + <> = Buf0, + decode_fragmented_1(Buf, Unit, Res). + +decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) -> + Sz = N * Unit, + <> = Buf0, + {<>, Buf}; +decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) -> + Sz = N * Unit, + <> = Buf0, + {<>, Buf}; +decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) -> + SegSz = SegSz0 * Unit * 16384, + <> = Buf0, + Res = <>, + decode_fragmented_1(Buf, Unit, Res). + +encode_chars(Val, NumBits) -> + << + <> || + C <- Val + >>. + +encode_components(Cs, _Encoder, 0, Acc) -> + {Cs, lists:reverse(Acc)}; +encode_components([C | Cs], Encoder, Size, Acc) -> + B = Encoder(C), + encode_components(Cs, Encoder, Size - 1, [B | Acc]). + +encode_fragmented(Bin, Unit) -> + encode_fragmented_1(Bin, Unit, 4). + +encode_fragmented_1(Bin, Unit, N) -> + SegSz = Unit * N * 16384, + case Bin of + <> -> + [<<3:2,N:6>>, B | encode_fragmented_1(T, Unit, N)]; + _ when N > 1 -> + encode_fragmented_1(Bin, Unit, N - 1); + _ -> + case bit_size(Bin) div Unit of + Len when Len < 128 -> + [Len, Bin]; + Len when Len < 16384 -> + [<<2:2,Len:14>>, Bin] + end + end. + +encode_fragmented_sof(Fun, Comps, Len) -> + encode_fragmented_sof_1(Fun, Comps, Len, 4). + +encode_fragmented_sof_1(Encoder, Comps0, Len0, N) -> + SegSz = N * 16384, + if + Len0 >= SegSz -> + {Comps, B} = encode_components(Comps0, Encoder, SegSz, []), + Len = Len0 - SegSz, + [<<3:2,N:6>>, + B | + encode_fragmented_sof_1(Encoder, Comps, Len, N)]; + N > 1 -> + encode_fragmented_sof_1(Encoder, Comps0, Len0, N - 1); + Len0 < 128 -> + {[], B} = encode_components(Comps0, Encoder, Len0, []), + [Len0 | B]; + Len0 < 16384 -> + {[], B} = encode_components(Comps0, Encoder, Len0, []), + [<<2:2,Len0:14>> | B] + end. + +encode_unconstrained_number(Val) when not is_integer(Val) -> + exit({error, {asn1, {illegal_integer, Val}}}); +encode_unconstrained_number(Val) when Val >= 0 -> + if + Val < 128 -> + [1, Val]; + Val < 256 -> + [<<2,0>>, Val]; + true -> + case binary:encode_unsigned(Val) of + <<0:1,_/bitstring>> = Bin -> + case byte_size(Bin) of + Sz when Sz < 128 -> + [Sz, Bin]; + Sz when Sz < 16384 -> + [<<2:2,Sz:14>>, Bin] + end; + <<1:1,_/bitstring>> = Bin -> + case byte_size(Bin) + 1 of + Sz when Sz < 128 -> + [Sz, 0, Bin]; + Sz when Sz < 16384 -> + [<<2:2,Sz:14,0:8>>, Bin] + end + end + end; +encode_unconstrained_number(Val) -> + Oct = enint(Val, []), + Len = length(Oct), + if + Len < 128 -> + [Len | Oct]; + Len < 16384 -> + [<<2:2,Len:14>> | Oct] + end. + +enint(-1, [B1 | T]) when B1 > 127 -> + [B1 | T]; +enint(N, Acc) -> + enint(N bsr 8, [N band 255 | Acc]). diff --git a/asn1_uper/GajumaruSerialization.hrl b/asn1_uper/GajumaruSerialization.hrl new file mode 100644 index 0000000..4c5d52e --- /dev/null +++ b/asn1_uper/GajumaruSerialization.hrl @@ -0,0 +1,76 @@ +%% Generated by the Erlang ASN.1 compiler. Version: 5.4.3 +%% Purpose: Erlang record definitions for each named and unnamed +%% SEQUENCE and SET, and macro definitions for each value +%% definition in module GajumaruSerialization. + +-ifndef(_GAJUMARUSERIALIZATION_HRL_). +-define(_GAJUMARUSERIALIZATION_HRL_, true). + +-record('GajumaruData', { + tag, + vsn, + content +}). + +-record('TemplateField', { + name = asn1_NOVALUE, + value +}). + +-record('KeyValue', { + key, + val +}). + +-record('Id', { + type, + value +}). + +-record('Account', { + foo, + bar +}). + +-record('SignedTx', { + signatures, + transaction +}). + +-record('ContractV1', { + sourceHash, + typeInfo, + byteCode +}). + +-record('ContractV2', { + sourceHash, + typeInfo, + byteCode, + compilerVersion +}). + +-record('ContractV3', { + sourceHash, + typeInfo, + byteCode, + compilerVersion, + payable +}). + +-record('TypeInfoV1', { + typeHash, + name, + argType, + outType +}). + +-record('TypeInfoV3', { + typeHash, + name, + payable, + argType, + outType +}). + +-endif. %% _GAJUMARUSERIALIZATION_HRL_ diff --git a/doc/asn1_compact.md b/doc/asn1_compact.md new file mode 100644 index 0000000..e55d5ac --- /dev/null +++ b/doc/asn1_compact.md @@ -0,0 +1,70 @@ +# ASN.1 for Static Serialization - Compact Wire Format + +## Goal +Use portable ASN.1 techniques to produce the most compact *deterministic* (stable/idempotent for hashing) wire format for gmserialization **static** encoding, based on existing templates. + +Focus is on the wire format itself (not RLP translation for legacy, which is deferred). + +## Approach +- The `asn1/GajumaruSerialization.asn` is the single source of truth (abstract syntax). +- Use **Unaligned PER (UPER)** as the standard compact canonical encoding rule provided by the ASN.1 framework. + - Portable across languages/tools that support ASN.1 UPER. + - Deterministic for a fixed schema (no extensibility, consistent packing). +- Optimize the schema for packing: + - Constrain INTEGER ranges. + - Provide `staticFields` (SEQUENCE OF Value) -- no field names (names are never on the wire for static case). + - Provide `CompactStatic` top-level type to avoid unnecessary CHOICE overhead for the common static path. + - Concrete SEQUENCEs for well-known objects (SignedTx, ContractV* etc.) when possible. +- Encode with the generated ASN.1 module: ` 'GajumaruSerialization':encode('CompactStatic', Value) `. + +## Results (example sizes) + +Using current optimized UPER: + +- Tiny object (tag/vsn + int + 1-byte bin): 9 bytes (legacy RLP = 5) +- List of 3 ints: 13 bytes (legacy = 7) +- Signed tx example: 11 bytes (legacy = 7) +- 256-byte payload: ~263 bytes (legacy ~264) -- matches or slightly better + +PER/UPER overhead is mainly the structural tags for the generic case. Concrete types and `staticFields` + `CompactStatic` minimize it. + +Compared to DER (previous orientation): dramatically better (e.g. tiny case was ~36B in DER). + +## Usage in Erlang (for the compact format) + +```erlang +% Build value according to schema (using staticFields for best compactness) +Value = {'CompactStatic', Tag, Vsn, [ + {'intValue', 42}, + {'binaryValue', <<"data">>} + % ... +]}, + +{ok, CompactBytes} = 'GajumaruSerialization':encode('CompactStatic', Value). +``` + +Compile the schema with: +``` +asn1ct:compile("GajumaruSerialization.asn", [uper]). +``` + +## Schema Notes +- `staticFields` should be used for generic static templates (mirrors legacy positional encoding). +- Concrete types (e.g. `signedTx`) are preferred when the structure is fixed. +- `TemplateFields` (with names) is kept for debug/transition but not optimal for wire size. +- The model directly reflects the static `template()` types from `gmserialization.erl`. + +## Portability +Any language with an ASN.1 UPER codec can produce and consume the exact same bytes by using the schema and the same value construction rules. + +## Stability +- UPER encoding of this schema is stable (tested roundtrip + re-encode identical). +- No random/padding choices. +- Same input value always produces identical bytes. + +## Limitations / Future +- For very small objects, hand-crafted RLP is still smaller because it has almost no structural overhead. +- If an even more compact custom encoding is desired while keeping the model, a custom "encoding rule" can be implemented driven by the schema (similar to how the RLP layer works, but targeting a new bit-packed format). +- Dynamic encoder (gmser_dyn) is out of scope. + +See also: `asn1/GajumaruSerialization.asn`, `asn1_compact/`, tests in `src/gmser_asn1_rlp.erl` (for value shapes), `doc/static.md`. diff --git a/doc/static.md b/doc/static.md index 991116b..943a001 100644 --- a/doc/static.md +++ b/doc/static.md @@ -59,7 +59,8 @@ The template 'language' is defined by these types: ```erlang -type template() :: [{field_name(), type()}]. -type field_name() :: atom(). --type type() :: 'int' +-type type() :: 'int' % bignum (non-negative, for amounts etc. up to 10^30 Pucks) + | 'uint128' | 'uint64' | 'uint32' | 'uint16' | 'uint8' | 'bool' | 'binary' | 'id' %% As defined in aec_id.erl diff --git a/src/gmser_asn1_rlp.erl b/src/gmser_asn1_rlp.erl index e8cbd15..674d167 100644 --- a/src/gmser_asn1_rlp.erl +++ b/src/gmser_asn1_rlp.erl @@ -27,7 +27,12 @@ %%% {account, {'Account', Foo, Bar}} %%% ... %%% Value is one of: -%%% {intValue, integer()} +%%% {bigIntValue, integer()} % bignum (the original "int" for Pucks etc.) +%%% {uint128Value, integer()} +%%% {uint64Value, integer()} +%%% {uint32Value, integer()} +%%% {uint16Value, integer()} +%%% {uint8Value, integer()} %%% {binaryValue, binary()} %%% {boolValue, boolean()} %%% {listValue, [Value]} @@ -137,7 +142,12 @@ encode_type_info_v3(T) when is_tuple(T), tuple_size(T) =:= 5 -> %%%=================================================================== -spec encode_asn1_value(term()) -> binary() | [term()]. -encode_asn1_value({intValue, I}) -> encode_basic(int, I); +encode_asn1_value({bigIntValue, I}) -> encode_basic(int, I); +encode_asn1_value({uint128Value, I}) -> encode_basic(int, I); +encode_asn1_value({uint64Value, I}) -> encode_basic(int, I); +encode_asn1_value({uint32Value, I}) -> encode_basic(int, I); +encode_asn1_value({uint16Value, I}) -> encode_basic(int, I); +encode_asn1_value({uint8Value, I}) -> encode_basic(int, I); encode_asn1_value({binaryValue, B}) -> encode_basic(binary, B); encode_asn1_value({boolValue, B}) -> encode_basic(bool, B); encode_asn1_value({listValue, L}) when is_list(L) -> @@ -200,12 +210,12 @@ encode_basic(Type, Val) -> %% This is the key property for a thin RLP production layer. equivalence_simple_fields_test() -> - T = [{foo, int}, {bar, binary}], + T = [{foo, uint32}, {bar, binary}], V = [{foo, 1}, {bar, <<2>>}], Legacy = gmser_chain_objects:serialize(account, 1, T, V), Asn1 = {'GajumaruData', 10, 1, {templateFields, [ - {'TemplateField', <<"foo">>, {intValue, 1}}, + {'TemplateField', <<"foo">>, {uint32Value, 1}}, {'TemplateField', <<"bar">>, {binaryValue, <<2>>}} ]}}, New = encode(Asn1), @@ -220,7 +230,7 @@ equivalence_zero_and_empty_test() -> Legacy = gmser_chain_objects:serialize(account, 1, T, V), Asn1 = {'GajumaruData', 10, 1, {templateFields, [ - {'TemplateField', <<"foo">>, {intValue, 0}}, + {'TemplateField', <<"foo">>, {bigIntValue, 0}}, {'TemplateField', <<"bar">>, {binaryValue, <<>>}} ]}}, ?assertEqual(Legacy, encode(Asn1)). @@ -232,7 +242,7 @@ equivalence_list_field_test() -> Asn1 = {'GajumaruData', 10, 1, {templateFields, [ {'TemplateField', <<"xs">>, {listValue, [ - {intValue, 1}, {intValue, 2}, {intValue, 3} + {bigIntValue, 1}, {bigIntValue, 2}, {bigIntValue, 3} ]}} ]}}, ?assertEqual(Legacy, encode(Asn1)). @@ -244,7 +254,7 @@ equivalence_tuple_field_test() -> Asn1 = {'GajumaruData', 10, 1, {templateFields, [ {'TemplateField', <<"p">>, {tupleValue, [ - {intValue, 42}, {binaryValue, <<"hi">>} + {bigIntValue, 42}, {binaryValue, <<"hi">>} ]}} ]}}, ?assertEqual(Legacy, encode(Asn1)). diff --git a/src/gmserialization.erl b/src/gmserialization.erl index 8f70d57..746ae0b 100644 --- a/src/gmserialization.erl +++ b/src/gmserialization.erl @@ -29,7 +29,12 @@ -type template() :: [{field_name(), type()}]. -type field_name() :: atom(). --type type() :: 'int' +-type type() :: 'int' % bignum (non-negative, arbitrary size; used for Pucks amounts etc. up to 10^30) + | 'uint128' + | 'uint64' + | 'uint32' + | 'uint16' + | 'uint8' | 'bool' | 'binary' | 'id' %% As defined in aec_id.erl @@ -118,6 +123,16 @@ encode_field(#{items := Items}, Map) -> encode_field(Type, T) when tuple_size(Type) =:= tuple_size(T) -> Zipped = lists:zip(tuple_to_list(Type), tuple_to_list(T)), [encode_field(X, Y) || {X, Y} <- Zipped]; +encode_field(uint128, X) when is_integer(X), X >= 0, X < (1 bsl 128) -> + binary:encode_unsigned(X); +encode_field(uint64, X) when is_integer(X), X >= 0, X < (1 bsl 64) -> + binary:encode_unsigned(X); +encode_field(uint32, X) when is_integer(X), X >= 0, X < (1 bsl 32) -> + binary:encode_unsigned(X); +encode_field(uint16, X) when is_integer(X), X >= 0, X < (1 bsl 16) -> + binary:encode_unsigned(X); +encode_field(uint8, X) when is_integer(X), X >= 0, X < (1 bsl 8) -> + binary:encode_unsigned(X); encode_field(int, X) when is_integer(X), X >= 0 -> binary:encode_unsigned(X); encode_field(binary, X) when is_binary(X) -> X; @@ -141,6 +156,31 @@ decode_field(#{items := Items}, List) when length(List) =:= length(Items) -> decode_field(Type, List) when length(List) =:= tuple_size(Type) -> Zipped = lists:zip(tuple_to_list(Type), List), list_to_tuple([decode_field(X, Y) || {X, Y} <- Zipped]); +decode_field(uint128, X) when is_binary(X) -> + I = binary:decode_unsigned(X), + if I < (1 bsl 128) -> I; + true -> error({illegal, uint128, X}) + end; +decode_field(uint64, X) when is_binary(X) -> + I = binary:decode_unsigned(X), + if I < (1 bsl 64) -> I; + true -> error({illegal, uint64, X}) + end; +decode_field(uint32, X) when is_binary(X) -> + I = binary:decode_unsigned(X), + if I < (1 bsl 32) -> I; + true -> error({illegal, uint32, X}) + end; +decode_field(uint16, X) when is_binary(X) -> + I = binary:decode_unsigned(X), + if I < (1 bsl 16) -> I; + true -> error({illegal, uint16, X}) + end; +decode_field(uint8, X) when is_binary(X) -> + I = binary:decode_unsigned(X), + if I < (1 bsl 8) -> I; + true -> error({illegal, uint8, X}) + end; decode_field(int, <<0:8, X/binary>> = B) when X =/= <<>> -> error({illegal, int, B}); decode_field(int, X) when is_binary(X) -> binary:decode_unsigned(X); -- 2.30.2