/* Wipe the secret key if it is no longer needed */
crypto_wipe(sk, 64);
.Ed
+.Pp
+It is also possible to implement a safer API that provides a combined
+key abstraction:
+.Bd -literal -offset indent
+void eddsa_sign_key_pair(uint8_t secret_key[64],
+ uint8_t public_key[32],
+ uint8_t seed[32])
+{
+ /* Copy seed to secret key then wipes the seed. */
+ /* Accounts for buffer overlaps. */
+ uint8_t sk[32];
+ memcpy(sk , seed, 32); crypto_wipe(seed, 32);
+ memcpy(secret_key, sk , 32); crypto_wipe(sk , 32);
+
+ crypto_sign_public_key(secret_key + 32, secret_key);
+ memmove(public_key, secret_key + 32, 32);
+}
+
+void eddsa_sign(uint8_t signature [64],
+ const uint8_t secret_key[64],
+ const uint8_t *message, size_t message_size)
+{
+ crypto_sign(signature, secret_key, secret_key + 32,
+ message, message_size);
+}
+.Ed
+.Pp
+With this API we can generate a key pair from a seed:
+.Bd -literal -offset indent
+uint8_t seed[32]; /* Random seed */
+uint8_t sk [64]; /* Combined secret key */
+uint8_t pk [32]; /* Public key */
+arc4random_buf(seed, 32);
+eddsa_sign_key_pair(sk, pk, seed);
+/* Wipe the secret key if it is no longer needed */
+crypto_wipe(sk, 64);
+.Ed
+.Pp
+Then we can sign with the composite private key:
+.Bd -literal -offset indent
+uint8_t sk [64]; /* Combined secret key from above */
+const uint8_t message [11] = "Lorem ipsu"; /* Message to sign */
+uint8_t signature[64];
+eddsa_sign(signature, sk, message, 10);
+/* Wipe the secret key if it is no longer needed */
+crypto_wipe(sk, 64);
+.Ed
.Sh SEE ALSO
.Xr crypto_blake2b 3monocypher ,
.Xr crypto_x25519 3monocypher ,