| @@ -25,7 +25,7 @@ else | |||
| ARCH ?= arch_arm_32 | |||
| endif | |||
| FIELD ?= p448 | |||
| FIELD ?= p255 | |||
| WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \ | |||
| -Wmissing-declarations -Wunused-function -Wno-overlength-strings $(EXWARN) | |||
| @@ -1,651 +1,8 @@ | |||
| /** | |||
| * @file decaf.h | |||
| * @author Mike Hamburg | |||
| * | |||
| * @copyright | |||
| * Copyright (c) 2015 Cryptography Research, Inc. \n | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| * | |||
| * @brief A group of prime order p. | |||
| * | |||
| * The Decaf library implements cryptographic operations on a an elliptic curve | |||
| * group of prime order p. It accomplishes this by using a twisted Edwards | |||
| * curve (isogenous to Ed448-Goldilocks) and wiping out the cofactor. | |||
| * | |||
| * The formulas are all complete and have no special cases, except that | |||
| * decaf_448_decode can fail because not every sequence of bytes is a valid group | |||
| * element. | |||
| * | |||
| * The formulas contain no data-dependent branches, timing or memory accesses, | |||
| * except for decaf_448_base_double_scalarmul_non_secret. | |||
| * | |||
| * This library may support multiple curves eventually. The Ed448-Goldilocks | |||
| * specific identifiers are prefixed with DECAF_448 or decaf_448. | |||
| */ | |||
| #ifndef __DECAF_448_H__ | |||
| #define __DECAF_448_H__ 1 | |||
| #include <stdint.h> | |||
| #include <sys/types.h> | |||
| #ifndef __DECAF_H__ | |||
| #define __DECAF_H__ 1 | |||
| /* Goldilocks' build flags default to hidden and stripping executables. */ | |||
| /** @cond internal */ | |||
| #if defined(DOXYGEN) && !defined(__attribute__) | |||
| #define __attribute__((x)) | |||
| #endif | |||
| #define API_VIS __attribute__((visibility("default"))) | |||
| #define NOINLINE __attribute__((noinline)) | |||
| #define WARN_UNUSED __attribute__((warn_unused_result)) | |||
| #define NONNULL1 __attribute__((nonnull(1))) | |||
| #define NONNULL2 __attribute__((nonnull(1,2))) | |||
| #define NONNULL3 __attribute__((nonnull(1,2,3))) | |||
| #define NONNULL4 __attribute__((nonnull(1,2,3,4))) | |||
| #define NONNULL5 __attribute__((nonnull(1,2,3,4,5))) | |||
| #include "decaf_255.h" // MAGIC | |||
| /* Internal word types */ | |||
| #if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \ | |||
| && !defined(DECAF_FORCE_32_BIT) | |||
| #define DECAF_WORD_BITS 64 | |||
| typedef uint64_t decaf_word_t, decaf_bool_t; | |||
| typedef __uint128_t decaf_dword_t; | |||
| #else | |||
| #define DECAF_WORD_BITS 32 | |||
| typedef uint32_t decaf_word_t, decaf_bool_t; | |||
| typedef uint64_t decaf_dword_t; | |||
| #endif | |||
| #endif /* __DECAF_H__ */ | |||
| #define DECAF_448_LIMBS (512/DECAF_WORD_BITS) | |||
| #define DECAF_448_SCALAR_BITS 446 | |||
| #define DECAF_448_SCALAR_LIMBS (448/DECAF_WORD_BITS) | |||
| /** Galois field element internal structure */ | |||
| typedef struct gf_s { | |||
| decaf_word_t limb[DECAF_448_LIMBS]; | |||
| } __attribute__((aligned(32))) gf_s, gf[1]; | |||
| /** @endcond */ | |||
| /** Number of bytes in a serialized point. */ | |||
| #define DECAF_448_SER_BYTES 56 | |||
| /** Number of bytes in a serialized scalar. */ | |||
| #define DECAF_448_SCALAR_BYTES 56 | |||
| /** Twisted Edwards (-1,d-1) extended homogeneous coordinates */ | |||
| typedef struct decaf_448_point_s { /**@cond internal*/gf x,y,z,t;/**@endcond*/ } decaf_448_point_t[1]; | |||
| /** Precomputed table based on a point. Can be trivial implementation. */ | |||
| struct decaf_448_precomputed_s; | |||
| /** Precomputed table based on a point. Can be trivial implementation. */ | |||
| typedef struct decaf_448_precomputed_s decaf_448_precomputed_s; | |||
| /** Size and alignment of precomputed point tables. */ | |||
| extern const size_t sizeof_decaf_448_precomputed_s API_VIS, alignof_decaf_448_precomputed_s API_VIS; | |||
| /** Scalar is stored packed, because we don't need the speed. */ | |||
| typedef struct decaf_448_scalar_s { | |||
| /** @cond internal */ | |||
| decaf_word_t limb[DECAF_448_SCALAR_LIMBS]; | |||
| /** @endcond */ | |||
| } decaf_448_scalar_t[1]; | |||
| /** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */ | |||
| static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0; | |||
| /** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */ | |||
| static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/, | |||
| DECAF_FAILURE = 0 /*DECAF_FALSE*/; | |||
| /** A scalar equal to 1. */ | |||
| extern const decaf_448_scalar_t decaf_448_scalar_one API_VIS; | |||
| /** A scalar equal to 0. */ | |||
| extern const decaf_448_scalar_t decaf_448_scalar_zero API_VIS; | |||
| /** The identity point on the curve. */ | |||
| extern const decaf_448_point_t decaf_448_point_identity API_VIS; | |||
| /** | |||
| * An arbitrarily chosen base point on the curve. | |||
| * Equal to Ed448-Goldilocks base point defined by DJB, except of course that | |||
| * it's on the twist in this case. TODO: choose a base point with nice encoding? | |||
| */ | |||
| extern const decaf_448_point_t decaf_448_point_base API_VIS; | |||
| /** Precomputed table for the base point on the curve. */ | |||
| extern const struct decaf_448_precomputed_s *decaf_448_precomputed_base API_VIS; | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /** | |||
| * @brief Read a scalar from wire format or from bytes. | |||
| * | |||
| * @param [in] ser Serialized form of a scalar. | |||
| * @param [out] out Deserialized form. | |||
| * | |||
| * @retval DECAF_SUCCESS The scalar was correctly encoded. | |||
| * @retval DECAF_FAILURE The scalar was greater than the modulus, | |||
| * and has been reduced modulo that modulus. | |||
| */ | |||
| decaf_bool_t decaf_448_scalar_decode ( | |||
| decaf_448_scalar_t out, | |||
| const unsigned char ser[DECAF_448_SCALAR_BYTES] | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Read a scalar from wire format or from bytes. Reduces mod | |||
| * scalar prime. | |||
| * | |||
| * @param [in] ser Serialized form of a scalar. | |||
| * @param [in] ser_len Length of serialized form. | |||
| * @param [out] out Deserialized form. | |||
| */ | |||
| void decaf_448_scalar_decode_long ( | |||
| decaf_448_scalar_t out, | |||
| const unsigned char *ser, | |||
| size_t ser_len | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Serialize a scalar to wire format. | |||
| * | |||
| * @param [out] ser Serialized form of a scalar. | |||
| * @param [in] s Deserialized scalar. | |||
| */ | |||
| void decaf_448_scalar_encode ( | |||
| unsigned char ser[DECAF_448_SCALAR_BYTES], | |||
| const decaf_448_scalar_t s | |||
| ) API_VIS NONNULL2 NOINLINE NOINLINE; | |||
| /** | |||
| * @brief Add two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a+b. | |||
| */ | |||
| void decaf_448_scalar_add ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a, | |||
| const decaf_448_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Compare two scalars. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @retval DECAF_TRUE The scalars are equal. | |||
| * @retval DECAF_FALSE The scalars are not equal. | |||
| */ | |||
| decaf_bool_t decaf_448_scalar_eq ( | |||
| const decaf_448_scalar_t a, | |||
| const decaf_448_scalar_t b | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Subtract two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a-b. | |||
| */ | |||
| void decaf_448_scalar_sub ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a, | |||
| const decaf_448_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a*b. | |||
| */ | |||
| void decaf_448_scalar_mul ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a, | |||
| const decaf_448_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Invert a scalar. When passed zero, return 0. The input and output may alias. | |||
| * @param [in] a A scalar. | |||
| * @param [out] out 1/a. | |||
| * @return DECAF_TRUE The input is nonzero. | |||
| */ | |||
| decaf_bool_t decaf_448_scalar_invert ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Copy a scalar. The scalars may use the same memory, in which | |||
| * case this function does nothing. | |||
| * @param [in] a A scalar. | |||
| * @param [out] out Will become a copy of a. | |||
| */ | |||
| static inline void NONNULL2 decaf_448_scalar_copy ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a | |||
| ) { | |||
| *out = *a; | |||
| } | |||
| /** | |||
| * @brief Set a scalar to an integer. | |||
| * @param [in] a An integer. | |||
| * @param [out] out Will become equal to a. | |||
| * @todo Make inline? | |||
| */ | |||
| void decaf_448_scalar_set( | |||
| decaf_448_scalar_t out, | |||
| decaf_word_t a | |||
| ) API_VIS NONNULL1; | |||
| /** | |||
| * @brief Encode a point as a sequence of bytes. | |||
| * | |||
| * @param [out] ser The byte representation of the point. | |||
| * @param [in] pt The point to encode. | |||
| */ | |||
| void decaf_448_point_encode ( | |||
| uint8_t ser[DECAF_448_SER_BYTES], | |||
| const decaf_448_point_t pt | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Decode a point from a sequence of bytes. | |||
| * | |||
| * Every point has a unique encoding, so not every | |||
| * sequence of bytes is a valid encoding. If an invalid | |||
| * encoding is given, the output is undefined. | |||
| * | |||
| * @param [out] pt The decoded point. | |||
| * @param [in] ser The serialized version of the point. | |||
| * @param [in] allow_identity DECAF_TRUE if the identity is a legal input. | |||
| * @retval DECAF_SUCCESS The decoding succeeded. | |||
| * @retval DECAF_FAILURE The decoding didn't succeed, because | |||
| * ser does not represent a point. | |||
| */ | |||
| decaf_bool_t decaf_448_point_decode ( | |||
| decaf_448_point_t pt, | |||
| const uint8_t ser[DECAF_448_SER_BYTES], | |||
| decaf_bool_t allow_identity | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Copy a point. The input and output may alias, | |||
| * in which case this function does nothing. | |||
| * | |||
| * @param [out] a A copy of the point. | |||
| * @param [in] b Any point. | |||
| */ | |||
| static inline void NONNULL2 decaf_448_point_copy ( | |||
| decaf_448_point_t a, | |||
| const decaf_448_point_t b | |||
| ) { | |||
| *a=*b; | |||
| } | |||
| /** | |||
| * @brief Test whether two points are equal. If yes, return | |||
| * DECAF_TRUE, else return DECAF_FALSE. | |||
| * | |||
| * @param [in] a A point. | |||
| * @param [in] b Another point. | |||
| * @retval DECAF_TRUE The points are equal. | |||
| * @retval DECAF_FALSE The points are not equal. | |||
| */ | |||
| decaf_bool_t decaf_448_point_eq ( | |||
| const decaf_448_point_t a, | |||
| const decaf_448_point_t b | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Add two points to produce a third point. The | |||
| * input points and output point can be pointers to the same | |||
| * memory. | |||
| * | |||
| * @param [out] sum The sum a+b. | |||
| * @param [in] a An addend. | |||
| * @param [in] b An addend. | |||
| */ | |||
| void decaf_448_point_add ( | |||
| decaf_448_point_t sum, | |||
| const decaf_448_point_t a, | |||
| const decaf_448_point_t b | |||
| ) API_VIS NONNULL3; | |||
| /** | |||
| * @brief Double a point. Equivalent to | |||
| * decaf_448_point_add(two_a,a,a), but potentially faster. | |||
| * | |||
| * @param [out] two_a The sum a+a. | |||
| * @param [in] a A point. | |||
| */ | |||
| void decaf_448_point_double ( | |||
| decaf_448_point_t two_a, | |||
| const decaf_448_point_t a | |||
| ) API_VIS NONNULL2; | |||
| /** | |||
| * @brief Subtract two points to produce a third point. The | |||
| * input points and output point can be pointers to the same | |||
| * memory. | |||
| * | |||
| * @param [out] diff The difference a-b. | |||
| * @param [in] a The minuend. | |||
| * @param [in] b The subtrahend. | |||
| */ | |||
| void decaf_448_point_sub ( | |||
| decaf_448_point_t diff, | |||
| const decaf_448_point_t a, | |||
| const decaf_448_point_t b | |||
| ) API_VIS NONNULL3; | |||
| /** | |||
| * @brief Negate a point to produce another point. The input | |||
| * and output points can use the same memory. | |||
| * | |||
| * @param [out] nega The negated input point | |||
| * @param [in] a The input point. | |||
| */ | |||
| void decaf_448_point_negate ( | |||
| decaf_448_point_t nega, | |||
| const decaf_448_point_t a | |||
| ) API_VIS NONNULL2; | |||
| /** | |||
| * @brief Multiply a base point by a scalar: scaled = scalar*base. | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| */ | |||
| void decaf_448_point_scalarmul ( | |||
| decaf_448_point_t scaled, | |||
| const decaf_448_point_t base, | |||
| const decaf_448_scalar_t scalar | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply a base point by a scalar: scaled = scalar*base. | |||
| * This function operates directly on serialized forms. | |||
| * | |||
| * @warning This function is experimental. It may not be supported | |||
| * long-term. | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| * @param [in] allow_identity Allow the input to be the identity. | |||
| * @param [in] short_circuit Allow a fast return if the input is illegal. | |||
| * | |||
| * @retval DECAF_SUCCESS The scalarmul succeeded. | |||
| * @retval DECAF_FAILURE The scalarmul didn't succeed, because | |||
| * base does not represent a point. | |||
| */ | |||
| decaf_bool_t decaf_448_direct_scalarmul ( | |||
| uint8_t scaled[DECAF_448_SER_BYTES], | |||
| const uint8_t base[DECAF_448_SER_BYTES], | |||
| const decaf_448_scalar_t scalar, | |||
| decaf_bool_t allow_identity, | |||
| decaf_bool_t short_circuit | |||
| ) API_VIS NONNULL3 WARN_UNUSED NOINLINE; | |||
| /** | |||
| * @brief Precompute a table for fast scalar multiplication. | |||
| * Some implementations do not include precomputed points; for | |||
| * those implementations, this implementation simply copies the | |||
| * point. | |||
| * | |||
| * @param [out] a A precomputed table of multiples of the point. | |||
| * @param [in] b Any point. | |||
| */ | |||
| void decaf_448_precompute ( | |||
| decaf_448_precomputed_s *a, | |||
| const decaf_448_point_t b | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Multiply a precomputed base point by a scalar: | |||
| * scaled = scalar*base. | |||
| * Some implementations do not include precomputed points; for | |||
| * those implementations, this function is the same as | |||
| * decaf_448_point_scalarmul | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| * | |||
| * @todo precomputed dsmul? const or variable time? | |||
| */ | |||
| void decaf_448_precomputed_scalarmul ( | |||
| decaf_448_point_t scaled, | |||
| const decaf_448_precomputed_s *base, | |||
| const decaf_448_scalar_t scalar | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply two base points by two scalars: | |||
| * scaled = scalar1*base1 + scalar2*base2. | |||
| * | |||
| * Equivalent to two calls to decaf_448_point_scalarmul, but may be | |||
| * faster. | |||
| * | |||
| * @param [out] combo The linear combination scalar1*base1 + scalar2*base2. | |||
| * @param [in] base1 A first point to be scaled. | |||
| * @param [in] scalar1 A first scalar to multiply by. | |||
| * @param [in] base2 A second point to be scaled. | |||
| * @param [in] scalar2 A second scalar to multiply by. | |||
| */ | |||
| void decaf_448_point_double_scalarmul ( | |||
| decaf_448_point_t combo, | |||
| const decaf_448_point_t base1, | |||
| const decaf_448_scalar_t scalar1, | |||
| const decaf_448_point_t base2, | |||
| const decaf_448_scalar_t scalar2 | |||
| ) API_VIS NONNULL5 NOINLINE; | |||
| /** | |||
| * @brief Multiply two base points by two scalars: | |||
| * scaled = scalar1*decaf_448_point_base + scalar2*base2. | |||
| * | |||
| * Otherwise equivalent to decaf_448_point_double_scalarmul, but may be | |||
| * faster at the expense of being variable time. | |||
| * | |||
| * @param [out] combo The linear combination scalar1*base + scalar2*base2. | |||
| * @param [in] scalar1 A first scalar to multiply by. | |||
| * @param [in] base2 A second point to be scaled. | |||
| * @param [in] scalar2 A second scalar to multiply by. | |||
| * | |||
| * @warning: This function takes variable time, and may leak the scalars | |||
| * used. It is designed for signature verification. | |||
| */ | |||
| void decaf_448_base_double_scalarmul_non_secret ( | |||
| decaf_448_point_t combo, | |||
| const decaf_448_scalar_t scalar1, | |||
| const decaf_448_point_t base2, | |||
| const decaf_448_scalar_t scalar2 | |||
| ) API_VIS NONNULL4 NOINLINE; | |||
| /** | |||
| * @brief Test that a point is valid, for debugging purposes. | |||
| * | |||
| * @param [in] toTest The point to test. | |||
| * @retval DECAF_TRUE The point is valid. | |||
| * @retval DECAF_FALSE The point is invalid. | |||
| */ | |||
| decaf_bool_t decaf_448_point_valid ( | |||
| const decaf_448_point_t toTest | |||
| ) API_VIS WARN_UNUSED NONNULL1 NOINLINE; | |||
| /** | |||
| * @brief 2-torque a point, for debugging purposes. | |||
| * | |||
| * @param [out] q The point to torque. | |||
| * @param [in] p The point to torque. | |||
| */ | |||
| void decaf_448_point_debugging_2torque ( | |||
| decaf_448_point_t q, | |||
| const decaf_448_point_t p | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Almost-Elligator-like hash to curve. | |||
| * | |||
| * Call this function with the output of a hash to make a hash to the curve. | |||
| * | |||
| * This function runs Elligator2 on the decaf_448 Jacobi quartic model. It then | |||
| * uses the isogeny to put the result in twisted Edwards form. As a result, | |||
| * it is safe (cannot produce points of order 4), and would be compatible with | |||
| * hypothetical other implementations of Decaf using a Montgomery or untwisted | |||
| * Edwards model. | |||
| * | |||
| * Unlike Elligator, this function may be up to 4:1 on [0,(p-1)/2]: | |||
| * A factor of 2 due to the isogeny. | |||
| * A factor of 2 because we quotient out the 2-torsion. | |||
| * | |||
| * This makes it about 8:1 overall. | |||
| * | |||
| * Negating the input (mod q) results in the same point. Inverting the input | |||
| * (mod q) results in the negative point. This is the same as Elligator. | |||
| * | |||
| * This function isn't quite indifferentiable from a random oracle. | |||
| * However, it is suitable for many protocols, including SPEKE and SPAKE2 EE. | |||
| * Furthermore, calling it twice with independent seeds and adding the results | |||
| * is indifferentiable from a random oracle. | |||
| * | |||
| * @param [in] hashed_data Output of some hash function. | |||
| * @param [out] pt The data hashed to the curve. | |||
| * @return A "hint" value which can be used to help invert the encoding. | |||
| */ | |||
| unsigned char | |||
| decaf_448_point_from_hash_nonuniform ( | |||
| decaf_448_point_t pt, | |||
| const unsigned char hashed_data[DECAF_448_SER_BYTES] | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Inverse of elligator-like hash to curve. | |||
| * | |||
| * This function writes to the buffer, to make it so that | |||
| * decaf_448_point_from_hash_nonuniform(buffer) = pt,hint | |||
| * if possible. | |||
| * | |||
| * @param [out] recovered_hash Encoded data. | |||
| * @param [in] pt The point to encode. | |||
| * @param [in] hint The hint value returned from | |||
| * decaf_448_point_from_hash_nonuniform. | |||
| * | |||
| * @retval DECAF_SUCCESS The inverse succeeded. | |||
| * @retval DECAF_FAILURE The pt isn't the image of | |||
| * decaf_448_point_from_hash_nonuniform with the given hint. | |||
| * | |||
| * @warning The hinting system is subject to change, especially in corner cases. | |||
| * @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF. | |||
| */ | |||
| decaf_bool_t | |||
| decaf_448_invert_elligator_nonuniform ( | |||
| unsigned char recovered_hash[DECAF_448_SER_BYTES], | |||
| const decaf_448_point_t pt, | |||
| unsigned char hint | |||
| ) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
| /** | |||
| * @brief Inverse of elligator-like hash to curve, uniform. | |||
| * | |||
| * This function modifies the first DECAF_448_SER_BYTES of the | |||
| * buffer, to make it so that | |||
| * decaf_448_point_from_hash_uniform(buffer) = pt,hint | |||
| * if possible. | |||
| * | |||
| * @param [out] recovered_hash Encoded data. | |||
| * @param [in] pt The point to encode. | |||
| * @param [in] hint The hint value returned from | |||
| * decaf_448_point_from_hash_nonuniform. | |||
| * | |||
| * @retval DECAF_SUCCESS The inverse succeeded. | |||
| * @retval DECAF_FAILURE The pt isn't the image of | |||
| * decaf_448_point_from_hash_uniform with the given hint. | |||
| * | |||
| * @warning The hinting system is subject to change, especially in corner cases. | |||
| * @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF. | |||
| */ | |||
| decaf_bool_t | |||
| decaf_448_invert_elligator_uniform ( | |||
| unsigned char recovered_hash[2*DECAF_448_SER_BYTES], | |||
| const decaf_448_point_t pt, | |||
| unsigned char hint | |||
| ) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
| /** | |||
| * @brief Indifferentiable hash function encoding to curve. | |||
| * | |||
| * Equivalent to calling decaf_448_point_from_hash_nonuniform twice and adding. | |||
| * | |||
| * @param [in] hashed_data Output of some hash function. | |||
| * @param [out] pt The data hashed to the curve. | |||
| * @return A "hint" value which can be used to help invert the encoding. | |||
| */ | |||
| unsigned char decaf_448_point_from_hash_uniform ( | |||
| decaf_448_point_t pt, | |||
| const unsigned char hashed_data[2*DECAF_448_SER_BYTES] | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Overwrite data with zeros. Uses memset_s if available. | |||
| */ | |||
| void decaf_bzero ( | |||
| void *data, | |||
| size_t size | |||
| ) NONNULL1 API_VIS NOINLINE; | |||
| /** | |||
| * @brief Compare two buffers, returning DECAF_TRUE if they are equal. | |||
| */ | |||
| decaf_bool_t decaf_memeq ( | |||
| const void *data1, | |||
| const void *data2, | |||
| size_t size | |||
| ) NONNULL2 WARN_UNUSED API_VIS NOINLINE; | |||
| /** | |||
| * @brief Overwrite scalar with zeros. | |||
| */ | |||
| void decaf_448_scalar_destroy ( | |||
| decaf_448_scalar_t scalar | |||
| ) NONNULL1 API_VIS; | |||
| /** | |||
| * @brief Overwrite point with zeros. | |||
| * @todo Use this internally. | |||
| */ | |||
| void decaf_448_point_destroy ( | |||
| decaf_448_point_t point | |||
| ) NONNULL1 API_VIS; | |||
| /** | |||
| * @brief Overwrite point with zeros. | |||
| * @todo Use this internally. | |||
| */ | |||
| void decaf_448_precomputed_destroy ( | |||
| decaf_448_precomputed_s *pre | |||
| ) NONNULL1 API_VIS; | |||
| /* TODO: functions to invert point_from_hash?? */ | |||
| #undef API_VIS | |||
| #undef WARN_UNUSED | |||
| #undef NOINLINE | |||
| #undef NONNULL1 | |||
| #undef NONNULL2 | |||
| #undef NONNULL3 | |||
| #undef NONNULL4 | |||
| #undef NONNULL5 | |||
| #ifdef __cplusplus | |||
| } /* extern "C" */ | |||
| #endif | |||
| #endif /* __DECAF_448_H__ */ | |||
| @@ -1,738 +1,8 @@ | |||
| /** | |||
| * @file decaf.hxx | |||
| * @author Mike Hamburg | |||
| * | |||
| * @copyright | |||
| * Copyright (c) 2015 Cryptography Research, Inc. \n | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| * | |||
| * @brief A group of prime order p, C++ wrapper. | |||
| * | |||
| * The Decaf library implements cryptographic operations on a an elliptic curve | |||
| * group of prime order p. It accomplishes this by using a twisted Edwards | |||
| * curve (isogenous to Ed448-Goldilocks) and wiping out the cofactor. | |||
| * | |||
| * The formulas are all complete and have no special cases, except that | |||
| * decaf_448_decode can fail because not every sequence of bytes is a valid group | |||
| * element. | |||
| * | |||
| * The formulas contain no data-dependent branches, timing or memory accesses, | |||
| * except for decaf_448_base_double_scalarmul_non_secret. | |||
| */ | |||
| #ifndef __DECAF_448_HXX__ | |||
| #define __DECAF_448_HXX__ 1 | |||
| /** This code uses posix_memalign. */ | |||
| #define _XOPEN_SOURCE 600 | |||
| #include <stdlib.h> | |||
| #include <string.h> /* for memcpy */ | |||
| #ifndef __DECAF_HXX__ | |||
| #define __DECAF_HXX__ 1 | |||
| #include "decaf.h" | |||
| #include <string> | |||
| #include <sys/types.h> | |||
| #include <limits.h> | |||
| #include "decaf_255.hxx" // MAGIC | |||
| /* TODO: This is incomplete */ | |||
| /* TODO: attribute nonnull */ | |||
| #endif /* __DECAF_H__ */ | |||
| /** @cond internal */ | |||
| #if __cplusplus >= 201103L | |||
| #define NOEXCEPT noexcept | |||
| #define EXPLICIT_CON explicit | |||
| #define GET_DATA(str) ((const unsigned char *)&(str)[0]) | |||
| #else | |||
| #define NOEXCEPT throw() | |||
| #define EXPLICIT_CON | |||
| #define GET_DATA(str) ((const unsigned char *)((str).data())) | |||
| #endif | |||
| /** @endcond */ | |||
| namespace decaf { | |||
| /** @brief An exception for when crypto (ie point decode) has failed. */ | |||
| class CryptoException : public std::exception { | |||
| public: | |||
| /** @return "CryptoException" */ | |||
| virtual const char * what() const NOEXCEPT { return "CryptoException"; } | |||
| }; | |||
| /** @brief An exception for when crypto (ie point decode) has failed. */ | |||
| class LengthException : public std::exception { | |||
| public: | |||
| /** @return "CryptoException" */ | |||
| virtual const char * what() const NOEXCEPT { return "LengthException"; } | |||
| }; | |||
| /** | |||
| * Securely erase contents of memory. | |||
| */ | |||
| static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); } | |||
| /** Block object */ | |||
| class Block { | |||
| protected: | |||
| unsigned char *data_; | |||
| size_t size_; | |||
| public: | |||
| /** Empty init */ | |||
| inline Block() NOEXCEPT : data_(NULL), size_(0) {} | |||
| /** Init from C string */ | |||
| inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {} | |||
| /** Unowned init */ | |||
| inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {} | |||
| /** Block from std::string */ | |||
| inline Block(const std::string &s) : data_((unsigned char *)GET_DATA(s)), size_(s.size()) {} | |||
| /** Get const data */ | |||
| inline const unsigned char *data() const NOEXCEPT { return data_; } | |||
| /** Get the size */ | |||
| inline size_t size() const NOEXCEPT { return size_; } | |||
| /** Autocast to const unsigned char * */ | |||
| inline operator const unsigned char*() const NOEXCEPT { return data_; } | |||
| /** Convert to C++ string */ | |||
| inline std::string get_string() const { | |||
| return std::string((const char *)data_,size_); | |||
| } | |||
| /** Slice the buffer*/ | |||
| inline Block slice(size_t off, size_t length) const throw(LengthException) { | |||
| if (off > size() || length > size() - off) | |||
| throw LengthException(); | |||
| return Block(data()+off, length); | |||
| } | |||
| /** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */ | |||
| inline virtual ~Block() {}; | |||
| }; | |||
| class TmpBuffer; | |||
| class Buffer : public Block { | |||
| public: | |||
| /** Null init */ | |||
| inline Buffer() NOEXCEPT : Block() {} | |||
| /** Unowned init */ | |||
| inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {} | |||
| /** Get unconst data */ | |||
| inline unsigned char *data() NOEXCEPT { return data_; } | |||
| /** Get const data */ | |||
| inline const unsigned char *data() const NOEXCEPT { return data_; } | |||
| /** Autocast to const unsigned char * */ | |||
| inline operator const unsigned char*() const NOEXCEPT { return data_; } | |||
| /** Autocast to unsigned char */ | |||
| inline operator unsigned char*() NOEXCEPT { return data_; } | |||
| /** Slice the buffer*/ | |||
| inline TmpBuffer slice(size_t off, size_t length) throw(LengthException); | |||
| }; | |||
| class TmpBuffer : public Buffer { | |||
| public: | |||
| /** Unowned init */ | |||
| inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {} | |||
| }; | |||
| TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) { | |||
| if (off > size() || length > size() - off) throw LengthException(); | |||
| return TmpBuffer(data()+off, length); | |||
| } | |||
| /** A self-erasing block of data */ | |||
| class SecureBuffer : public Buffer { | |||
| public: | |||
| /** Null secure block */ | |||
| inline SecureBuffer() NOEXCEPT : Buffer() {} | |||
| /** Construct empty from size */ | |||
| inline SecureBuffer(size_t size) { | |||
| data_ = new unsigned char[size_ = size]; | |||
| memset(data_,0,size); | |||
| } | |||
| /** Construct from data */ | |||
| inline SecureBuffer(const unsigned char *data, size_t size){ | |||
| data_ = new unsigned char[size_ = size]; | |||
| memcpy(data_, data, size); | |||
| } | |||
| /** Copy constructor */ | |||
| inline SecureBuffer(const Block ©) : Buffer() { *this = copy; } | |||
| /** Copy-assign constructor */ | |||
| inline SecureBuffer& operator=(const Block ©) throw(std::bad_alloc) { | |||
| if (© == this) return *this; | |||
| clear(); | |||
| data_ = new unsigned char[size_ = copy.size()]; | |||
| memcpy(data_,copy.data(),size_); | |||
| return *this; | |||
| } | |||
| /** Copy-assign constructor */ | |||
| inline SecureBuffer& operator=(const SecureBuffer ©) throw(std::bad_alloc) { | |||
| if (© == this) return *this; | |||
| clear(); | |||
| data_ = new unsigned char[size_ = copy.size()]; | |||
| memcpy(data_,copy.data(),size_); | |||
| return *this; | |||
| } | |||
| /** Destructor erases data */ | |||
| ~SecureBuffer() NOEXCEPT { clear(); } | |||
| /** Clear data */ | |||
| inline void clear() NOEXCEPT { | |||
| if (data_ == NULL) return; | |||
| really_bzero(data_,size_); | |||
| delete[] data_; | |||
| data_ = NULL; | |||
| size_ = 0; | |||
| } | |||
| #if __cplusplus >= 201103L | |||
| /** Move constructor */ | |||
| inline SecureBuffer(SecureBuffer &&move) { *this = move; } | |||
| /** Move non-constructor */ | |||
| inline SecureBuffer(Block &&move) { *this = (Block &)move; } | |||
| /** Move-assign constructor. TODO: check that this actually gets used.*/ | |||
| inline SecureBuffer& operator=(SecureBuffer &&move) { | |||
| clear(); | |||
| data_ = move.data_; move.data_ = NULL; | |||
| size_ = move.size_; move.size_ = 0; | |||
| return *this; | |||
| } | |||
| /** C++11-only explicit cast */ | |||
| inline explicit operator std::string() const { return get_string(); } | |||
| #endif | |||
| }; | |||
| /** @brief Passed to constructors to avoid (conservative) initialization */ | |||
| struct NOINIT {}; | |||
| /**@cond internal*/ | |||
| /** Forward-declare sponge RNG object */ | |||
| class SpongeRng; | |||
| /**@endcond*/ | |||
| /** | |||
| * @brief Ed448-Goldilocks/Decaf instantiation of group. | |||
| */ | |||
| struct Ed448 { | |||
| /** @cond internal */ | |||
| class Point; | |||
| class Precomputed; | |||
| /** @endcond */ | |||
| /** | |||
| * @brief A scalar modulo the curve order. | |||
| * Supports the usual arithmetic operations, all in constant time. | |||
| */ | |||
| class Scalar { | |||
| public: | |||
| /** @brief Size of a serialized element */ | |||
| static const size_t SER_BYTES = DECAF_448_SCALAR_BYTES; | |||
| /** @brief access to the underlying scalar object */ | |||
| decaf_448_scalar_t s; | |||
| /** @brief Don't initialize. */ | |||
| inline Scalar(const NOINIT &) NOEXCEPT {} | |||
| /** @brief Set to an unsigned word */ | |||
| inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; } | |||
| /** @brief Set to a signed word */ | |||
| inline Scalar(const int w) NOEXCEPT { *this = w; } | |||
| /** @brief Construct from RNG */ | |||
| inline explicit Scalar(SpongeRng &rng) NOEXCEPT; | |||
| /** @brief Construct from decaf_scalar_t object. */ | |||
| inline Scalar(const decaf_448_scalar_t &t = decaf_448_scalar_zero) NOEXCEPT { decaf_448_scalar_copy(s,t); } | |||
| /** @brief Copy constructor. */ | |||
| inline Scalar(const Scalar &x) NOEXCEPT { *this = x; } | |||
| /** @brief Construct from arbitrary-length little-endian byte sequence. */ | |||
| inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; } | |||
| /** @brief Assignment. */ | |||
| inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; } | |||
| /** @brief Assign from unsigned word. */ | |||
| inline Scalar& operator=(decaf_word_t w) NOEXCEPT { decaf_448_scalar_set(s,w); return *this; } | |||
| /** @brief Assign from signed int. */ | |||
| inline Scalar& operator=(int w) NOEXCEPT { | |||
| Scalar t(-(decaf_word_t)INT_MIN); | |||
| decaf_448_scalar_set(s,(decaf_word_t)w - (decaf_word_t)INT_MIN); | |||
| *this -= t; | |||
| return *this; | |||
| } | |||
| /** Destructor securely erases the scalar. */ | |||
| inline ~Scalar() NOEXCEPT { decaf_448_scalar_destroy(s); } | |||
| /** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */ | |||
| inline Scalar &operator=(const Block &bl) NOEXCEPT { | |||
| decaf_448_scalar_decode_long(s,bl.data(),bl.size()); return *this; | |||
| } | |||
| /** | |||
| * @brief Decode from correct-length little-endian byte sequence. | |||
| * @return DECAF_FAILURE if the scalar is greater than or equal to the group order q. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Scalar &sc, const unsigned char buffer[SER_BYTES] | |||
| ) NOEXCEPT { | |||
| return decaf_448_scalar_decode(sc.s,buffer); | |||
| } | |||
| /** @brief Decode from correct-length little-endian byte sequence in C++ string. */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Scalar &sc, const Block &buffer | |||
| ) NOEXCEPT { | |||
| if (buffer.size() != SER_BYTES) return DECAF_FAILURE; | |||
| return decaf_448_scalar_decode(sc.s,buffer); | |||
| } | |||
| /** @brief Encode to fixed-length string */ | |||
| inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT { | |||
| SecureBuffer buf(SER_BYTES); decaf_448_scalar_encode(buf,s); return buf; | |||
| } | |||
| /** @brief Encode to fixed-length buffer */ | |||
| inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{ | |||
| decaf_448_scalar_encode(buffer, s); | |||
| } | |||
| /** Add. */ | |||
| inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_add(r.s,s,q.s); return r; } | |||
| /** Add to this. */ | |||
| inline Scalar &operator+=(const Scalar &q) NOEXCEPT { decaf_448_scalar_add(s,s,q.s); return *this; } | |||
| /** Subtract. */ | |||
| inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_sub(r.s,s,q.s); return r; } | |||
| /** Subtract from this. */ | |||
| inline Scalar &operator-=(const Scalar &q) NOEXCEPT { decaf_448_scalar_sub(s,s,q.s); return *this; } | |||
| /** Multiply */ | |||
| inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_mul(r.s,s,q.s); return r; } | |||
| /** Multiply into this. */ | |||
| inline Scalar &operator*=(const Scalar &q) NOEXCEPT { decaf_448_scalar_mul(s,s,q.s); return *this; } | |||
| /** Negate */ | |||
| inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_sub(r.s,decaf_448_scalar_zero,s); return r; } | |||
| /** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */ | |||
| inline Scalar inverse() const NOEXCEPT { Scalar r; decaf_448_scalar_invert(r.s,s); return r; } | |||
| /** @brief Divide by inverting q. If q == 0, return 0. */ | |||
| inline Scalar operator/ (const Scalar &q) const NOEXCEPT { return *this * q.inverse(); } | |||
| /** @brief Divide by inverting q. If q == 0, return 0. */ | |||
| inline Scalar &operator/=(const Scalar &q) NOEXCEPT { return *this *= q.inverse(); } | |||
| /** @brief Compare in constant time */ | |||
| inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); } | |||
| /** @brief Compare in constant time */ | |||
| inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_448_scalar_eq(s,q.s); } | |||
| /** @brief Scalarmul with scalar on left. */ | |||
| inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); } | |||
| /** @brief Scalarmul-precomputed with scalar on left. */ | |||
| inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); } | |||
| /** @brief Direct scalar multiplication. */ | |||
| inline SecureBuffer direct_scalarmul( | |||
| const Block &in, | |||
| decaf_bool_t allow_identity=DECAF_FALSE, | |||
| decaf_bool_t short_circuit=DECAF_TRUE | |||
| ) const throw(CryptoException) { | |||
| SecureBuffer out(/*FIXME Point::*/SER_BYTES); | |||
| if (!decaf_448_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit)) | |||
| throw CryptoException(); | |||
| return out; | |||
| } | |||
| }; | |||
| /** | |||
| * @brief Element of prime-order group. | |||
| */ | |||
| class Point { | |||
| public: | |||
| /** @brief Size of a serialized element */ | |||
| static const size_t SER_BYTES = DECAF_448_SER_BYTES; | |||
| /** @brief Size of a stegged element */ | |||
| static const size_t STEG_BYTES = DECAF_448_SER_BYTES + 8; | |||
| /** @brief Bytes required for hash */ | |||
| static const size_t HASH_BYTES = DECAF_448_SER_BYTES; | |||
| /** The c-level object. */ | |||
| decaf_448_point_t p; | |||
| /** @brief Don't initialize. */ | |||
| inline Point(const NOINIT &) NOEXCEPT {} | |||
| /** @brief Constructor sets to identity by default. */ | |||
| inline Point(const decaf_448_point_t &q = decaf_448_point_identity) NOEXCEPT { decaf_448_point_copy(p,q); } | |||
| /** @brief Copy constructor. */ | |||
| inline Point(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); } | |||
| /** @brief Assignment. */ | |||
| inline Point& operator=(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); return *this; } | |||
| /** @brief Destructor securely erases the point. */ | |||
| inline ~Point() NOEXCEPT { decaf_448_point_destroy(p); } | |||
| /** @brief Construct from RNG */ | |||
| inline explicit Point(SpongeRng &rng, bool uniform = true) NOEXCEPT; | |||
| /** | |||
| * @brief Initialize from C++ fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. | |||
| */ | |||
| inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) { | |||
| if (!decode(*this,s,allow_identity)) throw CryptoException(); | |||
| } | |||
| /** | |||
| * @brief Initialize from C fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. | |||
| */ | |||
| inline explicit Point(const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE) | |||
| throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); } | |||
| /** | |||
| * @brief Initialize from C fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @retval DECAF_SUCCESS the string was successfully decoded. | |||
| * @return DECAF_FAILURE the string wasn't the encoding of a point, or was the identity | |||
| * and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Point &p, const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE | |||
| ) NOEXCEPT { | |||
| return decaf_448_point_decode(p.p,buffer,allow_identity); | |||
| } | |||
| /** | |||
| * @brief Initialize from C++ fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @retval DECAF_SUCCESS the string was successfully decoded. | |||
| * @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
| ) NOEXCEPT { | |||
| if (buffer.size() != SER_BYTES) return DECAF_FAILURE; | |||
| return decaf_448_point_decode(p.p,buffer.data(),allow_identity); | |||
| } | |||
| /** | |||
| * @brief Map uniformly to the curve from a hash buffer. | |||
| * The empty or all-zero string maps to the identity, as does the string "\x01". | |||
| * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform, | |||
| * but the buffer will be zero-padded on the right. | |||
| */ | |||
| static inline Point from_hash ( const Block &s ) NOEXCEPT { | |||
| Point p((NOINIT())); p.set_to_hash(s); return p; | |||
| } | |||
| /** | |||
| * @brief Map to the curve from a hash buffer. | |||
| * The empty or all-zero string maps to the identity, as does the string "\x01". | |||
| * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform, | |||
| * but the buffer will be zero-padded on the right. | |||
| */ | |||
| inline unsigned char set_to_hash( const Block &s ) NOEXCEPT { | |||
| if (s.size() < HASH_BYTES) { | |||
| SecureBuffer b(HASH_BYTES); | |||
| memcpy(b.data(), s.data(), s.size()); | |||
| return decaf_448_point_from_hash_nonuniform(p,b); | |||
| } else if (s.size() == HASH_BYTES) { | |||
| return decaf_448_point_from_hash_nonuniform(p,s); | |||
| } else if (s.size() < 2*HASH_BYTES) { | |||
| SecureBuffer b(2*HASH_BYTES); | |||
| memcpy(b.data(), s.data(), s.size()); | |||
| return decaf_448_point_from_hash_uniform(p,b); | |||
| } else { | |||
| return decaf_448_point_from_hash_uniform(p,s); | |||
| } | |||
| } | |||
| /** | |||
| * @brief Encode to string. The identity encodes to the all-zero string. | |||
| */ | |||
| inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT { | |||
| SecureBuffer buffer(SER_BYTES); | |||
| decaf_448_point_encode(buffer, p); | |||
| return buffer; | |||
| } | |||
| /** | |||
| * @brief Encode to a C buffer. The identity encodes to all zeros. | |||
| */ | |||
| inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{ | |||
| decaf_448_point_encode(buffer, p); | |||
| } | |||
| /** @brief Point add. */ | |||
| inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_add(r.p,p,q.p); return r; } | |||
| /** @brief Point add. */ | |||
| inline Point &operator+=(const Point &q) NOEXCEPT { decaf_448_point_add(p,p,q.p); return *this; } | |||
| /** @brief Point subtract. */ | |||
| inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_sub(r.p,p,q.p); return r; } | |||
| /** @brief Point subtract. */ | |||
| inline Point &operator-=(const Point &q) NOEXCEPT { decaf_448_point_sub(p,p,q.p); return *this; } | |||
| /** @brief Point negate. */ | |||
| inline Point operator- () const NOEXCEPT { Point r((NOINIT())); decaf_448_point_negate(r.p,p); return r; } | |||
| /** @brief Double the point out of place. */ | |||
| inline Point times_two () const NOEXCEPT { Point r((NOINIT())); decaf_448_point_double(r.p,p); return r; } | |||
| /** @brief Double the point in place. */ | |||
| inline Point &double_in_place() NOEXCEPT { decaf_448_point_double(p,p); return *this; } | |||
| /** @brief Constant-time compare. */ | |||
| inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_448_point_eq(p,q.p); } | |||
| /** @brief Constant-time compare. */ | |||
| inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_448_point_eq(p,q.p); } | |||
| /** @brief Scalar multiply. */ | |||
| inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_scalarmul(r.p,p,s.s); return r; } | |||
| /** @brief Scalar multiply in place. */ | |||
| inline Point &operator*=(const Scalar &s) NOEXCEPT { decaf_448_point_scalarmul(p,p,s.s); return *this; } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point &operator/=(const Scalar &s) NOEXCEPT { return (*this) *= s.inverse(); } | |||
| /** @brief Validate / sanity check */ | |||
| inline bool validate() const NOEXCEPT { return !!decaf_448_point_valid(p); } | |||
| /** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */ | |||
| static inline Point double_scalarmul ( | |||
| const Point &q, const Scalar &qs, const Point &r, const Scalar &rs | |||
| ) NOEXCEPT { | |||
| Point p((NOINIT())); decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
| } | |||
| /** | |||
| * @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. | |||
| * For those who like their scalars before the point. | |||
| */ | |||
| static inline Point double_scalarmul ( | |||
| const Scalar &qs, const Point &q, const Scalar &rs, const Point &r | |||
| ) NOEXCEPT { | |||
| Point p((NOINIT())); decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
| } | |||
| /** | |||
| * @brief Double-scalar multiply: this point by the first scalar and base by the second scalar. | |||
| * @warning This function takes variable time, and may leak the scalars (or points, but currently | |||
| * it doesn't). | |||
| */ | |||
| inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT { | |||
| Point r((NOINIT())); decaf_448_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r; | |||
| } | |||
| inline Point& debugging_torque_in_place() { | |||
| decaf_448_point_debugging_2torque(p,p); | |||
| return *this; | |||
| } | |||
| inline bool invert_elligator ( | |||
| Buffer &buf, unsigned char hint | |||
| ) const NOEXCEPT { | |||
| unsigned char buf2[2*HASH_BYTES]; | |||
| memset(buf2,0,sizeof(buf2)); | |||
| memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
| decaf_bool_t ret; | |||
| if (buf.size() > HASH_BYTES) { | |||
| ret = decaf_448_invert_elligator_uniform(buf2, p, hint); | |||
| } else { | |||
| ret = decaf_448_invert_elligator_nonuniform(buf2, p, hint); | |||
| } | |||
| if (buf.size() < HASH_BYTES) { | |||
| ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size()); | |||
| } | |||
| memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
| decaf_bzero(buf2,sizeof(buf2)); | |||
| return !!ret; | |||
| } | |||
| /** @brief Steganographically encode this */ | |||
| inline SecureBuffer steg_encode(SpongeRng &rng) const NOEXCEPT; | |||
| /** @brief Return the base point */ | |||
| static inline const Point base() NOEXCEPT { return Point(decaf_448_point_base); } | |||
| /** @brief Return the identity point */ | |||
| static inline const Point identity() NOEXCEPT { return Point(decaf_448_point_identity); } | |||
| }; | |||
| /** | |||
| * @brief Precomputed table of points. | |||
| * Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is. | |||
| * Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to | |||
| * stack-allocate a 15kiB object anyway. | |||
| */ | |||
| class Precomputed { | |||
| private: | |||
| /** @cond internal */ | |||
| union { | |||
| decaf_448_precomputed_s *mine; | |||
| const decaf_448_precomputed_s *yours; | |||
| } ours; | |||
| bool isMine; | |||
| inline void clear() NOEXCEPT { | |||
| if (isMine) { | |||
| decaf_448_precomputed_destroy(ours.mine); | |||
| free(ours.mine); | |||
| ours.yours = decaf_448_precomputed_base; | |||
| isMine = false; | |||
| } | |||
| } | |||
| inline void alloc() throw(std::bad_alloc) { | |||
| if (isMine) return; | |||
| int ret = posix_memalign((void**)&ours.mine, alignof_decaf_448_precomputed_s,sizeof_decaf_448_precomputed_s); | |||
| if (ret || !ours.mine) { | |||
| isMine = false; | |||
| throw std::bad_alloc(); | |||
| } | |||
| isMine = true; | |||
| } | |||
| inline const decaf_448_precomputed_s *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; } | |||
| /** @endcond */ | |||
| public: | |||
| /** Destructor securely erases the memory. */ | |||
| inline ~Precomputed() NOEXCEPT { clear(); } | |||
| /** | |||
| * @brief Initialize from underlying type, declared as a reference to prevent | |||
| * it from being called with 0, thereby breaking override. | |||
| * | |||
| * The underlying object must remain valid throughout the lifetime of this one. | |||
| * | |||
| * By default, initializes to the table for the base point. | |||
| * | |||
| * @warning The empty initializer makes this equal to base, unlike the empty | |||
| * initializer for points which makes this equal to the identity. | |||
| */ | |||
| inline Precomputed( | |||
| const decaf_448_precomputed_s &yours = *decaf_448_precomputed_base | |||
| ) NOEXCEPT { | |||
| ours.yours = &yours; | |||
| isMine = false; | |||
| } | |||
| /** | |||
| * @brief Assign. This may require an allocation and memcpy. | |||
| */ | |||
| inline Precomputed &operator=(const Precomputed &it) throw(std::bad_alloc) { | |||
| if (this == &it) return *this; | |||
| if (it.isMine) { | |||
| alloc(); | |||
| memcpy(ours.mine,it.ours.mine,sizeof_decaf_448_precomputed_s); | |||
| } else { | |||
| clear(); | |||
| ours.yours = it.ours.yours; | |||
| } | |||
| isMine = it.isMine; | |||
| return *this; | |||
| } | |||
| /** | |||
| * @brief Initilaize from point. Must allocate memory, and may throw. | |||
| */ | |||
| inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) { | |||
| alloc(); | |||
| decaf_448_precompute(ours.mine,it.p); | |||
| return *this; | |||
| } | |||
| /** | |||
| * @brief Copy constructor. | |||
| */ | |||
| inline Precomputed(const Precomputed &it) throw(std::bad_alloc) : isMine(false) { *this = it; } | |||
| /** | |||
| * @brief Constructor which initializes from point. | |||
| */ | |||
| inline explicit Precomputed(const Point &it) throw(std::bad_alloc) : isMine(false) { *this = it; } | |||
| #if __cplusplus >= 201103L | |||
| inline Precomputed &operator=(Precomputed &&it) NOEXCEPT { | |||
| if (this == &it) return *this; | |||
| clear(); | |||
| ours = it.ours; | |||
| isMine = it.isMine; | |||
| it.isMine = false; | |||
| it.ours.yours = decaf_448_precomputed_base; | |||
| return *this; | |||
| } | |||
| inline Precomputed(Precomputed &&it) NOEXCEPT : isMine(false) { *this = it; } | |||
| #endif | |||
| /** @brief Fixed base scalarmul. */ | |||
| inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_448_precomputed_scalarmul(r.p,get(),s.s); return r; } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); } | |||
| /** @brief Return the table for the base point. */ | |||
| static inline const Precomputed base() NOEXCEPT { return Precomputed(*decaf_448_precomputed_base); } | |||
| }; | |||
| }; /* struct Decaf448 */ | |||
| #undef NOEXCEPT | |||
| #undef EXPLICIT_CON | |||
| #undef GET_DATA | |||
| } /* namespace decaf */ | |||
| #endif /* __DECAF_448_HXX__ */ | |||
| @@ -0,0 +1,651 @@ | |||
| /** | |||
| * @file decaf_255.h | |||
| * @author Mike Hamburg | |||
| * | |||
| * @copyright | |||
| * Copyright (c) 2015 Cryptography Research, Inc. \n | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| * | |||
| * @brief A group of prime order p. | |||
| * | |||
| * The Decaf library implements cryptographic operations on a an elliptic curve | |||
| * group of prime order p. It accomplishes this by using a twisted Edwards | |||
| * curve (isogenous to Ed255-Goldilocks) and wiping out the cofactor. | |||
| * | |||
| * The formulas are all complete and have no special cases, except that | |||
| * decaf_255_decode can fail because not every sequence of bytes is a valid group | |||
| * element. | |||
| * | |||
| * The formulas contain no data-dependent branches, timing or memory accesses, | |||
| * except for decaf_255_base_double_scalarmul_non_secret. | |||
| * | |||
| * This library may support multiple curves eventually. The Ed255-Goldilocks | |||
| * specific identifiers are prefixed with DECAF_255 or decaf_255. | |||
| */ | |||
| #ifndef __DECAF_255_H__ | |||
| #define __DECAF_255_H__ 1 | |||
| #include <stdint.h> | |||
| #include <sys/types.h> | |||
| /* Goldilocks' build flags default to hidden and stripping executables. */ | |||
| /** @cond internal */ | |||
| #if defined(DOXYGEN) && !defined(__attribute__) | |||
| #define __attribute__((x)) | |||
| #endif | |||
| #define API_VIS __attribute__((visibility("default"))) | |||
| #define NOINLINE __attribute__((noinline)) | |||
| #define WARN_UNUSED __attribute__((warn_unused_result)) | |||
| #define NONNULL1 __attribute__((nonnull(1))) | |||
| #define NONNULL2 __attribute__((nonnull(1,2))) | |||
| #define NONNULL3 __attribute__((nonnull(1,2,3))) | |||
| #define NONNULL4 __attribute__((nonnull(1,2,3,4))) | |||
| #define NONNULL5 __attribute__((nonnull(1,2,3,4,5))) | |||
| /* Internal word types */ | |||
| #if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \ | |||
| && !defined(DECAF_FORCE_32_BIT) | |||
| #define DECAF_WORD_BITS 64 | |||
| typedef uint64_t decaf_word_t, decaf_bool_t; | |||
| typedef __uint128_t decaf_dword_t; | |||
| #else | |||
| #define DECAF_WORD_BITS 32 | |||
| typedef uint32_t decaf_word_t, decaf_bool_t; | |||
| typedef uint64_t decaf_dword_t; | |||
| #endif | |||
| #define DECAF_255_LIMBS (320/DECAF_WORD_BITS) | |||
| #define DECAF_255_SCALAR_BITS 252 | |||
| #define DECAF_255_SCALAR_LIMBS (256/DECAF_WORD_BITS) | |||
| /** Galois field element internal structure */ | |||
| typedef struct gf_s { | |||
| decaf_word_t limb[DECAF_255_LIMBS]; | |||
| } __attribute__((aligned(32))) gf_s, gf[1]; | |||
| /** @endcond */ | |||
| /** Number of bytes in a serialized point. */ | |||
| #define DECAF_255_SER_BYTES 32 | |||
| /** Number of bytes in a serialized scalar. */ | |||
| #define DECAF_255_SCALAR_BYTES 32 | |||
| /** Twisted Edwards (-1,d-1) extended homogeneous coordinates */ | |||
| typedef struct decaf_255_point_s { /**@cond internal*/gf x,y,z,t;/**@endcond*/ } decaf_255_point_t[1]; | |||
| /** Precomputed table based on a point. Can be trivial implementation. */ | |||
| struct decaf_255_precomputed_s; | |||
| /** Precomputed table based on a point. Can be trivial implementation. */ | |||
| typedef struct decaf_255_precomputed_s decaf_255_precomputed_s; | |||
| /** Size and alignment of precomputed point tables. */ | |||
| extern const size_t sizeof_decaf_255_precomputed_s API_VIS, alignof_decaf_255_precomputed_s API_VIS; | |||
| /** Scalar is stored packed, because we don't need the speed. */ | |||
| typedef struct decaf_255_scalar_s { | |||
| /** @cond internal */ | |||
| decaf_word_t limb[DECAF_255_SCALAR_LIMBS]; | |||
| /** @endcond */ | |||
| } decaf_255_scalar_t[1]; | |||
| /** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */ | |||
| static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0; | |||
| /** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */ | |||
| static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/, | |||
| DECAF_FAILURE = 0 /*DECAF_FALSE*/; | |||
| /** A scalar equal to 1. */ | |||
| extern const decaf_255_scalar_t decaf_255_scalar_one API_VIS; | |||
| /** A scalar equal to 0. */ | |||
| extern const decaf_255_scalar_t decaf_255_scalar_zero API_VIS; | |||
| /** The identity point on the curve. */ | |||
| extern const decaf_255_point_t decaf_255_point_identity API_VIS; | |||
| /** | |||
| * An arbitrarily chosen base point on the curve. | |||
| * Equal to Ed255-Goldilocks base point defined by DJB, except of course that | |||
| * it's on the twist in this case. TODO: choose a base point with nice encoding? | |||
| */ | |||
| extern const decaf_255_point_t decaf_255_point_base API_VIS; | |||
| /** Precomputed table for the base point on the curve. */ | |||
| extern const struct decaf_255_precomputed_s *decaf_255_precomputed_base API_VIS; | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /** | |||
| * @brief Read a scalar from wire format or from bytes. | |||
| * | |||
| * @param [in] ser Serialized form of a scalar. | |||
| * @param [out] out Deserialized form. | |||
| * | |||
| * @retval DECAF_SUCCESS The scalar was correctly encoded. | |||
| * @retval DECAF_FAILURE The scalar was greater than the modulus, | |||
| * and has been reduced modulo that modulus. | |||
| */ | |||
| decaf_bool_t decaf_255_scalar_decode ( | |||
| decaf_255_scalar_t out, | |||
| const unsigned char ser[DECAF_255_SCALAR_BYTES] | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Read a scalar from wire format or from bytes. Reduces mod | |||
| * scalar prime. | |||
| * | |||
| * @param [in] ser Serialized form of a scalar. | |||
| * @param [in] ser_len Length of serialized form. | |||
| * @param [out] out Deserialized form. | |||
| */ | |||
| void decaf_255_scalar_decode_long ( | |||
| decaf_255_scalar_t out, | |||
| const unsigned char *ser, | |||
| size_t ser_len | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Serialize a scalar to wire format. | |||
| * | |||
| * @param [out] ser Serialized form of a scalar. | |||
| * @param [in] s Deserialized scalar. | |||
| */ | |||
| void decaf_255_scalar_encode ( | |||
| unsigned char ser[DECAF_255_SCALAR_BYTES], | |||
| const decaf_255_scalar_t s | |||
| ) API_VIS NONNULL2 NOINLINE NOINLINE; | |||
| /** | |||
| * @brief Add two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a+b. | |||
| */ | |||
| void decaf_255_scalar_add ( | |||
| decaf_255_scalar_t out, | |||
| const decaf_255_scalar_t a, | |||
| const decaf_255_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Compare two scalars. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @retval DECAF_TRUE The scalars are equal. | |||
| * @retval DECAF_FALSE The scalars are not equal. | |||
| */ | |||
| decaf_bool_t decaf_255_scalar_eq ( | |||
| const decaf_255_scalar_t a, | |||
| const decaf_255_scalar_t b | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Subtract two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a-b. | |||
| */ | |||
| void decaf_255_scalar_sub ( | |||
| decaf_255_scalar_t out, | |||
| const decaf_255_scalar_t a, | |||
| const decaf_255_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a*b. | |||
| */ | |||
| void decaf_255_scalar_mul ( | |||
| decaf_255_scalar_t out, | |||
| const decaf_255_scalar_t a, | |||
| const decaf_255_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Invert a scalar. When passed zero, return 0. The input and output may alias. | |||
| * @param [in] a A scalar. | |||
| * @param [out] out 1/a. | |||
| * @return DECAF_TRUE The input is nonzero. | |||
| */ | |||
| decaf_bool_t decaf_255_scalar_invert ( | |||
| decaf_255_scalar_t out, | |||
| const decaf_255_scalar_t a | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Copy a scalar. The scalars may use the same memory, in which | |||
| * case this function does nothing. | |||
| * @param [in] a A scalar. | |||
| * @param [out] out Will become a copy of a. | |||
| */ | |||
| static inline void NONNULL2 decaf_255_scalar_copy ( | |||
| decaf_255_scalar_t out, | |||
| const decaf_255_scalar_t a | |||
| ) { | |||
| *out = *a; | |||
| } | |||
| /** | |||
| * @brief Set a scalar to an integer. | |||
| * @param [in] a An integer. | |||
| * @param [out] out Will become equal to a. | |||
| * @todo Make inline? | |||
| */ | |||
| void decaf_255_scalar_set( | |||
| decaf_255_scalar_t out, | |||
| decaf_word_t a | |||
| ) API_VIS NONNULL1; | |||
| /** | |||
| * @brief Encode a point as a sequence of bytes. | |||
| * | |||
| * @param [out] ser The byte representation of the point. | |||
| * @param [in] pt The point to encode. | |||
| */ | |||
| void decaf_255_point_encode ( | |||
| uint8_t ser[DECAF_255_SER_BYTES], | |||
| const decaf_255_point_t pt | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Decode a point from a sequence of bytes. | |||
| * | |||
| * Every point has a unique encoding, so not every | |||
| * sequence of bytes is a valid encoding. If an invalid | |||
| * encoding is given, the output is undefined. | |||
| * | |||
| * @param [out] pt The decoded point. | |||
| * @param [in] ser The serialized version of the point. | |||
| * @param [in] allow_identity DECAF_TRUE if the identity is a legal input. | |||
| * @retval DECAF_SUCCESS The decoding succeeded. | |||
| * @retval DECAF_FAILURE The decoding didn't succeed, because | |||
| * ser does not represent a point. | |||
| */ | |||
| decaf_bool_t decaf_255_point_decode ( | |||
| decaf_255_point_t pt, | |||
| const uint8_t ser[DECAF_255_SER_BYTES], | |||
| decaf_bool_t allow_identity | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Copy a point. The input and output may alias, | |||
| * in which case this function does nothing. | |||
| * | |||
| * @param [out] a A copy of the point. | |||
| * @param [in] b Any point. | |||
| */ | |||
| static inline void NONNULL2 decaf_255_point_copy ( | |||
| decaf_255_point_t a, | |||
| const decaf_255_point_t b | |||
| ) { | |||
| *a=*b; | |||
| } | |||
| /** | |||
| * @brief Test whether two points are equal. If yes, return | |||
| * DECAF_TRUE, else return DECAF_FALSE. | |||
| * | |||
| * @param [in] a A point. | |||
| * @param [in] b Another point. | |||
| * @retval DECAF_TRUE The points are equal. | |||
| * @retval DECAF_FALSE The points are not equal. | |||
| */ | |||
| decaf_bool_t decaf_255_point_eq ( | |||
| const decaf_255_point_t a, | |||
| const decaf_255_point_t b | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Add two points to produce a third point. The | |||
| * input points and output point can be pointers to the same | |||
| * memory. | |||
| * | |||
| * @param [out] sum The sum a+b. | |||
| * @param [in] a An addend. | |||
| * @param [in] b An addend. | |||
| */ | |||
| void decaf_255_point_add ( | |||
| decaf_255_point_t sum, | |||
| const decaf_255_point_t a, | |||
| const decaf_255_point_t b | |||
| ) API_VIS NONNULL3; | |||
| /** | |||
| * @brief Double a point. Equivalent to | |||
| * decaf_255_point_add(two_a,a,a), but potentially faster. | |||
| * | |||
| * @param [out] two_a The sum a+a. | |||
| * @param [in] a A point. | |||
| */ | |||
| void decaf_255_point_double ( | |||
| decaf_255_point_t two_a, | |||
| const decaf_255_point_t a | |||
| ) API_VIS NONNULL2; | |||
| /** | |||
| * @brief Subtract two points to produce a third point. The | |||
| * input points and output point can be pointers to the same | |||
| * memory. | |||
| * | |||
| * @param [out] diff The difference a-b. | |||
| * @param [in] a The minuend. | |||
| * @param [in] b The subtrahend. | |||
| */ | |||
| void decaf_255_point_sub ( | |||
| decaf_255_point_t diff, | |||
| const decaf_255_point_t a, | |||
| const decaf_255_point_t b | |||
| ) API_VIS NONNULL3; | |||
| /** | |||
| * @brief Negate a point to produce another point. The input | |||
| * and output points can use the same memory. | |||
| * | |||
| * @param [out] nega The negated input point | |||
| * @param [in] a The input point. | |||
| */ | |||
| void decaf_255_point_negate ( | |||
| decaf_255_point_t nega, | |||
| const decaf_255_point_t a | |||
| ) API_VIS NONNULL2; | |||
| /** | |||
| * @brief Multiply a base point by a scalar: scaled = scalar*base. | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| */ | |||
| void decaf_255_point_scalarmul ( | |||
| decaf_255_point_t scaled, | |||
| const decaf_255_point_t base, | |||
| const decaf_255_scalar_t scalar | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply a base point by a scalar: scaled = scalar*base. | |||
| * This function operates directly on serialized forms. | |||
| * | |||
| * @warning This function is experimental. It may not be supported | |||
| * long-term. | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| * @param [in] allow_identity Allow the input to be the identity. | |||
| * @param [in] short_circuit Allow a fast return if the input is illegal. | |||
| * | |||
| * @retval DECAF_SUCCESS The scalarmul succeeded. | |||
| * @retval DECAF_FAILURE The scalarmul didn't succeed, because | |||
| * base does not represent a point. | |||
| */ | |||
| decaf_bool_t decaf_255_direct_scalarmul ( | |||
| uint8_t scaled[DECAF_255_SER_BYTES], | |||
| const uint8_t base[DECAF_255_SER_BYTES], | |||
| const decaf_255_scalar_t scalar, | |||
| decaf_bool_t allow_identity, | |||
| decaf_bool_t short_circuit | |||
| ) API_VIS NONNULL3 WARN_UNUSED NOINLINE; | |||
| /** | |||
| * @brief Precompute a table for fast scalar multiplication. | |||
| * Some implementations do not include precomputed points; for | |||
| * those implementations, this implementation simply copies the | |||
| * point. | |||
| * | |||
| * @param [out] a A precomputed table of multiples of the point. | |||
| * @param [in] b Any point. | |||
| */ | |||
| void decaf_255_precompute ( | |||
| decaf_255_precomputed_s *a, | |||
| const decaf_255_point_t b | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Multiply a precomputed base point by a scalar: | |||
| * scaled = scalar*base. | |||
| * Some implementations do not include precomputed points; for | |||
| * those implementations, this function is the same as | |||
| * decaf_255_point_scalarmul | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| * | |||
| * @todo precomputed dsmul? const or variable time? | |||
| */ | |||
| void decaf_255_precomputed_scalarmul ( | |||
| decaf_255_point_t scaled, | |||
| const decaf_255_precomputed_s *base, | |||
| const decaf_255_scalar_t scalar | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply two base points by two scalars: | |||
| * scaled = scalar1*base1 + scalar2*base2. | |||
| * | |||
| * Equivalent to two calls to decaf_255_point_scalarmul, but may be | |||
| * faster. | |||
| * | |||
| * @param [out] combo The linear combination scalar1*base1 + scalar2*base2. | |||
| * @param [in] base1 A first point to be scaled. | |||
| * @param [in] scalar1 A first scalar to multiply by. | |||
| * @param [in] base2 A second point to be scaled. | |||
| * @param [in] scalar2 A second scalar to multiply by. | |||
| */ | |||
| void decaf_255_point_double_scalarmul ( | |||
| decaf_255_point_t combo, | |||
| const decaf_255_point_t base1, | |||
| const decaf_255_scalar_t scalar1, | |||
| const decaf_255_point_t base2, | |||
| const decaf_255_scalar_t scalar2 | |||
| ) API_VIS NONNULL5 NOINLINE; | |||
| /** | |||
| * @brief Multiply two base points by two scalars: | |||
| * scaled = scalar1*decaf_255_point_base + scalar2*base2. | |||
| * | |||
| * Otherwise equivalent to decaf_255_point_double_scalarmul, but may be | |||
| * faster at the expense of being variable time. | |||
| * | |||
| * @param [out] combo The linear combination scalar1*base + scalar2*base2. | |||
| * @param [in] scalar1 A first scalar to multiply by. | |||
| * @param [in] base2 A second point to be scaled. | |||
| * @param [in] scalar2 A second scalar to multiply by. | |||
| * | |||
| * @warning: This function takes variable time, and may leak the scalars | |||
| * used. It is designed for signature verification. | |||
| */ | |||
| void decaf_255_base_double_scalarmul_non_secret ( | |||
| decaf_255_point_t combo, | |||
| const decaf_255_scalar_t scalar1, | |||
| const decaf_255_point_t base2, | |||
| const decaf_255_scalar_t scalar2 | |||
| ) API_VIS NONNULL4 NOINLINE; | |||
| /** | |||
| * @brief Test that a point is valid, for debugging purposes. | |||
| * | |||
| * @param [in] toTest The point to test. | |||
| * @retval DECAF_TRUE The point is valid. | |||
| * @retval DECAF_FALSE The point is invalid. | |||
| */ | |||
| decaf_bool_t decaf_255_point_valid ( | |||
| const decaf_255_point_t toTest | |||
| ) API_VIS WARN_UNUSED NONNULL1 NOINLINE; | |||
| /** | |||
| * @brief 2-torque a point, for debugging purposes. | |||
| * | |||
| * @param [out] q The point to torque. | |||
| * @param [in] p The point to torque. | |||
| */ | |||
| void decaf_255_point_debugging_2torque ( | |||
| decaf_255_point_t q, | |||
| const decaf_255_point_t p | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Almost-Elligator-like hash to curve. | |||
| * | |||
| * Call this function with the output of a hash to make a hash to the curve. | |||
| * | |||
| * This function runs Elligator2 on the decaf_255 Jacobi quartic model. It then | |||
| * uses the isogeny to put the result in twisted Edwards form. As a result, | |||
| * it is safe (cannot produce points of order 4), and would be compatible with | |||
| * hypothetical other implementations of Decaf using a Montgomery or untwisted | |||
| * Edwards model. | |||
| * | |||
| * Unlike Elligator, this function may be up to 4:1 on [0,(p-1)/2]: | |||
| * A factor of 2 due to the isogeny. | |||
| * A factor of 2 because we quotient out the 2-torsion. | |||
| * | |||
| * This makes it about 8:1 overall. | |||
| * | |||
| * Negating the input (mod q) results in the same point. Inverting the input | |||
| * (mod q) results in the negative point. This is the same as Elligator. | |||
| * | |||
| * This function isn't quite indifferentiable from a random oracle. | |||
| * However, it is suitable for many protocols, including SPEKE and SPAKE2 EE. | |||
| * Furthermore, calling it twice with independent seeds and adding the results | |||
| * is indifferentiable from a random oracle. | |||
| * | |||
| * @param [in] hashed_data Output of some hash function. | |||
| * @param [out] pt The data hashed to the curve. | |||
| * @return A "hint" value which can be used to help invert the encoding. | |||
| */ | |||
| unsigned char | |||
| decaf_255_point_from_hash_nonuniform ( | |||
| decaf_255_point_t pt, | |||
| const unsigned char hashed_data[DECAF_255_SER_BYTES] | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Inverse of elligator-like hash to curve. | |||
| * | |||
| * This function writes to the buffer, to make it so that | |||
| * decaf_255_point_from_hash_nonuniform(buffer) = pt,hint | |||
| * if possible. | |||
| * | |||
| * @param [out] recovered_hash Encoded data. | |||
| * @param [in] pt The point to encode. | |||
| * @param [in] hint The hint value returned from | |||
| * decaf_255_point_from_hash_nonuniform. | |||
| * | |||
| * @retval DECAF_SUCCESS The inverse succeeded. | |||
| * @retval DECAF_FAILURE The pt isn't the image of | |||
| * decaf_255_point_from_hash_nonuniform with the given hint. | |||
| * | |||
| * @warning The hinting system is subject to change, especially in corner cases. | |||
| * @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF. | |||
| */ | |||
| decaf_bool_t | |||
| decaf_255_invert_elligator_nonuniform ( | |||
| unsigned char recovered_hash[DECAF_255_SER_BYTES], | |||
| const decaf_255_point_t pt, | |||
| unsigned char hint | |||
| ) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
| /** | |||
| * @brief Inverse of elligator-like hash to curve, uniform. | |||
| * | |||
| * This function modifies the first DECAF_255_SER_BYTES of the | |||
| * buffer, to make it so that | |||
| * decaf_255_point_from_hash_uniform(buffer) = pt,hint | |||
| * if possible. | |||
| * | |||
| * @param [out] recovered_hash Encoded data. | |||
| * @param [in] pt The point to encode. | |||
| * @param [in] hint The hint value returned from | |||
| * decaf_255_point_from_hash_nonuniform. | |||
| * | |||
| * @retval DECAF_SUCCESS The inverse succeeded. | |||
| * @retval DECAF_FAILURE The pt isn't the image of | |||
| * decaf_255_point_from_hash_uniform with the given hint. | |||
| * | |||
| * @warning The hinting system is subject to change, especially in corner cases. | |||
| * @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF. | |||
| */ | |||
| decaf_bool_t | |||
| decaf_255_invert_elligator_uniform ( | |||
| unsigned char recovered_hash[2*DECAF_255_SER_BYTES], | |||
| const decaf_255_point_t pt, | |||
| unsigned char hint | |||
| ) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
| /** | |||
| * @brief Indifferentiable hash function encoding to curve. | |||
| * | |||
| * Equivalent to calling decaf_255_point_from_hash_nonuniform twice and adding. | |||
| * | |||
| * @param [in] hashed_data Output of some hash function. | |||
| * @param [out] pt The data hashed to the curve. | |||
| * @return A "hint" value which can be used to help invert the encoding. | |||
| */ | |||
| unsigned char decaf_255_point_from_hash_uniform ( | |||
| decaf_255_point_t pt, | |||
| const unsigned char hashed_data[2*DECAF_255_SER_BYTES] | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Overwrite data with zeros. Uses memset_s if available. | |||
| */ | |||
| void decaf_bzero ( | |||
| void *data, | |||
| size_t size | |||
| ) NONNULL1 API_VIS NOINLINE; | |||
| /** | |||
| * @brief Compare two buffers, returning DECAF_TRUE if they are equal. | |||
| */ | |||
| decaf_bool_t decaf_memeq ( | |||
| const void *data1, | |||
| const void *data2, | |||
| size_t size | |||
| ) NONNULL2 WARN_UNUSED API_VIS NOINLINE; | |||
| /** | |||
| * @brief Overwrite scalar with zeros. | |||
| */ | |||
| void decaf_255_scalar_destroy ( | |||
| decaf_255_scalar_t scalar | |||
| ) NONNULL1 API_VIS; | |||
| /** | |||
| * @brief Overwrite point with zeros. | |||
| * @todo Use this internally. | |||
| */ | |||
| void decaf_255_point_destroy ( | |||
| decaf_255_point_t point | |||
| ) NONNULL1 API_VIS; | |||
| /** | |||
| * @brief Overwrite point with zeros. | |||
| * @todo Use this internally. | |||
| */ | |||
| void decaf_255_precomputed_destroy ( | |||
| decaf_255_precomputed_s *pre | |||
| ) NONNULL1 API_VIS; | |||
| /* TODO: functions to invert point_from_hash?? */ | |||
| #undef API_VIS | |||
| #undef WARN_UNUSED | |||
| #undef NOINLINE | |||
| #undef NONNULL1 | |||
| #undef NONNULL2 | |||
| #undef NONNULL3 | |||
| #undef NONNULL4 | |||
| #undef NONNULL5 | |||
| #ifdef __cplusplus | |||
| } /* extern "C" */ | |||
| #endif | |||
| #endif /* __DECAF_255_H__ */ | |||
| @@ -0,0 +1,738 @@ | |||
| /** | |||
| * @file decaf_255.hxx | |||
| * @author Mike Hamburg | |||
| * | |||
| * @copyright | |||
| * Copyright (c) 2015 Cryptography Research, Inc. \n | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| * | |||
| * @brief A group of prime order p, C++ wrapper. | |||
| * | |||
| * The Decaf library implements cryptographic operations on a an elliptic curve | |||
| * group of prime order p. It accomplishes this by using a twisted Edwards | |||
| * curve (isogenous to Ed255-Goldilocks) and wiping out the cofactor. | |||
| * | |||
| * The formulas are all complete and have no special cases, except that | |||
| * decaf_255_decode can fail because not every sequence of bytes is a valid group | |||
| * element. | |||
| * | |||
| * The formulas contain no data-dependent branches, timing or memory accesses, | |||
| * except for decaf_255_base_double_scalarmul_non_secret. | |||
| */ | |||
| #ifndef __DECAF_255_HXX__ | |||
| #define __DECAF_255_HXX__ 1 | |||
| /** This code uses posix_memalign. */ | |||
| #define _XOPEN_SOURCE 600 | |||
| #include <stdlib.h> | |||
| #include <string.h> /* for memcpy */ | |||
| #include "decaf.h" | |||
| #include <string> | |||
| #include <sys/types.h> | |||
| #include <limits.h> | |||
| /* TODO: This is incomplete */ | |||
| /* TODO: attribute nonnull */ | |||
| /** @cond internal */ | |||
| #if __cplusplus >= 201103L | |||
| #define NOEXCEPT noexcept | |||
| #define EXPLICIT_CON explicit | |||
| #define GET_DATA(str) ((const unsigned char *)&(str)[0]) | |||
| #else | |||
| #define NOEXCEPT throw() | |||
| #define EXPLICIT_CON | |||
| #define GET_DATA(str) ((const unsigned char *)((str).data())) | |||
| #endif | |||
| /** @endcond */ | |||
| namespace decaf { | |||
| /** @brief An exception for when crypto (ie point decode) has failed. */ | |||
| class CryptoException : public std::exception { | |||
| public: | |||
| /** @return "CryptoException" */ | |||
| virtual const char * what() const NOEXCEPT { return "CryptoException"; } | |||
| }; | |||
| /** @brief An exception for when crypto (ie point decode) has failed. */ | |||
| class LengthException : public std::exception { | |||
| public: | |||
| /** @return "CryptoException" */ | |||
| virtual const char * what() const NOEXCEPT { return "LengthException"; } | |||
| }; | |||
| /** | |||
| * Securely erase contents of memory. | |||
| */ | |||
| static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); } | |||
| /** Block object */ | |||
| class Block { | |||
| protected: | |||
| unsigned char *data_; | |||
| size_t size_; | |||
| public: | |||
| /** Empty init */ | |||
| inline Block() NOEXCEPT : data_(NULL), size_(0) {} | |||
| /** Init from C string */ | |||
| inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {} | |||
| /** Unowned init */ | |||
| inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {} | |||
| /** Block from std::string */ | |||
| inline Block(const std::string &s) : data_((unsigned char *)GET_DATA(s)), size_(s.size()) {} | |||
| /** Get const data */ | |||
| inline const unsigned char *data() const NOEXCEPT { return data_; } | |||
| /** Get the size */ | |||
| inline size_t size() const NOEXCEPT { return size_; } | |||
| /** Autocast to const unsigned char * */ | |||
| inline operator const unsigned char*() const NOEXCEPT { return data_; } | |||
| /** Convert to C++ string */ | |||
| inline std::string get_string() const { | |||
| return std::string((const char *)data_,size_); | |||
| } | |||
| /** Slice the buffer*/ | |||
| inline Block slice(size_t off, size_t length) const throw(LengthException) { | |||
| if (off > size() || length > size() - off) | |||
| throw LengthException(); | |||
| return Block(data()+off, length); | |||
| } | |||
| /** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */ | |||
| inline virtual ~Block() {}; | |||
| }; | |||
| class TmpBuffer; | |||
| class Buffer : public Block { | |||
| public: | |||
| /** Null init */ | |||
| inline Buffer() NOEXCEPT : Block() {} | |||
| /** Unowned init */ | |||
| inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {} | |||
| /** Get unconst data */ | |||
| inline unsigned char *data() NOEXCEPT { return data_; } | |||
| /** Get const data */ | |||
| inline const unsigned char *data() const NOEXCEPT { return data_; } | |||
| /** Autocast to const unsigned char * */ | |||
| inline operator const unsigned char*() const NOEXCEPT { return data_; } | |||
| /** Autocast to unsigned char */ | |||
| inline operator unsigned char*() NOEXCEPT { return data_; } | |||
| /** Slice the buffer*/ | |||
| inline TmpBuffer slice(size_t off, size_t length) throw(LengthException); | |||
| }; | |||
| class TmpBuffer : public Buffer { | |||
| public: | |||
| /** Unowned init */ | |||
| inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {} | |||
| }; | |||
| TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) { | |||
| if (off > size() || length > size() - off) throw LengthException(); | |||
| return TmpBuffer(data()+off, length); | |||
| } | |||
| /** A self-erasing block of data */ | |||
| class SecureBuffer : public Buffer { | |||
| public: | |||
| /** Null secure block */ | |||
| inline SecureBuffer() NOEXCEPT : Buffer() {} | |||
| /** Construct empty from size */ | |||
| inline SecureBuffer(size_t size) { | |||
| data_ = new unsigned char[size_ = size]; | |||
| memset(data_,0,size); | |||
| } | |||
| /** Construct from data */ | |||
| inline SecureBuffer(const unsigned char *data, size_t size){ | |||
| data_ = new unsigned char[size_ = size]; | |||
| memcpy(data_, data, size); | |||
| } | |||
| /** Copy constructor */ | |||
| inline SecureBuffer(const Block ©) : Buffer() { *this = copy; } | |||
| /** Copy-assign constructor */ | |||
| inline SecureBuffer& operator=(const Block ©) throw(std::bad_alloc) { | |||
| if (© == this) return *this; | |||
| clear(); | |||
| data_ = new unsigned char[size_ = copy.size()]; | |||
| memcpy(data_,copy.data(),size_); | |||
| return *this; | |||
| } | |||
| /** Copy-assign constructor */ | |||
| inline SecureBuffer& operator=(const SecureBuffer ©) throw(std::bad_alloc) { | |||
| if (© == this) return *this; | |||
| clear(); | |||
| data_ = new unsigned char[size_ = copy.size()]; | |||
| memcpy(data_,copy.data(),size_); | |||
| return *this; | |||
| } | |||
| /** Destructor erases data */ | |||
| ~SecureBuffer() NOEXCEPT { clear(); } | |||
| /** Clear data */ | |||
| inline void clear() NOEXCEPT { | |||
| if (data_ == NULL) return; | |||
| really_bzero(data_,size_); | |||
| delete[] data_; | |||
| data_ = NULL; | |||
| size_ = 0; | |||
| } | |||
| #if __cplusplus >= 201103L | |||
| /** Move constructor */ | |||
| inline SecureBuffer(SecureBuffer &&move) { *this = move; } | |||
| /** Move non-constructor */ | |||
| inline SecureBuffer(Block &&move) { *this = (Block &)move; } | |||
| /** Move-assign constructor. TODO: check that this actually gets used.*/ | |||
| inline SecureBuffer& operator=(SecureBuffer &&move) { | |||
| clear(); | |||
| data_ = move.data_; move.data_ = NULL; | |||
| size_ = move.size_; move.size_ = 0; | |||
| return *this; | |||
| } | |||
| /** C++11-only explicit cast */ | |||
| inline explicit operator std::string() const { return get_string(); } | |||
| #endif | |||
| }; | |||
| /** @brief Passed to constructors to avoid (conservative) initialization */ | |||
| struct NOINIT {}; | |||
| /**@cond internal*/ | |||
| /** Forward-declare sponge RNG object */ | |||
| class SpongeRng; | |||
| /**@endcond*/ | |||
| /** | |||
| * @brief Ed255-Goldilocks/Decaf instantiation of group. | |||
| */ | |||
| struct Ed255 { | |||
| /** @cond internal */ | |||
| class Point; | |||
| class Precomputed; | |||
| /** @endcond */ | |||
| /** | |||
| * @brief A scalar modulo the curve order. | |||
| * Supports the usual arithmetic operations, all in constant time. | |||
| */ | |||
| class Scalar { | |||
| public: | |||
| /** @brief Size of a serialized element */ | |||
| static const size_t SER_BYTES = DECAF_255_SCALAR_BYTES; | |||
| /** @brief access to the underlying scalar object */ | |||
| decaf_255_scalar_t s; | |||
| /** @brief Don't initialize. */ | |||
| inline Scalar(const NOINIT &) NOEXCEPT {} | |||
| /** @brief Set to an unsigned word */ | |||
| inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; } | |||
| /** @brief Set to a signed word */ | |||
| inline Scalar(const int w) NOEXCEPT { *this = w; } | |||
| /** @brief Construct from RNG */ | |||
| inline explicit Scalar(SpongeRng &rng) NOEXCEPT; | |||
| /** @brief Construct from decaf_scalar_t object. */ | |||
| inline Scalar(const decaf_255_scalar_t &t = decaf_255_scalar_zero) NOEXCEPT { decaf_255_scalar_copy(s,t); } | |||
| /** @brief Copy constructor. */ | |||
| inline Scalar(const Scalar &x) NOEXCEPT { *this = x; } | |||
| /** @brief Construct from arbitrary-length little-endian byte sequence. */ | |||
| inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; } | |||
| /** @brief Assignment. */ | |||
| inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_255_scalar_copy(s,x.s); return *this; } | |||
| /** @brief Assign from unsigned word. */ | |||
| inline Scalar& operator=(decaf_word_t w) NOEXCEPT { decaf_255_scalar_set(s,w); return *this; } | |||
| /** @brief Assign from signed int. */ | |||
| inline Scalar& operator=(int w) NOEXCEPT { | |||
| Scalar t(-(decaf_word_t)INT_MIN); | |||
| decaf_255_scalar_set(s,(decaf_word_t)w - (decaf_word_t)INT_MIN); | |||
| *this -= t; | |||
| return *this; | |||
| } | |||
| /** Destructor securely erases the scalar. */ | |||
| inline ~Scalar() NOEXCEPT { decaf_255_scalar_destroy(s); } | |||
| /** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */ | |||
| inline Scalar &operator=(const Block &bl) NOEXCEPT { | |||
| decaf_255_scalar_decode_long(s,bl.data(),bl.size()); return *this; | |||
| } | |||
| /** | |||
| * @brief Decode from correct-length little-endian byte sequence. | |||
| * @return DECAF_FAILURE if the scalar is greater than or equal to the group order q. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Scalar &sc, const unsigned char buffer[SER_BYTES] | |||
| ) NOEXCEPT { | |||
| return decaf_255_scalar_decode(sc.s,buffer); | |||
| } | |||
| /** @brief Decode from correct-length little-endian byte sequence in C++ string. */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Scalar &sc, const Block &buffer | |||
| ) NOEXCEPT { | |||
| if (buffer.size() != SER_BYTES) return DECAF_FAILURE; | |||
| return decaf_255_scalar_decode(sc.s,buffer); | |||
| } | |||
| /** @brief Encode to fixed-length string */ | |||
| inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT { | |||
| SecureBuffer buf(SER_BYTES); decaf_255_scalar_encode(buf,s); return buf; | |||
| } | |||
| /** @brief Encode to fixed-length buffer */ | |||
| inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{ | |||
| decaf_255_scalar_encode(buffer, s); | |||
| } | |||
| /** Add. */ | |||
| inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_add(r.s,s,q.s); return r; } | |||
| /** Add to this. */ | |||
| inline Scalar &operator+=(const Scalar &q) NOEXCEPT { decaf_255_scalar_add(s,s,q.s); return *this; } | |||
| /** Subtract. */ | |||
| inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_sub(r.s,s,q.s); return r; } | |||
| /** Subtract from this. */ | |||
| inline Scalar &operator-=(const Scalar &q) NOEXCEPT { decaf_255_scalar_sub(s,s,q.s); return *this; } | |||
| /** Multiply */ | |||
| inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_mul(r.s,s,q.s); return r; } | |||
| /** Multiply into this. */ | |||
| inline Scalar &operator*=(const Scalar &q) NOEXCEPT { decaf_255_scalar_mul(s,s,q.s); return *this; } | |||
| /** Negate */ | |||
| inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_sub(r.s,decaf_255_scalar_zero,s); return r; } | |||
| /** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */ | |||
| inline Scalar inverse() const NOEXCEPT { Scalar r; decaf_255_scalar_invert(r.s,s); return r; } | |||
| /** @brief Divide by inverting q. If q == 0, return 0. */ | |||
| inline Scalar operator/ (const Scalar &q) const NOEXCEPT { return *this * q.inverse(); } | |||
| /** @brief Divide by inverting q. If q == 0, return 0. */ | |||
| inline Scalar &operator/=(const Scalar &q) NOEXCEPT { return *this *= q.inverse(); } | |||
| /** @brief Compare in constant time */ | |||
| inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); } | |||
| /** @brief Compare in constant time */ | |||
| inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_255_scalar_eq(s,q.s); } | |||
| /** @brief Scalarmul with scalar on left. */ | |||
| inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); } | |||
| /** @brief Scalarmul-precomputed with scalar on left. */ | |||
| inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); } | |||
| /** @brief Direct scalar multiplication. */ | |||
| inline SecureBuffer direct_scalarmul( | |||
| const Block &in, | |||
| decaf_bool_t allow_identity=DECAF_FALSE, | |||
| decaf_bool_t short_circuit=DECAF_TRUE | |||
| ) const throw(CryptoException) { | |||
| SecureBuffer out(/*FIXME Point::*/SER_BYTES); | |||
| if (!decaf_255_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit)) | |||
| throw CryptoException(); | |||
| return out; | |||
| } | |||
| }; | |||
| /** | |||
| * @brief Element of prime-order group. | |||
| */ | |||
| class Point { | |||
| public: | |||
| /** @brief Size of a serialized element */ | |||
| static const size_t SER_BYTES = DECAF_255_SER_BYTES; | |||
| /** @brief Size of a stegged element */ | |||
| static const size_t STEG_BYTES = DECAF_255_SER_BYTES + 8; | |||
| /** @brief Bytes required for hash */ | |||
| static const size_t HASH_BYTES = DECAF_255_SER_BYTES; | |||
| /** The c-level object. */ | |||
| decaf_255_point_t p; | |||
| /** @brief Don't initialize. */ | |||
| inline Point(const NOINIT &) NOEXCEPT {} | |||
| /** @brief Constructor sets to identity by default. */ | |||
| inline Point(const decaf_255_point_t &q = decaf_255_point_identity) NOEXCEPT { decaf_255_point_copy(p,q); } | |||
| /** @brief Copy constructor. */ | |||
| inline Point(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); } | |||
| /** @brief Assignment. */ | |||
| inline Point& operator=(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); return *this; } | |||
| /** @brief Destructor securely erases the point. */ | |||
| inline ~Point() NOEXCEPT { decaf_255_point_destroy(p); } | |||
| /** @brief Construct from RNG */ | |||
| inline explicit Point(SpongeRng &rng, bool uniform = true) NOEXCEPT; | |||
| /** | |||
| * @brief Initialize from C++ fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. | |||
| */ | |||
| inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) { | |||
| if (!decode(*this,s,allow_identity)) throw CryptoException(); | |||
| } | |||
| /** | |||
| * @brief Initialize from C fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. | |||
| */ | |||
| inline explicit Point(const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE) | |||
| throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); } | |||
| /** | |||
| * @brief Initialize from C fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @retval DECAF_SUCCESS the string was successfully decoded. | |||
| * @return DECAF_FAILURE the string wasn't the encoding of a point, or was the identity | |||
| * and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Point &p, const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE | |||
| ) NOEXCEPT { | |||
| return decaf_255_point_decode(p.p,buffer,allow_identity); | |||
| } | |||
| /** | |||
| * @brief Initialize from C++ fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @retval DECAF_SUCCESS the string was successfully decoded. | |||
| * @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
| ) NOEXCEPT { | |||
| if (buffer.size() != SER_BYTES) return DECAF_FAILURE; | |||
| return decaf_255_point_decode(p.p,buffer.data(),allow_identity); | |||
| } | |||
| /** | |||
| * @brief Map uniformly to the curve from a hash buffer. | |||
| * The empty or all-zero string maps to the identity, as does the string "\x01". | |||
| * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform, | |||
| * but the buffer will be zero-padded on the right. | |||
| */ | |||
| static inline Point from_hash ( const Block &s ) NOEXCEPT { | |||
| Point p((NOINIT())); p.set_to_hash(s); return p; | |||
| } | |||
| /** | |||
| * @brief Map to the curve from a hash buffer. | |||
| * The empty or all-zero string maps to the identity, as does the string "\x01". | |||
| * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform, | |||
| * but the buffer will be zero-padded on the right. | |||
| */ | |||
| inline unsigned char set_to_hash( const Block &s ) NOEXCEPT { | |||
| if (s.size() < HASH_BYTES) { | |||
| SecureBuffer b(HASH_BYTES); | |||
| memcpy(b.data(), s.data(), s.size()); | |||
| return decaf_255_point_from_hash_nonuniform(p,b); | |||
| } else if (s.size() == HASH_BYTES) { | |||
| return decaf_255_point_from_hash_nonuniform(p,s); | |||
| } else if (s.size() < 2*HASH_BYTES) { | |||
| SecureBuffer b(2*HASH_BYTES); | |||
| memcpy(b.data(), s.data(), s.size()); | |||
| return decaf_255_point_from_hash_uniform(p,b); | |||
| } else { | |||
| return decaf_255_point_from_hash_uniform(p,s); | |||
| } | |||
| } | |||
| /** | |||
| * @brief Encode to string. The identity encodes to the all-zero string. | |||
| */ | |||
| inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT { | |||
| SecureBuffer buffer(SER_BYTES); | |||
| decaf_255_point_encode(buffer, p); | |||
| return buffer; | |||
| } | |||
| /** | |||
| * @brief Encode to a C buffer. The identity encodes to all zeros. | |||
| */ | |||
| inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{ | |||
| decaf_255_point_encode(buffer, p); | |||
| } | |||
| /** @brief Point add. */ | |||
| inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_add(r.p,p,q.p); return r; } | |||
| /** @brief Point add. */ | |||
| inline Point &operator+=(const Point &q) NOEXCEPT { decaf_255_point_add(p,p,q.p); return *this; } | |||
| /** @brief Point subtract. */ | |||
| inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_sub(r.p,p,q.p); return r; } | |||
| /** @brief Point subtract. */ | |||
| inline Point &operator-=(const Point &q) NOEXCEPT { decaf_255_point_sub(p,p,q.p); return *this; } | |||
| /** @brief Point negate. */ | |||
| inline Point operator- () const NOEXCEPT { Point r((NOINIT())); decaf_255_point_negate(r.p,p); return r; } | |||
| /** @brief Double the point out of place. */ | |||
| inline Point times_two () const NOEXCEPT { Point r((NOINIT())); decaf_255_point_double(r.p,p); return r; } | |||
| /** @brief Double the point in place. */ | |||
| inline Point &double_in_place() NOEXCEPT { decaf_255_point_double(p,p); return *this; } | |||
| /** @brief Constant-time compare. */ | |||
| inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_255_point_eq(p,q.p); } | |||
| /** @brief Constant-time compare. */ | |||
| inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_255_point_eq(p,q.p); } | |||
| /** @brief Scalar multiply. */ | |||
| inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_scalarmul(r.p,p,s.s); return r; } | |||
| /** @brief Scalar multiply in place. */ | |||
| inline Point &operator*=(const Scalar &s) NOEXCEPT { decaf_255_point_scalarmul(p,p,s.s); return *this; } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point &operator/=(const Scalar &s) NOEXCEPT { return (*this) *= s.inverse(); } | |||
| /** @brief Validate / sanity check */ | |||
| inline bool validate() const NOEXCEPT { return !!decaf_255_point_valid(p); } | |||
| /** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */ | |||
| static inline Point double_scalarmul ( | |||
| const Point &q, const Scalar &qs, const Point &r, const Scalar &rs | |||
| ) NOEXCEPT { | |||
| Point p((NOINIT())); decaf_255_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
| } | |||
| /** | |||
| * @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. | |||
| * For those who like their scalars before the point. | |||
| */ | |||
| static inline Point double_scalarmul ( | |||
| const Scalar &qs, const Point &q, const Scalar &rs, const Point &r | |||
| ) NOEXCEPT { | |||
| Point p((NOINIT())); decaf_255_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
| } | |||
| /** | |||
| * @brief Double-scalar multiply: this point by the first scalar and base by the second scalar. | |||
| * @warning This function takes variable time, and may leak the scalars (or points, but currently | |||
| * it doesn't). | |||
| */ | |||
| inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT { | |||
| Point r((NOINIT())); decaf_255_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r; | |||
| } | |||
| inline Point& debugging_torque_in_place() { | |||
| decaf_255_point_debugging_2torque(p,p); | |||
| return *this; | |||
| } | |||
| inline bool invert_elligator ( | |||
| Buffer &buf, unsigned char hint | |||
| ) const NOEXCEPT { | |||
| unsigned char buf2[2*HASH_BYTES]; | |||
| memset(buf2,0,sizeof(buf2)); | |||
| memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
| decaf_bool_t ret; | |||
| if (buf.size() > HASH_BYTES) { | |||
| ret = decaf_255_invert_elligator_uniform(buf2, p, hint); | |||
| } else { | |||
| ret = decaf_255_invert_elligator_nonuniform(buf2, p, hint); | |||
| } | |||
| if (buf.size() < HASH_BYTES) { | |||
| ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size()); | |||
| } | |||
| memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
| decaf_bzero(buf2,sizeof(buf2)); | |||
| return !!ret; | |||
| } | |||
| /** @brief Steganographically encode this */ | |||
| inline SecureBuffer steg_encode(SpongeRng &rng) const NOEXCEPT; | |||
| /** @brief Return the base point */ | |||
| static inline const Point base() NOEXCEPT { return Point(decaf_255_point_base); } | |||
| /** @brief Return the identity point */ | |||
| static inline const Point identity() NOEXCEPT { return Point(decaf_255_point_identity); } | |||
| }; | |||
| /** | |||
| * @brief Precomputed table of points. | |||
| * Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is. | |||
| * Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to | |||
| * stack-allocate a 15kiB object anyway. | |||
| */ | |||
| class Precomputed { | |||
| private: | |||
| /** @cond internal */ | |||
| union { | |||
| decaf_255_precomputed_s *mine; | |||
| const decaf_255_precomputed_s *yours; | |||
| } ours; | |||
| bool isMine; | |||
| inline void clear() NOEXCEPT { | |||
| if (isMine) { | |||
| decaf_255_precomputed_destroy(ours.mine); | |||
| free(ours.mine); | |||
| ours.yours = decaf_255_precomputed_base; | |||
| isMine = false; | |||
| } | |||
| } | |||
| inline void alloc() throw(std::bad_alloc) { | |||
| if (isMine) return; | |||
| int ret = posix_memalign((void**)&ours.mine, alignof_decaf_255_precomputed_s,sizeof_decaf_255_precomputed_s); | |||
| if (ret || !ours.mine) { | |||
| isMine = false; | |||
| throw std::bad_alloc(); | |||
| } | |||
| isMine = true; | |||
| } | |||
| inline const decaf_255_precomputed_s *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; } | |||
| /** @endcond */ | |||
| public: | |||
| /** Destructor securely erases the memory. */ | |||
| inline ~Precomputed() NOEXCEPT { clear(); } | |||
| /** | |||
| * @brief Initialize from underlying type, declared as a reference to prevent | |||
| * it from being called with 0, thereby breaking override. | |||
| * | |||
| * The underlying object must remain valid throughout the lifetime of this one. | |||
| * | |||
| * By default, initializes to the table for the base point. | |||
| * | |||
| * @warning The empty initializer makes this equal to base, unlike the empty | |||
| * initializer for points which makes this equal to the identity. | |||
| */ | |||
| inline Precomputed( | |||
| const decaf_255_precomputed_s &yours = *decaf_255_precomputed_base | |||
| ) NOEXCEPT { | |||
| ours.yours = &yours; | |||
| isMine = false; | |||
| } | |||
| /** | |||
| * @brief Assign. This may require an allocation and memcpy. | |||
| */ | |||
| inline Precomputed &operator=(const Precomputed &it) throw(std::bad_alloc) { | |||
| if (this == &it) return *this; | |||
| if (it.isMine) { | |||
| alloc(); | |||
| memcpy(ours.mine,it.ours.mine,sizeof_decaf_255_precomputed_s); | |||
| } else { | |||
| clear(); | |||
| ours.yours = it.ours.yours; | |||
| } | |||
| isMine = it.isMine; | |||
| return *this; | |||
| } | |||
| /** | |||
| * @brief Initilaize from point. Must allocate memory, and may throw. | |||
| */ | |||
| inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) { | |||
| alloc(); | |||
| decaf_255_precompute(ours.mine,it.p); | |||
| return *this; | |||
| } | |||
| /** | |||
| * @brief Copy constructor. | |||
| */ | |||
| inline Precomputed(const Precomputed &it) throw(std::bad_alloc) : isMine(false) { *this = it; } | |||
| /** | |||
| * @brief Constructor which initializes from point. | |||
| */ | |||
| inline explicit Precomputed(const Point &it) throw(std::bad_alloc) : isMine(false) { *this = it; } | |||
| #if __cplusplus >= 201103L | |||
| inline Precomputed &operator=(Precomputed &&it) NOEXCEPT { | |||
| if (this == &it) return *this; | |||
| clear(); | |||
| ours = it.ours; | |||
| isMine = it.isMine; | |||
| it.isMine = false; | |||
| it.ours.yours = decaf_255_precomputed_base; | |||
| return *this; | |||
| } | |||
| inline Precomputed(Precomputed &&it) NOEXCEPT : isMine(false) { *this = it; } | |||
| #endif | |||
| /** @brief Fixed base scalarmul. */ | |||
| inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_255_precomputed_scalarmul(r.p,get(),s.s); return r; } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); } | |||
| /** @brief Return the table for the base point. */ | |||
| static inline const Precomputed base() NOEXCEPT { return Precomputed(*decaf_255_precomputed_base); } | |||
| }; | |||
| }; /* struct Decaf255 */ | |||
| #undef NOEXCEPT | |||
| #undef EXPLICIT_CON | |||
| #undef GET_DATA | |||
| } /* namespace decaf */ | |||
| #endif /* __DECAF_255_HXX__ */ | |||
| @@ -0,0 +1,651 @@ | |||
| /** | |||
| * @file decaf_448.h | |||
| * @author Mike Hamburg | |||
| * | |||
| * @copyright | |||
| * Copyright (c) 2015 Cryptography Research, Inc. \n | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| * | |||
| * @brief A group of prime order p. | |||
| * | |||
| * The Decaf library implements cryptographic operations on a an elliptic curve | |||
| * group of prime order p. It accomplishes this by using a twisted Edwards | |||
| * curve (isogenous to Ed448-Goldilocks) and wiping out the cofactor. | |||
| * | |||
| * The formulas are all complete and have no special cases, except that | |||
| * decaf_448_decode can fail because not every sequence of bytes is a valid group | |||
| * element. | |||
| * | |||
| * The formulas contain no data-dependent branches, timing or memory accesses, | |||
| * except for decaf_448_base_double_scalarmul_non_secret. | |||
| * | |||
| * This library may support multiple curves eventually. The Ed448-Goldilocks | |||
| * specific identifiers are prefixed with DECAF_448 or decaf_448. | |||
| */ | |||
| #ifndef __DECAF_448_H__ | |||
| #define __DECAF_448_H__ 1 | |||
| #include <stdint.h> | |||
| #include <sys/types.h> | |||
| /* Goldilocks' build flags default to hidden and stripping executables. */ | |||
| /** @cond internal */ | |||
| #if defined(DOXYGEN) && !defined(__attribute__) | |||
| #define __attribute__((x)) | |||
| #endif | |||
| #define API_VIS __attribute__((visibility("default"))) | |||
| #define NOINLINE __attribute__((noinline)) | |||
| #define WARN_UNUSED __attribute__((warn_unused_result)) | |||
| #define NONNULL1 __attribute__((nonnull(1))) | |||
| #define NONNULL2 __attribute__((nonnull(1,2))) | |||
| #define NONNULL3 __attribute__((nonnull(1,2,3))) | |||
| #define NONNULL4 __attribute__((nonnull(1,2,3,4))) | |||
| #define NONNULL5 __attribute__((nonnull(1,2,3,4,5))) | |||
| /* Internal word types */ | |||
| #if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \ | |||
| && !defined(DECAF_FORCE_32_BIT) | |||
| #define DECAF_WORD_BITS 64 | |||
| typedef uint64_t decaf_word_t, decaf_bool_t; | |||
| typedef __uint128_t decaf_dword_t; | |||
| #else | |||
| #define DECAF_WORD_BITS 32 | |||
| typedef uint32_t decaf_word_t, decaf_bool_t; | |||
| typedef uint64_t decaf_dword_t; | |||
| #endif | |||
| #define DECAF_448_LIMBS (512/DECAF_WORD_BITS) | |||
| #define DECAF_448_SCALAR_BITS 446 | |||
| #define DECAF_448_SCALAR_LIMBS (448/DECAF_WORD_BITS) | |||
| /** Galois field element internal structure */ | |||
| typedef struct gf_s { | |||
| decaf_word_t limb[DECAF_448_LIMBS]; | |||
| } __attribute__((aligned(32))) gf_s, gf[1]; | |||
| /** @endcond */ | |||
| /** Number of bytes in a serialized point. */ | |||
| #define DECAF_448_SER_BYTES 56 | |||
| /** Number of bytes in a serialized scalar. */ | |||
| #define DECAF_448_SCALAR_BYTES 56 | |||
| /** Twisted Edwards (-1,d-1) extended homogeneous coordinates */ | |||
| typedef struct decaf_448_point_s { /**@cond internal*/gf x,y,z,t;/**@endcond*/ } decaf_448_point_t[1]; | |||
| /** Precomputed table based on a point. Can be trivial implementation. */ | |||
| struct decaf_448_precomputed_s; | |||
| /** Precomputed table based on a point. Can be trivial implementation. */ | |||
| typedef struct decaf_448_precomputed_s decaf_448_precomputed_s; | |||
| /** Size and alignment of precomputed point tables. */ | |||
| extern const size_t sizeof_decaf_448_precomputed_s API_VIS, alignof_decaf_448_precomputed_s API_VIS; | |||
| /** Scalar is stored packed, because we don't need the speed. */ | |||
| typedef struct decaf_448_scalar_s { | |||
| /** @cond internal */ | |||
| decaf_word_t limb[DECAF_448_SCALAR_LIMBS]; | |||
| /** @endcond */ | |||
| } decaf_448_scalar_t[1]; | |||
| /** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */ | |||
| static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0; | |||
| /** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */ | |||
| static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/, | |||
| DECAF_FAILURE = 0 /*DECAF_FALSE*/; | |||
| /** A scalar equal to 1. */ | |||
| extern const decaf_448_scalar_t decaf_448_scalar_one API_VIS; | |||
| /** A scalar equal to 0. */ | |||
| extern const decaf_448_scalar_t decaf_448_scalar_zero API_VIS; | |||
| /** The identity point on the curve. */ | |||
| extern const decaf_448_point_t decaf_448_point_identity API_VIS; | |||
| /** | |||
| * An arbitrarily chosen base point on the curve. | |||
| * Equal to Ed448-Goldilocks base point defined by DJB, except of course that | |||
| * it's on the twist in this case. TODO: choose a base point with nice encoding? | |||
| */ | |||
| extern const decaf_448_point_t decaf_448_point_base API_VIS; | |||
| /** Precomputed table for the base point on the curve. */ | |||
| extern const struct decaf_448_precomputed_s *decaf_448_precomputed_base API_VIS; | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /** | |||
| * @brief Read a scalar from wire format or from bytes. | |||
| * | |||
| * @param [in] ser Serialized form of a scalar. | |||
| * @param [out] out Deserialized form. | |||
| * | |||
| * @retval DECAF_SUCCESS The scalar was correctly encoded. | |||
| * @retval DECAF_FAILURE The scalar was greater than the modulus, | |||
| * and has been reduced modulo that modulus. | |||
| */ | |||
| decaf_bool_t decaf_448_scalar_decode ( | |||
| decaf_448_scalar_t out, | |||
| const unsigned char ser[DECAF_448_SCALAR_BYTES] | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Read a scalar from wire format or from bytes. Reduces mod | |||
| * scalar prime. | |||
| * | |||
| * @param [in] ser Serialized form of a scalar. | |||
| * @param [in] ser_len Length of serialized form. | |||
| * @param [out] out Deserialized form. | |||
| */ | |||
| void decaf_448_scalar_decode_long ( | |||
| decaf_448_scalar_t out, | |||
| const unsigned char *ser, | |||
| size_t ser_len | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Serialize a scalar to wire format. | |||
| * | |||
| * @param [out] ser Serialized form of a scalar. | |||
| * @param [in] s Deserialized scalar. | |||
| */ | |||
| void decaf_448_scalar_encode ( | |||
| unsigned char ser[DECAF_448_SCALAR_BYTES], | |||
| const decaf_448_scalar_t s | |||
| ) API_VIS NONNULL2 NOINLINE NOINLINE; | |||
| /** | |||
| * @brief Add two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a+b. | |||
| */ | |||
| void decaf_448_scalar_add ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a, | |||
| const decaf_448_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Compare two scalars. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @retval DECAF_TRUE The scalars are equal. | |||
| * @retval DECAF_FALSE The scalars are not equal. | |||
| */ | |||
| decaf_bool_t decaf_448_scalar_eq ( | |||
| const decaf_448_scalar_t a, | |||
| const decaf_448_scalar_t b | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Subtract two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a-b. | |||
| */ | |||
| void decaf_448_scalar_sub ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a, | |||
| const decaf_448_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply two scalars. The scalars may use the same memory. | |||
| * @param [in] a One scalar. | |||
| * @param [in] b Another scalar. | |||
| * @param [out] out a*b. | |||
| */ | |||
| void decaf_448_scalar_mul ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a, | |||
| const decaf_448_scalar_t b | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Invert a scalar. When passed zero, return 0. The input and output may alias. | |||
| * @param [in] a A scalar. | |||
| * @param [out] out 1/a. | |||
| * @return DECAF_TRUE The input is nonzero. | |||
| */ | |||
| decaf_bool_t decaf_448_scalar_invert ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Copy a scalar. The scalars may use the same memory, in which | |||
| * case this function does nothing. | |||
| * @param [in] a A scalar. | |||
| * @param [out] out Will become a copy of a. | |||
| */ | |||
| static inline void NONNULL2 decaf_448_scalar_copy ( | |||
| decaf_448_scalar_t out, | |||
| const decaf_448_scalar_t a | |||
| ) { | |||
| *out = *a; | |||
| } | |||
| /** | |||
| * @brief Set a scalar to an integer. | |||
| * @param [in] a An integer. | |||
| * @param [out] out Will become equal to a. | |||
| * @todo Make inline? | |||
| */ | |||
| void decaf_448_scalar_set( | |||
| decaf_448_scalar_t out, | |||
| decaf_word_t a | |||
| ) API_VIS NONNULL1; | |||
| /** | |||
| * @brief Encode a point as a sequence of bytes. | |||
| * | |||
| * @param [out] ser The byte representation of the point. | |||
| * @param [in] pt The point to encode. | |||
| */ | |||
| void decaf_448_point_encode ( | |||
| uint8_t ser[DECAF_448_SER_BYTES], | |||
| const decaf_448_point_t pt | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Decode a point from a sequence of bytes. | |||
| * | |||
| * Every point has a unique encoding, so not every | |||
| * sequence of bytes is a valid encoding. If an invalid | |||
| * encoding is given, the output is undefined. | |||
| * | |||
| * @param [out] pt The decoded point. | |||
| * @param [in] ser The serialized version of the point. | |||
| * @param [in] allow_identity DECAF_TRUE if the identity is a legal input. | |||
| * @retval DECAF_SUCCESS The decoding succeeded. | |||
| * @retval DECAF_FAILURE The decoding didn't succeed, because | |||
| * ser does not represent a point. | |||
| */ | |||
| decaf_bool_t decaf_448_point_decode ( | |||
| decaf_448_point_t pt, | |||
| const uint8_t ser[DECAF_448_SER_BYTES], | |||
| decaf_bool_t allow_identity | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Copy a point. The input and output may alias, | |||
| * in which case this function does nothing. | |||
| * | |||
| * @param [out] a A copy of the point. | |||
| * @param [in] b Any point. | |||
| */ | |||
| static inline void NONNULL2 decaf_448_point_copy ( | |||
| decaf_448_point_t a, | |||
| const decaf_448_point_t b | |||
| ) { | |||
| *a=*b; | |||
| } | |||
| /** | |||
| * @brief Test whether two points are equal. If yes, return | |||
| * DECAF_TRUE, else return DECAF_FALSE. | |||
| * | |||
| * @param [in] a A point. | |||
| * @param [in] b Another point. | |||
| * @retval DECAF_TRUE The points are equal. | |||
| * @retval DECAF_FALSE The points are not equal. | |||
| */ | |||
| decaf_bool_t decaf_448_point_eq ( | |||
| const decaf_448_point_t a, | |||
| const decaf_448_point_t b | |||
| ) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Add two points to produce a third point. The | |||
| * input points and output point can be pointers to the same | |||
| * memory. | |||
| * | |||
| * @param [out] sum The sum a+b. | |||
| * @param [in] a An addend. | |||
| * @param [in] b An addend. | |||
| */ | |||
| void decaf_448_point_add ( | |||
| decaf_448_point_t sum, | |||
| const decaf_448_point_t a, | |||
| const decaf_448_point_t b | |||
| ) API_VIS NONNULL3; | |||
| /** | |||
| * @brief Double a point. Equivalent to | |||
| * decaf_448_point_add(two_a,a,a), but potentially faster. | |||
| * | |||
| * @param [out] two_a The sum a+a. | |||
| * @param [in] a A point. | |||
| */ | |||
| void decaf_448_point_double ( | |||
| decaf_448_point_t two_a, | |||
| const decaf_448_point_t a | |||
| ) API_VIS NONNULL2; | |||
| /** | |||
| * @brief Subtract two points to produce a third point. The | |||
| * input points and output point can be pointers to the same | |||
| * memory. | |||
| * | |||
| * @param [out] diff The difference a-b. | |||
| * @param [in] a The minuend. | |||
| * @param [in] b The subtrahend. | |||
| */ | |||
| void decaf_448_point_sub ( | |||
| decaf_448_point_t diff, | |||
| const decaf_448_point_t a, | |||
| const decaf_448_point_t b | |||
| ) API_VIS NONNULL3; | |||
| /** | |||
| * @brief Negate a point to produce another point. The input | |||
| * and output points can use the same memory. | |||
| * | |||
| * @param [out] nega The negated input point | |||
| * @param [in] a The input point. | |||
| */ | |||
| void decaf_448_point_negate ( | |||
| decaf_448_point_t nega, | |||
| const decaf_448_point_t a | |||
| ) API_VIS NONNULL2; | |||
| /** | |||
| * @brief Multiply a base point by a scalar: scaled = scalar*base. | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| */ | |||
| void decaf_448_point_scalarmul ( | |||
| decaf_448_point_t scaled, | |||
| const decaf_448_point_t base, | |||
| const decaf_448_scalar_t scalar | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply a base point by a scalar: scaled = scalar*base. | |||
| * This function operates directly on serialized forms. | |||
| * | |||
| * @warning This function is experimental. It may not be supported | |||
| * long-term. | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| * @param [in] allow_identity Allow the input to be the identity. | |||
| * @param [in] short_circuit Allow a fast return if the input is illegal. | |||
| * | |||
| * @retval DECAF_SUCCESS The scalarmul succeeded. | |||
| * @retval DECAF_FAILURE The scalarmul didn't succeed, because | |||
| * base does not represent a point. | |||
| */ | |||
| decaf_bool_t decaf_448_direct_scalarmul ( | |||
| uint8_t scaled[DECAF_448_SER_BYTES], | |||
| const uint8_t base[DECAF_448_SER_BYTES], | |||
| const decaf_448_scalar_t scalar, | |||
| decaf_bool_t allow_identity, | |||
| decaf_bool_t short_circuit | |||
| ) API_VIS NONNULL3 WARN_UNUSED NOINLINE; | |||
| /** | |||
| * @brief Precompute a table for fast scalar multiplication. | |||
| * Some implementations do not include precomputed points; for | |||
| * those implementations, this implementation simply copies the | |||
| * point. | |||
| * | |||
| * @param [out] a A precomputed table of multiples of the point. | |||
| * @param [in] b Any point. | |||
| */ | |||
| void decaf_448_precompute ( | |||
| decaf_448_precomputed_s *a, | |||
| const decaf_448_point_t b | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Multiply a precomputed base point by a scalar: | |||
| * scaled = scalar*base. | |||
| * Some implementations do not include precomputed points; for | |||
| * those implementations, this function is the same as | |||
| * decaf_448_point_scalarmul | |||
| * | |||
| * @param [out] scaled The scaled point base*scalar | |||
| * @param [in] base The point to be scaled. | |||
| * @param [in] scalar The scalar to multiply by. | |||
| * | |||
| * @todo precomputed dsmul? const or variable time? | |||
| */ | |||
| void decaf_448_precomputed_scalarmul ( | |||
| decaf_448_point_t scaled, | |||
| const decaf_448_precomputed_s *base, | |||
| const decaf_448_scalar_t scalar | |||
| ) API_VIS NONNULL3 NOINLINE; | |||
| /** | |||
| * @brief Multiply two base points by two scalars: | |||
| * scaled = scalar1*base1 + scalar2*base2. | |||
| * | |||
| * Equivalent to two calls to decaf_448_point_scalarmul, but may be | |||
| * faster. | |||
| * | |||
| * @param [out] combo The linear combination scalar1*base1 + scalar2*base2. | |||
| * @param [in] base1 A first point to be scaled. | |||
| * @param [in] scalar1 A first scalar to multiply by. | |||
| * @param [in] base2 A second point to be scaled. | |||
| * @param [in] scalar2 A second scalar to multiply by. | |||
| */ | |||
| void decaf_448_point_double_scalarmul ( | |||
| decaf_448_point_t combo, | |||
| const decaf_448_point_t base1, | |||
| const decaf_448_scalar_t scalar1, | |||
| const decaf_448_point_t base2, | |||
| const decaf_448_scalar_t scalar2 | |||
| ) API_VIS NONNULL5 NOINLINE; | |||
| /** | |||
| * @brief Multiply two base points by two scalars: | |||
| * scaled = scalar1*decaf_448_point_base + scalar2*base2. | |||
| * | |||
| * Otherwise equivalent to decaf_448_point_double_scalarmul, but may be | |||
| * faster at the expense of being variable time. | |||
| * | |||
| * @param [out] combo The linear combination scalar1*base + scalar2*base2. | |||
| * @param [in] scalar1 A first scalar to multiply by. | |||
| * @param [in] base2 A second point to be scaled. | |||
| * @param [in] scalar2 A second scalar to multiply by. | |||
| * | |||
| * @warning: This function takes variable time, and may leak the scalars | |||
| * used. It is designed for signature verification. | |||
| */ | |||
| void decaf_448_base_double_scalarmul_non_secret ( | |||
| decaf_448_point_t combo, | |||
| const decaf_448_scalar_t scalar1, | |||
| const decaf_448_point_t base2, | |||
| const decaf_448_scalar_t scalar2 | |||
| ) API_VIS NONNULL4 NOINLINE; | |||
| /** | |||
| * @brief Test that a point is valid, for debugging purposes. | |||
| * | |||
| * @param [in] toTest The point to test. | |||
| * @retval DECAF_TRUE The point is valid. | |||
| * @retval DECAF_FALSE The point is invalid. | |||
| */ | |||
| decaf_bool_t decaf_448_point_valid ( | |||
| const decaf_448_point_t toTest | |||
| ) API_VIS WARN_UNUSED NONNULL1 NOINLINE; | |||
| /** | |||
| * @brief 2-torque a point, for debugging purposes. | |||
| * | |||
| * @param [out] q The point to torque. | |||
| * @param [in] p The point to torque. | |||
| */ | |||
| void decaf_448_point_debugging_2torque ( | |||
| decaf_448_point_t q, | |||
| const decaf_448_point_t p | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Almost-Elligator-like hash to curve. | |||
| * | |||
| * Call this function with the output of a hash to make a hash to the curve. | |||
| * | |||
| * This function runs Elligator2 on the decaf_448 Jacobi quartic model. It then | |||
| * uses the isogeny to put the result in twisted Edwards form. As a result, | |||
| * it is safe (cannot produce points of order 4), and would be compatible with | |||
| * hypothetical other implementations of Decaf using a Montgomery or untwisted | |||
| * Edwards model. | |||
| * | |||
| * Unlike Elligator, this function may be up to 4:1 on [0,(p-1)/2]: | |||
| * A factor of 2 due to the isogeny. | |||
| * A factor of 2 because we quotient out the 2-torsion. | |||
| * | |||
| * This makes it about 8:1 overall. | |||
| * | |||
| * Negating the input (mod q) results in the same point. Inverting the input | |||
| * (mod q) results in the negative point. This is the same as Elligator. | |||
| * | |||
| * This function isn't quite indifferentiable from a random oracle. | |||
| * However, it is suitable for many protocols, including SPEKE and SPAKE2 EE. | |||
| * Furthermore, calling it twice with independent seeds and adding the results | |||
| * is indifferentiable from a random oracle. | |||
| * | |||
| * @param [in] hashed_data Output of some hash function. | |||
| * @param [out] pt The data hashed to the curve. | |||
| * @return A "hint" value which can be used to help invert the encoding. | |||
| */ | |||
| unsigned char | |||
| decaf_448_point_from_hash_nonuniform ( | |||
| decaf_448_point_t pt, | |||
| const unsigned char hashed_data[DECAF_448_SER_BYTES] | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Inverse of elligator-like hash to curve. | |||
| * | |||
| * This function writes to the buffer, to make it so that | |||
| * decaf_448_point_from_hash_nonuniform(buffer) = pt,hint | |||
| * if possible. | |||
| * | |||
| * @param [out] recovered_hash Encoded data. | |||
| * @param [in] pt The point to encode. | |||
| * @param [in] hint The hint value returned from | |||
| * decaf_448_point_from_hash_nonuniform. | |||
| * | |||
| * @retval DECAF_SUCCESS The inverse succeeded. | |||
| * @retval DECAF_FAILURE The pt isn't the image of | |||
| * decaf_448_point_from_hash_nonuniform with the given hint. | |||
| * | |||
| * @warning The hinting system is subject to change, especially in corner cases. | |||
| * @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF. | |||
| */ | |||
| decaf_bool_t | |||
| decaf_448_invert_elligator_nonuniform ( | |||
| unsigned char recovered_hash[DECAF_448_SER_BYTES], | |||
| const decaf_448_point_t pt, | |||
| unsigned char hint | |||
| ) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
| /** | |||
| * @brief Inverse of elligator-like hash to curve, uniform. | |||
| * | |||
| * This function modifies the first DECAF_448_SER_BYTES of the | |||
| * buffer, to make it so that | |||
| * decaf_448_point_from_hash_uniform(buffer) = pt,hint | |||
| * if possible. | |||
| * | |||
| * @param [out] recovered_hash Encoded data. | |||
| * @param [in] pt The point to encode. | |||
| * @param [in] hint The hint value returned from | |||
| * decaf_448_point_from_hash_nonuniform. | |||
| * | |||
| * @retval DECAF_SUCCESS The inverse succeeded. | |||
| * @retval DECAF_FAILURE The pt isn't the image of | |||
| * decaf_448_point_from_hash_uniform with the given hint. | |||
| * | |||
| * @warning The hinting system is subject to change, especially in corner cases. | |||
| * @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF. | |||
| */ | |||
| decaf_bool_t | |||
| decaf_448_invert_elligator_uniform ( | |||
| unsigned char recovered_hash[2*DECAF_448_SER_BYTES], | |||
| const decaf_448_point_t pt, | |||
| unsigned char hint | |||
| ) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
| /** | |||
| * @brief Indifferentiable hash function encoding to curve. | |||
| * | |||
| * Equivalent to calling decaf_448_point_from_hash_nonuniform twice and adding. | |||
| * | |||
| * @param [in] hashed_data Output of some hash function. | |||
| * @param [out] pt The data hashed to the curve. | |||
| * @return A "hint" value which can be used to help invert the encoding. | |||
| */ | |||
| unsigned char decaf_448_point_from_hash_uniform ( | |||
| decaf_448_point_t pt, | |||
| const unsigned char hashed_data[2*DECAF_448_SER_BYTES] | |||
| ) API_VIS NONNULL2 NOINLINE; | |||
| /** | |||
| * @brief Overwrite data with zeros. Uses memset_s if available. | |||
| */ | |||
| void decaf_bzero ( | |||
| void *data, | |||
| size_t size | |||
| ) NONNULL1 API_VIS NOINLINE; | |||
| /** | |||
| * @brief Compare two buffers, returning DECAF_TRUE if they are equal. | |||
| */ | |||
| decaf_bool_t decaf_memeq ( | |||
| const void *data1, | |||
| const void *data2, | |||
| size_t size | |||
| ) NONNULL2 WARN_UNUSED API_VIS NOINLINE; | |||
| /** | |||
| * @brief Overwrite scalar with zeros. | |||
| */ | |||
| void decaf_448_scalar_destroy ( | |||
| decaf_448_scalar_t scalar | |||
| ) NONNULL1 API_VIS; | |||
| /** | |||
| * @brief Overwrite point with zeros. | |||
| * @todo Use this internally. | |||
| */ | |||
| void decaf_448_point_destroy ( | |||
| decaf_448_point_t point | |||
| ) NONNULL1 API_VIS; | |||
| /** | |||
| * @brief Overwrite point with zeros. | |||
| * @todo Use this internally. | |||
| */ | |||
| void decaf_448_precomputed_destroy ( | |||
| decaf_448_precomputed_s *pre | |||
| ) NONNULL1 API_VIS; | |||
| /* TODO: functions to invert point_from_hash?? */ | |||
| #undef API_VIS | |||
| #undef WARN_UNUSED | |||
| #undef NOINLINE | |||
| #undef NONNULL1 | |||
| #undef NONNULL2 | |||
| #undef NONNULL3 | |||
| #undef NONNULL4 | |||
| #undef NONNULL5 | |||
| #ifdef __cplusplus | |||
| } /* extern "C" */ | |||
| #endif | |||
| #endif /* __DECAF_448_H__ */ | |||
| @@ -0,0 +1,738 @@ | |||
| /** | |||
| * @file decaf_448.hxx | |||
| * @author Mike Hamburg | |||
| * | |||
| * @copyright | |||
| * Copyright (c) 2015 Cryptography Research, Inc. \n | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| * | |||
| * @brief A group of prime order p, C++ wrapper. | |||
| * | |||
| * The Decaf library implements cryptographic operations on a an elliptic curve | |||
| * group of prime order p. It accomplishes this by using a twisted Edwards | |||
| * curve (isogenous to Ed448-Goldilocks) and wiping out the cofactor. | |||
| * | |||
| * The formulas are all complete and have no special cases, except that | |||
| * decaf_448_decode can fail because not every sequence of bytes is a valid group | |||
| * element. | |||
| * | |||
| * The formulas contain no data-dependent branches, timing or memory accesses, | |||
| * except for decaf_448_base_double_scalarmul_non_secret. | |||
| */ | |||
| #ifndef __DECAF_448_HXX__ | |||
| #define __DECAF_448_HXX__ 1 | |||
| /** This code uses posix_memalign. */ | |||
| #define _XOPEN_SOURCE 600 | |||
| #include <stdlib.h> | |||
| #include <string.h> /* for memcpy */ | |||
| #include "decaf.h" | |||
| #include <string> | |||
| #include <sys/types.h> | |||
| #include <limits.h> | |||
| /* TODO: This is incomplete */ | |||
| /* TODO: attribute nonnull */ | |||
| /** @cond internal */ | |||
| #if __cplusplus >= 201103L | |||
| #define NOEXCEPT noexcept | |||
| #define EXPLICIT_CON explicit | |||
| #define GET_DATA(str) ((const unsigned char *)&(str)[0]) | |||
| #else | |||
| #define NOEXCEPT throw() | |||
| #define EXPLICIT_CON | |||
| #define GET_DATA(str) ((const unsigned char *)((str).data())) | |||
| #endif | |||
| /** @endcond */ | |||
| namespace decaf { | |||
| /** @brief An exception for when crypto (ie point decode) has failed. */ | |||
| class CryptoException : public std::exception { | |||
| public: | |||
| /** @return "CryptoException" */ | |||
| virtual const char * what() const NOEXCEPT { return "CryptoException"; } | |||
| }; | |||
| /** @brief An exception for when crypto (ie point decode) has failed. */ | |||
| class LengthException : public std::exception { | |||
| public: | |||
| /** @return "CryptoException" */ | |||
| virtual const char * what() const NOEXCEPT { return "LengthException"; } | |||
| }; | |||
| /** | |||
| * Securely erase contents of memory. | |||
| */ | |||
| static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); } | |||
| /** Block object */ | |||
| class Block { | |||
| protected: | |||
| unsigned char *data_; | |||
| size_t size_; | |||
| public: | |||
| /** Empty init */ | |||
| inline Block() NOEXCEPT : data_(NULL), size_(0) {} | |||
| /** Init from C string */ | |||
| inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {} | |||
| /** Unowned init */ | |||
| inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {} | |||
| /** Block from std::string */ | |||
| inline Block(const std::string &s) : data_((unsigned char *)GET_DATA(s)), size_(s.size()) {} | |||
| /** Get const data */ | |||
| inline const unsigned char *data() const NOEXCEPT { return data_; } | |||
| /** Get the size */ | |||
| inline size_t size() const NOEXCEPT { return size_; } | |||
| /** Autocast to const unsigned char * */ | |||
| inline operator const unsigned char*() const NOEXCEPT { return data_; } | |||
| /** Convert to C++ string */ | |||
| inline std::string get_string() const { | |||
| return std::string((const char *)data_,size_); | |||
| } | |||
| /** Slice the buffer*/ | |||
| inline Block slice(size_t off, size_t length) const throw(LengthException) { | |||
| if (off > size() || length > size() - off) | |||
| throw LengthException(); | |||
| return Block(data()+off, length); | |||
| } | |||
| /** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */ | |||
| inline virtual ~Block() {}; | |||
| }; | |||
| class TmpBuffer; | |||
| class Buffer : public Block { | |||
| public: | |||
| /** Null init */ | |||
| inline Buffer() NOEXCEPT : Block() {} | |||
| /** Unowned init */ | |||
| inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {} | |||
| /** Get unconst data */ | |||
| inline unsigned char *data() NOEXCEPT { return data_; } | |||
| /** Get const data */ | |||
| inline const unsigned char *data() const NOEXCEPT { return data_; } | |||
| /** Autocast to const unsigned char * */ | |||
| inline operator const unsigned char*() const NOEXCEPT { return data_; } | |||
| /** Autocast to unsigned char */ | |||
| inline operator unsigned char*() NOEXCEPT { return data_; } | |||
| /** Slice the buffer*/ | |||
| inline TmpBuffer slice(size_t off, size_t length) throw(LengthException); | |||
| }; | |||
| class TmpBuffer : public Buffer { | |||
| public: | |||
| /** Unowned init */ | |||
| inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {} | |||
| }; | |||
| TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) { | |||
| if (off > size() || length > size() - off) throw LengthException(); | |||
| return TmpBuffer(data()+off, length); | |||
| } | |||
| /** A self-erasing block of data */ | |||
| class SecureBuffer : public Buffer { | |||
| public: | |||
| /** Null secure block */ | |||
| inline SecureBuffer() NOEXCEPT : Buffer() {} | |||
| /** Construct empty from size */ | |||
| inline SecureBuffer(size_t size) { | |||
| data_ = new unsigned char[size_ = size]; | |||
| memset(data_,0,size); | |||
| } | |||
| /** Construct from data */ | |||
| inline SecureBuffer(const unsigned char *data, size_t size){ | |||
| data_ = new unsigned char[size_ = size]; | |||
| memcpy(data_, data, size); | |||
| } | |||
| /** Copy constructor */ | |||
| inline SecureBuffer(const Block ©) : Buffer() { *this = copy; } | |||
| /** Copy-assign constructor */ | |||
| inline SecureBuffer& operator=(const Block ©) throw(std::bad_alloc) { | |||
| if (© == this) return *this; | |||
| clear(); | |||
| data_ = new unsigned char[size_ = copy.size()]; | |||
| memcpy(data_,copy.data(),size_); | |||
| return *this; | |||
| } | |||
| /** Copy-assign constructor */ | |||
| inline SecureBuffer& operator=(const SecureBuffer ©) throw(std::bad_alloc) { | |||
| if (© == this) return *this; | |||
| clear(); | |||
| data_ = new unsigned char[size_ = copy.size()]; | |||
| memcpy(data_,copy.data(),size_); | |||
| return *this; | |||
| } | |||
| /** Destructor erases data */ | |||
| ~SecureBuffer() NOEXCEPT { clear(); } | |||
| /** Clear data */ | |||
| inline void clear() NOEXCEPT { | |||
| if (data_ == NULL) return; | |||
| really_bzero(data_,size_); | |||
| delete[] data_; | |||
| data_ = NULL; | |||
| size_ = 0; | |||
| } | |||
| #if __cplusplus >= 201103L | |||
| /** Move constructor */ | |||
| inline SecureBuffer(SecureBuffer &&move) { *this = move; } | |||
| /** Move non-constructor */ | |||
| inline SecureBuffer(Block &&move) { *this = (Block &)move; } | |||
| /** Move-assign constructor. TODO: check that this actually gets used.*/ | |||
| inline SecureBuffer& operator=(SecureBuffer &&move) { | |||
| clear(); | |||
| data_ = move.data_; move.data_ = NULL; | |||
| size_ = move.size_; move.size_ = 0; | |||
| return *this; | |||
| } | |||
| /** C++11-only explicit cast */ | |||
| inline explicit operator std::string() const { return get_string(); } | |||
| #endif | |||
| }; | |||
| /** @brief Passed to constructors to avoid (conservative) initialization */ | |||
| struct NOINIT {}; | |||
| /**@cond internal*/ | |||
| /** Forward-declare sponge RNG object */ | |||
| class SpongeRng; | |||
| /**@endcond*/ | |||
| /** | |||
| * @brief Ed448-Goldilocks/Decaf instantiation of group. | |||
| */ | |||
| struct Ed448 { | |||
| /** @cond internal */ | |||
| class Point; | |||
| class Precomputed; | |||
| /** @endcond */ | |||
| /** | |||
| * @brief A scalar modulo the curve order. | |||
| * Supports the usual arithmetic operations, all in constant time. | |||
| */ | |||
| class Scalar { | |||
| public: | |||
| /** @brief Size of a serialized element */ | |||
| static const size_t SER_BYTES = DECAF_448_SCALAR_BYTES; | |||
| /** @brief access to the underlying scalar object */ | |||
| decaf_448_scalar_t s; | |||
| /** @brief Don't initialize. */ | |||
| inline Scalar(const NOINIT &) NOEXCEPT {} | |||
| /** @brief Set to an unsigned word */ | |||
| inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; } | |||
| /** @brief Set to a signed word */ | |||
| inline Scalar(const int w) NOEXCEPT { *this = w; } | |||
| /** @brief Construct from RNG */ | |||
| inline explicit Scalar(SpongeRng &rng) NOEXCEPT; | |||
| /** @brief Construct from decaf_scalar_t object. */ | |||
| inline Scalar(const decaf_448_scalar_t &t = decaf_448_scalar_zero) NOEXCEPT { decaf_448_scalar_copy(s,t); } | |||
| /** @brief Copy constructor. */ | |||
| inline Scalar(const Scalar &x) NOEXCEPT { *this = x; } | |||
| /** @brief Construct from arbitrary-length little-endian byte sequence. */ | |||
| inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; } | |||
| /** @brief Assignment. */ | |||
| inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; } | |||
| /** @brief Assign from unsigned word. */ | |||
| inline Scalar& operator=(decaf_word_t w) NOEXCEPT { decaf_448_scalar_set(s,w); return *this; } | |||
| /** @brief Assign from signed int. */ | |||
| inline Scalar& operator=(int w) NOEXCEPT { | |||
| Scalar t(-(decaf_word_t)INT_MIN); | |||
| decaf_448_scalar_set(s,(decaf_word_t)w - (decaf_word_t)INT_MIN); | |||
| *this -= t; | |||
| return *this; | |||
| } | |||
| /** Destructor securely erases the scalar. */ | |||
| inline ~Scalar() NOEXCEPT { decaf_448_scalar_destroy(s); } | |||
| /** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */ | |||
| inline Scalar &operator=(const Block &bl) NOEXCEPT { | |||
| decaf_448_scalar_decode_long(s,bl.data(),bl.size()); return *this; | |||
| } | |||
| /** | |||
| * @brief Decode from correct-length little-endian byte sequence. | |||
| * @return DECAF_FAILURE if the scalar is greater than or equal to the group order q. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Scalar &sc, const unsigned char buffer[SER_BYTES] | |||
| ) NOEXCEPT { | |||
| return decaf_448_scalar_decode(sc.s,buffer); | |||
| } | |||
| /** @brief Decode from correct-length little-endian byte sequence in C++ string. */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Scalar &sc, const Block &buffer | |||
| ) NOEXCEPT { | |||
| if (buffer.size() != SER_BYTES) return DECAF_FAILURE; | |||
| return decaf_448_scalar_decode(sc.s,buffer); | |||
| } | |||
| /** @brief Encode to fixed-length string */ | |||
| inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT { | |||
| SecureBuffer buf(SER_BYTES); decaf_448_scalar_encode(buf,s); return buf; | |||
| } | |||
| /** @brief Encode to fixed-length buffer */ | |||
| inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{ | |||
| decaf_448_scalar_encode(buffer, s); | |||
| } | |||
| /** Add. */ | |||
| inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_add(r.s,s,q.s); return r; } | |||
| /** Add to this. */ | |||
| inline Scalar &operator+=(const Scalar &q) NOEXCEPT { decaf_448_scalar_add(s,s,q.s); return *this; } | |||
| /** Subtract. */ | |||
| inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_sub(r.s,s,q.s); return r; } | |||
| /** Subtract from this. */ | |||
| inline Scalar &operator-=(const Scalar &q) NOEXCEPT { decaf_448_scalar_sub(s,s,q.s); return *this; } | |||
| /** Multiply */ | |||
| inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_mul(r.s,s,q.s); return r; } | |||
| /** Multiply into this. */ | |||
| inline Scalar &operator*=(const Scalar &q) NOEXCEPT { decaf_448_scalar_mul(s,s,q.s); return *this; } | |||
| /** Negate */ | |||
| inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_sub(r.s,decaf_448_scalar_zero,s); return r; } | |||
| /** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */ | |||
| inline Scalar inverse() const NOEXCEPT { Scalar r; decaf_448_scalar_invert(r.s,s); return r; } | |||
| /** @brief Divide by inverting q. If q == 0, return 0. */ | |||
| inline Scalar operator/ (const Scalar &q) const NOEXCEPT { return *this * q.inverse(); } | |||
| /** @brief Divide by inverting q. If q == 0, return 0. */ | |||
| inline Scalar &operator/=(const Scalar &q) NOEXCEPT { return *this *= q.inverse(); } | |||
| /** @brief Compare in constant time */ | |||
| inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); } | |||
| /** @brief Compare in constant time */ | |||
| inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_448_scalar_eq(s,q.s); } | |||
| /** @brief Scalarmul with scalar on left. */ | |||
| inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); } | |||
| /** @brief Scalarmul-precomputed with scalar on left. */ | |||
| inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); } | |||
| /** @brief Direct scalar multiplication. */ | |||
| inline SecureBuffer direct_scalarmul( | |||
| const Block &in, | |||
| decaf_bool_t allow_identity=DECAF_FALSE, | |||
| decaf_bool_t short_circuit=DECAF_TRUE | |||
| ) const throw(CryptoException) { | |||
| SecureBuffer out(/*FIXME Point::*/SER_BYTES); | |||
| if (!decaf_448_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit)) | |||
| throw CryptoException(); | |||
| return out; | |||
| } | |||
| }; | |||
| /** | |||
| * @brief Element of prime-order group. | |||
| */ | |||
| class Point { | |||
| public: | |||
| /** @brief Size of a serialized element */ | |||
| static const size_t SER_BYTES = DECAF_448_SER_BYTES; | |||
| /** @brief Size of a stegged element */ | |||
| static const size_t STEG_BYTES = DECAF_448_SER_BYTES + 8; | |||
| /** @brief Bytes required for hash */ | |||
| static const size_t HASH_BYTES = DECAF_448_SER_BYTES; | |||
| /** The c-level object. */ | |||
| decaf_448_point_t p; | |||
| /** @brief Don't initialize. */ | |||
| inline Point(const NOINIT &) NOEXCEPT {} | |||
| /** @brief Constructor sets to identity by default. */ | |||
| inline Point(const decaf_448_point_t &q = decaf_448_point_identity) NOEXCEPT { decaf_448_point_copy(p,q); } | |||
| /** @brief Copy constructor. */ | |||
| inline Point(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); } | |||
| /** @brief Assignment. */ | |||
| inline Point& operator=(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); return *this; } | |||
| /** @brief Destructor securely erases the point. */ | |||
| inline ~Point() NOEXCEPT { decaf_448_point_destroy(p); } | |||
| /** @brief Construct from RNG */ | |||
| inline explicit Point(SpongeRng &rng, bool uniform = true) NOEXCEPT; | |||
| /** | |||
| * @brief Initialize from C++ fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. | |||
| */ | |||
| inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) { | |||
| if (!decode(*this,s,allow_identity)) throw CryptoException(); | |||
| } | |||
| /** | |||
| * @brief Initialize from C fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. | |||
| */ | |||
| inline explicit Point(const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE) | |||
| throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); } | |||
| /** | |||
| * @brief Initialize from C fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @retval DECAF_SUCCESS the string was successfully decoded. | |||
| * @return DECAF_FAILURE the string wasn't the encoding of a point, or was the identity | |||
| * and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Point &p, const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE | |||
| ) NOEXCEPT { | |||
| return decaf_448_point_decode(p.p,buffer,allow_identity); | |||
| } | |||
| /** | |||
| * @brief Initialize from C++ fixed-length byte string. | |||
| * The all-zero string maps to the identity. | |||
| * | |||
| * @retval DECAF_SUCCESS the string was successfully decoded. | |||
| * @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point, | |||
| * or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. | |||
| */ | |||
| static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
| Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
| ) NOEXCEPT { | |||
| if (buffer.size() != SER_BYTES) return DECAF_FAILURE; | |||
| return decaf_448_point_decode(p.p,buffer.data(),allow_identity); | |||
| } | |||
| /** | |||
| * @brief Map uniformly to the curve from a hash buffer. | |||
| * The empty or all-zero string maps to the identity, as does the string "\x01". | |||
| * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform, | |||
| * but the buffer will be zero-padded on the right. | |||
| */ | |||
| static inline Point from_hash ( const Block &s ) NOEXCEPT { | |||
| Point p((NOINIT())); p.set_to_hash(s); return p; | |||
| } | |||
| /** | |||
| * @brief Map to the curve from a hash buffer. | |||
| * The empty or all-zero string maps to the identity, as does the string "\x01". | |||
| * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform, | |||
| * but the buffer will be zero-padded on the right. | |||
| */ | |||
| inline unsigned char set_to_hash( const Block &s ) NOEXCEPT { | |||
| if (s.size() < HASH_BYTES) { | |||
| SecureBuffer b(HASH_BYTES); | |||
| memcpy(b.data(), s.data(), s.size()); | |||
| return decaf_448_point_from_hash_nonuniform(p,b); | |||
| } else if (s.size() == HASH_BYTES) { | |||
| return decaf_448_point_from_hash_nonuniform(p,s); | |||
| } else if (s.size() < 2*HASH_BYTES) { | |||
| SecureBuffer b(2*HASH_BYTES); | |||
| memcpy(b.data(), s.data(), s.size()); | |||
| return decaf_448_point_from_hash_uniform(p,b); | |||
| } else { | |||
| return decaf_448_point_from_hash_uniform(p,s); | |||
| } | |||
| } | |||
| /** | |||
| * @brief Encode to string. The identity encodes to the all-zero string. | |||
| */ | |||
| inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT { | |||
| SecureBuffer buffer(SER_BYTES); | |||
| decaf_448_point_encode(buffer, p); | |||
| return buffer; | |||
| } | |||
| /** | |||
| * @brief Encode to a C buffer. The identity encodes to all zeros. | |||
| */ | |||
| inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{ | |||
| decaf_448_point_encode(buffer, p); | |||
| } | |||
| /** @brief Point add. */ | |||
| inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_add(r.p,p,q.p); return r; } | |||
| /** @brief Point add. */ | |||
| inline Point &operator+=(const Point &q) NOEXCEPT { decaf_448_point_add(p,p,q.p); return *this; } | |||
| /** @brief Point subtract. */ | |||
| inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_sub(r.p,p,q.p); return r; } | |||
| /** @brief Point subtract. */ | |||
| inline Point &operator-=(const Point &q) NOEXCEPT { decaf_448_point_sub(p,p,q.p); return *this; } | |||
| /** @brief Point negate. */ | |||
| inline Point operator- () const NOEXCEPT { Point r((NOINIT())); decaf_448_point_negate(r.p,p); return r; } | |||
| /** @brief Double the point out of place. */ | |||
| inline Point times_two () const NOEXCEPT { Point r((NOINIT())); decaf_448_point_double(r.p,p); return r; } | |||
| /** @brief Double the point in place. */ | |||
| inline Point &double_in_place() NOEXCEPT { decaf_448_point_double(p,p); return *this; } | |||
| /** @brief Constant-time compare. */ | |||
| inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_448_point_eq(p,q.p); } | |||
| /** @brief Constant-time compare. */ | |||
| inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_448_point_eq(p,q.p); } | |||
| /** @brief Scalar multiply. */ | |||
| inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_scalarmul(r.p,p,s.s); return r; } | |||
| /** @brief Scalar multiply in place. */ | |||
| inline Point &operator*=(const Scalar &s) NOEXCEPT { decaf_448_point_scalarmul(p,p,s.s); return *this; } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point &operator/=(const Scalar &s) NOEXCEPT { return (*this) *= s.inverse(); } | |||
| /** @brief Validate / sanity check */ | |||
| inline bool validate() const NOEXCEPT { return !!decaf_448_point_valid(p); } | |||
| /** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */ | |||
| static inline Point double_scalarmul ( | |||
| const Point &q, const Scalar &qs, const Point &r, const Scalar &rs | |||
| ) NOEXCEPT { | |||
| Point p((NOINIT())); decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
| } | |||
| /** | |||
| * @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. | |||
| * For those who like their scalars before the point. | |||
| */ | |||
| static inline Point double_scalarmul ( | |||
| const Scalar &qs, const Point &q, const Scalar &rs, const Point &r | |||
| ) NOEXCEPT { | |||
| Point p((NOINIT())); decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
| } | |||
| /** | |||
| * @brief Double-scalar multiply: this point by the first scalar and base by the second scalar. | |||
| * @warning This function takes variable time, and may leak the scalars (or points, but currently | |||
| * it doesn't). | |||
| */ | |||
| inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT { | |||
| Point r((NOINIT())); decaf_448_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r; | |||
| } | |||
| inline Point& debugging_torque_in_place() { | |||
| decaf_448_point_debugging_2torque(p,p); | |||
| return *this; | |||
| } | |||
| inline bool invert_elligator ( | |||
| Buffer &buf, unsigned char hint | |||
| ) const NOEXCEPT { | |||
| unsigned char buf2[2*HASH_BYTES]; | |||
| memset(buf2,0,sizeof(buf2)); | |||
| memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
| decaf_bool_t ret; | |||
| if (buf.size() > HASH_BYTES) { | |||
| ret = decaf_448_invert_elligator_uniform(buf2, p, hint); | |||
| } else { | |||
| ret = decaf_448_invert_elligator_nonuniform(buf2, p, hint); | |||
| } | |||
| if (buf.size() < HASH_BYTES) { | |||
| ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size()); | |||
| } | |||
| memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
| decaf_bzero(buf2,sizeof(buf2)); | |||
| return !!ret; | |||
| } | |||
| /** @brief Steganographically encode this */ | |||
| inline SecureBuffer steg_encode(SpongeRng &rng) const NOEXCEPT; | |||
| /** @brief Return the base point */ | |||
| static inline const Point base() NOEXCEPT { return Point(decaf_448_point_base); } | |||
| /** @brief Return the identity point */ | |||
| static inline const Point identity() NOEXCEPT { return Point(decaf_448_point_identity); } | |||
| }; | |||
| /** | |||
| * @brief Precomputed table of points. | |||
| * Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is. | |||
| * Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to | |||
| * stack-allocate a 15kiB object anyway. | |||
| */ | |||
| class Precomputed { | |||
| private: | |||
| /** @cond internal */ | |||
| union { | |||
| decaf_448_precomputed_s *mine; | |||
| const decaf_448_precomputed_s *yours; | |||
| } ours; | |||
| bool isMine; | |||
| inline void clear() NOEXCEPT { | |||
| if (isMine) { | |||
| decaf_448_precomputed_destroy(ours.mine); | |||
| free(ours.mine); | |||
| ours.yours = decaf_448_precomputed_base; | |||
| isMine = false; | |||
| } | |||
| } | |||
| inline void alloc() throw(std::bad_alloc) { | |||
| if (isMine) return; | |||
| int ret = posix_memalign((void**)&ours.mine, alignof_decaf_448_precomputed_s,sizeof_decaf_448_precomputed_s); | |||
| if (ret || !ours.mine) { | |||
| isMine = false; | |||
| throw std::bad_alloc(); | |||
| } | |||
| isMine = true; | |||
| } | |||
| inline const decaf_448_precomputed_s *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; } | |||
| /** @endcond */ | |||
| public: | |||
| /** Destructor securely erases the memory. */ | |||
| inline ~Precomputed() NOEXCEPT { clear(); } | |||
| /** | |||
| * @brief Initialize from underlying type, declared as a reference to prevent | |||
| * it from being called with 0, thereby breaking override. | |||
| * | |||
| * The underlying object must remain valid throughout the lifetime of this one. | |||
| * | |||
| * By default, initializes to the table for the base point. | |||
| * | |||
| * @warning The empty initializer makes this equal to base, unlike the empty | |||
| * initializer for points which makes this equal to the identity. | |||
| */ | |||
| inline Precomputed( | |||
| const decaf_448_precomputed_s &yours = *decaf_448_precomputed_base | |||
| ) NOEXCEPT { | |||
| ours.yours = &yours; | |||
| isMine = false; | |||
| } | |||
| /** | |||
| * @brief Assign. This may require an allocation and memcpy. | |||
| */ | |||
| inline Precomputed &operator=(const Precomputed &it) throw(std::bad_alloc) { | |||
| if (this == &it) return *this; | |||
| if (it.isMine) { | |||
| alloc(); | |||
| memcpy(ours.mine,it.ours.mine,sizeof_decaf_448_precomputed_s); | |||
| } else { | |||
| clear(); | |||
| ours.yours = it.ours.yours; | |||
| } | |||
| isMine = it.isMine; | |||
| return *this; | |||
| } | |||
| /** | |||
| * @brief Initilaize from point. Must allocate memory, and may throw. | |||
| */ | |||
| inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) { | |||
| alloc(); | |||
| decaf_448_precompute(ours.mine,it.p); | |||
| return *this; | |||
| } | |||
| /** | |||
| * @brief Copy constructor. | |||
| */ | |||
| inline Precomputed(const Precomputed &it) throw(std::bad_alloc) : isMine(false) { *this = it; } | |||
| /** | |||
| * @brief Constructor which initializes from point. | |||
| */ | |||
| inline explicit Precomputed(const Point &it) throw(std::bad_alloc) : isMine(false) { *this = it; } | |||
| #if __cplusplus >= 201103L | |||
| inline Precomputed &operator=(Precomputed &&it) NOEXCEPT { | |||
| if (this == &it) return *this; | |||
| clear(); | |||
| ours = it.ours; | |||
| isMine = it.isMine; | |||
| it.isMine = false; | |||
| it.ours.yours = decaf_448_precomputed_base; | |||
| return *this; | |||
| } | |||
| inline Precomputed(Precomputed &&it) NOEXCEPT : isMine(false) { *this = it; } | |||
| #endif | |||
| /** @brief Fixed base scalarmul. */ | |||
| inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_448_precomputed_scalarmul(r.p,get(),s.s); return r; } | |||
| /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
| inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); } | |||
| /** @brief Return the table for the base point. */ | |||
| static inline const Precomputed base() NOEXCEPT { return Precomputed(*decaf_448_precomputed_base); } | |||
| }; | |||
| }; /* struct Decaf448 */ | |||
| #undef NOEXCEPT | |||
| #undef EXPLICIT_CON | |||
| #undef GET_DATA | |||
| } /* namespace decaf */ | |||
| #endif /* __DECAF_448_HXX__ */ | |||
| @@ -11,60 +11,60 @@ | |||
| #include "decaf_crypto.h" | |||
| #include <string.h> | |||
| static const unsigned int DECAF_448_SCALAR_OVERKILL_BYTES = DECAF_448_SCALAR_BYTES + 8; | |||
| static const unsigned int DECAF_255_SCALAR_OVERKILL_BYTES = DECAF_255_SCALAR_BYTES + 8; | |||
| void decaf_448_derive_private_key ( | |||
| decaf_448_private_key_t priv, | |||
| const decaf_448_symmetric_key_t proto | |||
| void decaf_255_derive_private_key ( | |||
| decaf_255_private_key_t priv, | |||
| const decaf_255_symmetric_key_t proto | |||
| ) { | |||
| const char *magic = "decaf_448_derive_private_key"; | |||
| uint8_t encoded_scalar[DECAF_448_SCALAR_OVERKILL_BYTES]; | |||
| decaf_448_point_t pub; | |||
| const char *magic = "decaf_255_derive_private_key"; | |||
| uint8_t encoded_scalar[DECAF_255_SCALAR_OVERKILL_BYTES]; | |||
| decaf_255_point_t pub; | |||
| keccak_sponge_t sponge; | |||
| shake256_init(sponge); | |||
| shake256_update(sponge, proto, sizeof(decaf_448_symmetric_key_t)); | |||
| shake256_update(sponge, proto, sizeof(decaf_255_symmetric_key_t)); | |||
| shake256_update(sponge, (const unsigned char *)magic, strlen(magic)); | |||
| shake256_final(sponge, encoded_scalar, sizeof(encoded_scalar)); | |||
| shake256_destroy(sponge); | |||
| memcpy(priv->sym, proto, sizeof(decaf_448_symmetric_key_t)); | |||
| decaf_448_scalar_decode_long(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar)); | |||
| memcpy(priv->sym, proto, sizeof(decaf_255_symmetric_key_t)); | |||
| decaf_255_scalar_decode_long(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar)); | |||
| decaf_448_precomputed_scalarmul(pub, decaf_448_precomputed_base, priv->secret_scalar); | |||
| decaf_448_point_encode(priv->pub, pub); | |||
| decaf_255_precomputed_scalarmul(pub, decaf_255_precomputed_base, priv->secret_scalar); | |||
| decaf_255_point_encode(priv->pub, pub); | |||
| decaf_bzero(encoded_scalar, sizeof(encoded_scalar)); | |||
| } | |||
| void | |||
| decaf_448_destroy_private_key ( | |||
| decaf_448_private_key_t priv | |||
| decaf_255_destroy_private_key ( | |||
| decaf_255_private_key_t priv | |||
| ) { | |||
| decaf_bzero((void*)priv, sizeof(decaf_448_private_key_t)); | |||
| decaf_bzero((void*)priv, sizeof(decaf_255_private_key_t)); | |||
| } | |||
| void decaf_448_private_to_public ( | |||
| decaf_448_public_key_t pub, | |||
| const decaf_448_private_key_t priv | |||
| void decaf_255_private_to_public ( | |||
| decaf_255_public_key_t pub, | |||
| const decaf_255_private_key_t priv | |||
| ) { | |||
| memcpy(pub, priv->pub, sizeof(decaf_448_public_key_t)); | |||
| memcpy(pub, priv->pub, sizeof(decaf_255_public_key_t)); | |||
| } | |||
| decaf_bool_t | |||
| decaf_448_shared_secret ( | |||
| decaf_255_shared_secret ( | |||
| uint8_t *shared, | |||
| size_t shared_bytes, | |||
| const decaf_448_private_key_t my_privkey, | |||
| const decaf_448_public_key_t your_pubkey | |||
| const decaf_255_private_key_t my_privkey, | |||
| const decaf_255_public_key_t your_pubkey | |||
| ) { | |||
| uint8_t ss_ser[DECAF_448_SER_BYTES]; | |||
| const char *nope = "decaf_448_ss_invalid"; | |||
| uint8_t ss_ser[DECAF_255_SER_BYTES]; | |||
| const char *nope = "decaf_255_ss_invalid"; | |||
| unsigned i; | |||
| /* Lexsort keys. Less will be -1 if mine is less, and 0 otherwise. */ | |||
| uint16_t less = 0; | |||
| for (i=0; i<DECAF_448_SER_BYTES; i++) { | |||
| for (i=0; i<DECAF_255_SER_BYTES; i++) { | |||
| uint16_t delta = my_privkey->pub[i]; | |||
| delta -= your_pubkey[i]; | |||
| /* Case: | |||
| @@ -92,7 +92,7 @@ decaf_448_shared_secret ( | |||
| } | |||
| shake256_update(sponge, ss_ser, sizeof(ss_ser)); | |||
| decaf_bool_t ret = decaf_448_direct_scalarmul(ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE); | |||
| decaf_bool_t ret = decaf_255_direct_scalarmul(ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE); | |||
| /* If invalid, then replace ... */ | |||
| for (i=0; i<sizeof(ss_ser); i++) { | |||
| ss_ser[i] &= ret; | |||
| @@ -114,16 +114,16 @@ decaf_448_shared_secret ( | |||
| } | |||
| void | |||
| decaf_448_sign_shake ( | |||
| decaf_448_signature_t sig, | |||
| const decaf_448_private_key_t priv, | |||
| decaf_255_sign_shake ( | |||
| decaf_255_signature_t sig, | |||
| const decaf_255_private_key_t priv, | |||
| const keccak_sponge_t shake | |||
| ) { | |||
| const char *magic = "decaf_448_sign_shake"; | |||
| const char *magic = "decaf_255_sign_shake"; | |||
| uint8_t overkill[DECAF_448_SCALAR_OVERKILL_BYTES], encoded[DECAF_448_SER_BYTES]; | |||
| decaf_448_point_t point; | |||
| decaf_448_scalar_t nonce, challenge; | |||
| uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES], encoded[DECAF_255_SER_BYTES]; | |||
| decaf_255_point_t point; | |||
| decaf_255_scalar_t nonce, challenge; | |||
| /* Derive nonce */ | |||
| keccak_sponge_t ctx; | |||
| @@ -132,9 +132,9 @@ decaf_448_sign_shake ( | |||
| shake256_update(ctx, (const unsigned char *)magic, strlen(magic)); | |||
| shake256_final(ctx, overkill, sizeof(overkill)); | |||
| decaf_448_scalar_decode_long(nonce, overkill, sizeof(overkill)); | |||
| decaf_448_precomputed_scalarmul(point, decaf_448_precomputed_base, nonce); | |||
| decaf_448_point_encode(encoded, point); | |||
| decaf_255_scalar_decode_long(nonce, overkill, sizeof(overkill)); | |||
| decaf_255_precomputed_scalarmul(point, decaf_255_precomputed_base, nonce); | |||
| decaf_255_point_encode(encoded, point); | |||
| /* Derive challenge */ | |||
| memcpy(ctx, shake, sizeof(ctx)); | |||
| @@ -142,83 +142,83 @@ decaf_448_sign_shake ( | |||
| shake256_update(ctx, encoded, sizeof(encoded)); | |||
| shake256_final(ctx, overkill, sizeof(overkill)); | |||
| shake256_destroy(ctx); | |||
| decaf_448_scalar_decode_long(challenge, overkill, sizeof(overkill)); | |||
| decaf_255_scalar_decode_long(challenge, overkill, sizeof(overkill)); | |||
| /* Respond */ | |||
| decaf_448_scalar_mul(challenge, challenge, priv->secret_scalar); | |||
| decaf_448_scalar_sub(nonce, nonce, challenge); | |||
| decaf_255_scalar_mul(challenge, challenge, priv->secret_scalar); | |||
| decaf_255_scalar_sub(nonce, nonce, challenge); | |||
| /* Save results */ | |||
| memcpy(sig, encoded, sizeof(encoded)); | |||
| decaf_448_scalar_encode(&sig[sizeof(encoded)], nonce); | |||
| decaf_255_scalar_encode(&sig[sizeof(encoded)], nonce); | |||
| /* Clean up */ | |||
| decaf_448_scalar_destroy(nonce); | |||
| decaf_448_scalar_destroy(challenge); | |||
| decaf_255_scalar_destroy(nonce); | |||
| decaf_255_scalar_destroy(challenge); | |||
| decaf_bzero(overkill,sizeof(overkill)); | |||
| decaf_bzero(encoded,sizeof(encoded)); | |||
| } | |||
| decaf_bool_t | |||
| decaf_448_verify_shake ( | |||
| const decaf_448_signature_t sig, | |||
| const decaf_448_public_key_t pub, | |||
| decaf_255_verify_shake ( | |||
| const decaf_255_signature_t sig, | |||
| const decaf_255_public_key_t pub, | |||
| const keccak_sponge_t shake | |||
| ) { | |||
| decaf_bool_t ret; | |||
| uint8_t overkill[DECAF_448_SCALAR_OVERKILL_BYTES]; | |||
| decaf_448_point_t point, pubpoint; | |||
| decaf_448_scalar_t challenge, response; | |||
| uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES]; | |||
| decaf_255_point_t point, pubpoint; | |||
| decaf_255_scalar_t challenge, response; | |||
| /* Derive challenge */ | |||
| keccak_sponge_t ctx; | |||
| memcpy(ctx, shake, sizeof(ctx)); | |||
| shake256_update(ctx, pub, sizeof(decaf_448_public_key_t)); | |||
| shake256_update(ctx, sig, DECAF_448_SER_BYTES); | |||
| shake256_update(ctx, pub, sizeof(decaf_255_public_key_t)); | |||
| shake256_update(ctx, sig, DECAF_255_SER_BYTES); | |||
| shake256_final(ctx, overkill, sizeof(overkill)); | |||
| shake256_destroy(ctx); | |||
| decaf_448_scalar_decode_long(challenge, overkill, sizeof(overkill)); | |||
| decaf_255_scalar_decode_long(challenge, overkill, sizeof(overkill)); | |||
| /* Decode points. */ | |||
| ret = decaf_448_point_decode(point, sig, DECAF_TRUE); | |||
| ret &= decaf_448_point_decode(pubpoint, pub, DECAF_FALSE); | |||
| ret &= decaf_448_scalar_decode(response, &sig[DECAF_448_SER_BYTES]); | |||
| ret = decaf_255_point_decode(point, sig, DECAF_TRUE); | |||
| ret &= decaf_255_point_decode(pubpoint, pub, DECAF_FALSE); | |||
| ret &= decaf_255_scalar_decode(response, &sig[DECAF_255_SER_BYTES]); | |||
| decaf_448_base_double_scalarmul_non_secret ( | |||
| decaf_255_base_double_scalarmul_non_secret ( | |||
| pubpoint, response, pubpoint, challenge | |||
| ); | |||
| ret &= decaf_448_point_eq(pubpoint, point); | |||
| ret &= decaf_255_point_eq(pubpoint, point); | |||
| return ret; | |||
| } | |||
| void | |||
| decaf_448_sign ( | |||
| decaf_448_signature_t sig, | |||
| const decaf_448_private_key_t priv, | |||
| decaf_255_sign ( | |||
| decaf_255_signature_t sig, | |||
| const decaf_255_private_key_t priv, | |||
| const unsigned char *message, | |||
| size_t message_len | |||
| ) { | |||
| keccak_sponge_t ctx; | |||
| shake256_init(ctx); | |||
| shake256_update(ctx, message, message_len); | |||
| decaf_448_sign_shake(sig, priv, ctx); | |||
| decaf_255_sign_shake(sig, priv, ctx); | |||
| shake256_destroy(ctx); | |||
| } | |||
| decaf_bool_t | |||
| decaf_448_verify ( | |||
| const decaf_448_signature_t sig, | |||
| const decaf_448_public_key_t pub, | |||
| decaf_255_verify ( | |||
| const decaf_255_signature_t sig, | |||
| const decaf_255_public_key_t pub, | |||
| const unsigned char *message, | |||
| size_t message_len | |||
| ) { | |||
| keccak_sponge_t ctx; | |||
| shake256_init(ctx); | |||
| shake256_update(ctx, message, message_len); | |||
| decaf_bool_t ret = decaf_448_verify_shake(sig, pub, ctx); | |||
| decaf_bool_t ret = decaf_255_verify_shake(sig, pub, ctx); | |||
| shake256_destroy(ctx); | |||
| return ret; | |||
| } | |||
| @@ -13,20 +13,20 @@ | |||
| #include "decaf.h" | |||
| #include <string.h> | |||
| #include "field.h" | |||
| #include "decaf_448_config.h" | |||
| #include "decaf_255_config.h" | |||
| #define WBITS DECAF_WORD_BITS | |||
| /* Rename table for eventual factoring into .c.inc, MSR ECC style */ | |||
| #define SCALAR_LIMBS DECAF_448_SCALAR_LIMBS | |||
| #define SCALAR_BITS DECAF_448_SCALAR_BITS | |||
| #define NLIMBS DECAF_448_LIMBS | |||
| #define API_NS(_id) decaf_448_##_id | |||
| #define API_NS2(_pref,_id) _pref##_decaf_448_##_id | |||
| #define scalar_t decaf_448_scalar_t | |||
| #define point_t decaf_448_point_t | |||
| #define precomputed_s decaf_448_precomputed_s | |||
| #define SER_BYTES DECAF_448_SER_BYTES | |||
| #define SCALAR_LIMBS DECAF_255_SCALAR_LIMBS | |||
| #define SCALAR_BITS DECAF_255_SCALAR_BITS | |||
| #define NLIMBS DECAF_255_LIMBS | |||
| #define API_NS(_id) decaf_255_##_id | |||
| #define API_NS2(_pref,_id) _pref##_decaf_255_##_id | |||
| #define scalar_t decaf_255_scalar_t | |||
| #define point_t decaf_255_point_t | |||
| #define precomputed_s decaf_255_precomputed_s | |||
| #define SER_BYTES DECAF_255_SER_BYTES | |||
| #if WBITS == 64 | |||
| typedef __int128_t decaf_sdword_t; | |||
| @@ -45,25 +45,23 @@ typedef int64_t decaf_sdword_t; | |||
| #define siv static inline void __attribute__((always_inline)) | |||
| static const gf ZERO = {{{0}}}, ONE = {{{1}}}, TWO = {{{2}}}; | |||
| static const int EDWARDS_D = -39081; | |||
| static const int EDWARDS_D = 121665; | |||
| static const scalar_t sc_p = {{{ | |||
| SC_LIMB(0x2378c292ab5844f3), | |||
| SC_LIMB(0x216cc2728dc58f55), | |||
| SC_LIMB(0xc44edb49aed63690), | |||
| SC_LIMB(0xffffffff7cca23e9), | |||
| SC_LIMB(0xffffffffffffffff), | |||
| SC_LIMB(0xffffffffffffffff), | |||
| SC_LIMB(0x3fffffffffffffff) | |||
| SC_LIMB(0x5812631a5cf5d3ed), | |||
| SC_LIMB(0x14def9dea2f79cd6), | |||
| SC_LIMB(0), | |||
| SC_LIMB(0), | |||
| SC_LIMB(0x1000000000000000) | |||
| }}}; | |||
| const scalar_t API_NS(scalar_one) = {{{1}}}, API_NS(scalar_zero) = {{{0}}}; | |||
| extern const scalar_t sc_r2; | |||
| extern const decaf_word_t MONTGOMERY_FACTOR; | |||
| /* sqrt(5) = 2phi-1 from the curve spec. Not exported, but used by pregen tool. */ | |||
| /* sqrt(9) = 3 from the curve spec. Not exported, but used by pregen tool. */ | |||
| const unsigned char base_point_ser_for_pregen[SER_BYTES] = { | |||
| -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1 | |||
| 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | |||
| }; | |||
| extern const point_t API_NS(point_base); | |||
| @@ -324,7 +322,8 @@ decaf_bool_t API_NS(scalar_invert) ( | |||
| scalar_t out, | |||
| const scalar_t a | |||
| ) { | |||
| /* FIELD MAGIC */ | |||
| #if 0 | |||
| /* FIELD MAGIC. FIXME: not updated for 25519 */ | |||
| scalar_t chain[7], tmp; | |||
| sc_montmul(chain[0],a,sc_r2); | |||
| @@ -371,6 +370,11 @@ decaf_bool_t API_NS(scalar_invert) ( | |||
| API_NS(scalar_destroy)(chain[i]); | |||
| } | |||
| return ~API_NS(scalar_eq)(out,API_NS(scalar_zero)); | |||
| #else | |||
| (void)out; | |||
| (void)a; | |||
| return 0; | |||
| #endif | |||
| } | |||
| void API_NS(scalar_sub) ( | |||
| @@ -1067,7 +1071,7 @@ unsigned char API_NS(point_from_hash_nonuniform) ( | |||
| decaf_bool_t | |||
| API_NS(invert_elligator_nonuniform) ( | |||
| unsigned char recovered_hash[DECAF_448_SER_BYTES], | |||
| unsigned char recovered_hash[DECAF_255_SER_BYTES], | |||
| const point_t p, | |||
| unsigned char hint | |||
| ) { | |||
| @@ -12,11 +12,11 @@ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include "decaf.h" | |||
| #include "decaf_448_config.h" /* MAGIC */ | |||
| #include "decaf_255_config.h" /* MAGIC */ | |||
| #include "field.h" | |||
| #define API_NS(_id) decaf_448_##_id | |||
| #define API_NS2(_pref,_id) _pref##_decaf_448_##_id | |||
| #define API_NS(_id) decaf_255_##_id | |||
| #define API_NS2(_pref,_id) _pref##_decaf_255_##_id | |||
| /* To satisfy linker. */ | |||
| const field_t API_NS(precomputed_base_as_fe)[1]; | |||
| @@ -24,7 +24,7 @@ const API_NS(scalar_t) API_NS(precomputed_scalarmul_adjustment); | |||
| const API_NS(scalar_t) API_NS(point_scalarmul_adjustment); | |||
| const API_NS(scalar_t) sc_r2 = {{{0}}}; | |||
| const decaf_word_t MONTGOMERY_FACTOR = 0; | |||
| const unsigned char base_point_ser_for_pregen[DECAF_448_SER_BYTES]; | |||
| const unsigned char base_point_ser_for_pregen[DECAF_255_SER_BYTES]; | |||
| const API_NS(point_t) API_NS(point_base); | |||
| @@ -94,8 +94,8 @@ int main(int argc, char **argv) { | |||
| printf("/** @warning: this file was automatically generated. */\n"); | |||
| printf("#include \"field.h\"\n\n"); | |||
| printf("#include \"decaf.h\"\n\n"); | |||
| printf("#define API_NS(_id) decaf_448_##_id\n"); | |||
| printf("#define API_NS2(_pref,_id) _pref##_decaf_448_##_id\n"); | |||
| printf("#define API_NS(_id) decaf_255_##_id\n"); | |||
| printf("#define API_NS2(_pref,_id) _pref##_decaf_255_##_id\n"); | |||
| output = (const field_t *)real_point_base; | |||
| printf("const API_NS(point_t) API_NS(point_base) = {{\n"); | |||
| @@ -138,8 +138,8 @@ int main(int argc, char **argv) { | |||
| scalar_print("API_NS(precomputed_scalarmul_adjustment)", smadj); | |||
| API_NS(scalar_copy)(smadj,API_NS(scalar_one)); | |||
| for (i=0; i<DECAF_448_SCALAR_BITS-1 + DECAF_WINDOW_BITS | |||
| - ((DECAF_448_SCALAR_BITS-1)%DECAF_WINDOW_BITS); i++) { | |||
| for (i=0; i<DECAF_255_SCALAR_BITS-1 + DECAF_WINDOW_BITS | |||
| - ((DECAF_255_SCALAR_BITS-1)%DECAF_WINDOW_BITS); i++) { | |||
| API_NS(scalar_add)(smadj,smadj,smadj); | |||
| } | |||
| API_NS(scalar_sub)(smadj, smadj, API_NS(scalar_one)); | |||
| @@ -0,0 +1 @@ | |||
| #define WORD_BITS 64 | |||
| @@ -0,0 +1,318 @@ | |||
| /* Copyright (c) 2014 Cryptography Research, Inc. | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| */ | |||
| #include "p25519.h" | |||
| static __inline__ __uint128_t widemul( | |||
| const uint64_t a, | |||
| const uint64_t b | |||
| ) { | |||
| return ((__uint128_t)a) * ((__uint128_t)b); | |||
| } | |||
| static __inline__ uint64_t is_zero(uint64_t a) { | |||
| /* let's hope the compiler isn't clever enough to optimize this. */ | |||
| return (((__uint128_t)a)-1)>>64; | |||
| } | |||
| void | |||
| p255_mul ( | |||
| p255_t *__restrict__ cs, | |||
| const p255_t *as, | |||
| const p255_t *bs | |||
| ) { | |||
| const uint64_t *a = as->limb, *b = bs->limb; | |||
| uint64_t *c = cs->limb; | |||
| __uint128_t accum0 = 0, accum1 = 0, accum2; | |||
| uint64_t mask = (1ull<<51) - 1; | |||
| uint64_t aa[4], bb[4], bbb[4]; | |||
| unsigned int i; | |||
| for (i=0; i<4; i++) { | |||
| aa[i] = a[i] + a[i+4]; | |||
| bb[i] = b[i] + b[i+4]; | |||
| bbb[i] = bb[i] + b[i+4]; | |||
| } | |||
| int I_HATE_UNROLLED_LOOPS = 0; | |||
| if (I_HATE_UNROLLED_LOOPS) { | |||
| /* The compiler probably won't unroll this, | |||
| * so it's like 80% slower. | |||
| */ | |||
| for (i=0; i<4; i++) { | |||
| accum2 = 0; | |||
| unsigned int j; | |||
| for (j=0; j<=i; j++) { | |||
| accum2 += widemul(a[j], b[i-j]); | |||
| accum1 += widemul(aa[j], bb[i-j]); | |||
| accum0 += widemul(a[j+4], b[i-j+4]); | |||
| } | |||
| for (; j<4; j++) { | |||
| accum2 += widemul(a[j], b[i-j+8]); | |||
| accum1 += widemul(aa[j], bbb[i-j+4]); | |||
| accum0 += widemul(a[j+4], bb[i-j+4]); | |||
| } | |||
| accum1 -= accum2; | |||
| accum0 += accum2; | |||
| c[i] = ((uint64_t)(accum0)) & mask; | |||
| c[i+4] = ((uint64_t)(accum1)) & mask; | |||
| accum0 >>= 56; | |||
| accum1 >>= 56; | |||
| } | |||
| } else { | |||
| accum2 = widemul(a[0], b[0]); | |||
| accum1 += widemul(aa[0], bb[0]); | |||
| accum0 += widemul(a[4], b[4]); | |||
| accum2 += widemul(a[1], b[7]); | |||
| accum1 += widemul(aa[1], bbb[3]); | |||
| accum0 += widemul(a[5], bb[3]); | |||
| accum2 += widemul(a[2], b[6]); | |||
| accum1 += widemul(aa[2], bbb[2]); | |||
| accum0 += widemul(a[6], bb[2]); | |||
| accum2 += widemul(a[3], b[5]); | |||
| accum1 += widemul(aa[3], bbb[1]); | |||
| accum0 += widemul(a[7], bb[1]); | |||
| accum1 -= accum2; | |||
| accum0 += accum2; | |||
| c[0] = ((uint64_t)(accum0)) & mask; | |||
| c[4] = ((uint64_t)(accum1)) & mask; | |||
| accum0 >>= 56; | |||
| accum1 >>= 56; | |||
| accum2 = widemul(a[0], b[1]); | |||
| accum1 += widemul(aa[0], bb[1]); | |||
| accum0 += widemul(a[4], b[5]); | |||
| accum2 += widemul(a[1], b[0]); | |||
| accum1 += widemul(aa[1], bb[0]); | |||
| accum0 += widemul(a[5], b[4]); | |||
| accum2 += widemul(a[2], b[7]); | |||
| accum1 += widemul(aa[2], bbb[3]); | |||
| accum0 += widemul(a[6], bb[3]); | |||
| accum2 += widemul(a[3], b[6]); | |||
| accum1 += widemul(aa[3], bbb[2]); | |||
| accum0 += widemul(a[7], bb[2]); | |||
| accum1 -= accum2; | |||
| accum0 += accum2; | |||
| c[1] = ((uint64_t)(accum0)) & mask; | |||
| c[5] = ((uint64_t)(accum1)) & mask; | |||
| accum0 >>= 56; | |||
| accum1 >>= 56; | |||
| accum2 = widemul(a[0], b[2]); | |||
| accum1 += widemul(aa[0], bb[2]); | |||
| accum0 += widemul(a[4], b[6]); | |||
| accum2 += widemul(a[1], b[1]); | |||
| accum1 += widemul(aa[1], bb[1]); | |||
| accum0 += widemul(a[5], b[5]); | |||
| accum2 += widemul(a[2], b[0]); | |||
| accum1 += widemul(aa[2], bb[0]); | |||
| accum0 += widemul(a[6], b[4]); | |||
| accum2 += widemul(a[3], b[7]); | |||
| accum1 += widemul(aa[3], bbb[3]); | |||
| accum0 += widemul(a[7], bb[3]); | |||
| accum1 -= accum2; | |||
| accum0 += accum2; | |||
| c[2] = ((uint64_t)(accum0)) & mask; | |||
| c[6] = ((uint64_t)(accum1)) & mask; | |||
| accum0 >>= 56; | |||
| accum1 >>= 56; | |||
| accum2 = widemul(a[0], b[3]); | |||
| accum1 += widemul(aa[0], bb[3]); | |||
| accum0 += widemul(a[4], b[7]); | |||
| accum2 += widemul(a[1], b[2]); | |||
| accum1 += widemul(aa[1], bb[2]); | |||
| accum0 += widemul(a[5], b[6]); | |||
| accum2 += widemul(a[2], b[1]); | |||
| accum1 += widemul(aa[2], bb[1]); | |||
| accum0 += widemul(a[6], b[5]); | |||
| accum2 += widemul(a[3], b[0]); | |||
| accum1 += widemul(aa[3], bb[0]); | |||
| accum0 += widemul(a[7], b[4]); | |||
| accum1 -= accum2; | |||
| accum0 += accum2; | |||
| c[3] = ((uint64_t)(accum0)) & mask; | |||
| c[7] = ((uint64_t)(accum1)) & mask; | |||
| accum0 >>= 56; | |||
| accum1 >>= 56; | |||
| } /* !I_HATE_UNROLLED_LOOPS */ | |||
| accum0 += accum1; | |||
| accum0 += c[4]; | |||
| accum1 += c[0]; | |||
| c[4] = ((uint64_t)(accum0)) & mask; | |||
| c[0] = ((uint64_t)(accum1)) & mask; | |||
| accum0 >>= 56; | |||
| accum1 >>= 56; | |||
| c[5] += ((uint64_t)(accum0)); | |||
| c[1] += ((uint64_t)(accum1)); | |||
| } | |||
| void | |||
| p255_mulw ( | |||
| p255_t *__restrict__ cs, | |||
| const p255_t *as, | |||
| uint64_t b | |||
| ) { | |||
| const uint64_t *a = as->limb; | |||
| uint64_t *c = cs->limb; | |||
| __uint128_t accum0 = 0, accum4 = 0; | |||
| uint64_t mask = (1ull<<56) - 1; | |||
| int i; | |||
| for (i=0; i<4; i++) { | |||
| accum0 += widemul(b, a[i]); | |||
| accum4 += widemul(b, a[i+4]); | |||
| c[i] = accum0 & mask; accum0 >>= 56; | |||
| c[i+4] = accum4 & mask; accum4 >>= 56; | |||
| } | |||
| accum0 += accum4 + c[4]; | |||
| c[4] = accum0 & mask; | |||
| c[5] += accum0 >> 56; | |||
| accum4 += c[0]; | |||
| c[0] = accum4 & mask; | |||
| c[1] += accum4 >> 56; | |||
| } | |||
| void | |||
| p255_sqr ( | |||
| p255_t *__restrict__ cs, | |||
| const p255_t *as | |||
| ) { | |||
| p255_mul(cs,as,as); // TODO | |||
| } | |||
| void | |||
| p255_strong_reduce ( | |||
| p255_t *a | |||
| ) { | |||
| uint64_t mask = (1ull<<56)-1; | |||
| /* first, clear high */ | |||
| a->limb[4] += a->limb[7]>>56; | |||
| a->limb[0] += a->limb[7]>>56; | |||
| a->limb[7] &= mask; | |||
| /* now the total is less than 2^255 - 2^(255-56) + 2^(255-56+8) < 2p */ | |||
| /* compute total_value - p. No need to reduce mod p. */ | |||
| __int128_t scarry = 0; | |||
| int i; | |||
| for (i=0; i<8; i++) { | |||
| scarry = scarry + a->limb[i] - ((i==4)?mask-1:mask); | |||
| a->limb[i] = scarry & mask; | |||
| scarry >>= 56; | |||
| } | |||
| /* uncommon case: it was >= p, so now scarry = 0 and this = x | |||
| * common case: it was < p, so now scarry = -1 and this = x - p + 2^255 | |||
| * so let's add back in p. will carry back off the top for 2^255. | |||
| */ | |||
| assert(is_zero(scarry) | is_zero(scarry+1)); | |||
| uint64_t scarry_mask = scarry & mask; | |||
| __uint128_t carry = 0; | |||
| /* add it back */ | |||
| for (i=0; i<8; i++) { | |||
| carry = carry + a->limb[i] + ((i==4)?(scarry_mask&~1):scarry_mask); | |||
| a->limb[i] = carry & mask; | |||
| carry >>= 56; | |||
| } | |||
| assert(is_zero(carry + scarry)); | |||
| } | |||
| void | |||
| p255_serialize ( | |||
| uint8_t serial[32], | |||
| const struct p255_t *x | |||
| ) { | |||
| int i,j; | |||
| p255_t red; | |||
| p255_copy(&red, x); | |||
| p255_strong_reduce(&red); | |||
| for (i=0; i<8; i++) { | |||
| for (j=0; j<7; j++) { | |||
| serial[7*i+j] = red.limb[i]; | |||
| red.limb[i] >>= 8; | |||
| } | |||
| assert(red.limb[i] == 0); | |||
| } | |||
| } | |||
| mask_t | |||
| p255_deserialize ( | |||
| p255_t *x, | |||
| const uint8_t serial[32] | |||
| ) { | |||
| int i,j; | |||
| for (i=0; i<8; i++) { | |||
| uint64_t out = 0; | |||
| for (j=0; j<7; j++) { | |||
| out |= ((uint64_t)serial[7*i+j])<<(8*j); | |||
| } | |||
| x->limb[i] = out; | |||
| } | |||
| /* Check for reduction. | |||
| * | |||
| * The idea is to create a variable ge which is all ones (rather, 56 ones) | |||
| * if and only if the low $i$ words of $x$ are >= those of p. | |||
| * | |||
| * Remember p = little_endian(1111,1111,1111,1111,1110,1111,1111,1111) | |||
| */ | |||
| uint64_t ge = -1, mask = (1ull<<56)-1; | |||
| for (i=0; i<4; i++) { | |||
| ge &= x->limb[i]; | |||
| } | |||
| /* At this point, ge = 1111 iff bottom are all 1111. Now propagate if 1110, or set if 1111 */ | |||
| ge = (ge & (x->limb[4] + 1)) | is_zero(x->limb[4] ^ mask); | |||
| /* Propagate the rest */ | |||
| for (i=5; i<8; i++) { | |||
| ge &= x->limb[i]; | |||
| } | |||
| return ~is_zero(ge ^ mask); | |||
| } | |||
| @@ -0,0 +1,155 @@ | |||
| /* Copyright (c) 2014 Cryptography Research, Inc. | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| */ | |||
| #ifndef __P255_H__ | |||
| #define __P255_H__ 1 | |||
| #include <stdint.h> | |||
| #include <assert.h> | |||
| #include <string.h> | |||
| #include "word.h" | |||
| typedef struct p255_t { | |||
| uint64_t limb[5]; | |||
| } p255_t; | |||
| #define LBITS 51 | |||
| #define FIELD_LITERAL(a,b,c,d,e) {{a,b,c,d,e}} | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| static __inline__ void | |||
| p255_add_RAW ( | |||
| p255_t *out, | |||
| const p255_t *a, | |||
| const p255_t *b | |||
| ) __attribute__((unused)); | |||
| static __inline__ void | |||
| p255_sub_RAW ( | |||
| p255_t *out, | |||
| const p255_t *a, | |||
| const p255_t *b | |||
| ) __attribute__((unused)); | |||
| static __inline__ void | |||
| p255_copy ( | |||
| p255_t *out, | |||
| const p255_t *a | |||
| ) __attribute__((unused)); | |||
| static __inline__ void | |||
| p255_weak_reduce ( | |||
| p255_t *inout | |||
| ) __attribute__((unused)); | |||
| void | |||
| p255_strong_reduce ( | |||
| p255_t *inout | |||
| ); | |||
| static __inline__ void | |||
| p255_bias ( | |||
| p255_t *inout, | |||
| int amount | |||
| ) __attribute__((unused)); | |||
| void | |||
| p255_mul ( | |||
| p255_t *__restrict__ out, | |||
| const p255_t *a, | |||
| const p255_t *b | |||
| ); | |||
| void | |||
| p255_mulw ( | |||
| p255_t *__restrict__ out, | |||
| const p255_t *a, | |||
| uint64_t b | |||
| ); | |||
| void | |||
| p255_sqr ( | |||
| p255_t *__restrict__ out, | |||
| const p255_t *a | |||
| ); | |||
| void | |||
| p255_serialize ( | |||
| uint8_t serial[32], | |||
| const struct p255_t *x | |||
| ); | |||
| mask_t | |||
| p255_deserialize ( | |||
| p255_t *x, | |||
| const uint8_t serial[32] | |||
| ); | |||
| /* -------------- Inline functions begin here -------------- */ | |||
| void | |||
| p255_add_RAW ( | |||
| p255_t *out, | |||
| const p255_t *a, | |||
| const p255_t *b | |||
| ) { | |||
| unsigned int i; | |||
| for (i=0; i<5; i++) { | |||
| out->limb[i] = a->limb[i] + b->limb[i]; | |||
| } | |||
| p255_weak_reduce(out); | |||
| } | |||
| void | |||
| p255_sub_RAW ( | |||
| p255_t *out, | |||
| const p255_t *a, | |||
| const p255_t *b | |||
| ) { | |||
| unsigned int i; | |||
| uint64_t co1 = ((1ull<<51)-1)*2, co2 = co1-36; | |||
| for (i=0; i<5; i++) { | |||
| out->limb[i] = a->limb[i] - b->limb[i] + ((i==0) ? co2 : co1); | |||
| } | |||
| p255_weak_reduce(out); | |||
| } | |||
| void | |||
| p255_copy ( | |||
| p255_t *out, | |||
| const p255_t *a | |||
| ) { | |||
| memcpy(out,a,sizeof(*a)); | |||
| } | |||
| void | |||
| p255_bias ( | |||
| p255_t *a, | |||
| int amt | |||
| ) { | |||
| (void) a; | |||
| (void) amt; | |||
| } | |||
| void | |||
| p255_weak_reduce ( | |||
| p255_t *a | |||
| ) { | |||
| uint64_t mask = (1ull<<51) - 1; | |||
| uint64_t tmp = a->limb[5] >> 51; | |||
| int i; | |||
| for (i=7; i>0; i--) { | |||
| a->limb[i] = (a->limb[i] & mask) + (a->limb[i-1]>>51); | |||
| } | |||
| a->limb[0] = (a->limb[0] & mask) + tmp*19; | |||
| } | |||
| #ifdef __cplusplus | |||
| }; /* extern "C" */ | |||
| #endif | |||
| #endif /* __P255_H__ */ | |||
| @@ -0,0 +1,67 @@ | |||
| /** | |||
| * @cond internal | |||
| * @file f_arithmetic.c | |||
| * @copyright | |||
| * Copyright (c) 2014 Cryptography Research, Inc. \n | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| * @author Mike Hamburg | |||
| * @brief Field-specific arithmetic. | |||
| */ | |||
| #include "field.h" | |||
| extern field_a_t ONE; // TODO | |||
| static const field_a_t SQRT_MINUS_ONE = FIELD_LITERAL( // FIXME goes elsewhere? | |||
| 0x61b274a0ea0b0, | |||
| 0x0d5a5fc8f189d, | |||
| 0x7ef5e9cbd0c60, | |||
| 0x78595a6804c9e, | |||
| 0x2b8324804fc1d | |||
| ); | |||
| void | |||
| field_isr ( | |||
| field_a_t a, | |||
| const field_a_t x | |||
| ) { | |||
| field_a_t st[3], tmp1, tmp2; | |||
| const struct { unsigned char sh, idx } ops[] = { | |||
| {1,2},{1,2},{3,1},{6,0},{1,2},{12,1},{25,1},{25,1},{50,0},{125,0},{2,2},{1,2} | |||
| }; | |||
| field_cpy(st[0],x); | |||
| field_cpy(st[1],x); | |||
| field_cpy(st[2],x); | |||
| int i; | |||
| for (i=0; i<sizeof(ops)/sizeof(ops[0]); i++) { | |||
| field_sqrn(tmp1, st[1^i&1], ops[i].sh); | |||
| field_mul(tmp2, tmp1, st[ops[i].idx]); | |||
| field_cpy(st[i&1], tmp2); | |||
| } | |||
| mask_t m = field_eq(st[1], ONE); | |||
| cond_sel(tmp1,SQRT_MINUS_ONE,ONE,m); | |||
| field_mul(a,tmp1,st[0]); | |||
| }; | |||
| void | |||
| field_isr ( | |||
| field_a_t a, | |||
| const field_a_t x | |||
| ) { | |||
| field_a_t st[3], tmp1, tmp2; | |||
| const struct { unsigned char sh, idx } ops[] = { | |||
| {1,2},{1,2},{3,1},{6,0},{1,2},{12,1},{25,1},{25,1},{50,0},{125,0},{2,2},{1,2} | |||
| }; | |||
| field_cpy(st[0],x); | |||
| field_cpy(st[1],x); | |||
| field_cpy(st[2],x); | |||
| int i; | |||
| for (i=0; i<sizeof(ops)/sizeof(ops[0]); i++) { | |||
| field_sqrn(tmp1, st[1^i&1], ops[i].sh); | |||
| field_mul(tmp2, tmp1, st[ops[i].idx]); | |||
| field_cpy(st[i&1], tmp2); | |||
| } | |||
| mask_t m = field_eq(st[1], ONE); | |||
| } | |||
| @@ -0,0 +1,32 @@ | |||
| /** | |||
| * @file f_field.h | |||
| * @brief Field-specific code. | |||
| * @copyright | |||
| * Copyright (c) 2014 Cryptography Research, Inc. \n | |||
| * Released under the MIT License. See LICENSE.txt for license information. | |||
| * @author Mike Hamburg | |||
| */ | |||
| #ifndef __F_FIELD_H__ | |||
| #define __F_FIELD_H__ 1 | |||
| #include "constant_time.h" | |||
| #include <string.h> | |||
| #include "p25519.h" | |||
| #define FIELD_LIT_LIMB_BITS 51 | |||
| #define FIELD_BITS 255 | |||
| #define field_t p255_t | |||
| #define field_mul p255_mul | |||
| #define field_sqr p255_sqr | |||
| #define field_add_RAW p255_add_RAW | |||
| #define field_sub_RAW p255_sub_RAW | |||
| #define field_mulw p255_mulw | |||
| #define field_bias p255_bias | |||
| #define field_isr p255_isr | |||
| #define field_inverse p255_inverse | |||
| #define field_weak_reduce p255_weak_reduce | |||
| #define field_strong_reduce p255_strong_reduce | |||
| #define field_serialize p255_serialize | |||
| #define field_deserialize p255_deserialize | |||
| #endif /* __F_FIELD_H__ */ | |||
| @@ -21,9 +21,9 @@ | |||
| #include <algorithm> | |||
| using namespace decaf; | |||
| typedef Ed448::Scalar Scalar; | |||
| typedef Ed448::Point Point; | |||
| typedef Ed448::Precomputed Precomputed; | |||
| typedef Ed255::Scalar Scalar; | |||
| typedef Ed255::Point Point; | |||
| typedef Ed255::Precomputed Precomputed; | |||
| static __inline__ void __attribute__((unused)) ignore_result ( int result ) { (void)result; } | |||
| @@ -281,10 +281,10 @@ int main(int argc, char **argv) { | |||
| if (argc >= 2 && !strcmp(argv[1], "--micro")) | |||
| micro = true; | |||
| decaf_448_public_key_t p1,p2; | |||
| decaf_448_private_key_t s1,s2; | |||
| decaf_448_symmetric_key_t r1,r2; | |||
| decaf_448_signature_t sig1; | |||
| decaf_255_public_key_t p1,p2; | |||
| decaf_255_private_key_t s1,s2; | |||
| decaf_255_symmetric_key_t r1,r2; | |||
| decaf_255_signature_t sig1; | |||
| unsigned char ss[32]; | |||
| memset(r1,1,sizeof(r1)); | |||
| @@ -348,25 +348,25 @@ int main(int argc, char **argv) { | |||
| printf("\nMacro-benchmarks:\n"); | |||
| for (Benchmark b("Keygen"); b.iter(); ) { | |||
| decaf_448_derive_private_key(s1,r1); | |||
| decaf_255_derive_private_key(s1,r1); | |||
| } | |||
| decaf_448_private_to_public(p1,s1); | |||
| decaf_448_derive_private_key(s2,r2); | |||
| decaf_448_private_to_public(p2,s2); | |||
| decaf_255_private_to_public(p1,s1); | |||
| decaf_255_derive_private_key(s2,r2); | |||
| decaf_255_private_to_public(p2,s2); | |||
| for (Benchmark b("Shared secret"); b.iter(); ) { | |||
| decaf_bool_t ret = decaf_448_shared_secret(ss,sizeof(ss),s1,p2); | |||
| decaf_bool_t ret = decaf_255_shared_secret(ss,sizeof(ss),s1,p2); | |||
| ignore_result(ret); | |||
| assert(ret); | |||
| } | |||
| for (Benchmark b("Sign"); b.iter(); ) { | |||
| decaf_448_sign(sig1,s1,umessage,lmessage); | |||
| decaf_255_sign(sig1,s1,umessage,lmessage); | |||
| } | |||
| for (Benchmark b("Verify"); b.iter(); ) { | |||
| decaf_bool_t ret = decaf_448_verify(sig1,p1,umessage,lmessage); | |||
| decaf_bool_t ret = decaf_255_verify(sig1,p1,umessage,lmessage); | |||
| umessage[0]++; | |||
| umessage[1]^=umessage[0]; | |||
| ignore_result(ret); | |||
| @@ -127,7 +127,7 @@ static void test_arithmetic() { | |||
| for (int i=0; i<NTESTS*10 && test.passing_now; i++) { | |||
| /* TODO: pathological cases */ | |||
| size_t sob = DECAF_448_SCALAR_BYTES + 8 - (i%16); | |||
| size_t sob = DECAF_255_SCALAR_BYTES + 8 - (i%16); | |||
| Scalar x(rng.read(sob)); | |||
| Scalar y(rng.read(sob)); | |||
| Scalar z(rng.read(sob)); | |||
| @@ -244,31 +244,31 @@ static void test_decaf() { | |||
| Test test("Sample crypto"); | |||
| decaf::SpongeRng rng(decaf::Block("test_decaf")); | |||
| decaf_448_symmetric_key_t proto1,proto2; | |||
| decaf_448_private_key_t s1,s2; | |||
| decaf_448_public_key_t p1,p2; | |||
| decaf_448_signature_t sig; | |||
| decaf_255_symmetric_key_t proto1,proto2; | |||
| decaf_255_private_key_t s1,s2; | |||
| decaf_255_public_key_t p1,p2; | |||
| decaf_255_signature_t sig; | |||
| unsigned char shared1[1234],shared2[1234]; | |||
| const char *message = "Hello, world!"; | |||
| for (int i=0; i<NTESTS && test.passing_now; i++) { | |||
| rng.read(decaf::TmpBuffer(proto1,sizeof(proto1))); | |||
| rng.read(decaf::TmpBuffer(proto2,sizeof(proto2))); | |||
| decaf_448_derive_private_key(s1,proto1); | |||
| decaf_448_private_to_public(p1,s1); | |||
| decaf_448_derive_private_key(s2,proto2); | |||
| decaf_448_private_to_public(p2,s2); | |||
| if (!decaf_448_shared_secret (shared1,sizeof(shared1),s1,p2)) { | |||
| decaf_255_derive_private_key(s1,proto1); | |||
| decaf_255_private_to_public(p1,s1); | |||
| decaf_255_derive_private_key(s2,proto2); | |||
| decaf_255_private_to_public(p2,s2); | |||
| if (!decaf_255_shared_secret (shared1,sizeof(shared1),s1,p2)) { | |||
| test.fail(); printf("Fail ss12\n"); | |||
| } | |||
| if (!decaf_448_shared_secret (shared2,sizeof(shared2),s2,p1)) { | |||
| if (!decaf_255_shared_secret (shared2,sizeof(shared2),s2,p1)) { | |||
| test.fail(); printf("Fail ss21\n"); | |||
| } | |||
| if (memcmp(shared1,shared2,sizeof(shared1))) { | |||
| test.fail(); printf("Fail ss21 == ss12\n"); | |||
| } | |||
| decaf_448_sign (sig,s1,(const unsigned char *)message,strlen(message)); | |||
| if (!decaf_448_verify (sig,p1,(const unsigned char *)message,strlen(message))) { | |||
| decaf_255_sign (sig,s1,(const unsigned char *)message,strlen(message)); | |||
| if (!decaf_255_verify (sig,p1,(const unsigned char *)message,strlen(message))) { | |||
| test.fail(); printf("Fail sig ver\n"); | |||
| } | |||
| } | |||
| @@ -277,9 +277,9 @@ static void test_decaf() { | |||
| int main(int argc, char **argv) { | |||
| (void) argc; (void) argv; | |||
| Tests<decaf::Ed448>::test_arithmetic(); | |||
| Tests<decaf::Ed448>::test_elligator(); | |||
| Tests<decaf::Ed448>::test_ec(); | |||
| Tests<decaf::Ed255>::test_arithmetic(); | |||
| Tests<decaf::Ed255>::test_elligator(); | |||
| Tests<decaf::Ed255>::test_ec(); | |||
| test_decaf(); | |||
| if (passing) printf("Passed all tests.\n"); | |||