.\" This file is dual-licensed.  Choose whichever you want.
.\"
.\" The first licence is a regular 2-clause BSD licence.  The second licence
.\" is the CC-0 from Creative Commons. It is intended to release Monocypher
.\" to the public domain.  The BSD licence serves as a fallback option.
.\"
.\" SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
.\"
.\" ----------------------------------------------------------------------------
.\"
.\" Copyright (c) 2019-2020 Fabio Scotoni
.\" All rights reserved.
.\"
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions are
.\" met:
.\"
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer.
.\"
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in the
.\"    documentation and/or other materials provided with the
.\"    distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" ----------------------------------------------------------------------------
.\"
.\" Written in 2019-2020 by Fabio Scotoni
.\"
.\" To the extent possible under law, the author(s) have dedicated all copyright
.\" and related neighboring rights to this software to the public domain
.\" worldwide.  This software is distributed without any warranty.
.\"
.\" You should have received a copy of the CC0 Public Domain Dedication along
.\" with this software.  If not, see
.\" <https://creativecommons.org/publicdomain/zero/1.0/>
.\"
.Dd December 28, 2019
.Dt CRYPTO_SIGN_INIT_FIRST_PASS_CUSTOM_HASH 3MONOCYPHER
.Os
.Sh NAME
.Nm crypto_sign_init_first_pass_custom_hash ,
.Nm crypto_sign_public_key_custom_hash ,
.Nm crypto_check_init_custom_hash
.Nd public key signatures with custom hash functions
.Sh SYNOPSIS
.In monocypher.h
.Ft void
.Fo crypto_sign_init_first_pass_custom_hash
.Fa "crypto_sign_ctx_abstract *ctx"
.Fa "const uint8_t secret_key[32]"
.Fa "const uint8_t public_key[32]"
.Fa "const crypto_sign_vtable *hash"
.Fc
.Ft void
.Fo crypto_sign_public_key_custom_hash
.Fa "uint8_t public_key[32]"
.Fa "const uint8_t secret_key[32]"
.Fa "const crypto_sign_vtable *hash"
.Fc
.Ft void
.Fo crypto_check_init_custom_hash
.Fa "crypto_sign_ctx_abstract *ctx"
.Fa "const uint8_t signature[64]"
.Fa "const uint8_t public_key[32]"
.Fa "const crypto_sign_vtable *hash"
.Fc
.Sh DESCRIPTION
These functions are variants of the
.Xr crypto_sign_init_first_pass 3monocypher
family of functions:
They provide the ability to replace the EdDSA hash function with any
user-provided hash function.
.Pp
.Sy This is a highly advanced feature .
Interoperability of public key signatures
with other cryptographic libraries can normally be achieved by using
.Xr crypto_ed25519_sign 3monocypher
or
.Xr crypto_ed25519_sign_init_first_pass 3monocypher
already.
This interface is exposed only for completeness and to handle special
situations
(e.g. to use the hash function of the future winner of the NIST
lightweight crypto competition on a device with highly constrained
resources or taking advantage of hardware support for cryptographic
hash functions).
Whenever possible, these functions should be avoided.
.Pp
To make available a custom hash algorithm for use with these functions,
a
.Vt crypto_sign_vtable
structure must be provided.
It is defined as:
.Bd -literal
typedef struct {
    void (*hash)(uint8_t hash[64], const uint8_t *message,
                 size_t message_size);
    void (*init  )(void *ctx);
    void (*update)(void *ctx, const uint8_t *message,
                   size_t message_size);
    void (*final )(void *ctx, uint8_t hash[64]);
    size_t ctx_size;
} crypto_sign_vtable;
.Ed
.Pp
The context argument to the functions shall be referred to as
.Dq outer signing context .
The outer signing context must contain a
.Vt crypto_sign_ctx_abstract
as
.Em its first member .
Other than that, the outer signing context may be defined freely.
Logically, it is required to contain some kind of hash context as well,
else it cannot work as a custom hash function.
.Pp
Because the calling code cannot know the real type of the outer signing
context,
it is cast to
.Vt void *
when calling the hash functions in the vtable,
but the
.Fa ctx
argument to the functions in the vtable is always guaranteed to be the
outer signing context.
.Pp
The hash functions must not fail.
If they somehow can fail,
they have no way to propagate its error status,
and thus the only ways to handle errors
are to either assume an error never occurs (if reasonable),
or to induce a crash in the code when an error occurs.
.Pp
The fields of
.Vt crypto_sign_vtable
are:
.Bl -tag -width Ds
.It Fa hash
Function that computes a 64-byte hash for a given message
and writes the computed hash to
.Fa hash .
The output length
.Em must
be exactly 64 bytes.
This will normally be constructed using the functions that provide the
.Fa init ,
.Fa update
and
.Fa final
members.
.It Fa init
Function that initialises the hash context of an outer signing context.
.It Fa update
Function that updates the hash context of an outer signing context.
It must be able to handle message sizes of at least 32 bytes.
.It Fa final
Function that finalises the hash context of an outer signing context
and writes the computed hash to
.Fa hash .
The output length
.Em must
be exactly 64 bytes.
This function should wipe the hash context with
.Xr crypto_wipe 3monocypher
if it contains pointers to objects outside the outer signing context.
Monocypher takes care of wiping the outer signing context.
.It Fa ctx_size
The size of the outer signing context as determined by
.Fn sizeof .
.El
.Pp
The functions indicated in the
.Vt crypto_sign_vtable
must be thread-safe if any of Monocypher's signing functions are
accessed from multiple threads.
.Pp
After calling
.Fn crypto_sign_init_first_pass_custom_hash
or
.Fn crypto_check_init_custom_hash ,
the
.Xr crypto_sign_update 3monocypher ,
.Xr crypto_sign_final 3monocypher ,
.Xr crypto_sign_init_second_pass 3monocypher ,
.Xr crypto_check_update 3monocypher ,
and
.Xr crypto_check_final 3monocypher
functions can be used as usual.
They will call into the hash vtable as required.
The same security considerations and semantics apply.
.Sh RETURN VALUES
These functions return nothing.
.Sh EXAMPLES
Defining and using a custom implementation of SHA-512 and crudely
checking its results against
.Xr crypto_ed25519_sign 3monocypher :
.Bd -literal -offset indent
struct outer_ctx {
    crypto_sign_ctx_abstract sctx;
    SHA2_CTX hash_ctx;
};

