.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "Crypt::PK::Ed448 3" .TH Crypt::PK::Ed448 3 2026-05-12 "perl v5.42.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Crypt::PK::Ed448 \- Digital signature based on Ed448 .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use Crypt::PK::Ed448; \& \& my $message = \*(Aqhello world\*(Aq; \& my $signer = Crypt::PK::Ed448\->new\->generate_key; \& my $signature = $signer\->sign_message($message); \& \& my $public_der = $signer\->export_key_der(\*(Aqpublic\*(Aq); \& my $verifier = Crypt::PK::Ed448\->new(\e$public_der); \& $verifier\->verify_message($signature, $message) or die "ERROR"; \& \& my $pk = Crypt::PK::Ed448\->new; \& $pk\->import_key_raw( \& pack("H*", "1b0055aad3b239a0fa1ed1ea8023151a5791d0bb556435299da6cf1aaa272d858b0238822654bc15f64adbab97f1bb9ec848d72cd8ad856800"), \& "public", \& ); \& \& my $sk = Crypt::PK::Ed448\->new; \& $sk\->import_key_raw( \& pack("H*", "f82bd65291965de46d87c7447863924e8efb8da36993618a784cd3b69a6d66e61cdc0a48a31e66bd8e81e4d77cedc311aa0f72a322ef3e4fad"), \& "private", \& ); .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" \&\fISince: CryptX\-0.089\fR .SH METHODS .IX Header "METHODS" .SS new .IX Subsection "new" .Vb 2 \& my $source = Crypt::PK::Ed448\->new(); \& $source\->generate_key; \& \& my $public_der = $source\->export_key_der(\*(Aqpublic\*(Aq); \& my $pub = Crypt::PK::Ed448\->new(\e$public_der); \& \& my $private_pem = $source\->export_key_pem(\*(Aqprivate\*(Aq, \*(Aqsecret\*(Aq, \*(AqAES\-256\-CBC\*(Aq); \& my $priv = Crypt::PK::Ed448\->new(\e$private_pem, \*(Aqsecret\*(Aq); .Ve .PP Passing \f(CW$filename\fR or \f(CW\*(C`\e$buffer\*(C'\fR to \f(CW\*(C`new\*(C'\fR is equivalent: both forms immediately import the key material into the new object. .SS generate_key .IX Subsection "generate_key" Returns the object itself (for chaining). .PP .Vb 1 \& $pk\->generate_key; .Ve .SS import_key .IX Subsection "import_key" Loads Ed448 private or public keys from DER, PEM, PKCS#8, X.509 certificates, SubjectPublicKeyInfo, or JWK. .PP .Vb 2 \& my $source = Crypt::PK::Ed448\->new(); \& $source\->generate_key; \& \& my $public_der = $source\->export_key_der(\*(Aqpublic\*(Aq); \& my $pub = Crypt::PK::Ed448\->new(); \& $pub\->import_key(\e$public_der); \& my $private_pem = $source\->export_key_pem(\*(Aqprivate\*(Aq, \*(Aqsecret\*(Aq, \*(AqAES\-256\-CBC\*(Aq); \& my $priv = Crypt::PK::Ed448\->new(); \& $priv\->import_key(\e$private_pem, \*(Aqsecret\*(Aq); \& $pk\->import_key({ \& curve => "ed448", \& pub => "1B0055AAD3B239A0FA1ED1EA8023151A5791D0BB556435299DA6CF1AAA272D858B0238822654BC15F64ADBAB97F1BB9EC848D72CD8AD856800", \& priv => "F82BD65291965DE46D87C7447863924E8EFB8DA36993618A784CD3B69A6D66E61CDC0A48A31E66BD8E81E4D77CEDC311AA0F72A322EF3E4FAD", \& }); \& $pk\->import_key({ \& kty => "OKP", \& crv => "Ed448", \& d => "\-CvWUpGWXeRth8dEeGOSTo77jaNpk2GKeEzTtpptZuYc3ApIox5mvY6B5Nd87cMRqg9yoyLvPk\-t", \& x => "GwBVqtOyOaD6HtHqgCMVGleR0LtVZDUpnabPGqonLYWLAjiCJlS8FfZK26uX8bueyEjXLNithWgA", \& }); .Ve .PP The same method also accepts filenames instead of buffers. .SS import_key_raw .IX Subsection "import_key_raw" Import raw public/private key bytes. .PP .Vb 2 \& $pk\->import_key_raw($key, \*(Aqpublic\*(Aq); \& $pk\->import_key_raw($key, \*(Aqprivate\*(Aq); .Ve .PP The raw key must be exactly 57 bytes long. .SS export_key_der .IX Subsection "export_key_der" Returns the key as a binary DER\-encoded string. .PP .Vb 2 \& my $der = $pk\->export_key_der(\*(Aqprivate\*(Aq); \& my $der = $pk\->export_key_der(\*(Aqpublic\*(Aq); .Ve .SS export_key_pem .IX Subsection "export_key_pem" Returns the key as a PEM\-encoded string (ASCII). .PP .Vb 3 \& my $pem = $pk\->export_key_pem(\*(Aqprivate\*(Aq); \& my $pem = $pk\->export_key_pem(\*(Aqpublic\*(Aq); \& my $pem = $pk\->export_key_pem(\*(Aqprivate\*(Aq, $password, \*(AqAES\-256\-CBC\*(Aq); .Ve .SS export_key_jwk .IX Subsection "export_key_jwk" Returns a JSON string, or a hashref if the optional second argument is true. .PP .Vb 2 \& my $json = $pk\->export_key_jwk(\*(Aqprivate\*(Aq); \& my $hash = $pk\->export_key_jwk(\*(Aqpublic\*(Aq, 1); .Ve .SS export_key_raw .IX Subsection "export_key_raw" Returns the raw key as a binary string. .PP .Vb 2 \& my $raw = $pk\->export_key_raw(\*(Aqprivate\*(Aq); \& my $raw = $pk\->export_key_raw(\*(Aqpublic\*(Aq); .Ve .SS sign_message .IX Subsection "sign_message" Returns the signature as a binary string. Ed448 uses a fixed hash internally (SHAKE256); unlike RSA or ECDSA there is no \f(CW$hash_name\fR parameter. .PP .Vb 1 \& my $signature = $priv\->sign_message($message); .Ve .SS verify_message .IX Subsection "verify_message" Returns \f(CW1\fR if the signature is valid, \f(CW0\fR otherwise. .PP .Vb 1 \& my $valid = $pub\->verify_message($signature, $message); .Ve .SS sign_message_ctx .IX Subsection "sign_message_ctx" Signs a message using Ed448ctx (RFC 8032 Section 5.2), which includes a mandatory context string (at most 255 bytes). The context string makes the signature domain\-separated: the same key signing the same message with a different context produces a different (and incompatible) signature. .PP \&\fBNote:\fR In contrast to Ed25519, plain Ed448 ("sign_message") is formally defined with an empty context string, so Ed448 and Ed448ctx with an empty context produce the same signature. .PP .Vb 1 \& my $signature = $priv\->sign_message_ctx($message, $context); .Ve .SS verify_message_ctx .IX Subsection "verify_message_ctx" Verifies a signature produced by "sign_message_ctx". .PP .Vb 1 \& my $valid = $pub\->verify_message_ctx($signature, $message, $context); .Ve .SS sign_message_ph .IX Subsection "sign_message_ph" Signs a message using Ed448ph (RFC 8032 Section 5.2), the "pre\-hashed" variant. The message is first hashed with SHAKE256 internally before signing. This is useful when signing very large messages or when only a hash of the message is available. An optional context string (at most 255 bytes) can be provided; it defaults to the empty string if omitted. .PP .Vb 2 \& my $signature = $priv\->sign_message_ph($message); \& my $signature = $priv\->sign_message_ph($message, $context); .Ve .SS verify_message_ph .IX Subsection "verify_message_ph" Verifies a signature produced by "sign_message_ph". .PP .Vb 2 \& my $valid = $pub\->verify_message_ph($signature, $message); \& my $valid = $pub\->verify_message_ph($signature, $message, $context); .Ve .SS is_private .IX Subsection "is_private" .Vb 1 \& my $rv = $pk\->is_private; .Ve .SS key2hash .IX Subsection "key2hash" Returns a hashref with the key components, or \f(CW\*(C`undef\*(C'\fR if no key is loaded. .PP .Vb 1 \& my $hash = $pk\->key2hash; .Ve .PP Returns a hash like: .PP .Vb 5 \& { \& curve => "ed448", \& pub => "1B0055AAD3B239A0FA1ED1EA8023151A5791D0BB556435299DA6CF1AAA272D858B0238822654BC15F64ADBAB97F1BB9EC848D72CD8AD856800", \& priv => "F82BD65291965DE46D87C7447863924E8EFB8DA36993618A784CD3B69A6D66E61CDC0A48A31E66BD8E81E4D77CEDC311AA0F72A322EF3E4FAD", \& } .Ve .SH "OpenSSL interoperability" .IX Header "OpenSSL interoperability" .Vb 3 \& # Generate a key with OpenSSL \& # openssl genpkey \-algorithm ed448 \-out ed448_priv.pem \& # openssl pkey \-in ed448_priv.pem \-pubout \-out ed448_pub.pem \& \& # Load the OpenSSL\-generated key in CryptX \& use Crypt::PK::Ed448; \& my $priv = Crypt::PK::Ed448\->new("ed448_priv.pem"); \& my $pub = Crypt::PK::Ed448\->new("ed448_pub.pem"); \& \& # Sign in CryptX, verify with OpenSSL \& my $message = "hello"; \& my $signature = $priv\->sign_message($message); \& \& # Export CryptX key for OpenSSL \& my $pem = $priv\->export_key_pem(\*(Aqprivate\*(Aq); \& # then: openssl pkey \-in priv.pem \-text \-noout .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" .IP \(bu 4 .IP \(bu 4 Crypt::PK::Ed25519