Files
gmserialization/asn1/GajumaruSerialization.erl
T
Ulf Wiger 6d7ab1e4ad
Gajumaru Serialization Tests / tests (push) Successful in 10s
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.
2026-07-07 10:05:30 +02:00

1403 lines
41 KiB
Erlang

%% 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, <<Unused,Bits/binary>>} | 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, <<Unused,Bits/binary>>} | 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),
<<Int:Len/signed-unit:8>> = 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, []).