+++ /dev/null
-crypto_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_sign_init_first_pass_custom_hash.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-.\" 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) 2017-2021 Loup Vaillant
-.\" Copyright (c) 2017-2018 Michael Savage
-.\" Copyright (c) 2017, 2019-2022 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 2017-2022 by Loup Vaillant, Michael Savage and 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 February 13, 2022
-.Dt CRYPTO_SIGN_INIT_FIRST_PASS 3MONOCYPHER
-.Os
-.Sh NAME
-.Nm crypto_sign_init_first_pass ,
-.Nm crypto_sign_update ,
-.Nm crypto_sign_final ,
-.Nm crypto_sign_init_second_pass ,
-.Nm crypto_check_init ,
-.Nm crypto_check_update ,
-.Nm crypto_check_final
-.Nd incremental public key signatures
-.Sh SYNOPSIS
-.In monocypher.h
-.Ft void
-.Fo crypto_sign_init_first_pass
-.Fa "crypto_sign_ctx *ctx"
-.Fa "const uint8_t secret_key[32]"
-.Fa "const uint8_t public_key[32]"
-.Fc
-.Ft void
-.Fo crypto_sign_update
-.Fa "crypto_sign_ctx *ctx"
-.Fa "const uint8_t *message"
-.Fa "size_t message_size"
-.Fc
-.Ft void
-.Fo crypto_sign_final
-.Fa "crypto_sign_ctx *ctx"
-.Fa "uint8_t signature[64]"
-.Fc
-.Ft void
-.Fo crypto_sign_init_second_pass
-.Fa "crypto_sign_ctx *ctx"
-.Fc
-.Ft void
-.Fo crypto_check_init
-.Fa "crypto_check_ctx *ctx"
-.Fa "const uint8_t signature[64]"
-.Fa "const uint8_t public_key[32]"
-.Fc
-.Ft void
-.Fo crypto_check_update
-.Fa "crypto_check_ctx *ctx"
-.Fa "const uint8_t *message"
-.Fa "size_t message_size"
-.Fc
-.Ft int
-.Fo crypto_check_final
-.Fa "crypto_check_ctx *ctx"
-.Fc
-.Sh DESCRIPTION
-These functions are variants of
-.Xr crypto_sign 3monocypher
-and
-.Xr crypto_check 3monocypher .
-Prefer those simpler functions if possible.
-.Pp
-The arguments are the same as those described in
-.Xr crypto_sign 3monocypher .
-.Pp
-This incremental interface can be used to sign or verify messages too
-large to fit in a single buffer.
-The arguments are the same as the direct interface described in
-.Xr crypto_sign 3monocypher .
-.Pp
-The direct and incremental interface produce and accept the same
-signatures.
-.Pp
-Signing is done in two passes.
-This requires five steps:
-.Bl -bullet
-.It
-Initialisation of the first pass with
-.Fn crypto_sign_init_first_pass .
-The public key is optional and will be recomputed if not provided.
-This recomputation doubles the execution time for short messages.
-.It
-The first pass proper, with
-.Fn crypto_sign_update .
-.Sy Under no circumstances must you forget the first pass .
-Forgetting to call
-.Fn crypto_sign_update
-will appear to work in that it produces valid signatures
-but also
-loses all security because attackers may now recover the secret key.
-.It
-Initialisation of the second pass with
-.Fn crypto_sign_init_second_pass .
-.It
-The second pass proper, with
-.Fn crypto_sign_update .
-The same update function is used for both passes.
-.It
-Signature generation with
-.Fn crypto_sign_final .
-This also wipes the context.
-.El
-.Pp
-Verification requires three steps:
-.Bl -bullet
-.It
-Initialisation with
-.Fn crypto_check_init .
-.It
-Update with
-.Fn crypto_check_update .
-.It
-Signature verification with
-.Fn crypto_check_final .
-.El
-.Sh RETURN VALUES
-.Fn crypto_sign_init_first_pass ,
-.Fn crypto_sign_init_second_pass ,
-.Fn crypto_sign_update ,
-.Fn crypto_sign_final ,
-.Fn crypto_check_init ,
-and
-.Fn crypto_check_update
-return nothing.
-.Pp
-.Fn crypto_check_final
-returns 0 for legitimate messages and -1 for forgeries.
-.Sh EXAMPLES
-Sign a message:
-.Bd -literal -offset indent
-uint8_t sk [ 32]; /* Secret key */
-const uint8_t pk [ 32]; /* Public key (optional) */
-const uint8_t message [500]; /* Message to sign */
-uint8_t signature[ 64]; /* Output signature */
-crypto_sign_ctx ctx;
-arc4random_buf(sk, 32);
-crypto_sign_public_key(pk, sk);
-crypto_sign_init_first_pass((crypto_sign_ctx_abstract*)&ctx, sk, pk);
-/* Wipe the secret key if no longer needed */
-crypto_wipe(sk, 32);
-for (size_t i = 0; i < 500; i += 100) {
- crypto_sign_update((crypto_sign_ctx_abstract*)&ctx, message + i, 100);
-}
-crypto_sign_init_second_pass((crypto_sign_ctx_abstract*)&ctx);
-for (size_t i = 0; i < 500; i += 100) {
- crypto_sign_update((crypto_sign_ctx_abstract*)&ctx, message + i, 100);
-}
-crypto_sign_final((crypto_sign_ctx_abstract*)&ctx, signature);
-.Ed
-.Pp
-Check the above:
-.Bd -literal -offset indent
-const uint8_t pk [ 32]; /* Public key */
-const uint8_t message [500]; /* Message to sign */
-const uint8_t signature[ 64]; /* Signature to check */
-crypto_check_ctx ctx;
-crypto_check_init((crypto_sign_ctx_abstract*)&ctx, signature, pk);
-for (size_t i = 0; i < 500; i += 100) {
- crypto_check_update((crypto_sign_ctx_abstract*)&ctx, message + i, 100);
-}
-if (crypto_check_final((crypto_sign_ctx_abstract*)&ctx)) {
- /* Message is corrupted, abort processing */
-} else {
- /* Message is genuine */
-}
-.Ed
-.Pp
-This interface can be used to mitigate attacks that leverage power
-analysis and fault injection (glitching) \(en both of which require
-physical access and appropriate equipment.
-We inject additional randomness (at least 32 bytes) and
-enough all-zero padding to fill the hash function's block size
-(128 bytes for both BLAKE2b and SHA-512).
-Note that
-.Fn crypto_sign_init_first_pass
-already fills 32 bytes,
-so randomness and padding must fill 32 bytes
-.Em less
-than the block
-size (96 bytes for BLAKE2b and SHA-512).
-Access to a cryptographically secure pseudo-random generator is a
-requirement for effective side-channel mitigation.
-Signing a message with increased power-related side-channel mitigations:
-.Bd -literal -offset indent
-const uint8_t message [ 500]; /* Message to sign */
-uint8_t sk [ 32]; /* Secret key */
-const uint8_t pk [ 32]; /* Public key (optional) */
-uint8_t signature[ 64]; /* Output signature */
-uint8_t buf [128-32] = {0}; /* Mitigation buffer */
-crypto_sign_ctx ctx;
-crypto_sign_ctx_abstract *actx = (crypto_sign_ctx_abstract *)&ctx;
-
-arc4random_buf(sk, 32);
-crypto_sign_public_key(pk, sk);
-
-arc4random_buf(buf, 32);
-/* The rest of buf MUST be zeroes. */
-
-crypto_sign_init_first_pass(actx, sk, pk);
-crypto_sign_update (actx, buf, sizeof(buf));
-crypto_sign_update (actx, message, 500);
-
-crypto_sign_init_second_pass(actx);
-crypto_sign_update (actx, message, 500);
-crypto_sign_final (actx, signature);
-
-crypto_wipe(buf, 32);
-/* Wipe the secret key if no longer needed */
-crypto_wipe(sk, 32);
-.Ed
-.Sh SEE ALSO
-.Xr crypto_blake2b 3monocypher ,
-.Xr crypto_x25519 3monocypher ,
-.Xr crypto_lock 3monocypher ,
-.Xr crypto_sign 3monocypher ,
-.Xr crypto_wipe 3monocypher ,
-.Xr intro 3monocypher
-.Sh STANDARDS
-These functions implement PureEdDSA with Curve25519 and BLAKE2b, as
-described in RFC 8032.
-This is the same as Ed25519, with BLAKE2b instead of SHA-512.
-.Pp
-The example for side-channel mitigation follows the methodology outlined
-in I-D.draft-mattsson-cfrg-det-sigs-with-noise-02.
-.Sh HISTORY
-The
-.Fn crypto_sign_init_first_pass ,
-.Fn crypto_sign_update ,
-.Fn crypto_sign_final ,
-.Fn crypto_sign_init_second_pass ,
-.Fn crypto_check_init ,
-.Fn crypto_check_update ,
-and
-.Fn crypto_check_final
-functions first appeared in Monocypher 1.1.0.
-.Pp
-Starting with Monocypher 2.0.5, modified signatures abusing the inherent
-signature malleability property of EdDSA now cause a non-zero return
-value of
-.Fn crypto_check_final ;
-in prior versions, such signatures would be accepted.
-.Pp
-.Sy A critical security vulnerability
-that caused all-zero signatures to be accepted was introduced in
-Monocypher 0.3;
-it was fixed in Monocypher 1.1.1 and 2.0.4.
-.Sh SECURITY CONSIDERATIONS
-Messages are not verified until the call to
-.Fn crypto_check_final .
-Messages may be stored before they are verified, but they cannot be
-.Em trusted .
-Processing untrusted messages increases the attack surface of the
-system.
-Doing so securely is hard.
-Do not process messages before calling
-.Fn crypto_check_final .
-.Pp
-When signing messages, the security considerations documented in
-.Xr crypto_sign 3monocypher
-also apply.
-If power-related side-channels are part of your threat model,
-note that there may still be other power-related side-channels (such as
-if the CPU leaks information when an operation overflows a register)
-that must be considered.
-.Sh IMPLEMENTATION DETAILS
-EdDSA signatures require two passes that cannot be performed in
-parallel.
-There are ways around this limitation, but they all lower security in
-some way.
-For this reason, Monocypher does not support them.
+++ /dev/null
-.\" 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 a custom hash algorithm available 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;
-otherwise 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 ,
-and
-.Fn crypto_check_init_first_pass_custom_hash
-functions first appeared in Monocypher 3.0.0.
+++ /dev/null
-crypto_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_sign_init_first_pass_custom_hash.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_sign_init_first_pass.3monocypher
\ No newline at end of file
implement EdDSA, with Curve25519 and BLAKE2b.
This is the same as the more famous Ed25519, with SHA-512 replaced by
the faster and more secure BLAKE2b.
-.Pp
-For highly specialised needs,
-it is possible to use a custom hash function with EdDSA;
-see
-.Xr crypto_sign_init_first_pass_custom_hash 3monocypher .
.Ss Constant time comparison
.Xr crypto_verify16 3monocypher ,
.Xr crypto_verify32 3monocypher ,
.Xr crypto_chacha20 3monocypher ,
.Xr crypto_chacha20_ctr 3monocypher ,
.Xr crypto_check 3monocypher ,
-.Xr crypto_check_final 3monocypher ,
-.Xr crypto_check_init 3monocypher ,
-.Xr crypto_check_init_custom_hash 3monocypher ,
-.Xr crypto_check_update 3monocypher ,
.Xr crypto_curve_to_hidden 3monocypher ,
.Xr crypto_from_eddsa_private 3monocypher ,
.Xr crypto_from_eddsa_public 3monocypher ,
.Xr crypto_poly1305_init 3monocypher ,
.Xr crypto_poly1305_update 3monocypher ,
.Xr crypto_sign 3monocypher ,
-.Xr crypto_sign_final 3monocypher ,
-.Xr crypto_sign_init_first_pass 3monocypher ,
-.Xr crypto_sign_init_first_pass_custom_hash 3monocypher ,
-.Xr crypto_sign_init_second_pass 3monocypher ,
.Xr crypto_sign_public_key 3monocypher ,
-.Xr crypto_sign_public_key_custom_hash 3monocypher ,
-.Xr crypto_sign_update 3monocypher ,
.Xr crypto_unlock 3monocypher ,
.Xr crypto_unlock_aead 3monocypher ,
.Xr crypto_verify16 3monocypher ,
.Xr crypto_from_ed25519_private 3monocypher ,
.Xr crypto_from_ed25519_public 3monocypher ,
.Xr crypto_ed25519_check 3monocypher ,
-.Xr crypto_ed25519_check_init 3monocypher ,
-.Xr crypto_ed25519_check_update 3monocypher ,
-.Xr crypto_ed25519_check_final 3monocypher ,
.Xr crypto_ed25519_public_key 3monocypher ,
.Xr crypto_ed25519_sign 3monocypher ,
-.Xr crypto_ed25519_sign_init_first_pass 3monocypher ,
-.Xr crypto_ed25519_sign_init_second_pass 3monocypher ,
-.Xr crypto_ed25519_sign_final 3monocypher ,
.Xr crypto_hmac_sha512 3monocypher ,
.Xr crypto_hmac_sha512_init 3monocypher ,
.Xr crypto_hmac_sha512_update 3monocypher ,
+++ /dev/null
-crypto_ed25519_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_ed25519_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_ed25519_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_ed25519_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-.\" 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, 2022 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 and 2022 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 February 13, 2022
-.Dt CRYPTO_ED25519_SIGN_INIT_FIRST_PASS 3MONOCYPHER
-.Os
-.Sh NAME
-.Nm crypto_ed25519_sign_init_first_pass ,
-.Nm crypto_ed25519_sign_update ,
-.Nm crypto_ed25519_sign_final ,
-.Nm crypto_ed25519_sign_init_second_pass ,
-.Nm crypto_ed25519_check_init ,
-.Nm crypto_ed25519_check_update ,
-.Nm crypto_ed25519_check_final
-.Nd incremental public key signatures
-.Sh SYNOPSIS
-.In monocypher-ed25519.h
-.Ft void
-.Fo crypto_ed25519_sign_init_first_pass
-.Fa "crypto_ed25519_sign_ctx *ctx"
-.Fa "const uint8_t secret_key[32]"
-.Fa "const uint8_t public_key[32]"
-.Fc
-.Ft void
-.Fo crypto_ed25519_sign_update
-.Fa "crypto_ed25519_sign_ctx *ctx"
-.Fa "const uint8_t *message"
-.Fa "size_t message_size"
-.Fc
-.Ft void
-.Fo crypto_ed25519_sign_final
-.Fa "crypto_ed25519_sign_ctx *ctx"
-.Fa "uint8_t signature[64]"
-.Fc
-.Ft void
-.Fo crypto_ed25519_sign_init_second_pass
-.Fa "crypto_ed25519_sign_ctx *ctx"
-.Fc
-.Ft void
-.Fo crypto_ed25519_check_init
-.Fa "crypto_ed25519_check_ctx *ctx"
-.Fa "const uint8_t signature[64]"
-.Fa "const uint8_t public_key[32]"
-.Fc
-.Ft void
-.Fo crypto_ed25519_check_update
-.Fa "crypto_ed25519_check_ctx *ctx"
-.Fa "const uint8_t *message"
-.Fa "size_t message_size"
-.Fc
-.Ft int
-.Fo crypto_ed25519_check_final
-.Fa "crypto_ed25519_check_ctx *ctx"
-.Fc
-.Sh DESCRIPTION
-These functions are variants of
-.Xr crypto_ed25519_sign 3monocypher
-and
-.Xr crypto_ed25519_check 3monocypher .
-Prefer those simpler functions if possible.
-.Pp
-These functions provide Ed25519 public key signatures and verification
-with SHA-512 as the underlying hash function.
-They are interoperable with other Ed25519 implementations.
-If you have no interoperability requirements, prefer
-.Xr crypto_sign 3monocypher .
-.Pp
-The arguments, security considerations, and semantics are the same as
-those described in
-.Xr crypto_sign_init_first_pass 3monocypher
-and
-.Xr crypto_sign 3monocypher .
-.Sh RETURN VALUES
-.Fn crypto_ed25519_sign_init_first_pass ,
-.Fn crypto_ed25519_sign_init_second_pass ,
-.Fn crypto_ed25519_sign_update ,
-.Fn crypto_ed25519_sign_final ,
-.Fn crypto_ed25519_check_init ,
-and
-.Fn crypto_ed25519_check_update
-return nothing.
-.Pp
-.Fn crypto_ed25519_check_final
-returns 0 for legitimate messages and -1 for forgeries.
-.Sh SEE ALSO
-.Xr crypto_blake2b 3monocypher ,
-.Xr crypto_x25519 3monocypher ,
-.Xr crypto_lock 3monocypher ,
-.Xr crypto_ed25519_sign 3monocypher ,
-.Xr crypto_sign 3monocypher ,
-.Xr crypto_sign_init_first_pass 3monocypher ,
-.Xr crypto_sha512 3monocypher ,
-.Xr crypto_wipe 3monocypher ,
-.Xr intro 3monocypher
-.Sh STANDARDS
-These functions implement Ed25519 as described in RFC 8032.
-.Sh HISTORY
-The
-.Fn crypto_ed25519_sign_init_first_pass ,
-.Fn crypto_ed25519_sign_update ,
-.Fn crypto_ed25519_sign_final ,
-.Fn crypto_ed25519_sign_init_second_pass ,
-.Fn crypto_ed25519_check_init ,
-.Fn crypto_ed25519_check_update ,
-and
-.Fn crypto_ed25519_check_final
-functions first appeared in Monocypher 3.0.0.
-They replace recompilation of Monocypher with the
-.Dv ED25519_SHA512
-preprocessor definition.
+++ /dev/null
-crypto_ed25519_sign_init_first_pass.3monocypher
\ No newline at end of file
+++ /dev/null
-crypto_ed25519_sign_init_first_pass.3monocypher
\ No newline at end of file
crypto_blake2b_general(hash, 64, 0, 0, message, message_size);
}
-static void blake2b_vtable_init(void *ctx) {
- crypto_blake2b_init(&((crypto_sign_ctx*)ctx)->hash);
-}
-static void blake2b_vtable_update(void *ctx, const u8 *m, size_t s) {
- crypto_blake2b_update(&((crypto_sign_ctx*)ctx)->hash, m, s);
-}
-static void blake2b_vtable_final(void *ctx, u8 *h) {
- crypto_blake2b_final(&((crypto_sign_ctx*)ctx)->hash, h);
-}
-const crypto_sign_vtable crypto_blake2b_vtable = {
- crypto_blake2b,
- blake2b_vtable_init,
- blake2b_vtable_update,
- blake2b_vtable_final,
- sizeof(crypto_sign_ctx),
-};
-
////////////////
/// Argon2 i ///
////////////////
}
// trim a scalar for scalar multiplication
-static void trim_scalar(u8 scalar[32])
+void crypto_eddsa_trim_scalar(u8 out[32], const u8 in[32])
{
- scalar[ 0] &= 248;
- scalar[31] &= 127;
- scalar[31] |= 64;
+ COPY(out, in, 32);
+ out[ 0] &= 248;
+ out[31] &= 127;
+ out[31] |= 64;
}
// get bit from scalar at position i
{
// restrict the possible scalar values
u8 e[32];
- COPY(e, your_secret_key, 32);
- trim_scalar(e);
+ crypto_eddsa_trim_scalar(e, your_secret_key);
scalarmult(raw_shared_secret, e, their_public_key, 255);
WIPE_BUFFER(e);
}
WIPE_BUFFER(xr);
}
-static void reduce(u8 r[64])
+void crypto_eddsa_reduce(u8 reduced[32], const u8 expanded[64])
{
u32 x[16];
- load32_le_buf(x, r, 16);
- mod_l(r, x);
+ load32_le_buf(x, expanded, 16);
+ mod_l(reduced, x);
WIPE_BUFFER(x);
}
// r = (a * b) + c
-static void mul_add(u8 r[32], const u8 a[32], const u8 b[32], const u8 c[32])
+void crypto_eddsa_mul_add(u8 r[32],
+ const u8 a[32], const u8 b[32], const u8 c[32])
{
u32 A[8]; load32_le_buf(A, a, 8);
u32 B[8]; load32_le_buf(B, b, 8);
// All bits set form: 1 means 1, 0 means -1
u8 s_scalar[32];
- mul_add(s_scalar, scalar, half_mod_L, half_ones);
+ crypto_eddsa_mul_add(s_scalar, scalar, half_mod_L, half_ones);
// Double and add ladder
fe tmp_a, tmp_b; // temporaries for addition
WIPE_BUFFER(s_scalar);
}
-void crypto_sign_public_key_custom_hash(u8 public_key[32],
- const u8 secret_key[32],
- const crypto_sign_vtable *hash)
+void crypto_eddsa_scalarbase(u8 point[32], const u8 scalar[32])
+{
+ ge P;
+ ge_scalarmult_base(&P, scalar);
+ ge_tobytes(point, &P);
+ WIPE_CTX(&P);
+}
+
+int crypto_eddsa_r_check(u8 r_check[32], const u8 public_key[32],
+ const u8 h_ram[32], const u8 s[32])
{
- u8 a[64];
- hash->hash(a, secret_key, 32);
- trim_scalar(a);
ge A;
- ge_scalarmult_base(&A, a);
- ge_tobytes(public_key, &A);
- WIPE_BUFFER(a);
- WIPE_CTX(&A);
+ u32 s32[8]; // s (different encoding)
+ load32_le_buf(s32, s, 8);
+
+ if (ge_frombytes_neg_vartime(&A, public_key) || // A = -pk
+ is_above_l(s32)) { // prevent s malleability
+ return -1;
+ }
+ ge_double_scalarmult_vartime(&A, h_ram, s); // A = [s]B - [h_ram]pk
+ ge_tobytes(r_check, &A); // r_check = A
+ return 0;
}
void crypto_sign_public_key(u8 public_key[32], const u8 secret_key[32])
{
- crypto_sign_public_key_custom_hash(public_key, secret_key,
- &crypto_blake2b_vtable);
+ u8 a[64];
+ crypto_blake2b(a, secret_key, 32);
+ crypto_eddsa_trim_scalar(a, a);
+ crypto_eddsa_scalarbase(public_key, a);
}
-void crypto_sign_init_first_pass_custom_hash(crypto_sign_ctx_abstract *ctx,
- const u8 secret_key[32],
- const u8 public_key[32],
- const crypto_sign_vtable *hash)
+static void hash_reduce(u8 h[32],
+ const u8 *a, size_t a_size,
+ const u8 *b, size_t b_size,
+ const u8 *c, size_t c_size)
{
- ctx->hash = hash; // set vtable
- u8 *a = ctx->buf;
- u8 *prefix = ctx->buf + 32;
- ctx->hash->hash(a, secret_key, 32);
- trim_scalar(a);
+ u8 hash[64];
+ crypto_blake2b_ctx ctx;
+ crypto_blake2b_init (&ctx);
+ crypto_blake2b_update(&ctx, a, a_size);
+ crypto_blake2b_update(&ctx, b, b_size);
+ crypto_blake2b_update(&ctx, c, c_size);
+ crypto_blake2b_final (&ctx, hash);
+ crypto_eddsa_reduce(h, hash);
+}
+void crypto_sign(u8 signature[64],
+ const u8 secret_key[32],
+ const u8 public_key[32],
+ const u8 *message, size_t message_size)
+{
+ u8 a[64];
+ crypto_blake2b(a, secret_key, 32);
+ crypto_eddsa_trim_scalar(a, a);
+ u8 pk[32]; // not secret, not wiped
if (public_key == 0) {
- crypto_sign_public_key_custom_hash(ctx->pk, secret_key, ctx->hash);
+ crypto_eddsa_scalarbase(pk, a);
} else {
- COPY(ctx->pk, public_key, 32);
+ COPY(pk, public_key, 32);
}
// Deterministic part of EdDSA: Construct a nonce by hashing the message
// An actual random number would work just fine, and would save us
// the trouble of hashing the message twice. If we did that
// however, the user could fuck it up and reuse the nonce.
- ctx->hash->init (ctx);
- ctx->hash->update(ctx, prefix , 32);
-}
+ u8 r[32];
+ hash_reduce(r, a + 32, 32, message, message_size, 0, 0);
-void crypto_sign_init_first_pass(crypto_sign_ctx_abstract *ctx,
- const u8 secret_key[32],
- const u8 public_key[32])
-{
- crypto_sign_init_first_pass_custom_hash(ctx, secret_key, public_key,
- &crypto_blake2b_vtable);
-}
+ // First half of the signature R = [r]B
+ u8 R[32]; // Not secret, not wiped
+ crypto_eddsa_scalarbase(R, r);
-void crypto_sign_update(crypto_sign_ctx_abstract *ctx,
- const u8 *msg, size_t msg_size)
-{
- ctx->hash->update(ctx, msg, msg_size);
-}
+ // Second half of the signature
+ u8 h_ram[32];
+ hash_reduce(h_ram, R, 32, pk, 32, message, message_size);
+ COPY(signature, R, 32);
+ crypto_eddsa_mul_add(signature + 32, h_ram, a, r); // s = h_ram * a + r
-void crypto_sign_init_second_pass(crypto_sign_ctx_abstract *ctx)
-{
- u8 *r = ctx->buf + 32;
- u8 *half_sig = ctx->buf + 64;
- ctx->hash->final(ctx, r);
- reduce(r);
-
- // first half of the signature = "random" nonce times the base point
- ge R;
- ge_scalarmult_base(&R, r);
- ge_tobytes(half_sig, &R);
- WIPE_CTX(&R);
-
- // Hash R, the public key, and the message together.
- // It cannot be done in parallel with the first hash.
- ctx->hash->init (ctx);
- ctx->hash->update(ctx, half_sig, 32);
- ctx->hash->update(ctx, ctx->pk , 32);
-}
-
-void crypto_sign_final(crypto_sign_ctx_abstract *ctx, u8 signature[64])
-{
- u8 *a = ctx->buf;
- u8 *r = ctx->buf + 32;
- u8 *half_sig = ctx->buf + 64;
- u8 h_ram[64];
- ctx->hash->final(ctx, h_ram);
- reduce(h_ram);
- COPY(signature, half_sig, 32);
- mul_add(signature + 32, h_ram, a, r); // s = h_ram * a + r
+ WIPE_BUFFER(a);
+ WIPE_BUFFER(r);
WIPE_BUFFER(h_ram);
- crypto_wipe(ctx, ctx->hash->ctx_size);
}
-void crypto_sign(u8 signature[64],
- const u8 secret_key[32],
- const u8 public_key[32],
+int crypto_check(const u8 signature[64], const u8 public_key[32],
const u8 *message, size_t message_size)
{
- crypto_sign_ctx ctx;
- crypto_sign_ctx_abstract *actx = (crypto_sign_ctx_abstract*)&ctx;
- crypto_sign_init_first_pass (actx, secret_key, public_key);
- crypto_sign_update (actx, message, message_size);
- crypto_sign_init_second_pass(actx);
- crypto_sign_update (actx, message, message_size);
- crypto_sign_final (actx, signature);
-}
-
-void crypto_check_init_custom_hash(crypto_check_ctx_abstract *ctx,
- const u8 signature[64],
- const u8 public_key[32],
- const crypto_sign_vtable *hash)
-{
- ctx->hash = hash; // set vtable
- COPY(ctx->buf, signature , 64);
- COPY(ctx->pk , public_key, 32);
- ctx->hash->init (ctx);
- ctx->hash->update(ctx, signature , 32);
- ctx->hash->update(ctx, public_key, 32);
-}
-
-void crypto_check_init(crypto_check_ctx_abstract *ctx, const u8 signature[64],
- const u8 public_key[32])
-{
- crypto_check_init_custom_hash(ctx, signature, public_key,
- &crypto_blake2b_vtable);
-}
-
-void crypto_check_update(crypto_check_ctx_abstract *ctx,
- const u8 *msg, size_t msg_size)
-{
- ctx->hash->update(ctx, msg, msg_size);
-}
-
-int crypto_check_final(crypto_check_ctx_abstract *ctx)
-{
- u8 *s = ctx->buf + 32; // s
- u8 h_ram[64];
- u32 s32[8]; // s (different encoding)
- ge A;
-
- ctx->hash->final(ctx, h_ram);
- reduce(h_ram);
- load32_le_buf(s32, s, 8);
- if (ge_frombytes_neg_vartime(&A, ctx->pk) || // A = -pk
- is_above_l(s32)) { // prevent s malleability
+ u8 h_ram [32];
+ u8 r_check[32];
+ hash_reduce(h_ram, signature, 32, public_key, 32, message, message_size);
+ if (crypto_eddsa_r_check(r_check, public_key, h_ram, signature + 32)) {
return -1;
}
- ge_double_scalarmult_vartime(&A, h_ram, s); // A = [s]B - [h_ram]pk
- ge_tobytes(ctx->pk, &A); // R_check = A
- return crypto_verify32(ctx->buf, ctx->pk); // R == R_check ? OK : fail
-}
-
-int crypto_check(const u8 signature[64], const u8 public_key[32],
- const u8 *message, size_t message_size)
-{
- crypto_check_ctx ctx;
- crypto_check_ctx_abstract *actx = (crypto_check_ctx_abstract*)&ctx;
- crypto_check_init (actx, signature, public_key);
- crypto_check_update(actx, message, message_size);
- return crypto_check_final(actx);
+ return crypto_verify32(r_check, signature); // R == R_check ? OK : fail
}
///////////////////////
};
// separate the main factor & the cofactor of the scalar
u8 scalar[32];
- COPY(scalar, secret_key, 32);
- trim_scalar(scalar);
+ crypto_eddsa_trim_scalar(scalar, secret_key);
// Separate the main factor and the cofactor
//
// Compute clean scalar multiplication
u8 scalar[32];
ge pk;
- COPY(scalar, secret_key, 32);
- trim_scalar(scalar);
+ crypto_eddsa_trim_scalar(scalar, secret_key);
ge_scalarmult_base(&pk, scalar);
// Compute low order point
0xfffffffe, 0xffffffff, 0xffffffff, 0x0fffffff,};
u8 scalar[32];
- COPY(scalar, private_key, 32);
- trim_scalar(scalar);
+ crypto_eddsa_trim_scalar(scalar, private_key);
// Convert the scalar in Montgomery form
// m_scl = scalar * 2^256 (modulo L)
/// Type definitions ///
////////////////////////
-// Vtable for EdDSA with a custom hash.
-// Instantiate it to define a custom hash.
-// Its size, contents, and layout, are part of the public API.
-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;
-
// Do not rely on the size or contents of any of the types below,
// they may change without notice.
size_t hash_size;
} crypto_blake2b_ctx;
-// Signatures (EdDSA)
-typedef struct {
- const crypto_sign_vtable *hash;
- uint8_t buf[96];
- uint8_t pk [32];
-} crypto_sign_ctx_abstract;
-typedef crypto_sign_ctx_abstract crypto_check_ctx_abstract;
-
-typedef struct {
- crypto_sign_ctx_abstract ctx;
- crypto_blake2b_ctx hash;
-} crypto_sign_ctx;
-typedef crypto_sign_ctx crypto_check_ctx;
-
////////////////////////////
/// High level interface ///
////////////////////////////
void crypto_blake2b_general_init(crypto_blake2b_ctx *ctx, size_t hash_size,
const uint8_t *key, size_t key_size);
-// vtable for signatures
-extern const crypto_sign_vtable crypto_blake2b_vtable;
-
// Password key derivation (Argon2 i)
// ----------------------------------
const uint8_t private_key[32],
const uint8_t curve_point[32]);
+// EdDSA
+// -----
+void crypto_eddsa_trim_scalar(uint8_t out[32], const uint8_t in[32]);
+void crypto_eddsa_reduce(uint8_t reduced[32], const uint8_t expanded[64]);
+void crypto_eddsa_mul_add(uint8_t r[32],
+ const uint8_t a[32],
+ const uint8_t b[32],
+ const uint8_t c[32]);
+void crypto_eddsa_scalarbase(uint8_t point[32], const uint8_t scalar[32]);
+int crypto_eddsa_r_check(uint8_t r_check[32],
+ const uint8_t public_key[32],
+ const uint8_t h_ram[32],
+ const uint8_t s[32]);
// EdDSA to X25519
// ---------------
void crypto_from_eddsa_public (uint8_t x25519[32], const uint8_t eddsa[32]);
-// EdDSA -- Incremental interface
-// ------------------------------
-
-// Signing (2 passes)
-// Make sure the two passes hash the same message,
-// else you might reveal the private key.
-void crypto_sign_init_first_pass(crypto_sign_ctx_abstract *ctx,
- const uint8_t secret_key[32],
- const uint8_t public_key[32]);
-void crypto_sign_update(crypto_sign_ctx_abstract *ctx,
- const uint8_t *message, size_t message_size);
-void crypto_sign_init_second_pass(crypto_sign_ctx_abstract *ctx);
-// use crypto_sign_update() again.
-void crypto_sign_final(crypto_sign_ctx_abstract *ctx, uint8_t signature[64]);
-
-// Verification (1 pass)
-// Make sure you don't use (parts of) the message
-// before you're done checking it.
-void crypto_check_init (crypto_check_ctx_abstract *ctx,
- const uint8_t signature[64],
- const uint8_t public_key[32]);
-void crypto_check_update(crypto_check_ctx_abstract *ctx,
- const uint8_t *message, size_t message_size);
-int crypto_check_final (crypto_check_ctx_abstract *ctx);
-
-// Custom hash interface
-void crypto_sign_public_key_custom_hash(uint8_t public_key[32],
- const uint8_t secret_key[32],
- const crypto_sign_vtable *hash);
-void crypto_sign_init_first_pass_custom_hash(crypto_sign_ctx_abstract *ctx,
- const uint8_t secret_key[32],
- const uint8_t public_key[32],
- const crypto_sign_vtable *hash);
-void crypto_check_init_custom_hash(crypto_check_ctx_abstract *ctx,
- const uint8_t signature[64],
- const uint8_t public_key[32],
- const crypto_sign_vtable *hash);
-
// Elligator 2
// -----------
crypto_sha512_final (&ctx, hash);
}
-static void sha512_vtable_init(void *ctx) {
- crypto_sha512_init(&((crypto_sign_ed25519_ctx*)ctx)->hash);
-}
-static void sha512_vtable_update(void *ctx, const u8 *m, size_t s) {
- crypto_sha512_update(&((crypto_sign_ed25519_ctx*)ctx)->hash, m, s);
-}
-static void sha512_vtable_final(void *ctx, u8 *h) {
- crypto_sha512_final(&((crypto_sign_ed25519_ctx*)ctx)->hash, h);
-}
-const crypto_sign_vtable crypto_sha512_vtable = {
- crypto_sha512,
- sha512_vtable_init,
- sha512_vtable_update,
- sha512_vtable_final,
- sizeof(crypto_sign_ed25519_ctx),
-};
-
////////////////////
/// HMAC SHA 512 ///
////////////////////
///////////////
/// Ed25519 ///
///////////////
-
-void crypto_ed25519_public_key(u8 public_key[32],
- const u8 secret_key[32])
+void crypto_ed25519_public_key(u8 public_key[32], const u8 secret_key[32])
{
- crypto_sign_public_key_custom_hash(public_key, secret_key,
- &crypto_sha512_vtable);
-}
-
-void crypto_ed25519_sign_init_first_pass(crypto_sign_ctx_abstract *ctx,
- const u8 secret_key[32],
- const u8 public_key[32])
-{
- crypto_sign_init_first_pass_custom_hash(ctx, secret_key, public_key,
- &crypto_sha512_vtable);
+ u8 a[64];
+ crypto_sha512(a, secret_key, 32);
+ crypto_eddsa_trim_scalar(a, a);
+ crypto_eddsa_scalarbase(public_key, a);
}
-void crypto_ed25519_check_init(crypto_check_ctx_abstract *ctx,
- const u8 signature[64],
- const u8 public_key[32])
+static void hash_reduce(u8 h[32],
+ const u8 *a, size_t a_size,
+ const u8 *b, size_t b_size,
+ const u8 *c, size_t c_size)
{
- crypto_check_init_custom_hash(ctx, signature, public_key,
- &crypto_sha512_vtable);
+ u8 hash[64];
+ crypto_sha512_ctx ctx;
+ crypto_sha512_init (&ctx);
+ crypto_sha512_update(&ctx, a, a_size);
+ crypto_sha512_update(&ctx, b, b_size);
+ crypto_sha512_update(&ctx, c, c_size);
+ crypto_sha512_final (&ctx, hash);
+ crypto_eddsa_reduce(h, hash);
}
void crypto_ed25519_sign(u8 signature [64],
const u8 public_key[32],
const u8 *message, size_t message_size)
{
- crypto_sign_ed25519_ctx ctx;
- crypto_sign_ctx_abstract *actx = (crypto_sign_ctx_abstract*)&ctx;
- crypto_ed25519_sign_init_first_pass (actx, secret_key, public_key);
- crypto_ed25519_sign_update (actx, message, message_size);
- crypto_ed25519_sign_init_second_pass(actx);
- crypto_ed25519_sign_update (actx, message, message_size);
- crypto_ed25519_sign_final (actx, signature);
+ u8 a[64];
+ crypto_sha512(a, secret_key, 32);
+ crypto_eddsa_trim_scalar(a, a);
+ u8 pk[32]; // not secret, not wiped
+ if (public_key == 0) {
+ crypto_eddsa_scalarbase(pk, a);
+ } else {
+ COPY(pk, public_key, 32);
+ }
+
+ // Deterministic part of EdDSA: Construct a nonce by hashing the message
+ // instead of generating a random number.
+ // An actual random number would work just fine, and would save us
+ // the trouble of hashing the message twice. If we did that
+ // however, the user could fuck it up and reuse the nonce.
+ u8 r[32];
+ hash_reduce(r, a + 32, 32, message, message_size, 0, 0);
+
+ // First half of the signature R = [r]B
+ u8 R[32]; // Not secret, not wiped
+ crypto_eddsa_scalarbase(R, r);
+
+ // Second half of the signature
+ u8 h_ram[32];
+ hash_reduce(h_ram, R, 32, pk, 32, message, message_size);
+ COPY(signature, R, 32);
+ crypto_eddsa_mul_add(signature + 32, h_ram, a, r); // s = h_ram * a + r
+
+ WIPE_BUFFER(a);
+ WIPE_BUFFER(r);
+ WIPE_BUFFER(h_ram);
}
int crypto_ed25519_check(const u8 signature [64],
const u8 public_key[32],
const u8 *message, size_t message_size)
{
- crypto_check_ed25519_ctx ctx;
- crypto_check_ctx_abstract *actx = (crypto_check_ctx_abstract*)&ctx;
- crypto_ed25519_check_init (actx, signature, public_key);
- crypto_ed25519_check_update(actx, message, message_size);
- return crypto_ed25519_check_final(actx);
+ u8 h_ram [32];
+ u8 r_check[32];
+ hash_reduce(h_ram, signature, 32, public_key, 32, message, message_size);
+ if (crypto_eddsa_r_check(r_check, public_key, h_ram, signature + 32)) {
+ return -1;
+ }
+ return crypto_verify32(r_check, signature); // R == R_check ? OK : fail
}
void crypto_from_ed25519_private(u8 x25519[32], const u8 eddsa[32])
crypto_sha512_ctx ctx;
} crypto_hmac_sha512_ctx;
-typedef struct {
- crypto_sign_ctx_abstract ctx;
- crypto_sha512_ctx hash;
-} crypto_sign_ed25519_ctx;
-typedef crypto_sign_ed25519_ctx crypto_check_ed25519_ctx;
// SHA 512
// -------
void crypto_sha512(uint8_t hash[64],
const uint8_t *message, size_t message_size);
-// vtable for signatures
-extern const crypto_sign_vtable crypto_sha512_vtable;
-
// HMAC SHA 512
// ------------
// Ed25519
// -------
-// Generate public key
void crypto_ed25519_public_key(uint8_t public_key[32],
const uint8_t secret_key[32]);
-// Direct interface
void crypto_ed25519_sign(uint8_t signature [64],
const uint8_t secret_key[32],
const uint8_t public_key[32], // optional, may be 0
const uint8_t public_key[32],
const uint8_t *message, size_t message_size);
-// Incremental interface
-void crypto_ed25519_sign_init_first_pass(crypto_sign_ctx_abstract *ctx,
- const uint8_t secret_key[32],
- const uint8_t public_key[32]);
-#define crypto_ed25519_sign_update crypto_sign_update
-#define crypto_ed25519_sign_init_second_pass crypto_sign_init_second_pass
-// use crypto_ed25519_sign_update() again.
-#define crypto_ed25519_sign_final crypto_sign_final
-
-void crypto_ed25519_check_init(crypto_check_ctx_abstract *ctx,
- const uint8_t signature[64],
- const uint8_t public_key[32]);
-#define crypto_ed25519_check_update crypto_check_update
-#define crypto_ed25519_check_final crypto_check_final
-
void crypto_from_ed25519_private(uint8_t x25519[32], const uint8_t eddsa[32]);
#define crypto_from_ed25519_public crypto_from_eddsa_public
return status;
}
-// Tests that the input and output buffers of crypto_sha_512 can overlap.
+// Tests that the input and output buffers of HMAC can overlap.
static int p_hmac_sha512_overlap()
{
#undef INPUT_SIZE
return status;
}
-static int p_eddsa_incremental()
-{
- int status = 0;
- FOR (i, 0, MESSAGE_SIZE) {
- RANDOM_INPUT(msg, MESSAGE_SIZE);
- RANDOM_INPUT(sk, 32);
- u8 pk [32]; crypto_sign_public_key(pk, sk);
- u8 sig_mono[64]; crypto_sign(sig_mono, sk, pk, msg, MESSAGE_SIZE);
- u8 sig_incr[64];
- {
- crypto_sign_ctx ctx;
- crypto_sign_ctx_abstract *actx = (crypto_sign_ctx_abstract*)&ctx;
- crypto_sign_init_first_pass (actx, sk, pk);
- crypto_sign_update (actx, msg , i);
- crypto_sign_update (actx, msg+i, MESSAGE_SIZE-i);
- crypto_sign_init_second_pass(actx);
- crypto_sign_update (actx, msg , i);
- crypto_sign_update (actx, msg+i, MESSAGE_SIZE-i);
- crypto_sign_final (actx, sig_incr);
- }
- status |= memcmp(sig_mono, sig_incr, 64);
- status |= crypto_check(sig_mono, pk, msg, MESSAGE_SIZE);
- {
- crypto_check_ctx ctx;
- crypto_check_ctx_abstract *actx = (crypto_check_ctx_abstract*)&ctx;
- crypto_check_init (actx, sig_incr, pk);
- crypto_check_update(actx, msg , i);
- crypto_check_update(actx, msg+i, MESSAGE_SIZE-i);
- status |= crypto_check_final(actx);
- }
- }
- printf("%s: EdDSA (incremental)\n", status != 0 ? "FAILED" : "OK");
- return status;
-}
-
static int p_aead()
{
int status = 0;
status |= p_eddsa_roundtrip();
status |= p_eddsa_random();
status |= p_eddsa_overlap();
- status |= p_eddsa_incremental();
status |= p_aead();
status |= p_elligator_direct_msb();
status |= p_elligator_direct_overlap();