@@ -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"); | |||