Packages

macula

0.20.21
7.1.0 7.0.0 6.0.0 5.2.2 5.2.1 5.2.0 5.1.0 5.0.0 4.8.0 4.7.1 4.7.0 4.6.0 4.5.0 4.4.10 4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.1 4.3.0 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.1 4.1.0 4.0.0 3.16.0 3.15.3 3.15.2 3.15.1 3.14.0 3.13.0 3.12.1 3.12.0 3.11.1 3.11.0 3.10.3 3.10.2 3.10.1 3.9.0 3.8.0 3.7.0 3.5.0 3.4.0 3.3.0 3.2.0 3.1.0 3.0.0 2.1.1 2.1.0 2.0.0 1.5.2 1.5.1 1.4.30 1.4.29 1.4.28 1.4.27 1.4.26 1.4.25 1.4.24 1.4.23 1.4.22 1.4.21 1.4.20 1.4.19 1.4.18 1.4.17 1.4.16 1.4.15 1.4.14 1.4.13 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.1 1.3.0 1.2.0 1.1.0 1.0.10 1.0.9 1.0.8 1.0.7 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0 0.48.6 0.48.5 0.48.4 0.48.3 0.48.2 0.48.1 0.48.0 0.47.1 0.47.0 0.46.3 0.46.1 0.46.0 0.45.3 0.45.2 0.45.1 0.45.0 0.44.2 0.44.1 0.44.0 0.43.3 0.43.2 0.43.1 0.43.0 0.42.9 0.42.8 0.42.7 0.42.6 0.42.5 0.42.4 0.42.3 0.42.2 0.42.1 0.42.0 0.41.1 0.41.0 0.40.1 0.40.0 0.39.9 0.39.8 0.39.7 0.39.6 0.39.5 0.39.4 0.39.3 0.39.2 0.39.1 0.39.0 0.38.8 0.38.7 0.38.6 0.38.5 0.38.4 0.38.3 0.38.2 0.38.1 0.38.0 0.37.7 0.37.6 0.37.5 0.37.4 0.37.3 0.37.2 0.37.1 0.37.0 0.36.6 0.36.5 0.36.4 0.36.3 0.36.2 0.36.1 0.36.0 0.35.4 0.35.3 0.35.2 0.35.1 0.35.0 0.34.1 0.34.0 0.33.1 0.33.0 0.32.5 0.32.4 0.32.3 0.32.2 0.32.1 0.32.0 0.31.9 0.31.8 0.31.7 0.31.6 0.31.5 0.31.4 0.31.3 0.31.2 0.31.1 0.31.0 0.30.10 0.30.9 0.30.8 0.30.7 0.30.6 0.30.5 0.30.4 0.30.3 0.30.2 0.30.1 0.30.0 0.29.0 0.28.3 0.28.2 0.28.1 0.28.0 0.27.1 0.27.0 0.26.1 0.26.0 0.25.6 0.25.5 0.25.4 0.25.3 0.25.2 0.25.1 0.25.0 0.24.6 0.24.5 0.24.4 0.24.3 0.24.2 0.24.1 0.24.0 0.23.3 0.23.2 0.23.1 0.23.0 0.22.12 0.22.11 0.22.10 0.22.9 0.22.8 0.22.7 0.22.6 0.22.5 0.22.4 0.22.3 0.22.2 0.22.1 0.22.0 0.21.7 0.21.6 0.21.5 0.21.4 0.21.2 0.21.1 0.21.0 0.20.25 0.20.24 0.20.23 0.20.22 0.20.21 0.20.20 0.20.19 0.20.18 0.20.17 0.20.16 0.20.15 0.20.14 0.20.13 0.20.12 0.20.11 0.20.10 0.20.9 0.20.8 0.20.7 0.20.6 0.20.5 0.20.3 0.20.2 0.20.1 0.20.0 0.19.2 0.19.1 0.19.0 0.18.1 0.18.0 0.17.4 0.17.3 0.17.2 0.17.1 0.17.0 0.16.6 0.16.5 0.16.4 0.16.3 0.16.2 0.16.1 0.16.0 0.15.1 0.15.0 0.14.3 0.14.2 0.14.1 0.14.0 0.12.6 0.12.5 0.12.3 0.11.3 0.10.2 0.10.1 0.10.0 0.9.2 0.9.1 0.9.0 0.8.25 0.8.24 0.8.23 0.8.22 0.8.21 0.8.20 0.8.19 0.8.18 0.8.17 0.8.16 0.8.15 0.8.14 0.8.13 0.8.12 0.8.11 0.8.10 0.8.9 0.8.8 0.8.7 0.8.6 0.8.5 0.8.4 0.8.3 0.8.2 0.8.1 0.8.0 0.7.30 0.7.29 0.7.28 0.7.27 0.7.26 0.7.25 0.7.24 0.7.23 0.7.22 0.7.21 0.7.20 0.7.19 0.7.18 0.7.17 0.7.16 0.7.15 0.7.14 0.7.13 0.7.12 0.7.11 0.7.10 0.7.9 0.7.8 0.7.7 0.7.6 0.7.5 0.7.4 0.7.3 0.7.2 0.7.1 0.7.0 0.6.7 0.6.6 0.6.5 0.6.4 0.6.3 0.6.2 0.6.1 0.6.0 0.5.0 0.4.4 0.4.3 0.4.2 0.4.1 0.4.0 0.3.4 0.3.3 0.3.2 0.3.1

Macula HTTP/3 Mesh SDK — connect, subscribe, publish, call, advertise

Current section

Files

Jump to
macula src macula_registry_system macula_registry_verify.erl
Raw

src/macula_registry_system/macula_registry_verify.erl

