PoC: ASN.1 / DER serialization experiment
Gajumaru Serialization Tests / tests (push) Successful in 10s
Gajumaru Serialization Tests / tests (push) Successful in 10s
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.
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user