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.