-
Notifications
You must be signed in to change notification settings - Fork 95
Public key signatures
#define CONTEXT "Example"
#define MESSAGE "Test"
#define MESSAGE_LEN 4
hydro_sign_keypair key_pair;
hydro_sign_keygen(&key_pair);
uint8_t signature[hydro_sign_BYTES];
/* Sign the message using the secret key */
hydro_sign_create(signature, MESSAGE, MESSAGE_LEN, CONTEXT, key_pair.sk);
/* Verify the signature using the public key */
if (hydro_sign_verify(signature, MESSAGE, MESSAGE_LEN, CONTEXT, key_pair.pk) != 0) {
/* forged */
}
#define CONTEXT "Example"
#define MESSAGE_PART1 "first chunk"
#define MESSAGE_PART2 "second chunk"
#define MESSAGE_PART1_LEN 11
#define MESSAGE_PART2_LEN 12
hydro_sign_keypair key_pair;
hydro_sign_keygen(&key_pair);
uint8_t signature[hydro_sign_BYTES];
hydro_sign_state st;
/* Sign the message using the secret key */
hydro_sign_init(&st, CONTEXT);
hydro_sign_update(&st, MESSAGE_PART1, MESSAGE_PART1_LEN);
hydro_sign_update(&st, MESSAGE_PART2, MESSAGE_PART2_LEN);
hydro_sign_final_create(&st, signature, key_pair.sk);
/* Verify the signature using the public key */
hydro_sign_init(&st, CONTEXT);
hydro_sign_update(&st, MESSAGE_PART1, MESSAGE_PART1_LEN);
hydro_sign_update(&st, MESSAGE_PART2, MESSAGE_PART2_LEN);
if (hydro_sign_final_verify(&st, signature, key_pair.pk) != 0) {
/* forged */
}
In this system, a signer generates a key pair:
- a secret key, that will be used to sign any number of messages
- a public key, that anybody can use to verify that the signature for a message was actually 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.
void hydro_sign_keygen(hydro_sign_keypair *kp);
The hydro_sign_keygen()
function generates a secret key and a corresponding public key. The public key is put into kp->pk
(hydro_sign_PUBLICKEYBYTES
bytes) and the secret key into kp->sk
(hydro_sign_SECRETKEYBYTES
bytes).
void hydro_sign_keygen_deterministic(
hydro_sign_keypair *kp, const uint8_t seed[hydro_sign_SEEDBYTES]);
Using hydro_sign_keygen_deterministic()
, the key pair can be deterministically derived from a single key seed
(hydro_sign_SEEDBYTES
bytes).
int hydro_sign_create(uint8_t csig[hydro_sign_BYTES], const void *m_,
size_t mlen, const char ctx[hydro_sign_CONTEXTBYTES],
const uint8_t sk[hydro_sign_SECRETKEYBYTES]);
The hydro_sign_create()
function computes a signature for a message m_
whose length is mlen
bytes, using the secret key sk
and a context ctx
.
The signature is put into csig
, and is hydro_sign_BYTES
bytes long.
int hydro_sign_verify(const uint8_t csig[hydro_sign_BYTES], const void *m_,
size_t mlen, const char ctx[hydro_sign_CONTEXTBYTES],
const uint8_t pk[hydro_sign_PUBLICKEYBYTES]);
The hydro_sign_verify()
function checks that the signed message m_
whose length is smlen
bytes has a valid signature for the public key pk
and the context ctx
.
If the signature is doesn't appear to be valid, the function returns -1
.
On success, it returns 0
.
If the whole message doesn't fit in memory, it can be provided as a sequence of arbitrarily-sized chunks.
The multi-part API is almost the same for signing and for verification.
int hydro_sign_init(
hydro_sign_state *state, const char ctx[hydro_sign_CONTEXTBYTES]);
int hydro_sign_update(hydro_sign_state *state, const void *m_, size_t mlen);
int hydro_sign_final_create(hydro_sign_state *state,
uint8_t csig[hydro_sign_BYTES],
const uint8_t sk[hydro_sign_SECRETKEYBYTES]);
int hydro_sign_final_verify(hydro_sign_state *state,
const uint8_t csig[hydro_sign_BYTES],
const uint8_t pk[hydro_sign_PUBLICKEYBYTES]);
The hydro_sign_init()
function initializes a state state
using the context ctx
.
Individual chunks composing the entire message can then be hashed using hydro_sign_update()
.
In this function m_
is the address of a chunk, and mlen
its own length.
Finally:
-
hydro_sign_final_create()
can be used to compute a signature using the secret keysk
. - or
hydro_sign_final_verify()
can be used to verify a signature using the public keypk
.
hydro_sign_final_verify()
returns -1
if the signature doesn't appear to be valid for the given message, context and public key, or 0
if it could be successfully verified.
#define hydro_sign_BYTES 64
#define hydro_sign_CONTEXTBYTES 8
#define hydro_sign_PUBLICKEYBYTES 32
#define hydro_sign_SECRETKEYBYTES 64
#define hydro_sign_SEEDBYTES 32
typedef struct hydro_sign_state {
hydro_hash_state hash_st;
} hydro_sign_state;
typedef struct hydro_sign_keypair {
uint8_t pk[hydro_sign_PUBLICKEYBYTES];
uint8_t sk[hydro_sign_SECRETKEYBYTES];
} hydro_sign_keypair;
The nonces are non-deterministic. They are computed using the output of the CSPRNG as well as a hash of the message to be signed. As a result, signing the same message multiple times can produce different, all valid signatures. However, only the owner of the secret key can compute a valid signature.