Packages

Gleam implementation of JOSE (JWS, JWE, JWK, JWT) and COSE (COSE_Sign, COSE_Encrypt, COSE_Mac0, CWT) standards

Retired package: Deprecated

Current section

Files

Jump to
gose src gose@cose@mac0.erl
Raw

src/gose@cose@mac0.erl

-module(gose@cose@mac0).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gose/cose/mac0.gleam").
-export([new/1, serialize/1, serialize_tagged/1, payload/1, verifier/2, with_detached/1, with_aad/2, with_kid/2, with_content_type/2, with_critical/2, kid/1, content_type/1, critical/1, protected_headers/1, unprotected_headers/1, tag/3, verify_with_aad/3, verify/2, verify_detached_with_aad/4, verify_detached/3, parse/1]).
-export_type([untagged/0, tagged/0, mac0/1, verifier/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" COSE_Mac0 single-recipient MAC creation and verification\n"
" ([RFC 9052](https://www.rfc-editor.org/rfc/rfc9052.html)).\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import gose/algorithm\n"
" import gose/cose/mac0\n"
" import gose/key\n"
"\n"
" let k = key.generate_hmac_key(algorithm.HmacSha256)\n"
" let payload = <<\"hello\":utf8>>\n"
"\n"
" let assert Ok(tagged) =\n"
" mac0.new(algorithm.Hmac(algorithm.HmacSha256))\n"
" |> mac0.tag(k, payload)\n"
"\n"
" let data = mac0.serialize(tagged)\n"
" let assert Ok(parsed) = mac0.parse(data)\n"
" let assert Ok(verifier) =\n"
" mac0.verifier(algorithm.Hmac(algorithm.HmacSha256), keys: [k])\n"
" let assert Ok(Nil) = mac0.verify(verifier, parsed)\n"
" ```\n"
"\n"
" ## Phantom Types\n"
"\n"
" `Mac0(state)` uses a phantom type to track MAC state:\n"
" - `Untagged`: created via `new`, ready to tag\n"
" - `Tagged`: tagged or parsed, can be serialized or verified\n"
"\n"
" ## Algorithm Pinning\n"
"\n"
" Each verifier is pinned to a single algorithm. The token's protected\n"
" header `alg` must match the verifier's expected algorithm.\n"
).
-type untagged() :: any().
-type tagged() :: any().
-opaque mac0(RNC) :: {untagged_mac0,
list(gose@cose:header()),
list(gose@cose:header()),
boolean(),
bitstring()} |
{tagged_mac0,
list(gose@cose:header()),
bitstring(),
list(gose@cose:header()),
gleam@option:option(bitstring()),
bitstring()} |
{gleam_phantom, RNC}.
-opaque verifier() :: {verifier,
gose@algorithm:mac_alg(),
list(gose@key:key(bitstring()))}.
-file("src/gose/cose/mac0.gleam", 78).
?DOC(" Create a new untagged COSE_Mac0 message with the given MAC algorithm in the protected header.\n").
-spec new(gose@algorithm:mac_alg()) -> mac0(untagged()).
new(Alg) ->
Alg_id = gose@cose@algorithm:mac_alg_to_int(Alg),
{untagged_mac0, [{alg, Alg_id}], [], false, <<>>}.
-file("src/gose/cose/mac0.gleam", 137).
-spec to_cbor_value(mac0(tagged())) -> gose@cbor:value().
to_cbor_value(Message) ->
{Protected_serialized@1, Unprotected@1, Payload@1, Mac_tag@1} = case Message of
{tagged_mac0, _, Protected_serialized, Unprotected, Payload, Mac_tag} -> {
Protected_serialized,
Unprotected,
Payload,
Mac_tag};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"to_cbor_value"/utf8>>,
line => 138,
value => _assert_fail,
start => 4046,
'end' => 4163,
pattern_start => 4057,
pattern_end => 4153})
end,
Payload_value = case Payload@1 of
{some, P} ->
{bytes, P};
none ->
null
end,
{array,
[{bytes, Protected_serialized@1},
{map, gose@cose:headers_to_cbor(Unprotected@1)},
Payload_value,
{bytes, Mac_tag@1}]}.
-file("src/gose/cose/mac0.gleam", 128).
?DOC(" Encode a tagged message as an untagged CBOR COSE_Mac0 array.\n").
-spec serialize(mac0(tagged())) -> bitstring().
serialize(Message) ->
gose@cbor:encode(to_cbor_value(Message)).
-file("src/gose/cose/mac0.gleam", 133).
?DOC(" Encode a tagged message as a CBOR-tagged (tag 17) COSE_Mac0 structure.\n").
-spec serialize_tagged(mac0(tagged())) -> bitstring().
serialize_tagged(Message) ->
gose@cbor:encode({tag, 17, to_cbor_value(Message)}).
-file("src/gose/cose/mac0.gleam", 166).
?DOC(" Return the payload from a tagged message. Returns `Error(Nil)` if detached.\n").
-spec payload(mac0(tagged())) -> {ok, bitstring()} | {error, nil}.
payload(Message) ->
Payload@1 = case Message of
{tagged_mac0, _, _, _, Payload, _} -> Payload;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"payload"/utf8>>,
line => 167,
value => _assert_fail,
start => 4805,
'end' => 4850,
pattern_start => 4816,
pattern_end => 4840})
end,
gleam@option:to_result(Payload@1, nil).
-file("src/gose/cose/mac0.gleam", 172).
?DOC(" Build a verifier pinned to a single algorithm and one or more keys.\n").
-spec verifier(gose@algorithm:mac_alg(), list(gose@key:key(bitstring()))) -> {ok,
verifier()} |
{error, gose:gose_error()}.
verifier(Alg, Keys) ->
Signing_alg = {mac, Alg},
gose@internal@key_helpers:require_non_empty_keys(
Keys,
fun() ->
gleam@result:'try'(
gleam@list:try_each(
Keys,
fun(_capture) ->
gose@internal@key_helpers:validate_key_for_signing_verification(
Signing_alg,
_capture
)
end
),
fun(_) -> {ok, {verifier, Alg, Keys}} end
)
end
).
-file("src/gose/cose/mac0.gleam", 284).
?DOC(
" Mark the message for detached payload. The payload is still provided to\n"
" `tag` for MAC computation but not included in the serialized output.\n"
).
-spec with_detached(mac0(untagged())) -> mac0(untagged()).
with_detached(Message) ->
case Message of
{untagged_mac0, _, _, _, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"with_detached"/utf8>>,
line => 285,
value => _assert_fail,
start => 8366,
'end' => 8403,
pattern_start => 8377,
pattern_end => 8393})
end,
{untagged_mac0,
erlang:element(2, Message),
erlang:element(3, Message),
true,
erlang:element(5, Message)}.
-file("src/gose/cose/mac0.gleam", 290).
?DOC(" Set external additional authenticated data (AAD) for the MAC operation.\n").
-spec with_aad(mac0(untagged()), bitstring()) -> mac0(untagged()).
with_aad(Message, Aad) ->
case Message of
{untagged_mac0, _, _, _, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"with_aad"/utf8>>,
line => 291,
value => _assert_fail,
start => 8607,
'end' => 8644,
pattern_start => 8618,
pattern_end => 8634})
end,
{untagged_mac0,
erlang:element(2, Message),
erlang:element(3, Message),
erlang:element(4, Message),
Aad}.
-file("src/gose/cose/mac0.gleam", 296).
?DOC(" Add a key ID to the unprotected headers.\n").
-spec with_kid(mac0(untagged()), bitstring()) -> mac0(untagged()).
with_kid(Message, Kid) ->
Unprotected@1 = case Message of
{untagged_mac0, _, Unprotected, _, _} -> Unprotected;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"with_kid"/utf8>>,
line => 297,
value => _assert_fail,
start => 8807,
'end' => 8858,
pattern_start => 8818,
pattern_end => 8848})
end,
{untagged_mac0,
erlang:element(2, Message),
[{kid, Kid} | Unprotected@1],
erlang:element(4, Message),
erlang:element(5, Message)}.
-file("src/gose/cose/mac0.gleam", 305).
?DOC(
" Add a content type to the unprotected headers.\n"
"\n"
" RFC 9052 permits either bucket. MACed messages place it in unprotected,\n"
" consistent with `with_kid`.\n"
).
-spec with_content_type(mac0(untagged()), gose@cose:content_type()) -> mac0(untagged()).
with_content_type(Message, Ct) ->
Unprotected@1 = case Message of
{untagged_mac0, _, Unprotected, _, _} -> Unprotected;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"with_content_type"/utf8>>,
line => 309,
value => _assert_fail,
start => 9200,
'end' => 9251,
pattern_start => 9211,
pattern_end => 9241})
end,
{untagged_mac0,
erlang:element(2, Message),
[{content_type, Ct} | Unprotected@1],
erlang:element(4, Message),
erlang:element(5, Message)}.
-file("src/gose/cose/mac0.gleam", 314).
?DOC(" Add critical header labels to the protected headers.\n").
-spec with_critical(mac0(untagged()), list(integer())) -> mac0(untagged()).
with_critical(Message, Labels) ->
Protected@1 = case Message of
{untagged_mac0, Protected, _, _, _} -> Protected;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"with_critical"/utf8>>,
line => 318,
value => _assert_fail,
start => 9491,
'end' => 9540,
pattern_start => 9502,
pattern_end => 9530})
end,
{untagged_mac0,
[{crit, Labels} | Protected@1],
erlang:element(3, Message),
erlang:element(4, Message),
erlang:element(5, Message)}.
-file("src/gose/cose/mac0.gleam", 323).
?DOC(" Extract the key ID from the message headers.\n").
-spec kid(mac0(tagged())) -> {ok, bitstring()} | {error, gose:gose_error()}.
kid(Message) ->
{Protected@1, Unprotected@1} = case Message of
{tagged_mac0, Protected, _, Unprotected, _, _} -> {
Protected,
Unprotected};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"kid"/utf8>>,
line => 324,
value => _assert_fail,
start => 9738,
'end' => 9799,
pattern_start => 9749,
pattern_end => 9789})
end,
gose@cose:kid(lists:append(Protected@1, Unprotected@1)).
-file("src/gose/cose/mac0.gleam", 329).
?DOC(" Extract the content type from the message headers.\n").
-spec content_type(mac0(tagged())) -> {ok, gose@cose:content_type()} |
{error, gose:gose_error()}.
content_type(Message) ->
{Protected@1, Unprotected@1} = case Message of
{tagged_mac0, Protected, _, Unprotected, _, _} -> {
Protected,
Unprotected};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"content_type"/utf8>>,
line => 332,
value => _assert_fail,
start => 10002,
'end' => 10063,
pattern_start => 10013,
pattern_end => 10053})
end,
gose@cose:content_type(lists:append(Protected@1, Unprotected@1)).
-file("src/gose/cose/mac0.gleam", 337).
?DOC(" Extract the critical header labels from the message headers.\n").
-spec critical(mac0(tagged())) -> {ok, list(integer())} |
{error, gose:gose_error()}.
critical(Message) ->
{Protected@1, Unprotected@1} = case Message of
{tagged_mac0, Protected, _, Unprotected, _, _} -> {
Protected,
Unprotected};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"critical"/utf8>>,
line => 338,
value => _assert_fail,
start => 10269,
'end' => 10330,
pattern_start => 10280,
pattern_end => 10320})
end,
gose@cose:critical(lists:append(Protected@1, Unprotected@1)).
-file("src/gose/cose/mac0.gleam", 343).
?DOC(" Return the raw protected headers.\n").
-spec protected_headers(mac0(tagged())) -> list(gose@cose:header()).
protected_headers(Message) ->
Protected@1 = case Message of
{tagged_mac0, Protected, _, _, _, _} -> Protected;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"protected_headers"/utf8>>,
line => 344,
value => _assert_fail,
start => 10498,
'end' => 10545,
pattern_start => 10509,
pattern_end => 10535})
end,
Protected@1.
-file("src/gose/cose/mac0.gleam", 349).
?DOC(" Return the raw unprotected headers.\n").
-spec unprotected_headers(mac0(tagged())) -> list(gose@cose:header()).
unprotected_headers(Message) ->
Unprotected@1 = case Message of
{tagged_mac0, _, _, Unprotected, _, _} -> Unprotected;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"unprotected_headers"/utf8>>,
line => 350,
value => _assert_fail,
start => 10676,
'end' => 10725,
pattern_start => 10687,
pattern_end => 10715})
end,
Unprotected@1.
-file("src/gose/cose/mac0.gleam", 354).
-spec build_mac_structure(bitstring(), bitstring(), bitstring()) -> bitstring().
build_mac_structure(Protected_serialized, Aad, Payload) ->
gose@cbor:encode(
{array,
[{text, <<"MAC0"/utf8>>},
{bytes, Protected_serialized},
{bytes, Aad},
{bytes, Payload}]}
).
-file("src/gose/cose/mac0.gleam", 89).
?DOC(" Compute the MAC tag over the payload with the given key.\n").
-spec tag(mac0(untagged()), gose@key:key(bitstring()), bitstring()) -> {ok,
mac0(tagged())} |
{error, gose:gose_error()}.
tag(Message, Key, Payload) ->
{Protected@1, Unprotected@1, Detached@1, Aad@1} = case Message of
{untagged_mac0, Protected, Unprotected, Detached, Aad} -> {
Protected,
Unprotected,
Detached,
Aad};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"tag"/utf8>>,
line => 94,
value => _assert_fail,
start => 2659,
'end' => 2735,
pattern_start => 2670,
pattern_end => 2725})
end,
gleam@result:'try'(
gose@internal@cose_structure:extract_signing_alg_from_headers(
Protected@1
),
fun(Alg) ->
gleam@result:'try'(
gose@internal@key_helpers:validate_signing_key_type(Alg, Key),
fun(_) ->
gleam@result:'try'(
gose@internal@key_helpers:validate_key_use(
Key,
for_signing
),
fun(_) ->
gleam@result:'try'(
gose@internal@key_helpers:validate_key_ops(
Key,
for_signing
),
fun(_) ->
gleam@result:'try'(
gose@internal@key_helpers:validate_key_algorithm_signing(
Key,
Alg
),
fun(_) ->
Protected_serialized = gose@internal@cose_structure:serialize_protected(
Protected@1
),
To_mac = build_mac_structure(
Protected_serialized,
Aad@1,
Payload
),
gleam@result:'try'(
gose@internal@signing:compute_signature(
Alg,
Key,
To_mac
),
fun(Computed_tag) ->
Stored_payload = case Detached@1 of
true ->
none;
false ->
{some, Payload}
end,
{ok,
{tagged_mac0,
Protected@1,
Protected_serialized,
Unprotected@1,
Stored_payload,
Computed_tag}}
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/gose/cose/mac0.gleam", 196).
?DOC(" Verify the MAC tag with additional externally-supplied authenticated data (AAD).\n").
-spec verify_with_aad(verifier(), mac0(tagged()), bitstring()) -> {ok, nil} |
{error, gose:gose_error()}.
verify_with_aad(Verifier, Message, Aad) ->
{verifier, Expected_alg, Keys} = Verifier,
Expected_signing_alg = {mac, Expected_alg},
{
Protected@1,
Protected_serialized@1,
Unprotected@1,
Payload@1,
Mac_tag@1} = case Message of
{tagged_mac0,
Protected,
Protected_serialized,
Unprotected,
Payload,
Mac_tag} -> {
Protected,
Protected_serialized,
Unprotected,
Payload,
Mac_tag};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"verify_with_aad"/utf8>>,
line => 203,
value => _assert_fail,
start => 5917,
'end' => 6042,
pattern_start => 5928,
pattern_end => 6032})
end,
gleam@result:'try'(
gose@internal@cose_structure:extract_signing_alg_from_serialized(
Protected_serialized@1
),
fun(Actual_alg) ->
gleam@result:'try'(
gose@internal@key_helpers:require_matching_signing_algorithm(
Expected_signing_alg,
Actual_alg
),
fun(_) ->
gleam@result:'try'(
gose@internal@cose_structure:validate_crit(
Protected@1,
Unprotected@1
),
fun(_) ->
gleam@result:'try'(
gose@internal@cose_structure:require_embedded_payload(
Payload@1
),
fun(Payload_bytes) ->
To_mac = build_mac_structure(
Protected_serialized@1,
Aad,
Payload_bytes
),
gose@internal@cose_structure:try_verify_keys(
Expected_signing_alg,
Keys,
To_mac,
Mac_tag@1
)
end
)
end
)
end
)
end
).
-file("src/gose/cose/mac0.gleam", 188).
?DOC(" Verify the MAC tag of a COSE_Mac0 message against the verifier's expected algorithm and keys.\n").
-spec verify(verifier(), mac0(tagged())) -> {ok, nil} |
{error, gose:gose_error()}.
verify(Verifier, Message) ->
verify_with_aad(Verifier, Message, <<>>).
-file("src/gose/cose/mac0.gleam", 246).
?DOC(" Verify a detached-payload COSE_Mac0 message with external AAD.\n").
-spec verify_detached_with_aad(
verifier(),
mac0(tagged()),
bitstring(),
bitstring()
) -> {ok, nil} | {error, gose:gose_error()}.
verify_detached_with_aad(Verifier, Message, Payload, Aad) ->
{verifier, Expected_alg, Keys} = Verifier,
Expected_signing_alg = {mac, Expected_alg},
{
Protected@1,
Protected_serialized@1,
Unprotected@1,
Existing_payload@1,
Mac_tag@1} = case Message of
{tagged_mac0,
Protected,
Protected_serialized,
Unprotected,
Existing_payload,
Mac_tag} -> {
Protected,
Protected_serialized,
Unprotected,
Existing_payload,
Mac_tag};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gose/cose/mac0"/utf8>>,
function => <<"verify_detached_with_aad"/utf8>>,
line => 254,
value => _assert_fail,
start => 7421,
'end' => 7563,
pattern_start => 7432,
pattern_end => 7553})
end,
gleam@result:'try'(
gose@internal@cose_structure:require_detached_payload(
Existing_payload@1
),
fun(_) ->
gleam@result:'try'(
gose@internal@cose_structure:extract_signing_alg_from_serialized(
Protected_serialized@1
),
fun(Actual_alg) ->
gleam@result:'try'(
gose@internal@key_helpers:require_matching_signing_algorithm(
Expected_signing_alg,
Actual_alg
),
fun(_) ->
gleam@result:'try'(
gose@internal@cose_structure:validate_crit(
Protected@1,
Unprotected@1
),
fun(_) ->
To_mac = build_mac_structure(
Protected_serialized@1,
Aad,
Payload
),
gose@internal@cose_structure:try_verify_keys(
Expected_signing_alg,
Keys,
To_mac,
Mac_tag@1
)
end
)
end
)
end
)
end
).
-file("src/gose/cose/mac0.gleam", 237).
?DOC(
" Verify the MAC tag of a detached-payload COSE_Mac0 message.\n"
"\n"
" The caller must supply the payload that was detached from the message.\n"
" Returns an error if the message already contains an embedded payload.\n"
).
-spec verify_detached(verifier(), mac0(tagged()), bitstring()) -> {ok, nil} |
{error, gose:gose_error()}.
verify_detached(Verifier, Message, Payload) ->
verify_detached_with_aad(Verifier, Message, Payload, <<>>).
-file("src/gose/cose/mac0.gleam", 369).
-spec parse_cbor_value(gose@cbor:value()) -> {ok, mac0(tagged())} |
{error, gose:gose_error()}.
parse_cbor_value(Value) ->
gleam@result:'try'(
gose@internal@cose_structure:parse_cose_array_value(Value, 17, 4),
fun(Items) -> case Items of
[{bytes, Protected_serialized},
{map, Unprotected_cbor},
Payload_value,
{bytes, Mac_tag}] ->
gleam@result:'try'(
gose@internal@cose_structure:decode_protected(
Protected_serialized
),
fun(Protected) ->
gleam@result:'try'(
gose@internal@cose_structure:decode_unprotected(
Unprotected_cbor
),
fun(Unprotected) ->
gleam@result:'try'(
gose@internal@cose_structure:validate_no_header_overlap(
Protected,
Unprotected
),
fun(_) ->
gleam@result:'try'(
gose@internal@cose_structure:validate_iv_partial_iv_exclusion(
Protected,
Unprotected
),
fun(_) ->
gleam@result:'try'(
gose@internal@cose_structure:decode_payload(
Payload_value
),
fun(Payload) ->
{ok,
{tagged_mac0,
Protected,
Protected_serialized,
Unprotected,
Payload,
Mac_tag}}
end
)
end
)
end
)
end
)
end
);
_ ->
{error,
{parse_error, <<"invalid COSE_Mac0 structure"/utf8>>}}
end end
).
-file("src/gose/cose/mac0.gleam", 160).
?DOC(" Decode a CBOR-encoded COSE_Mac0 message, accepting both tagged and untagged forms.\n").
-spec parse(bitstring()) -> {ok, mac0(tagged())} | {error, gose:gose_error()}.
parse(Data) ->
gleam@result:'try'(
gose@cbor:decode(Data),
fun(Value) -> parse_cbor_value(Value) end
).