crypto_sign,
crypto_check,
crypto_sign_public_key —
public key signatures
#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:
-
-
- signature
- The signature.
-
-
- secret_key
- A 32-byte random number, known only to you. See
intro(3monocypher) about
random number generation (use your operating system's random number
generator). Do not use the same private key for both signatures and key
exchanges. The public keys are different, and revealing both may leak
information.
-
-
- public_key
- The public key, generated from
secret_key with
crypto_sign_public_key().
-
-
- message
- Message to sign.
-
-
- message_size
- Length of message, in
bytes.
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
crypto_key_exchange(3monocypher)
and
crypto_aead_lock(3monocypher)
instead.
An incremental interface is available; see
crypto_sign_init_first_pass(3monocypher).
crypto_sign_public_key() and
crypto_sign() return nothing. They cannot fail.
crypto_check() returns 0 for legitimate messages
and -1 for forgeries.
Generate a public key from a random secret key:
const uint8_t sk[32]; /* Random secret key */
uint8_t pk[32]; /* Matching public key */
crypto_sign_public_key(pk, sk);
/* Wipe the secret key if it is no longer needed */
crypto_wipe(sk, 32);
Sign a message:
const uint8_t sk [ 32]; /* Your secret key */
const uint8_t pk [ 32]; /* Matching public key */
const uint8_t message [500]; /* Message to sign */
uint8_t signature[ 64];
crypto_sign(signature, sk, pk, message, 500);
/* 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 [500]; /* Signed message */
const uint8_t signature[ 64]; /* Signature to check */
if (crypto_check(signature, pk, message, 500)) {
/* Message is corrupted, abort processing */
} else {
/* Message is genuine */
}
crypto_blake2b(3monocypher),
crypto_key_exchange(3monocypher),
crypto_lock(3monocypher),
intro(3monocypher)
These functions implement EdDSA with Curve25519 and Blake2b. This is the same as
Ed25519, with Blake2b instead of SHA-512. Ed25519 is described in RFC 7748.
Fault injection (also known as glitching) may be used to manipulate the
resulting signature and recover the secret key in some cases. This requires
hardware access. If attackers are expected to have such access and the
relevant equipment, use
crypto_check() to verify
the signature before sending it away. This verification reduces the speed of
the whole operation by a factor of 3, and only provides an incomplete
protection.