libsodium

Searchâ€¦

Public-key signatures

Example (combined mode)

#define MESSAGE (const unsigned char *) "test"

#define MESSAGE_LEN 4

â€‹

unsigned char pk[crypto_sign_PUBLICKEYBYTES];

unsigned char sk[crypto_sign_SECRETKEYBYTES];

crypto_sign_keypair(pk, sk);

â€‹

unsigned char signed_message[crypto_sign_BYTES + MESSAGE_LEN];

unsigned long long signed_message_len;

â€‹

crypto_sign(signed_message, &signed_message_len,

MESSAGE, MESSAGE_LEN, sk);

â€‹

unsigned char unsigned_message[MESSAGE_LEN];

unsigned long long unsigned_message_len;

if (crypto_sign_open(unsigned_message, &unsigned_message_len,

signed_message, signed_message_len, pk) != 0) {

/* incorrect signature! */

}

Example (detached mode)

#define MESSAGE (const unsigned char *) "test"

#define MESSAGE_LEN 4

â€‹

unsigned char pk[crypto_sign_PUBLICKEYBYTES];

unsigned char sk[crypto_sign_SECRETKEYBYTES];

crypto_sign_keypair(pk, sk);

â€‹

unsigned char sig[crypto_sign_BYTES];

â€‹

crypto_sign_detached(sig, NULL, MESSAGE, MESSAGE_LEN, sk);

â€‹

if (crypto_sign_verify_detached(sig, MESSAGE, MESSAGE_LEN, pk) != 0) {

/* incorrect signature! */

}

Example (multi-part message)

#define MESSAGE_PART1 \

((const unsigned char *) "Arbitrary data to hash")

#define MESSAGE_PART1_LEN 22

â€‹

#define MESSAGE_PART2 \

((const unsigned char *) "is longer than expected")

#define MESSAGE_PART2_LEN 23

â€‹

unsigned char pk[crypto_sign_PUBLICKEYBYTES];

unsigned char sk[crypto_sign_SECRETKEYBYTES];

crypto_sign_keypair(pk, sk);

â€‹

crypto_sign_state state;

unsigned char sig[crypto_sign_BYTES];

â€‹

/* signature creation */

â€‹

crypto_sign_init(&state)

crypto_sign_update(&state, MESSAGE_PART1, MESSAGE_PART1_LEN);

crypto_sign_update(&state, MESSAGE_PART2, MESSAGE_PART2_LEN);

crypto_sign_final_create(&state, sig, NULL, sk);

â€‹

/* signature verification */

â€‹

crypto_sign_init(&state)

crypto_sign_update(&state, MESSAGE_PART1, MESSAGE_PART1_LEN);

crypto_sign_update(&state, MESSAGE_PART2, MESSAGE_PART2_LEN);

if (crypto_sign_final_verify(&state, sig, pk) != 0) {

/* message forged! */

}

Purpose

In this system, a signer generates a key pair consisting of:

- A secret key, which you can use to append a signature to any number of messages.
- A public key, which anybody can use to verify that the signature appended to a message was issued by the creator of the public key.

Verifiers need to already know and ultimately trust a public key before messages signed using it can be verified.

Key pair generation

int crypto_sign_keypair(unsigned char *pk, unsigned char *sk);

The

`crypto_sign_keypair()`

function randomly generates a secret key and a corresponding public key. The public key is put into `pk`

(`crypto_sign_PUBLICKEYBYTES`

bytes) and the secret key into `sk`

(`crypto_sign_SECRETKEYBYTES`

bytes).int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk,

const unsigned char *seed);

Using

`crypto_sign_seed_keypair()`

, the key pair can also be deterministically derived from a single key `seed`

(`crypto_sign_SEEDBYTES`

bytes).Combined mode

int crypto_sign(unsigned char *sm, unsigned long long *smlen_p,

const unsigned char *m, unsigned long long mlen,

const unsigned char *sk);

The

`crypto_sign()`

function prepends a signature to a message `m`

, whose length is `mlen`

bytes, using the secret key `sk`

.The signed message, which includes the signature plus an unaltered copy of the message, is put into

`sm`

and is `crypto_sign_BYTES + mlen`

bytes long.If

`smlen`

is not a `NULL`

pointer, then the actual length of the signed message is stored in `smlen`

.int crypto_sign_open(unsigned char *m, unsigned long long *mlen_p,

const unsigned char *sm, unsigned long long smlen,

const unsigned char *pk);

The

`crypto_sign_open()`

function checks that the signed message `sm`

, whose length is `smlen`

bytes, has a valid signature for the public key `pk`

.If the signature isn't valid, then the function returns

`-1`

.On success, it puts the message without the signature into

`m`

, stores its length in `mlen`

if `mlen`

is not a `NULL`

pointer, and returns `0`

.Detached mode

In detached mode, the signature is stored without attaching a copy of the original message to it.

