Application distribution packer built with MoonBit

| You call | You get back | Shape |
|---|---|---|
| @LunaPack.pack(dir, pkg, opts) | the package, written | Unit (the manifest is in the file) |
| @LunaPack.bundle(exe, out, dirs, opts, launcher) | the self-extracting single file | Unit |
| @LunaPack.unpack(pkg, dest, run_scripts, key) | the tree, extracted and verified | Unit |
| @LunaPack.verify(pkg, key) | whether every entry is intact | Bool |
| @LunaPack.read_package_manifest(pkg) | the manifest of a package | Manifest |
| @LunaPack.probe_archive(path) | the offset of the archive and its manifest | (Int64, Manifest)? |
| @LunaPack.verify_extracted_dir(pkg, dir) | whether the files in dir still match the package | Bool |
| @LunaPack.new_pack_options(...) | the options of a package | PackOptions |
| @LunaPack.new_script(platform, body) | an install script | Script |
| @LunaPack.recover_encryption(info, key, passphrase) | the key of a sealed package | PackageKey |
| @LunaPack.x25519_public_key(secret) | the public key of a secret key | Bytes |
| @LunaPack.ed25519_public_key(seed) | the public key of a signing seed | Bytes |
| @LunaPack.ed25519_sign(seed, message) | a signature of a message | Bytes |
| @LunaPack.ed25519_verify(public, message, signature) | whether a signature holds | Bool |
| @LunaPack.public_key_pair(secret) | the two public keys of a secret key | PublicKeyPair |
| @LunaPack.ed25519_seed(secret) | the signing seed of a secret key | Bytes |
| @LunaPack.save_public_key_pair(path, encryption, signing) | the public key file of a pair | Unit |
| @LunaPack.load_public_key(path) | the encryption public key of a file | Bytes |
| @LunaPack.load_signing_public_key(path) | the signing public key of a file | Bytes |
| @LunaPack.sign_package(pkg, secret) | the signature of a package | PackageSignature |
| @LunaPack.verify_package_signature(pkg, sig, public) | whether the signature holds | Bool |
| @LunaPack.verify_package_digest(pkg, digest) | whether the package has that digest | Bool |
| @LunaPack.manifest_digest(offset, length, bytes) | the digest of a manifest | Bytes |
| @LunaPack.manifest_mac(key, offset, length, bytes) | the MAC of a manifest | Bytes |
moon add riantr/LunaPack@0.1.11import {
"riantr/LunaPack@0.1.11",
}///|
import {
"riantr/LunaPack" @lib,
}///|
import {
"riantr/LunaPack" @lp,
}| Package | Kind | Native | Wasm |
|---|---|---|---|
| riantr/LunaPack | library and executable | yes | yes |
| Asset | Platform |
|---|---|
| lunapack-windows-x86_64.exe | Windows |
| lunapack-linux-x86_64 | Linux |
| lunapack-macos-aarch64 | macOS (Apple Silicon) |
| lunapack.wasm | WebAssembly, for moonx |
| lunapack.core | the compiled package the WebAssembly module needs |
moon login # once
moon publish --dry-run # validate
moon publish # publish riantr/LunaPack
moonx riantr/LunaPack@latest --input-exe=... --output-exe=... --Files=...myapp.exe = [ LunaPack launcher ] + [ archive: myapp.exe, res/app.cfg, ... ]$ ./myapp.exe
LunaPack: starting D:/apps/.lunapack/9c445884d23653fb/myapp.exe# A bundle for Windows, made with the launcher of the release.
lunapack bundle -i ./myapp.exe -o ./myapp.exe \
--Files=./build --launcher ./lunapack-windows-x86_64.exeThe bundle is self-extracting when the launcher is a native LunaPack binary. The one that runs on this machine is used by default, so a native LunaPack always produces a self-extracting file. A bundle produced through moonx runs on WebAssembly and has no native binary of its own, so it needs one named with --launcher — see above.
$ ./myapp.exe --version
myapp 2.6.0
$ echo $?
0$ lunapack --input-exe=./myapp.exe --output-exe=./myapp.exe --Files=./build
md5 6b1b1e1f0a2c3d4e5f60718293a4b5c6 myapp.exe
...
scanned 392 files
bundled 392 files -> ./myapp.exe (icon copied)
output md5 0f1e2d3c4b5a69788796a5b4c3d2e1f0 myapp.exelunapack verify myapp.exe
lunapack info myapp.exe
lunapack unpack -i myapp.exe -o ./out+--------------------+ offset 0
| magic "APPKGD02" | 8 bytes
+--------------------+ offset 8
| entry payloads | stored back to back, raw, gzip, lz4 or sealed
+--------------------+
| integrity block | 40 bytes, or 72 for a sealed package
+--------------------+
| manifest (UTF-8 |
| JSON) |
+--------------------+
| magic "APPKGD02" | 8 bytes
| manifest offset | 8 bytes, little-endian int64
| manifest length | 8 bytes, little-endian int64
+--------------------+ end of file{
"format_version": 6,
"name": "myapp",
"version": "1.4.0",
"os": "linux",
"arch": "x86_64",
"checksum_algo": "sha256",
"compression": "auto",
"created_at": "2026-11-04T04:10:20Z",
"main_program": "myapp.exe",
"pre_install": { "platform": "posix", "body": "#!/bin/sh\n..." },
"post_install": null,
"entries": [
{
"path": "res/app.cfg",
"mode": 420,
"size": 22500,
"stored_size": 913,
"codec": "gzip",
"checksum": "0a77c24c45d0c61f906862c4706f5dd739166985e8fc5c6344dadd9220507b28",
"md5": "1520e796ba25554696b3cef6e913cc90",
"offset": 8
}
]
}| Layer | What it is | What it stops |
|---|---|---|
| SHA-256 of every entry | in the manifest | a payload that was changed or corrupted |
| MD5 of every entry | in the manifest | the same, by a second and independent algorithm |
| SHA-256 of the manifest | in the integrity block | a manifest that was changed in place, a truncated write |
| HMAC-SHA512 of the manifest | in the integrity block of a sealed package | a manifest that was rewritten by whoever holds the file |
| The cache is checked on every start | in the launcher | a payload that was changed after it was unpacked |
| The program is checked before it runs | in the launcher | a program that was changed between the check and the start |
| A damaged package is refused | everywhere | a package that was cut short being taken for something else |
| The paths of the entries are checked | everywhere | a path that writes outside the destination |
| The package is written in one piece | everywhere | a target that is half a package after a crash |
| The checksum is computed twice | in every checker | a fault in the machine that computes it |
| The signature of the host | next to the package | a package that was rewritten from top to bottom |
# The host signs the package with its secret key.
lunapack sign myapp.appkg --secret-key host.key --output myapp.appkg.sig
# Whoever holds the public key checks the signature.
lunapack verify myapp.appkg --signature myapp.appkg.sig --public-key host.publunapack verify myapp.appkg --expected-sha256 <the digest the host published>lunapack-public-key v1
x25519 751d2616ba1be8341b35f6cf2d73978e2cccecd1decd0f898b421a99618bc35f
ed25519 a8414c851959a5449aad50fe53b9d976028fd3122248cf87331bd0e0a8ea526e| Method | What it does |
|---|---|
| none | store the files as they are |
| gzip | gzip every entry |
| lz4 | LZ4 every entry |
| auto | gzip every entry, but keep the raw bytes when gzip would make the entry bigger (the default) |
| gzip | LZ4 | |
|---|---|---|
| packing | 39 s | 16 s |
| unpacking | 21 s | 19 s |
| size of the package | 139 MB | 175 MB |
| Method | What it does |
|---|---|
| x25519 | the package is sealed to the owner of a public key; only the owner of the secret key can open it |
| passphrase | the package is sealed with a passphrase |
# Make a pair of keys. The public key goes to the machine that seals the
# packages, the secret key to the machine that opens them.
lunapack keygen --public-key recipient.pub --secret-key recipient.key
# Seal a package to the owner of the public key.
lunapack pack -i ./app -o app.appkg \
--encryption-method x25519 --public-key recipient.pub
# Open it again with the secret key.
lunapack unpack -i app.appkg -o ./out --secret-key recipient.key
# Or with a passphrase.
lunapack pack -i ./app -o app.appkg \
--encryption-method passphrase --passphrase-file passphrase.txt
lunapack unpack -i app.appkg -o ./out --passphrase-file passphrase.txtlunapack-public-key v1
x25519 751d2616ba1be8341b35f6cf2d73978e2cccecd1decd0f898b421a99618bc35f
ed25519 a8414c851959a5449aad50fe53b9d976028fd3122248cf87331bd0e0a8ea526elunapack keygen --public-key recipient.pub --secret-key recipient.key \
--passphrase-file passphrase.txt| Extension | Target platform |
|---|---|
| .cmd, .bat, .ps1 | windows |
| .sh | posix (Linux + macOS) |
| anything else | any |
moonx riantr/LunaPack@latest \
--input-exe=[input-exe-path] \
--output-exe=[output-exe-path] \
--Files=[Pack-Folder]| Flag | Meaning |
|---|---|
| --input-exe | the application executable to distribute |
| --output-exe | the produced single-file bundle |
| --Files | folder of files to bundle with it (repeatable) |
moonx riantr/LunaPack@latest \
--input-file="x64/Release/App.exe" \
--output-file="App.exe" \
--Files="x64/Release"lunapack pack -i <input_dir> -o <output.appkg> [options]
lunapack bundle -i <exe> -o <output.exe> [--Files <dir>]... [options]
lunapack unpack -i <package> -o <dest_dir> [--skip-scripts]
lunapack verify <package> [--extracted <dir>]
lunapack sign <package> --secret-key <file> [--output <file>]
lunapack info <package>
lunapack keygen --public-key <file> --secret-key <file>lunapack verify myapp.exe --extracted .lunapack\b7e21c9f4d0a8356lunapack sign myapp.appkg --secret-key host.key --output myapp.appkg.siglunapack-signature v1
algorithm ed25519
package 0f2a... <- the SHA-256 of the package
manifest 8c41... <- the SHA-256 of the manifest
signature 3b90... <- the Ed25519 signature of the twoverify: OK (392 files)
verify: OK (392 files in .lunapack/b7e21c9f4d0a8356)
VERIFY OKverify: OK (392 files)
verify: md5 mismatch for appsettings.json: expected 86ff00ef... got 3ddcb685...
verify: FAILED (392 files checked)
VERIFY FAILEDmoon build --release
# -> _build/native/release/build/LunaPack.exe (every platform)| Option | Meaning |
|---|---|
| --input-file <path> | another name for --input-exe |
| --output-file <path> | another name for --output-exe |
| --name <name> | package name (default: input dir / exe name) |
| --version <ver> | package version (default: 0.1.0) |
| --os <os> | target OS tag (default: detected) |
| --arch <arch> | target arch tag (default: detected) |
| --pre-install <file> | script executed before extraction |
| --post-install <file> | script executed after extraction |
| --compression-method <m> | none, gzip, lz4 or auto (default: auto) |
| --launcher <file> | the launcher of the single file (default: this one) |
| --encryption-method <m> | x25519 or passphrase (default: none) |
| --public-key <file> | the public key of the recipient, or of the host that signed the package |
| --secret-key <file> | the secret key of the recipient |
| --passphrase-file <file> | the file that holds the passphrase |
| --passphrase <text> | the passphrase itself (visible in the process list) |
| --skip-scripts | unpack without running the install scripts |
| --extracted <dir> | with verify: also check the files already in <dir> |
| --signature <file> | with verify or unpack: the signature the host published |
| --expected-sha256 <hex> | with verify or unpack: the digest the host published |
| --output <file> | with sign: where the signature is written |
# Bundle an application and its resources into one self-extracting file.
lunapack --input-exe=./build/myapp \
--output-exe=./dist/myapp \
--Files=./build
# Or produce a plain archive instead.
lunapack pack -i ./myapp -o myapp.appkg \
--name myapp --version 1.4.0 \
--pre-install setup.sh --post-install setup.sh
lunapack verify myapp.appkg
lunapack unpack -i myapp.appkg -o /opt/myapp md5 6f5902ac237024bdd0c176cb93063dc4 a.txt
md5 3db2050fcf84bb631dcae417d3db518c sub/b.txt
scanned 2 files
packed 2 files -> myapp.appkg
output md5 63da650c906fe3ab1446b121a4edd4ca myapp.appkgunpacked 2 files -> /opt/myapp
md5 6f5902ac237024bdd0c176cb93063dc4 a.txt
md5 3db2050fcf84bb631dcae417d3db518c sub/b.txt
verified 2 files, 0 mismatcheslunapack ^
--input-exe="D:/src/App/bin/Release/net10.0-windows/App.exe" ^
--output-exe="D:/dist/App.exe" ^
--Files="D:/src/App/bin/Release/net10.0-windows"| Gate | What it checks |
|---|---|
| moon fmt --check | that the source is formatted the way the toolchain formats it |
| moon check --target native / --target wasm | that the module type-checks on both backends it claims |
| moon test --target native | the format, the compression, the encryption, the primitives |
| moon build --release --target native / --target wasm | that the binary and the WebAssembly module are produced |
| moon info + git diff --exit-code -- '*.mbti' | that the published interface is not stale |
| bash scripts/test_linux.sh | the round trip the unit tests do not cover |
| Guard that was removed | The test that went red |
|---|---|
| the SHA-256 of the manifest | a package whose manifest was changed is refused |
| the MAC of the manifest | a sealed package whose manifest was changed is refused |
| the check of the cache | the cache is only used again when it holds what the package carries |
| the check of the program | the program of a bundle is checked before it is started |
| the refusal of a damaged package | a damaged package is not taken for a file that is not a package |
| the write in one piece | a pack that fails leaves the target alone |
| the comparison of the two checksums | a checksum that is not the same twice is refused |
| the check of the signature | a signature does not hold for another public key |
| the check of the paths | a path that walks out of the destination is refused |
| the signing key of a pair | the signing key of a pair checks a signature made with it |
| the separation of the two roles | the two roles of a pair are separated |
moon add riantr/LunaPacklunapack bundle -i ./build/myapp -o ./dist/myapp --Files ./build
./dist/myapp --versionlunapack pack -i ./myapp -o myapp.appkg
lunapack verify myapp.appkg
lunapack unpack -i myapp.appkg -o /opt/myappmoon test # 127 tests
moon build --release --target native # the binary
moon build --release --target wasm # the WebAssembly module///|
async fn main {
// A plain archive: a directory, compressed per entry, checksummed per entry.
let opts = @lp.new_pack_options(
"myapp", // the name of the package
"1.4.0", // the version of the package
"linux", // the os tag
"x86_64", // the arch tag
None, // the pre-install script
None, // the post-install script
"auto", // the compression
)
@lp.pack("./myapp", "myapp.appkg", opts)
// The same application as a single self-extracting file. The launcher is the
// running program itself, and the main program is recorded by the bundle.
@lp.bundle("./build/myapp", "./dist/myapp", ["./build"], opts, "")
// Read the manifest back, and check the package.
let m = @lp.read_package_manifest("myapp.appkg")
let ok = @lp.verify("myapp.appkg", None)
@lp.unpack("myapp.appkg", "/opt/myapp", true, None)
}///|
async fn main {
match @lp.probe_archive("./dist/myapp") {
Some((offset, manifest)) => {
println("the archive starts at " + offset.to_string())
println("it holds " + manifest.entries.length().to_string() + " entries")
}
None => println("this file carries no LunaPack archive")
}
}///|
async fn main {
let m = @lp.read_package_manifest("secret.appkg")
match m.encryption {
Some(info) => {
let key = @lp.recover_encryption(info, "recipient.key", "")
@lp.unpack("secret.appkg", "./out", true, Some(key))
}
None => ()
}
}| Gate | Catches |
|---|---|
| moon fmt --check | a source file that is not formatted the way the toolchain formats it — a diff the next contributor would have to make |
| moon check --target native / --target wasm | a package that does not type-check on one of the two backends it claims to support |
| moon test --target native | a change in the format, the compression, the encryption or one of the primitives — every one of them is checked against a vector or against the reference implementation |
| moon info + git diff --exit-code -- '*.mbti' | a published interface that is stale: a symbol changed and the .mbti was not regenerated |
| bash scripts/test_linux.sh | a round trip the unit tests do not cover — the install scripts, the permission bits, the corruption detection, the bundle as a byte-identical round trip |
| the tag check of the release workflow | a tag that disagrees with the version in moon.mod, which would publish a module that is not the tree it was cut from |
pub struct Encryption {
method_name : String
recipient : String
ephemeral : String
salt : String
iterations : Int
key_check : String
}pub struct EncryptionOptions {
method_name : String
public_key : String
passphrase : String
iterations : Int
}pub struct Entry {
path : String
mode : Int
size : Int64
stored_size : Int64
codec : String
checksum : String
md5 : String
offset : Int64
}pub struct Manifest {
format_version : Int
name : String
version : String
os : String
arch : String
checksum_algo : String
compression : String
created_at : String
main_program : String
pre_install : Script?
post_install : Script?
encryption : Encryption?
entries : Array[Entry]
}pub struct PackOptions {
name : String
version : String
os : String
arch : String
pre_install : Script?
post_install : Script?
compression : String
main_program : String
encryption : EncryptionOptions?
}pub struct PackageKey {
master : Bytes
salt : Bytes
}pub struct PackageSignature {
package_digest : String
manifest_digest : String
signature : String
}pub struct PeFile {
data : Bytes
sections : Array[(Int64, Int64, Int64, Int64)]
resource_rva : Int64
resource_size : Int64
}pub struct Poly1305 {
r0 : UInt64
r1 : UInt64
r2 : UInt64
r3 : UInt64
r4 : UInt64
s0 : UInt64
s1 : UInt64
s2 : UInt64
s3 : UInt64
h0 : UInt64
h1 : UInt64
h2 : UInt64
h3 : UInt64
h4 : UInt64
buffer : Array[Byte]
}pub struct PublicKeyPair {
encryption : Bytes
signing : Bytes
}pub struct Script {
platform : String
body : String
}pub struct SealedPackage {
shared : Bytes
ephemeral : Bytes
recipient : Bytes
salt : Bytes
}let FORMAT_VERSION : Intlet GZIP_LEVEL : Intlet INTEGRITY_BLOCK_BYTES : Intlet INTEGRITY_BLOCK_BYTES_ENCRYPTED : Intlet INTEGRITY_DIGEST_BYTES : Intlet INTEGRITY_MAC_BYTES : Intlet INTEGRITY_MARKER : Stringlet INTEGRITY_MARKER_BYTES : Intlet INTEGRITY_MARKER_ENCRYPTED : Stringlet KEY_HEADER_BYTES : Intlet KEY_SALT_BYTES : Intlet MAGIC : Stringlet METHOD_PASSPHRASE : Stringlet METHOD_X25519 : Stringlet PASSPHRASE_ITERATIONS : Intlet PE_SUBSYSTEM_OFFSET : Int64let PUBLIC_KEY_ENCRYPTION : Stringlet PUBLIC_KEY_SIGNING : Stringasync fn bundle(input_exe : String, output_exe : String, file_dirs : Array[String], opts : PackOptions, launcher : String) -> Unitfn bytes_concat(a : Bytes, b : Bytes) -> Bytesfn chacha20_xor(key : Bytes, nonce : Bytes, counter : UInt, data : BytesView) -> Bytesfn chacha20poly1305_open(key : Bytes, nonce : Bytes, sealed_data : BytesView, aad : BytesView) -> Bytes?fn chacha20poly1305_seal(key : Bytes, nonce : Bytes, plaintext : BytesView, aad : BytesView) -> Bytesfn compress_with(data : Bytes, codec_name : String) -> (Bytes, String)fn compute_key_check(shared : Bytes, recipient : Bytes, ephemeral : Bytes, salt : Bytes) -> Bytesasync fn copy_icon(source_exe : String, target_exe : String) -> Boolfn current_exe_path() -> String?fn default_arch() -> Stringfn dirname(p : String) -> Stringfn ed25519_public_key(secret : Bytes) -> Bytes raisefn ed25519_seed(secret : Bytes) -> Bytesfn ed25519_sign(secret : Bytes, message : Bytes) -> Bytes raisefn ed25519_verify(public : Bytes, message : Bytes, signature : Bytes) -> Bool raiseasync fn ensure_parent_dir(path : String) -> Unitasync fn file_md5_hex(path : String) -> Stringfn gzip_decompress(data : Bytes) -> Bytesfn hex_to_bytes(text : String) -> Bytes?fn hkdf_expand_sha512(prk : Bytes, info : Bytes, length : Int) -> Bytesfn hkdf_extract_sha512(salt : Bytes, ikm : Bytes) -> Bytesfn hkdf_sha512(ikm : Bytes, salt : Bytes, info : Bytes, length : Int) -> Bytesfn hmac_sha512(key : Bytes, data : Bytes) -> Bytesfn host_platform() -> Stringfn i64_to_le8(v : Int64) -> Bytesfn integrity_block(moff : Int64, mlen : Int64, mbytes : Bytes) -> Bytes raisefn integrity_block_encrypted(key : PackageKey, moff : Int64, mlen : Int64, mbytes : Bytes) -> Bytes raisefn is_all_zero(data : Bytes) -> Boolfn is_integrity_block(block : Bytes) -> Boolfn is_integrity_block_encrypted(block : Bytes) -> Boolfn is_native_target() -> Boolasync fn is_protected_key_file(path : String) -> Boolfn iso8601_utc(epoch_millis : UInt64) -> Stringfn le8_to_i64(b : Bytes, start : Int) -> Int64async fn load_public_key(path : String) -> Bytesasync fn load_secret_key(path : String, passphrase : String) -> Bytesasync fn load_signing_public_key(path : String) -> Bytesfn lz4_compress_frame(data : Bytes) -> Bytesfn lz4_decompress_frame(src : Bytes, size : Int) -> Bytesfn magic_bytes() -> Bytesfn manifest_digest(moff : Int64, mlen : Int64, mbytes : Bytes) -> Bytes raisefn md5_hex_of_string(s : String) -> Stringfn new_encryption(method_name : String, recipient : String, ephemeral : String, salt : String, iterations : Int, key_check : String) -> Encryptionfn new_encryption_options(method_name : String, public_key : String, passphrase : String, iterations : Int) -> EncryptionOptionsfn new_pack_options(name : String, version : String, os : String, arch : String, pre_install : Script?, post_install : Script?, compression : String) -> PackOptionsfn new_package_signature(package_digest : String, manifest_digest : String, signature : String) -> PackageSignaturefn new_sealed_package(shared : Bytes, ephemeral : Bytes, recipient : Bytes, salt : Bytes) -> SealedPackagefn norm_sep(p : String) -> Stringasync fn package_manifest_digest(pkg : String) -> Stringfn package_tag_of(text : String) -> Stringfn passphrase_secret(passphrase : String, salt : Bytes, iterations : Int) -> Bytesfn pbkdf2_sha512(password : Bytes, salt : Bytes, iterations : Int, length : Int) -> Bytesfn pe_subsystem(data : Bytes) -> Intasync fn pe_subsystem_of(path : String) -> Intfn poly1305(key : Bytes, data : BytesView) -> Bytesasync fn recover_encryption(info : Encryption, secret_key : String, passphrase : String) -> PackageKeyfn redundant_md5(data : Bytes) -> String raisefn redundant_sha256(data : Bytes) -> String raiseasync fn remove_dir(path : String) -> Unitfn report_md5(path : String, digest : String) -> Unitasync fn report_output_md5(path : String) -> Unitasync fn run_install_script(platform : String, kind : String, script : Script, dest : String) -> Intasync fn save_public_key(path : String, public_key : Bytes) -> Unitasync fn save_public_key_pair(path : String, encryption : Bytes, signing : Bytes) -> Unitasync fn save_secret_key(path : String, secret_key : Bytes, passphrase : String) -> Unitasync fn save_secret_key_raw(path : String, secret_key : Bytes) -> Unitfn script_applies(script_platform : String, host : String) -> Boolfn script_file_name(platform : String, kind : String) -> Stringfn script_platform_of(path : String) -> Stringasync fn set_pe_subsystem(path : String, subsystem : Int) -> Boolasync fn set_permissions(platform : String, path : String, mode : Int) -> Unitfn sha256_hex(data : Bytes) -> Stringfn sha256_hex_of_string(s : String) -> Stringfn sha512_hex(data : Bytes) -> Stringfn shared_with_secret_key(secret : Bytes, ephemeral : Bytes) -> Bytesfn string_to_utf8_bytes(s : String) -> Bytesfn truncate_bytes(data : Bytes, count : Int) -> Bytesasync fn try_launch_self_extracting() -> Boolfn utf8_bytes_to_string(bs : Bytes) -> Stringasync fn verify_extracted_dir(pkg : String, dir : String) -> Boolasync fn verify_package_digest(path : String, expected : String) -> Boolfn with_defaults(opts : PackOptions, name : String, version : String, os : String, arch : String) -> PackOptionsfn x25519(scalar : Bytes, point : Bytes) -> Bytesfn x25519_public_key(scalar : Bytes) -> Bytesfn xxhash32(data : Bytes, start : Int, end : Int, seed : UInt) -> UInt