-module(kryptos@ec). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/kryptos/ec.gleam"). -export([coordinate_size/1, generate_key_pair/1, from_pem/1, from_der/1, to_pem/1, to_der/1, public_key_from_pem/1, public_key_from_der/1, public_key_from_raw_point/2, public_key_to_raw_point/1, public_key_to_pem/1, public_key_to_der/1, public_key_from_private_key/1, curve/1, public_key_curve/1, to_bytes/1, from_bytes/2]). -export_type([private_key/0, public_key/0, curve/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( " Elliptic Curve Cryptography key generation and management.\n" "\n" " This module provides key pair generation for elliptic curve cryptography,\n" " supporting standard NIST curves and secp256k1. EC keys can be used for\n" " both ECDSA signatures and ECDH key agreement.\n" "\n" " ## Key Generation\n" "\n" " ```gleam\n" " import kryptos/ec\n" "\n" " let #(private_key, public_key) = ec.generate_key_pair(ec.P256)\n" " ```\n" "\n" " ## Import/Export\n" "\n" " ```gleam\n" " import kryptos/ec\n" "\n" " let #(private_key, _public_key) = ec.generate_key_pair(ec.P256)\n" " let assert Ok(pem) = ec.to_pem(private_key)\n" " let assert Ok(#(imported_private, _)) = ec.from_pem(pem)\n" " ```\n" ). -type private_key() :: any(). -type public_key() :: any(). -type curve() :: p256 | p384 | p521 | secp256k1. -file("src/kryptos/ec.gleam", 56). ?DOC( " Returns the coordinate size in bytes for the given curve.\n" "\n" " This is the size of each coordinate (x or y) in an EC point.\n" "\n" " ## Parameters\n" " - `curve`: The elliptic curve\n" "\n" " ## Returns\n" " The coordinate size in bytes (32 for P256/Secp256k1, 48 for P384,\n" " 66 for P521).\n" ). -spec coordinate_size(curve()) -> integer(). coordinate_size(Curve) -> case Curve of p256 -> 32; secp256k1 -> 32; p384 -> 48; p521 -> 66 end. -file("src/kryptos/ec.gleam", 76). ?DOC( " Generates a new elliptic curve key pair.\n" "\n" " The private key should be kept secret and used for signing or ECDH key agreement.\n" " The public key can be shared and is used for signature verification or ECDH key agreement.\n" "\n" " ## Parameters\n" " - `curve`: The elliptic curve to use for key generation\n" "\n" " ## Returns\n" " A tuple of `#(private_key, public_key)`.\n" ). -spec generate_key_pair(curve()) -> {private_key(), public_key()}. generate_key_pair(Curve) -> kryptos_ffi:ec_generate_key_pair(Curve). -file("src/kryptos/ec.gleam", 89). ?DOC( " Imports an EC private key from PEM-encoded data.\n" "\n" " The key must be in PKCS#8 format.\n" "\n" " ## Parameters\n" " - `pem`: PEM-encoded key string\n" "\n" " ## Returns\n" " `Ok(#(private_key, public_key))` on success, `Error(Nil)` on failure.\n" ). -spec from_pem(binary()) -> {ok, {private_key(), public_key()}} | {error, nil}. from_pem(Pem) -> kryptos_ffi:ec_import_private_key_pem(Pem). -file("src/kryptos/ec.gleam", 102). ?DOC( " Imports an EC private key from DER-encoded data.\n" "\n" " The key must be in PKCS#8 format.\n" "\n" " ## Parameters\n" " - `der`: DER-encoded key data\n" "\n" " ## Returns\n" " `Ok(#(private_key, public_key))` on success, `Error(Nil)` on failure.\n" ). -spec from_der(bitstring()) -> {ok, {private_key(), public_key()}} | {error, nil}. from_der(Der) -> kryptos_ffi:ec_import_private_key_der(Der). -file("src/kryptos/ec.gleam", 113). ?DOC( " Exports an EC private key to PEM format.\n" "\n" " The key is exported in PKCS#8 format.\n" "\n" " ## Parameters\n" " - `key`: The private key to export\n" "\n" " ## Returns\n" " `Ok(pem_string)` on success, `Error(Nil)` on failure.\n" ). -spec to_pem(private_key()) -> {ok, binary()} | {error, nil}. to_pem(Key) -> _pipe = kryptos_ffi:ec_export_private_key_pem(Key), gleam@result:map( _pipe, fun(Pem) -> <<(gleam@string:trim_end(Pem))/binary, "\n"/utf8>> end ). -file("src/kryptos/ec.gleam", 132). ?DOC( " Exports an EC private key to DER format.\n" "\n" " The key is exported in PKCS#8 format.\n" "\n" " ## Parameters\n" " - `key`: The private key to export\n" "\n" " ## Returns\n" " `Ok(der_data)` on success, `Error(Nil)` on failure.\n" ). -spec to_der(private_key()) -> {ok, bitstring()} | {error, nil}. to_der(Key) -> kryptos_ffi:ec_export_private_key_der(Key). -file("src/kryptos/ec.gleam", 145). ?DOC( " Imports an EC public key from PEM-encoded data.\n" "\n" " The key must be in SPKI format.\n" "\n" " ## Parameters\n" " - `pem`: PEM-encoded key string\n" "\n" " ## Returns\n" " `Ok(public_key)` on success, `Error(Nil)` on failure.\n" ). -spec public_key_from_pem(binary()) -> {ok, public_key()} | {error, nil}. public_key_from_pem(Pem) -> kryptos_ffi:ec_import_public_key_pem(Pem). -file("src/kryptos/ec.gleam", 158). ?DOC( " Imports an EC public key from DER-encoded data.\n" "\n" " The key must be in SPKI format.\n" "\n" " ## Parameters\n" " - `der`: DER-encoded key data\n" "\n" " ## Returns\n" " `Ok(public_key)` on success, `Error(Nil)` on failure.\n" ). -spec public_key_from_der(bitstring()) -> {ok, public_key()} | {error, nil}. public_key_from_der(Der) -> kryptos_ffi:ec_import_public_key_der(Der). -file("src/kryptos/ec.gleam", 184). ?DOC( " Imports an EC public key from an uncompressed SEC1 point.\n" "\n" " The point must be in uncompressed format: `0x04 || x || y`\n" " where x and y are the coordinates padded to the curve's coordinate size.\n" "\n" " ## Parameters\n" " - `curve`: The elliptic curve (P256, P384, P521, or Secp256k1)\n" " - `point`: The uncompressed point bytes (1 + 2 * coordinate_size bytes)\n" "\n" " ## Returns\n" " `Ok(public_key)` on success, `Error(Nil)` if the format is invalid\n" " or the point is not on the curve.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import kryptos/ec\n" "\n" " let #(_private_key, public_key) = ec.generate_key_pair(ec.P256)\n" " let point = ec.public_key_to_raw_point(public_key)\n" " let assert Ok(imported) = ec.public_key_from_raw_point(ec.P256, point)\n" " ```\n" ). -spec public_key_from_raw_point(curve(), bitstring()) -> {ok, public_key()} | {error, nil}. public_key_from_raw_point(Curve, Point) -> kryptos_ffi:ec_public_key_from_raw_point(Curve, Point). -file("src/kryptos/ec.gleam", 201). ?DOC( " Exports a public key to uncompressed SEC1 point format.\n" "\n" " Returns a BitArray in the format: `0x04 || X || Y` where X and Y are\n" " the coordinates of the public key point, each padded to the curve's\n" " coordinate size.\n" "\n" " If the key was imported with a compressed point format, it will be\n" " automatically decompressed.\n" "\n" " This is the inverse of `public_key_from_raw_point`.\n" ). -spec public_key_to_raw_point(public_key()) -> bitstring(). public_key_to_raw_point(Key) -> kryptos_ffi:ec_public_key_to_raw_point(Key). -file("src/kryptos/ec.gleam", 212). ?DOC( " Exports an EC public key to PEM format.\n" "\n" " The key is exported in SPKI format.\n" "\n" " ## Parameters\n" " - `key`: The public key to export\n" "\n" " ## Returns\n" " `Ok(pem_string)` on success, `Error(Nil)` on failure.\n" ). -spec public_key_to_pem(public_key()) -> {ok, binary()} | {error, nil}. public_key_to_pem(Key) -> _pipe = kryptos_ffi:ec_export_public_key_pem(Key), gleam@result:map( _pipe, fun(Pem) -> <<(gleam@string:trim_end(Pem))/binary, "\n"/utf8>> end ). -file("src/kryptos/ec.gleam", 232). ?DOC( " Exports an EC public key to DER format.\n" "\n" " The key is exported in SPKI format.\n" "\n" " ## Parameters\n" " - `key`: The public key to export\n" "\n" " ## Returns\n" " `Ok(der_data)` on success, `Error(Nil)` on failure.\n" ). -spec public_key_to_der(public_key()) -> {ok, bitstring()} | {error, nil}. public_key_to_der(Key) -> kryptos_ffi:ec_export_public_key_der(Key). -file("src/kryptos/ec.gleam", 243). ?DOC( " Derives the public key from an EC private key.\n" "\n" " ## Parameters\n" " - `key`: The private key\n" "\n" " ## Returns\n" " The corresponding public key.\n" ). -spec public_key_from_private_key(private_key()) -> public_key(). public_key_from_private_key(Key) -> kryptos_ffi:ec_public_key_from_private(Key). -file("src/kryptos/ec.gleam", 254). ?DOC( " Returns the curve for an EC private key.\n" "\n" " ## Parameters\n" " - `key`: The private key\n" "\n" " ## Returns\n" " The curve used by this key.\n" ). -spec curve(private_key()) -> curve(). curve(Key) -> kryptos_ffi:ec_private_key_curve(Key). -file("src/kryptos/ec.gleam", 265). ?DOC( " Returns the curve for an EC public key.\n" "\n" " ## Parameters\n" " - `key`: The public key\n" "\n" " ## Returns\n" " The curve used by this key.\n" ). -spec public_key_curve(public_key()) -> curve(). public_key_curve(Key) -> kryptos_ffi:ec_public_key_curve(Key). -file("src/kryptos/ec.gleam", 288). ?DOC( " Exports an EC private key to raw scalar bytes.\n" "\n" " Returns the private scalar (the \"d\" value in JWK terminology) as\n" " big-endian bytes. The size matches the curve's coordinate size.\n" "\n" " ## Parameters\n" " - `key`: The private key to export\n" "\n" " ## Returns\n" " The raw private scalar bytes.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import kryptos/ec\n" "\n" " let #(private_key, _public_key) = ec.generate_key_pair(ec.P256)\n" " let scalar = ec.to_bytes(private_key)\n" " ```\n" ). -spec to_bytes(private_key()) -> bitstring(). to_bytes(Key) -> kryptos_ffi:ec_private_key_to_bytes(Key). -file("src/kryptos/ec.gleam", 314). ?DOC( " Imports an EC private key from raw scalar bytes.\n" "\n" " The scalar should be in big-endian format with size matching the\n" " curve's coordinate size (32 bytes for P256/Secp256k1, 48 for P384,\n" " 66 for P521).\n" "\n" " ## Parameters\n" " - `curve`: The elliptic curve\n" " - `private_bytes`: The raw private scalar bytes\n" "\n" " ## Returns\n" " `Ok(#(private_key, public_key))` on success, `Error(Nil)` if invalid.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import kryptos/ec\n" "\n" " let #(private_key, _public_key) = ec.generate_key_pair(ec.P256)\n" " let scalar = ec.to_bytes(private_key)\n" " let assert Ok(#(imported, _pub)) = ec.from_bytes(ec.P256, scalar)\n" " ```\n" ). -spec from_bytes(curve(), bitstring()) -> {ok, {private_key(), public_key()}} | {error, nil}. from_bytes(Curve, Private_bytes) -> kryptos_ffi:ec_private_key_from_bytes(Curve, Private_bytes).