int crypto_sign_detached(unsigned char *sig, unsigned long long *siglen_p,

const unsigned char *m, unsigned long long mlen,

const unsigned char *sk);

The

`crypto_sign_detached()`

function signs the message `m`

, whose length is `mlen`

bytes, using the secret key `sk`

and puts the signature into `sig`

, which can be up to `crypto_sign_BYTES`

bytes long.The actual length of the signature is put into

`siglen`

if `siglen`

is not `NULL`

.It is safe to ignore

`siglen`

and always consider a signature as `crypto_sign_BYTES`

bytes long; shorter signatures will be transparently padded with zeros if necessary.int crypto_sign_verify_detached(const unsigned char *sig,

const unsigned char *m,

unsigned long long mlen,

const unsigned char *pk);

The

`crypto_sign_verify_detached()`

function verifies that `sig`

is a valid signature for the message `m`

, whose length is `mlen`

bytes, using the signer's public key `pk`

.It returns

`-1`

if signature verification fails and `0`

on success.Multi-part messages

If the message doesn't fit in memory, then it can be provided as a sequence of arbitrarily-sized chunks.

This uses the Ed25519ph signature system, which pre-hashes the message. In other words, what gets signed is not the message itself but its image through a hash function.

If the message *can* fit in memory and be supplied as a single chunk, then the single-part API should be preferred.

Note:

`Ed25519ph(m)`

is intentionally not equivalent to `Ed25519(SHA512(m))`

.If, for some reason, you need to pre-hash the message yourself, then use the multi-part

`crypto_generichash_*()`

APIs and sign the 512-bit output.int crypto_sign_init(crypto_sign_state *state);

The

`crypto_sign_init()`

function initializes the state `state`

. This function must be called before the first `crypto_sign_update()`

call.int crypto_sign_update(crypto_sign_state *state,

const unsigned char *m, unsigned long long mlen);

Add a new chunk

`m`

of length `mlen`

bytes to the message that will eventually be signed.After all parts have been supplied, one of the following functions can be called:

int crypto_sign_final_create(crypto_sign_state *state, unsigned char *sig,

unsigned long long *siglen_p,

const unsigned char *sk);

The

`crypto_sign_final_create()`

function computes a signature for the previously supplied message using the secret key `sk`

and puts it into `sig`

.If

`siglen_p`

is not `NULL`

, then the length of the signature is stored at this address.It is safe to ignore

`siglen`

and always consider a signature as `crypto_sign_BYTES`

bytes long; shorter signatures will be transparently padded with zeros if necessary.int crypto_sign_final_verify(crypto_sign_state *state, const unsigned char *sig,

const unsigned char *pk);

The

`crypto_sign_final_verify()`

function verifies that `sig`

is a valid signature using the public key `pk`

for the message whose content has been previously supplied using `crypto_update()`

.Extracting the seed and the public key from the secret key

The secret key includes the seed (either a random seed or the one given to

`crypto_sign_seed_keypair()`

) and public key.While the public key can always be derived from the seed, the precomputation saves a significant amount of CPU cycles when signing.

If required, Sodium provides two functions to extract the seed and public key from the secret key:

int crypto_sign_ed25519_sk_to_seed(unsigned char *seed,

const unsigned char *sk);

â€‹

int crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk);

The

`crypto_sign_ed25519_sk_to_seed()`

function extracts the seed from the secret key `sk`

and copies it into `seed`

(`crypto_sign_SEEDBYTES`

bytes).The

`crypto_sign_ed25519_sk_to_pk()`

function extracts the public key from the secret key `sk`

and copies it into `pk`

(`crypto_sign_PUBLICKEYBYTES`

bytes).Data structures

`crypto_sign_state`

, whose size can be retrieved using`crypto_sign_statebytes()`

Constants

`crypto_sign_PUBLICKEYBYTES`

`crypto_sign_SECRETKEYBYTES`

`crypto_sign_BYTES`

`crypto_sign_SEEDBYTES`

Algorithm details

- Single-part signature: Ed25519
- Multi-part signature: Ed25519ph

References

Notes

`crypto_sign_verify()`

and `crypto_sign_verify_detached()`

are only designed to verify signatures computed using `crypto_sign()`

and `crypto_sign_detached()`

.The original NaCl

`crypto_sign_open()`

implementation overwrote 64 bytes after the message, whereas the libsodium implementation doesn't write past the end of the message.Ed25519ph (used by the multi-part API) was implemented in libsodium 1.0.12.

The Ed25519 system was designed to compute deterministic signatures.

Non-deterministic (but also non-standard) signatures can be produced by compiling libsodium with the

`ED25519_NONDETERMINISTIC`

macro defined.Last modified 12d ago

Copy link

Outline

Example (combined mode)

Example (detached mode)

Example (multi-part message)

Purpose

Key pair generation

Combined mode

Detached mode

Multi-part messages

Extracting the seed and the public key from the secret key

Data structures

Constants

Algorithm details

References

Notes