CRYPTO_SIGN(3MONOCYPHER) | 3MONOCYPHER | CRYPTO_SIGN(3MONOCYPHER) |
crypto_sign
, crypto_check
,
crypto_sign_public_key
—
#include <monocypher.h>
void
crypto_sign_public_key
(uint8_t
public_key[32], const uint8_t
secret_key[32]);
void
crypto_sign
(uint8_t
signature[64], const uint8_t secret_key[32],
const uint8_t public_key[32], const
uint8_t *message, size_t message_size);
int
crypto_check
(const uint8_t
signature[64], const uint8_t public_key[32],
const uint8_t *message, size_t
message_size);
crypto_sign
() and crypto_check
()
provide EdDSA public key signatures and verification.
The arguments are:
crypto_sign_public_key
().signature and message may overlap.
crypto_sign_public_key
() computes the
public key of the specified secret key.
crypto_sign
() signs a message with
secret_key. The public key is optional and will be
recomputed if not provided. This recomputation doubles the execution
time.
crypto_check
() checks that a given
signature is genuine. Meaning, only someone who had the private key could
have signed the message. It does not run in constant time.
It does not have to in most threat models because nothing is secret:
everyone knows the public key, and the signature and message are rarely
secret. If the message needs to be secret, use a key exchange protocol
involving
crypto_x25519(3monocypher) and
then
crypto_lock_aead(3monocypher)
instead.
An incremental interface is available; see crypto_sign_init_first_pass(3monocypher).
crypto_sign_public_key
() and
crypto_sign
() return nothing.
crypto_check
() returns 0 for legitimate
messages and -1 for forgeries.
arc4random_buf
(), which fills the given buffer with
cryptographically secure random bytes. If
arc4random_buf
() does not exist on your system, see
intro(3monocypher) for advice about how to
generate cryptographically secure random bytes.
Generate a public key from a random secret key:
uint8_t sk[32]; /* Random secret key */ uint8_t pk[32]; /* Matching public key */ arc4random_buf(sk, 32); crypto_sign_public_key(pk, sk); /* Wipe the secret key if it is no longer needed */ crypto_wipe(sk, 32);
Sign a message:
uint8_t sk [32]; /* Secret key from above */ const uint8_t pk [32]; /* Matching public key */ const uint8_t message [11] = "Lorem ipsu"; /* Message to sign */ uint8_t signature[64]; crypto_sign(signature, sk, pk, message, 10); /* Wipe the secret key if it is no longer needed */ crypto_wipe(sk, 32);
Check the above:
const uint8_t pk [32]; /* Their public key */ const uint8_t message [11] = "Lorem ipsu"; /* Signed message */ const uint8_t signature[64]; /* Signature to check */ if (crypto_check(signature, pk, message, 10)) { /* Message is corrupted, abort processing */ } else { /* Message is genuine */ }
crypto_sign
(),
crypto_check
(), and
crypto_sign_public_key
() functions appeared in
Monocypher 0.2.
Starting with Monocypher 2.0.5, modified signatures abusing the
inherent signature malleability property of EdDSA now cause a non-zero
return value of crypto_check
(); in prior versions,
such signatures would be accepted.
A critical security vulnerability that caused all-zero signatures to be accepted was introduced in Monocypher 0.3; it was fixed in Monocypher 1.1.1 and 2.0.4.
On the other hand, EdDSA signatures are not unique like
cryptographic hashes. The signing procedure is deterministic by
specification and crypto_sign
() follows this
specification. However, someone with the private key can generate
arbitrarily many valid, canonical, and different signatures of the same
message. Because of this, never assume that signatures are unique.
February 13, 2022 | Debian |