%%%-------------------------------------------------------------------
%%% @doc Macula Registry Signature Verification
%%%
%%% Provides Ed25519 digital signature operations for package verification:
%%% - Keypair generation
%%% - Package signing
%%% - Signature verification
%%% - Public key validation
%%%
%%% All functions are stateless and can be called directly.
%%% @end
%%%-------------------------------------------------------------------
-module(macula_registry_verify).
%% API
-export([generate_keypair/0]).
-export([sign_package/3, sign_data/2]).
-export([verify_signature/3, verify_package/4]).
-export([validate_public_key/1, validate_private_key/1]).
-export([encode_public_key/1, decode_public_key/1]).
-export([compute_checksum/1]).
%% Ed25519 key sizes
-define(ED25519_PUBLIC_KEY_SIZE, 32).
-define(ED25519_PRIVATE_KEY_SIZE, 64). %% 32 bytes seed + 32 bytes public
%%%===================================================================
%%% API functions
%%%===================================================================
%% @doc Generate a new Ed25519 keypair
%% Returns {PublicKey, PrivateKey} as raw binaries
-spec generate_keypair() -> {PublicKey :: binary(), PrivateKey :: binary()}.
generate_keypair() ->
%% crypto:generate_key/2 returns {PubKey, PrivKey} tuple for eddsa
{PublicKey, PrivateKey} = crypto:generate_key(eddsa, ed25519),
{PublicKey, PrivateKey}.
%% @doc Sign package data (manifest + archive)
%% The signature covers the SHA-256 hash of (manifest_binary ++ beam_archive)
-spec sign_package(ManifestBin :: binary(), BeamArchive :: binary(), PrivateKey :: binary()) ->
{ok, Signature :: binary()} | {error, term()}.
sign_package(ManifestBin, BeamArchive, PrivateKey) ->
case validate_private_key(PrivateKey) of
ok ->
%% Combine manifest and archive for signing
DataToSign = <<ManifestBin/binary, BeamArchive/binary>>,
{ok, sign_data(DataToSign, PrivateKey)};
{error, _} = Error ->
Error
end.
%% @doc Sign arbitrary data with Ed25519 private key
-spec sign_data(Data :: binary(), PrivateKey :: binary()) -> Signature :: binary().
sign_data(Data, PrivateKey) ->
%% Hash the data first for consistent signing regardless of size
Hash = crypto:hash(sha256, Data),
crypto:sign(eddsa, none, Hash, [PrivateKey, ed25519]).
%% @doc Verify a signature against data and public key
-spec verify_signature(Data :: binary(), Signature :: binary(), PublicKey :: binary()) ->
ok | {error, invalid_signature}.
verify_signature(Data, Signature, PublicKey) ->
Hash = crypto:hash(sha256, Data),
case crypto:verify(eddsa, none, Hash, Signature, [PublicKey, ed25519]) of
true -> ok;
false -> {error, invalid_signature}
end.
%% @doc Verify package signature
%% Reconstructs the signed data from manifest and archive, then verifies
-spec verify_package(ManifestBin :: binary(), BeamArchive :: binary(),
Signature :: binary(), PublicKey :: binary()) ->
ok | {error, term()}.
verify_package(ManifestBin, BeamArchive, Signature, PublicKey) ->
case validate_public_key(PublicKey) of
ok ->
DataToVerify = <<ManifestBin/binary, BeamArchive/binary>>,
verify_signature(DataToVerify, Signature, PublicKey);
{error, _} = Error ->
Error
end.
%% @doc Validate that a binary is a valid Ed25519 public key
-spec validate_public_key(PublicKey :: binary()) -> ok | {error, invalid_key}.
validate_public_key(PublicKey) when is_binary(PublicKey) ->
case byte_size(PublicKey) of
?ED25519_PUBLIC_KEY_SIZE -> ok;
_ -> {error, invalid_key}
end;
validate_public_key(_) ->
{error, invalid_key}.
%% @doc Validate that a binary is a valid Ed25519 private key
-spec validate_private_key(PrivateKey :: binary()) -> ok | {error, invalid_key}.
validate_private_key(PrivateKey) when is_binary(PrivateKey) ->
case byte_size(PrivateKey) of
?ED25519_PRIVATE_KEY_SIZE -> ok;
?ED25519_PUBLIC_KEY_SIZE -> ok; %% Some APIs use 32-byte seed
_ -> {error, invalid_key}
end;
validate_private_key(_) ->
{error, invalid_key}.
%% @doc Encode public key as hex string for display/storage
-spec encode_public_key(PublicKey :: binary()) -> binary().
encode_public_key(PublicKey) ->
binary:encode_hex(PublicKey, lowercase).
%% @doc Decode hex-encoded public key back to binary
-spec decode_public_key(HexKey :: binary()) -> {ok, binary()} | {error, invalid_format}.
decode_public_key(HexKey) when is_binary(HexKey) ->
handle_hex_decode(catch binary:decode_hex(HexKey));
decode_public_key(_) ->
{error, invalid_format}.
%% @private Handle hex decode result
handle_hex_decode({'EXIT', _}) ->
{error, invalid_format};
handle_hex_decode(Decoded) when is_binary(Decoded) ->
validate_decoded_key(validate_public_key(Decoded), Decoded);
handle_hex_decode(_) ->
{error, invalid_format}.
%% @private Validate decoded key
validate_decoded_key(ok, Decoded) ->
{ok, Decoded};
validate_decoded_key(Error, _Decoded) ->
Error.
%% @doc Compute SHA-256 checksum of data
-spec compute_checksum(Data :: binary()) -> binary().
compute_checksum(Data) ->
crypto:hash(sha256, Data).