static void
my_hash(uint8_t hash[64], const uint8_t *msg, size_t len)
{
    SHA2_CTX ctx;
    SHA512Init(&ctx);
    SHA512Update(&ctx, msg, len);
    SHA512Final(hash, &ctx);
}

static void
my_init(void *ctx)
{
    struct outer_ctx *octx = (struct outer_ctx *)ctx;
    SHA512Init(&octx->hash_ctx);
}

static void
my_update(void *ctx, const uint8_t *msg, size_t len)
{
    struct outer_ctx *octx = (struct outer_ctx *)ctx;
    SHA512Update(&octx->hash_ctx, msg, len);
}

static void
my_final(void *ctx, uint8_t *hash)
{
    struct outer_ctx *octx = (struct outer_ctx *)ctx;
    SHA512Final(hash, &octx->hash_ctx);
}

static const crypto_sign_vtable my_vtable = {
    my_hash,
    my_init,
    my_update,
    my_final,
    sizeof(struct outer_ctx)
};

int
main(void)
{
    uint8_t theirs[64], mine[64];
    uint8_t sk[32] = {0x01, 0x02, 0x03, 0x04};
    const uint8_t msg[] = {
        0x00, 0x01, 0x02, 0x04
    };

    crypto_ed25519_sign(theirs, sk, NULL, msg, sizeof(msg));

    struct outer_ctx ctx;
    crypto_sign_ctx_abstract *actx = (crypto_sign_ctx_abstract*)&ctx;
    crypto_sign_init_first_pass_custom_hash(actx,
                                            sk, NULL, &my_vtable);
    crypto_wipe(sk, sizeof(sk));
    crypto_sign_update(          actx, msg, sizeof(msg));
    crypto_sign_init_second_pass(actx);
    crypto_sign_update(          actx, msg, sizeof(msg));
    crypto_sign_final(           actx, mine);

    if (crypto_verify64(theirs, mine) != 0) {
        fprintf(stderr, "theirs != mine\en");
        return 1;
    }
    puts("ok");
    return 0;
}
.Ed
.Sh SEE ALSO
.Xr crypto_blake2b 3monocypher ,
.Xr crypto_sha512 3monocypher ,
.Xr crypto_sign 3monocypher ,
.Xr crypto_sign_init_first_pass 3monocypher ,
.Xr crypto_wipe 3monocypher ,
.Xr intro 3monocypher
.Sh HISTORY
The
.Fn crypto_sign_init_first_pass_custom_hash ,
.Fn crypto_sign_public_key_custom_hash ,
.Fn crypto_check_init_first_pass_custom_hash
functions first appeared in Monocypher 3.0.0.
