Password hashing and verification for Gleam using external programs instead of native code building.
  • Gleam 96.4%
  • JavaScript 1.9%
  • Shell 0.9%
  • Erlang 0.8%
Find a file
2025-09-12 22:18:35 +03:00
priv Initial commit 2025-09-12 22:18:35 +03:00
src Initial commit 2025-09-12 22:18:35 +03:00
test Initial commit 2025-09-12 22:18:35 +03:00
.gitignore Initial commit 2025-09-12 22:18:35 +03:00
gleam.toml Initial commit 2025-09-12 22:18:35 +03:00
manifest.toml Initial commit 2025-09-12 22:18:35 +03:00
README.md Initial commit 2025-09-12 22:18:35 +03:00

Portomir

Package Version Hex Docs

Password hashing and verification for Gleam using external programs instead of native code building.

The only supported algorithm right now is argon2. See its page for further installation instructions.

Supports both Erlang and JavaScript targets.

gleam add portomir@1
import portomir/argon2

pub fn main() -> Nil {
  let hasher = argon2.init()

  let settings =
    argon2.Settings(
      version: 19,
      variant: argon2.Id,
      iterations: 15,
      memory_cost: 2048,
      parallelism: 4,
    )

  let salt = argon2.gen_salt()
  let password = "..."

  // Hashing
  echo argon2.hash(hasher, password, salt, settings)

  // Outputs something like
  // $argon2id$v=19$m=2048,t=15,p=4$c29tZXN1cGVybG9uZ3NhbHQ$O3hAW5NET9B1mj0pK2S+rqOJeeAP4gSgSLWJhpjp5K8


  // Parsing existing hashes to get the settings used to create them
  echo argon2.parse("$argon2id$v=19$m=4096,t=10,p=2$MTIzNDU2Nzg5MHNhbHRpbmVjcmFja2Vycw$iA+BvAMNqAKjV/qIbmbcbEkBC0rho9xTtI1IJwrAf08")

  // Outputs something like
  // Ok(Settings("1234567890saltinecrackers", 19, Id, 10, 4096, 2))


  // Verifying passwords against existing hashes
  echo argon2.verify(hasher, password, "$argon2id$v=19$m=2048,t=15,p=4$...")

  // Results in Ok(Nil) for a successful verification
}

Justification

There are already several libraries for password hashing in Gleam, for both Argon2 and bcrypt, so why this library?

The existing libraries rely on building Native Implemented Functions (NIFs) to do the actual hashing operations. This allows running such performance intensive code, which Erlang itself would not be suited for. However, it comes with some downsides:

  • Such a built release is no longer portable across systems, as it depends on the CPU architecture and possibly dynamically linked system libraries.
  • Building the release requires the installation of various build tooling.
  • If a NIF crashes, it takes down the whole Erlang VM. Although this is unlikely with well tested and widely used packages.
  • Due to the usage of NIFs, the current libraries only support the Erlang target.

Since Argon2 is also available as a command line program, instead of building native code, we can use that. It allows us to avoid the downsides listed above, but it does come with some of its own tradeoffs:

  • Running a command line program is going to be slower and probably use more memory. It has not been measured yet at which point this will become an issue.
  • A one-liner shell script is needed between Gleam and the program, since Erlang is unable to send EOF to the called program.

If the downsides of the NIF approach listed above are not issues for you, then you should probably look at those libraries.

Etymology

One of the Argon2 libraries is called Aragorn2, so Globerto suggested the name Portomir as a pun on Boromir.