@@ -40,7 +40,7 @@ endif | |||
WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \ | |||
-Wmissing-declarations -Wunused-function -Wno-overlength-strings $(EXWARN) | |||
INCFLAGS = -Isrc/include -Isrc/public_include | |||
INCFLAGS = -Isrc/include -Isrc/public_include -Ibuild/include | |||
LANGFLAGS = -std=c99 -fno-strict-aliasing | |||
LANGXXFLAGS = -fno-strict-aliasing | |||
GENFLAGS = -ffunction-sections -fdata-sections -fvisibility=hidden -fomit-frame-pointer -fPIC | |||
@@ -79,10 +79,15 @@ SAGE ?= sage | |||
SAGES= $(shell ls test/*.sage) | |||
BUILDPYS= $(SAGES:test/%.sage=$(BUILD_PY)/%.py) | |||
.PHONY: clean all test bench todo doc lib bat sage sagetest | |||
.PHONY: clean all test bench todo doc lib bat sage sagetest gen_headers | |||
.PRECIOUS: $(BUILD_ASM)/%.s $(BUILD_C)/%.c $(BUILD_IBIN)/% | |||
HEADERS= Makefile $(shell find src test -name "*.h") $(BUILD_OBJ)/timestamp | |||
GEN_HEADERS=\ | |||
$(BUILD_INC)/decaf/decaf_255.h \ | |||
$(BUILD_INC)/decaf/decaf_448.h \ | |||
$(BUILD_INC)/decaf/decaf_255.hxx \ | |||
$(BUILD_INC)/decaf/decaf_448.hxx | |||
HEADERS= Makefile $(shell find src test -name "*.h") $(BUILD_OBJ)/timestamp $(GEN_HEADERS) | |||
HEADERSXX = $(HEADERS) $(shell find . -name "*.hxx") | |||
# components needed by the lib | |||
@@ -123,6 +128,11 @@ $(BUILD_OBJ)/timestamp: | |||
$(BUILD_OBJ)/%.o: $(BUILD_ASM)/%.s | |||
$(ASM) $(ASFLAGS) -c -o $@ $< | |||
$(GEN_HEADERS): gen_headers | |||
gen_headers: src/gen_headers/*.py | |||
python -B src/gen_headers/main.py --hpre=$(BUILD_INC) --cpre=$(BUILD_C) | |||
################################################################ | |||
# Per-field code: call with field, arch | |||
################################################################ | |||
@@ -178,7 +188,6 @@ $(eval $(call define_curve,ed25519,p25519)) | |||
$(eval $(call define_field,p448,arch_x86_64)) | |||
$(eval $(call define_curve,ed448goldilocks,p448)) | |||
# The shakesum utility is in the public bin directory. | |||
$(BUILD_BIN)/shakesum: $(BUILD_OBJ)/shakesum.o $(BUILD_OBJ)/shake.o $(BUILD_OBJ)/utils.o | |||
$(LD) $(LDFLAGS) -o $@ $^ | |||
@@ -1,640 +0,0 @@ | |||
/** | |||
* @file decaf/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, based on Ed25519. | |||
*/ | |||
#ifndef __DECAF_255_H__ | |||
#define __DECAF_255_H__ 1 | |||
#include <decaf/common.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#define DECAF_255_LIMBS (320/DECAF_WORD_BITS) | |||
#define DECAF_255_SCALAR_BITS 253 | |||
#define DECAF_255_SCALAR_LIMBS (256/DECAF_WORD_BITS) | |||
/** Galois field element internal structure */ | |||
#ifndef __DECAF_255_GF_DEFINED__ | |||
#define __DECAF_255_GF_DEFINED__ 1 | |||
typedef struct gf_25519_s { | |||
/** @cond internal */ | |||
decaf_word_t limb[DECAF_255_LIMBS]; | |||
/** @endcond */ | |||
} __attribute__((aligned(32))) gf_25519_s, gf_25519_t[1]; | |||
#endif /* __DECAF_255_GF_DEFINED__ */ | |||
/** 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_25519_t 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]; | |||
/** 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. */ | |||
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; | |||
/** | |||
* @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_error_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_SUCCESS The input is nonzero. | |||
*/ | |||
decaf_error_t decaf_255_scalar_invert ( | |||
decaf_255_scalar_t out, | |||
const decaf_255_scalar_t a | |||
) API_VIS WARN_UNUSED 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 unsigned integer. | |||
* @param [in] a An integer. | |||
* @param [out] out Will become equal to a. | |||
*/ | |||
void decaf_255_scalar_set_unsigned ( | |||
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_error_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_error_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. | |||
*/ | |||
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 one base point by two scalars: | |||
* a1 = scalar1 * base | |||
* a2 = scalar2 * base | |||
* | |||
* Equivalent to two calls to decaf_255_point_scalarmul, but may be | |||
* faster. | |||
* | |||
* @param [out] a1 The first multiple | |||
* @param [out] a2 The second multiple | |||
* @param [in] base1 A point to be scaled. | |||
* @param [in] scalar1 A first scalar to multiply by. | |||
* @param [in] scalar2 A second scalar to multiply by. | |||
*/ | |||
void decaf_255_point_dual_scalarmul ( | |||
decaf_255_point_t a1, | |||
decaf_255_point_t a2, | |||
const decaf_255_point_t b, | |||
const decaf_255_scalar_t scalar1, | |||
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 Constant-time decision between two points. If pick_b | |||
* is zero, out = a; else out = b. | |||
* | |||
* @param [out] q The output. It may be the same as either input. | |||
* @param [in] a Any point. | |||
* @param [in] b Any point. | |||
* @param [in] pick_b If nonzero, choose point b. | |||
*/ | |||
void decaf_255_point_cond_sel ( | |||
decaf_255_point_t out, | |||
const decaf_255_point_t a, | |||
const decaf_255_point_t b, | |||
decaf_word_t pick_b | |||
) API_VIS NONNULL3 NOINLINE; | |||
/** | |||
* @brief Constant-time decision between two scalars. If pick_b | |||
* is zero, out = a; else out = b. | |||
* | |||
* @param [out] q The output. It may be the same as either input. | |||
* @param [in] a Any scalar. | |||
* @param [in] b Any scalar. | |||
* @param [in] pick_b If nonzero, choose scalar b. | |||
*/ | |||
void decaf_255_scalar_cond_sel ( | |||
decaf_255_scalar_t out, | |||
const decaf_255_scalar_t a, | |||
const decaf_255_scalar_t b, | |||
decaf_word_t pick_b | |||
) API_VIS NONNULL3 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 Torque a point, for debugging purposes. The output | |||
* will be equal to the input. | |||
* | |||
* @param [out] q The point to torque. | |||
* @param [in] p The point to torque. | |||
*/ | |||
void decaf_255_point_debugging_torque ( | |||
decaf_255_point_t q, | |||
const decaf_255_point_t p | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
* @brief Projectively scale a point, for debugging purposes. | |||
* The output will be equal to the input, and will be valid | |||
* even if the factor is zero. | |||
* | |||
* @param [out] q The point to scale. | |||
* @param [in] p The point to scale. | |||
* @param [in] factor Serialized GF factor to scale. | |||
*/ | |||
void decaf_255_point_debugging_pscale ( | |||
decaf_255_point_t q, | |||
const decaf_255_point_t p, | |||
const unsigned char factor[DECAF_255_SER_BYTES] | |||
) 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, or 16:1 overall on curves with cofactor 8. | |||
* | |||
* 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. | |||
*/ | |||
void | |||
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 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. | |||
*/ | |||
void 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 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 if | |||
* possible. Since there may be multiple preimages, the | |||
* "which" parameter chooses between them. To ensure uniform | |||
* inverse sampling, this function succeeds or fails | |||
* independently for different "which" values. | |||
* | |||
* @param [out] recovered_hash Encoded data. | |||
* @param [in] pt The point to encode. | |||
* @param [in] which A value determining which inverse point | |||
* to return. | |||
* | |||
* @retval DECAF_SUCCESS The inverse succeeded. | |||
* @retval DECAF_FAILURE The inverse failed. | |||
*/ | |||
decaf_error_t | |||
decaf_255_invert_elligator_nonuniform ( | |||
unsigned char recovered_hash[DECAF_255_SER_BYTES], | |||
const decaf_255_point_t pt, | |||
uint16_t which | |||
) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
/** | |||
* @brief Inverse of elligator-like hash to curve. | |||
* | |||
* This function writes to the buffer, to make it so that | |||
* decaf_255_point_from_hash_uniform(buffer) = pt if | |||
* possible. Since there may be multiple preimages, the | |||
* "which" parameter chooses between them. To ensure uniform | |||
* inverse sampling, this function succeeds or fails | |||
* independently for different "which" values. | |||
* | |||
* @param [out] recovered_hash Encoded data. | |||
* @param [in] pt The point to encode. | |||
* @param [in] which A value determining which inverse point | |||
* to return. | |||
* | |||
* @retval DECAF_SUCCESS The inverse succeeded. | |||
* @retval DECAF_FAILURE The inverse failed. | |||
*/ | |||
decaf_error_t | |||
decaf_255_invert_elligator_uniform ( | |||
unsigned char recovered_hash[2*DECAF_255_SER_BYTES], | |||
const decaf_255_point_t pt, | |||
uint16_t which | |||
) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
/** | |||
* @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 precomputed table with zeros. | |||
*/ | |||
void decaf_255_precomputed_destroy ( | |||
decaf_255_precomputed_s *pre | |||
) NONNULL1 API_VIS; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* __DECAF_255_H__ */ |
@@ -1,586 +0,0 @@ | |||
/** | |||
* @file decaf/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 Curve25519) 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. */ | |||
#ifndef _XOPEN_SOURCE | |||
#define _XOPEN_SOURCE 600 | |||
#endif | |||
#include <stdlib.h> | |||
#include <string.h> /* for memcpy */ | |||
#include <decaf.h> | |||
#include <decaf/secure_buffer.hxx> | |||
#include <string> | |||
#include <sys/types.h> | |||
#include <limits.h> | |||
/** @cond internal */ | |||
#if __cplusplus >= 201103L | |||
#define NOEXCEPT noexcept | |||
#else | |||
#define NOEXCEPT throw() | |||
#endif | |||
/** @endcond */ | |||
namespace decaf { | |||
/** | |||
* @brief Curve25519/Decaf instantiation of group. | |||
*/ | |||
struct IsoEd25519 { | |||
/** The name of the curve */ | |||
static inline const char *name() { return "IsoEd25519"; } | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int REMOVED_COFACTOR = 8; | |||
/** Residue class of field modulus: p == this mod 2*(this-1) */ | |||
static const int FIELD_MODULUS_TYPE = 5; | |||
/** @cond internal */ | |||
class Point; | |||
class Precomputed; | |||
/** @endcond */ | |||
/** | |||
* @brief A scalar modulo the curve order. | |||
* Supports the usual arithmetic operations, all in constant time. | |||
* FIXME: make it clearer which init-from-buffer operations reject scalars that are too big. | |||
*/ | |||
class Scalar : public Serializable<Scalar> { | |||
private: | |||
/** @brief wrapped C type */ | |||
typedef decaf_255_scalar_t Wrapped; | |||
public: | |||
/** @brief Size of a serialized element */ | |||
static const size_t SER_BYTES = DECAF_255_SCALAR_BYTES; | |||
/** @brief access to the underlying scalar object */ | |||
Wrapped 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(Rng &rng) NOEXCEPT { | |||
FixedArrayBuffer<SER_BYTES> sb(rng); | |||
*this = sb; | |||
} | |||
/** @brief Construct from decaf_scalar_t object. */ | |||
inline Scalar(const Wrapped &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 Serializable instance */ | |||
inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | |||
/** @brief Serializable instance */ | |||
inline void serializeInto(unsigned char *buffer) const NOEXCEPT { | |||
decaf_255_scalar_encode(buffer, s); | |||
} | |||
/** @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_unsigned(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_unsigned(s,(decaf_word_t)w - (decaf_word_t)INT_MIN); | |||
*this -= t; | |||
return *this; | |||
} | |||
/** Destructor securely zeorizes 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_error_t __attribute__((warn_unused_result)) decode ( | |||
Scalar &sc, const FixedBlock<SER_BYTES> buffer | |||
) NOEXCEPT { | |||
return decaf_255_scalar_decode(sc.s,buffer.data()); | |||
} | |||
/** 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 throw(CryptoException) { | |||
Scalar r; | |||
if (DECAF_SUCCESS != decaf_255_scalar_invert(r.s,s)) { | |||
throw CryptoException(); | |||
} | |||
return r; | |||
} | |||
/** @brief Divide by inverting q. If q == 0, return 0. */ | |||
inline Scalar operator/ (const Scalar &q) const throw(CryptoException) { return *this * q.inverse(); } | |||
/** @brief Divide by inverting q. If q == 0, return 0. */ | |||
inline Scalar &operator/=(const Scalar &q) throw(CryptoException) { 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); | |||
}; | |||
/** | |||
* @brief Element of prime-order group. | |||
*/ | |||
class Point : public Serializable<Point> { | |||
private: | |||
/** @brief wrapped C type */ | |||
typedef decaf_255_point_t Wrapped; | |||
public: | |||
/** @brief Size of a serialized element */ | |||
static const size_t SER_BYTES = DECAF_255_SER_BYTES; | |||
/** @brief Bytes required for hash */ | |||
static const size_t HASH_BYTES = SER_BYTES; | |||
/** @brief Size of a stegged element */ | |||
static const size_t STEG_BYTES = HASH_BYTES * 2; | |||
/** The c-level object. */ | |||
Wrapped p; | |||
/** @brief Don't initialize. */ | |||
inline Point(const NOINIT &) NOEXCEPT {} | |||
/** @brief Constructor sets to identity by default. */ | |||
inline Point(const Wrapped &q = decaf_255_point_identity) NOEXCEPT { decaf_255_point_copy(p,q); } | |||
/** @brief Copy constructor. */ | |||
inline Point(const Point &q) NOEXCEPT { *this = q; } | |||
/** @brief Assignment. */ | |||
inline Point& operator=(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); return *this; } | |||
/** @brief Destructor securely zeorizes the point. */ | |||
inline ~Point() NOEXCEPT { decaf_255_point_destroy(p); } | |||
/** @brief Construct from RNG */ | |||
inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT { | |||
if (uniform) { | |||
FixedArrayBuffer<2*HASH_BYTES> b(rng); | |||
set_to_hash(b); | |||
} else { | |||
FixedArrayBuffer<HASH_BYTES> b(rng); | |||
set_to_hash(b); | |||
} | |||
} | |||
/** | |||
* @brief Initialize from a 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 FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE) | |||
throw(CryptoException) { | |||
if (DECAF_SUCCESS != 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 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_error_t __attribute__((warn_unused_result)) decode ( | |||
Point &p, const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
) NOEXCEPT { | |||
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 void set_to_hash( const Block &s ) NOEXCEPT { | |||
if (s.size() < HASH_BYTES) { | |||
SecureBuffer b(HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
decaf_255_point_from_hash_nonuniform(p,b.data()); | |||
} else if (s.size() == HASH_BYTES) { | |||
decaf_255_point_from_hash_nonuniform(p,s.data()); | |||
} else if (s.size() < 2*HASH_BYTES) { | |||
SecureBuffer b(2*HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
decaf_255_point_from_hash_uniform(p,b.data()); | |||
} else { | |||
decaf_255_point_from_hash_uniform(p,s.data()); | |||
} | |||
} | |||
/** | |||
* @brief Encode to string. The identity encodes to the all-zero string. | |||
*/ | |||
inline operator SecureBuffer() const { | |||
SecureBuffer buffer(SER_BYTES); | |||
decaf_255_point_encode(buffer.data(), p); | |||
return buffer; | |||
} | |||
/** @brief Serializable instance */ | |||
inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | |||
/** @brief Serializable instance */ | |||
inline void serializeInto(unsigned char *buffer) 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 throw(CryptoException) { return (*this) * s.inverse(); } | |||
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
inline Point &operator/=(const Scalar &s) throw(CryptoException) { 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 Dual-scalar multiply, equivalent to this*r1, this*r2 but faster. */ | |||
inline void dual_scalarmul ( | |||
Point &q1, Point &q2, const Scalar &r1, const Scalar &r2 | |||
) const NOEXCEPT { | |||
decaf_255_point_dual_scalarmul(q1.p,q2.p,p,r1.s,r2.s); | |||
} | |||
/** | |||
* @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 { | |||
return double_scalarmul(q,qs,r,rs); | |||
} | |||
/** | |||
* @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; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */ | |||
inline Point debugging_torque() const NOEXCEPT { | |||
Point q; | |||
decaf_255_point_debugging_torque(q.p,p); | |||
return q; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data has a modified representation. */ | |||
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { | |||
Point q; | |||
decaf_255_point_debugging_pscale(q.p,p,factor.data()); | |||
return q; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data has a randomized representation. */ | |||
inline Point debugging_pscale(Rng &r) const NOEXCEPT { | |||
FixedArrayBuffer<SER_BYTES> sb(r); | |||
return debugging_pscale(sb); | |||
} | |||
/** | |||
* Modify buffer so that Point::from_hash(Buffer) == *this, and return DECAF_SUCCESS; | |||
* or leave buf unmodified and return DECAF_FAILURE. | |||
*/ | |||
inline decaf_error_t invert_elligator ( | |||
Buffer buf, uint16_t hint | |||
) const NOEXCEPT { | |||
unsigned char buf2[2*HASH_BYTES]; | |||
memset(buf2,0,sizeof(buf2)); | |||
memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
decaf_bool_t ret; | |||
if (buf.size() > HASH_BYTES) { | |||
ret = decaf_successful(decaf_255_invert_elligator_uniform(buf2, p, hint)); | |||
} else { | |||
ret = decaf_successful(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()); | |||
} | |||
if (ret) { | |||
/* TODO: make this constant time?? */ | |||
memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
} | |||
decaf_bzero(buf2,sizeof(buf2)); | |||
return decaf_succeed_if(ret); | |||
} | |||
/** @brief Steganographically encode this */ | |||
inline SecureBuffer steg_encode(Rng &rng, size_t size=STEG_BYTES) const throw(std::bad_alloc, LengthException) { | |||
if (size <= HASH_BYTES + 4 || size > 2*HASH_BYTES) throw LengthException(); | |||
SecureBuffer out(STEG_BYTES); | |||
decaf_error_t done; | |||
do { | |||
rng.read(Buffer(out).slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1)); | |||
done = invert_elligator(out, out[HASH_BYTES-1]); | |||
} while (!decaf_successful(done)); | |||
return out; | |||
} | |||
/** @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. | |||
*/ | |||
/** @cond internal */ | |||
typedef decaf_255_precomputed_s Precomputed_U; | |||
/** @endcond */ | |||
class Precomputed | |||
/** @cond internal */ | |||
: protected OwnedOrUnowned<Precomputed,Precomputed_U> | |||
/** @endcond */ | |||
{ | |||
public: | |||
/** Destructor securely zeorizes 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 Precomputed_U &yours = *defaultValue() | |||
) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>(yours) {} | |||
#if __cplusplus >= 201103L | |||
/** @brief Move-assign operator */ | |||
inline Precomputed &operator=(Precomputed &&it) NOEXCEPT { | |||
OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | |||
return *this; | |||
} | |||
/** @brief Move constructor */ | |||
inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>() { | |||
*this = it; | |||
} | |||
/** @brief Undelete copy operator */ | |||
inline Precomputed &operator=(const Precomputed &it) NOEXCEPT { | |||
OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | |||
return *this; | |||
} | |||
#endif | |||
/** | |||
* @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) | |||
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | |||
/** | |||
* @brief Constructor which initializes from point. | |||
*/ | |||
inline explicit Precomputed(const Point &it) throw(std::bad_alloc) | |||
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | |||
/** @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 throw(CryptoException) { return (*this) * s.inverse(); } | |||
/** @brief Return the table for the base point. */ | |||
static inline const Precomputed base() NOEXCEPT { return Precomputed(); } | |||
public: | |||
/** @cond internal */ | |||
friend class OwnedOrUnowned<Precomputed,Precomputed_U>; | |||
static inline size_t size() NOEXCEPT { return sizeof_decaf_255_precomputed_s; } | |||
static inline size_t alignment() NOEXCEPT { return alignof_decaf_255_precomputed_s; } | |||
static inline const Precomputed_U * defaultValue() NOEXCEPT { return decaf_255_precomputed_base; } | |||
/** @endcond */ | |||
}; | |||
}; /* struct IsoEd25519 */ | |||
/** @cond internal */ | |||
inline SecureBuffer IsoEd25519::Scalar::direct_scalarmul ( | |||
const Block &in, | |||
decaf_bool_t allow_identity, | |||
decaf_bool_t short_circuit | |||
) const throw(CryptoException) { | |||
SecureBuffer out(IsoEd25519::Point::SER_BYTES); | |||
if (DECAF_SUCCESS != | |||
decaf_255_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit) | |||
) { | |||
throw CryptoException(); | |||
} | |||
return out; | |||
} | |||
/** endcond */ | |||
#undef NOEXCEPT | |||
} /* namespace decaf */ | |||
#endif /* __DECAF_255_HXX__ */ |
@@ -1,641 +0,0 @@ | |||
/** | |||
* @file decaf/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, based on Ed448. | |||
*/ | |||
#ifndef __DECAF_448_H__ | |||
#define __DECAF_448_H__ 1 | |||
#include <decaf/common.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#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 */ | |||
#ifndef __DECAF_448_GF_DEFINED__ | |||
#define __DECAF_448_GF_DEFINED__ 1 | |||
typedef struct gf_448_s { | |||
/** @cond internal */ | |||
decaf_word_t limb[DECAF_448_LIMBS]; | |||
/** @endcond */ | |||
} __attribute__((aligned(32))) gf_448_s, gf_448_t[1]; | |||
#endif /* __DECAF_448_GF_DEFINED__ */ | |||
/** 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_448_t 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]; | |||
/** 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. */ | |||
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; | |||
/** | |||
* @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_error_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_SUCCESS The input is nonzero. | |||
*/ | |||
decaf_error_t decaf_448_scalar_invert ( | |||
decaf_448_scalar_t out, | |||
const decaf_448_scalar_t a | |||
) API_VIS WARN_UNUSED 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 unsigned integer. | |||
* @param [in] a An integer. | |||
* @param [out] out Will become equal to a. | |||
*/ | |||
void decaf_448_scalar_set_unsigned ( | |||
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_error_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_error_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. | |||
*/ | |||
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 one base point by two scalars: | |||
* a1 = scalar1 * base | |||
* a2 = scalar2 * base | |||
* | |||
* Equivalent to two calls to decaf_448_point_scalarmul, but may be | |||
* faster. | |||
* | |||
* @param [out] a1 The first multiple | |||
* @param [out] a2 The second multiple | |||
* @param [in] base1 A point to be scaled. | |||
* @param [in] scalar1 A first scalar to multiply by. | |||
* @param [in] scalar2 A second scalar to multiply by. | |||
*/ | |||
void decaf_448_point_dual_scalarmul ( | |||
decaf_448_point_t a1, | |||
decaf_448_point_t a2, | |||
const decaf_448_point_t b, | |||
const decaf_448_scalar_t scalar1, | |||
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 Constant-time decision between two points. If pick_b | |||
* is zero, out = a; else out = b. | |||
* | |||
* @param [out] q The output. It may be the same as either input. | |||
* @param [in] a Any point. | |||
* @param [in] b Any point. | |||
* @param [in] pick_b If nonzero, choose point b. | |||
*/ | |||
void decaf_448_point_cond_sel ( | |||
decaf_448_point_t out, | |||
const decaf_448_point_t a, | |||
const decaf_448_point_t b, | |||
decaf_word_t pick_b | |||
) API_VIS NONNULL3 NOINLINE; | |||
/** | |||
* @brief Constant-time decision between two scalars. If pick_b | |||
* is zero, out = a; else out = b. | |||
* | |||
* @param [out] q The output. It may be the same as either input. | |||
* @param [in] a Any scalar. | |||
* @param [in] b Any scalar. | |||
* @param [in] pick_b If nonzero, choose scalar b. | |||
*/ | |||
void decaf_448_scalar_cond_sel ( | |||
decaf_448_scalar_t out, | |||
const decaf_448_scalar_t a, | |||
const decaf_448_scalar_t b, | |||
decaf_word_t pick_b | |||
) API_VIS NONNULL3 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 Torque a point, for debugging purposes. The output | |||
* will be equal to the input. | |||
* | |||
* @param [out] q The point to torque. | |||
* @param [in] p The point to torque. | |||
*/ | |||
void decaf_448_point_debugging_torque ( | |||
decaf_448_point_t q, | |||
const decaf_448_point_t p | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
* @brief Projectively scale a point, for debugging purposes. | |||
* The output will be equal to the input, and will be valid | |||
* even if the factor is zero. | |||
* | |||
* @param [out] q The point to scale. | |||
* @param [in] p The point to scale. | |||
* @param [in] factor Serialized GF factor to scale. | |||
*/ | |||
void decaf_448_point_debugging_pscale ( | |||
decaf_448_point_t q, | |||
const decaf_448_point_t p, | |||
const unsigned char factor[DECAF_448_SER_BYTES] | |||
) 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, or 16:1 overall on curves with cofactor 8. | |||
* | |||
* 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. | |||
*/ | |||
void | |||
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 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. | |||
*/ | |||
void 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 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 if | |||
* possible. Since there may be multiple preimages, the | |||
* "which" parameter chooses between them. To ensure uniform | |||
* inverse sampling, this function succeeds or fails | |||
* independently for different "which" values. | |||
* | |||
* @param [out] recovered_hash Encoded data. | |||
* @param [in] pt The point to encode. | |||
* @param [in] which A value determining which inverse point | |||
* to return. | |||
* | |||
* @retval DECAF_SUCCESS The inverse succeeded. | |||
* @retval DECAF_FAILURE The inverse failed. | |||
*/ | |||
decaf_error_t | |||
decaf_448_invert_elligator_nonuniform ( | |||
unsigned char recovered_hash[DECAF_448_SER_BYTES], | |||
const decaf_448_point_t pt, | |||
uint16_t which | |||
) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
/** | |||
* @brief Inverse of elligator-like hash to curve. | |||
* | |||
* This function writes to the buffer, to make it so that | |||
* decaf_448_point_from_hash_uniform(buffer) = pt if | |||
* possible. Since there may be multiple preimages, the | |||
* "which" parameter chooses between them. To ensure uniform | |||
* inverse sampling, this function succeeds or fails | |||
* independently for different "which" values. | |||
* | |||
* @param [out] recovered_hash Encoded data. | |||
* @param [in] pt The point to encode. | |||
* @param [in] which A value determining which inverse point | |||
* to return. | |||
* | |||
* @retval DECAF_SUCCESS The inverse succeeded. | |||
* @retval DECAF_FAILURE The inverse failed. | |||
*/ | |||
decaf_error_t | |||
decaf_448_invert_elligator_uniform ( | |||
unsigned char recovered_hash[2*DECAF_448_SER_BYTES], | |||
const decaf_448_point_t pt, | |||
uint16_t which | |||
) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
/** | |||
* @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 precomputed table with zeros. | |||
*/ | |||
void decaf_448_precomputed_destroy ( | |||
decaf_448_precomputed_s *pre | |||
) NONNULL1 API_VIS; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* __DECAF_448_H__ */ |
@@ -1,584 +0,0 @@ | |||
/** | |||
* @file decaf/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. */ | |||
#ifndef _XOPEN_SOURCE | |||
#define _XOPEN_SOURCE 600 | |||
#endif | |||
#include <stdlib.h> | |||
#include <string.h> /* for memcpy */ | |||
#include <decaf.h> | |||
#include <decaf/secure_buffer.hxx> | |||
#include <string> | |||
#include <sys/types.h> | |||
#include <limits.h> | |||
/** @cond internal */ | |||
#if __cplusplus >= 201103L | |||
#define NOEXCEPT noexcept | |||
#else | |||
#define NOEXCEPT throw() | |||
#endif | |||
/** @endcond */ | |||
namespace decaf { | |||
/** | |||
* @brief Ed448-Goldilocks/Decaf instantiation of group. | |||
*/ | |||
struct Ed448Goldilocks { | |||
/** The name of the curve */ | |||
static inline const char *name() { return "Ed448-Goldilocks"; } | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int REMOVED_COFACTOR = 4; | |||
/** Residue class of field modulus: p == this mod 2*(this-1) */ | |||
static const int FIELD_MODULUS_TYPE = 3; | |||
/** @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 Serializable<Scalar> { | |||
private: | |||
/** @brief wrapped C type */ | |||
typedef decaf_448_scalar_t Wrapped; | |||
public: | |||
/** @brief Size of a serialized element */ | |||
static const size_t SER_BYTES = DECAF_448_SCALAR_BYTES; | |||
/** @brief access to the underlying scalar object */ | |||
Wrapped 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(Rng &rng) NOEXCEPT { | |||
FixedArrayBuffer<SER_BYTES> sb(rng); | |||
*this = sb; | |||
} | |||
/** @brief Construct from decaf_scalar_t object. */ | |||
inline Scalar(const Wrapped &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 Serializable instance */ | |||
inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | |||
/** @brief Serializable instance */ | |||
inline void serializeInto(unsigned char *buffer) const NOEXCEPT { | |||
decaf_448_scalar_encode(buffer, s); | |||
} | |||
/** @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_unsigned(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_unsigned(s,(decaf_word_t)w - (decaf_word_t)INT_MIN); | |||
*this -= t; | |||
return *this; | |||
} | |||
/** Destructor securely zeorizes 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_error_t __attribute__((warn_unused_result)) decode ( | |||
Scalar &sc, const FixedBlock<SER_BYTES> buffer | |||
) NOEXCEPT { | |||
return decaf_448_scalar_decode(sc.s,buffer.data()); | |||
} | |||
/** 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 throw(CryptoException) { | |||
Scalar r; | |||
if (DECAF_SUCCESS != decaf_448_scalar_invert(r.s,s)) { | |||
throw CryptoException(); | |||
} | |||
return r; | |||
} | |||
/** @brief Divide by inverting q. If q == 0, return 0. */ | |||
inline Scalar operator/ (const Scalar &q) const throw(CryptoException) { return *this * q.inverse(); } | |||
/** @brief Divide by inverting q. If q == 0, return 0. */ | |||
inline Scalar &operator/=(const Scalar &q) throw(CryptoException) { 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); | |||
}; | |||
/** | |||
* @brief Element of prime-order group. | |||
*/ | |||
class Point : public Serializable<Point> { | |||
private: | |||
/** @brief wrapped C type */ | |||
typedef decaf_448_point_t Wrapped; | |||
public: | |||
/** @brief Size of a serialized element */ | |||
static const size_t SER_BYTES = DECAF_448_SER_BYTES; | |||
/** @brief Bytes required for hash */ | |||
static const size_t HASH_BYTES = SER_BYTES; | |||
/** @brief Size of a stegged element */ | |||
static const size_t STEG_BYTES = HASH_BYTES * 2; | |||
/** The c-level object. */ | |||
Wrapped p; | |||
/** @brief Don't initialize. */ | |||
inline Point(const NOINIT &) NOEXCEPT {} | |||
/** @brief Constructor sets to identity by default. */ | |||
inline Point(const Wrapped &q = decaf_448_point_identity) NOEXCEPT { decaf_448_point_copy(p,q); } | |||
/** @brief Copy constructor. */ | |||
inline Point(const Point &q) NOEXCEPT { *this = q; } | |||
/** @brief Assignment. */ | |||
inline Point& operator=(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); return *this; } | |||
/** @brief Destructor securely zeorizes the point. */ | |||
inline ~Point() NOEXCEPT { decaf_448_point_destroy(p); } | |||
/** @brief Construct from RNG */ | |||
inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT { | |||
if (uniform) { | |||
FixedArrayBuffer<2*HASH_BYTES> b(rng); | |||
set_to_hash(b); | |||
} else { | |||
FixedArrayBuffer<HASH_BYTES> b(rng); | |||
set_to_hash(b); | |||
} | |||
} | |||
/** | |||
* @brief Initialize from a 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 FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE) | |||
throw(CryptoException) { | |||
if (DECAF_SUCCESS != 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 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_error_t __attribute__((warn_unused_result)) decode ( | |||
Point &p, const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
) NOEXCEPT { | |||
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 void set_to_hash( const Block &s ) NOEXCEPT { | |||
if (s.size() < HASH_BYTES) { | |||
SecureBuffer b(HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
decaf_448_point_from_hash_nonuniform(p,b.data()); | |||
} else if (s.size() == HASH_BYTES) { | |||
decaf_448_point_from_hash_nonuniform(p,s.data()); | |||
} else if (s.size() < 2*HASH_BYTES) { | |||
SecureBuffer b(2*HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
decaf_448_point_from_hash_uniform(p,b.data()); | |||
} else { | |||
decaf_448_point_from_hash_uniform(p,s.data()); | |||
} | |||
} | |||
/** | |||
* @brief Encode to string. The identity encodes to the all-zero string. | |||
*/ | |||
inline operator SecureBuffer() const { | |||
SecureBuffer buffer(SER_BYTES); | |||
decaf_448_point_encode(buffer.data(), p); | |||
return buffer; | |||
} | |||
/** @brief Serializable instance */ | |||
inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | |||
/** @brief Serializable instance */ | |||
inline void serializeInto(unsigned char *buffer) 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 throw(CryptoException) { return (*this) * s.inverse(); } | |||
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
inline Point &operator/=(const Scalar &s) throw(CryptoException) { 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 Dual-scalar multiply, equivalent to this*r1, this*r2 but faster. */ | |||
inline void dual_scalarmul ( | |||
Point &q1, Point &q2, const Scalar &r1, const Scalar &r2 | |||
) const NOEXCEPT { | |||
decaf_448_point_dual_scalarmul(q1.p,q2.p,p,r1.s,r2.s); | |||
} | |||
/** | |||
* @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 { | |||
return double_scalarmul(q,qs,r,rs); | |||
} | |||
/** | |||
* @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; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */ | |||
inline Point debugging_torque() const NOEXCEPT { | |||
Point q; | |||
decaf_448_point_debugging_torque(q.p,p); | |||
return q; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data has a modified representation. */ | |||
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { | |||
Point q; | |||
decaf_448_point_debugging_pscale(q.p,p,factor.data()); | |||
return q; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data has a randomized representation. */ | |||
inline Point debugging_pscale(Rng &r) const NOEXCEPT { | |||
FixedArrayBuffer<SER_BYTES> sb(r); | |||
return debugging_pscale(sb); | |||
} | |||
/** | |||
* Modify buffer so that Point::from_hash(Buffer) == *this, and return DECAF_SUCCESS; | |||
* or leave buf unmodified and return DECAF_FAILURE. | |||
*/ | |||
inline decaf_error_t invert_elligator ( | |||
Buffer buf, uint16_t hint | |||
) const NOEXCEPT { | |||
unsigned char buf2[2*HASH_BYTES]; | |||
memset(buf2,0,sizeof(buf2)); | |||
memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
decaf_bool_t ret; | |||
if (buf.size() > HASH_BYTES) { | |||
ret = decaf_successful(decaf_448_invert_elligator_uniform(buf2, p, hint)); | |||
} else { | |||
ret = decaf_successful(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()); | |||
} | |||
if (ret) { | |||
/* TODO: make this constant time?? */ | |||
memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
} | |||
decaf_bzero(buf2,sizeof(buf2)); | |||
return decaf_succeed_if(ret); | |||
} | |||
/** @brief Steganographically encode this */ | |||
inline SecureBuffer steg_encode(Rng &rng, size_t size=STEG_BYTES) const throw(std::bad_alloc, LengthException) { | |||
if (size <= HASH_BYTES + 4 || size > 2*HASH_BYTES) throw LengthException(); | |||
SecureBuffer out(STEG_BYTES); | |||
decaf_error_t done; | |||
do { | |||
rng.read(Buffer(out).slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1)); | |||
done = invert_elligator(out, out[HASH_BYTES-1]); | |||
} while (!decaf_successful(done)); | |||
return out; | |||
} | |||
/** @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. | |||
*/ | |||
/** @cond internal */ | |||
typedef decaf_448_precomputed_s Precomputed_U; | |||
/** @endcond */ | |||
class Precomputed | |||
/** @cond internal */ | |||
: protected OwnedOrUnowned<Precomputed,Precomputed_U> | |||
/** @endcond */ | |||
{ | |||
public: | |||
/** Destructor securely zeorizes 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 Precomputed_U &yours = *defaultValue() | |||
) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>(yours) {} | |||
#if __cplusplus >= 201103L | |||
/** @brief Move-assign operator */ | |||
inline Precomputed &operator=(Precomputed &&it) NOEXCEPT { | |||
OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | |||
return *this; | |||
} | |||
/** @brief Move constructor */ | |||
inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>() { | |||
*this = it; | |||
} | |||
/** @brief Undelete copy operator */ | |||
inline Precomputed &operator=(const Precomputed &it) NOEXCEPT { | |||
OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | |||
return *this; | |||
} | |||
#endif | |||
/** | |||
* @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) | |||
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | |||
/** | |||
* @brief Constructor which initializes from point. | |||
*/ | |||
inline explicit Precomputed(const Point &it) throw(std::bad_alloc) | |||
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | |||
/** @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 throw(CryptoException) { return (*this) * s.inverse(); } | |||
/** @brief Return the table for the base point. */ | |||
static inline const Precomputed base() NOEXCEPT { return Precomputed(); } | |||
public: | |||
/** @cond internal */ | |||
friend class OwnedOrUnowned<Precomputed,Precomputed_U>; | |||
static inline size_t size() NOEXCEPT { return sizeof_decaf_448_precomputed_s; } | |||
static inline size_t alignment() NOEXCEPT { return alignof_decaf_448_precomputed_s; } | |||
static inline const Precomputed_U * defaultValue() NOEXCEPT { return decaf_448_precomputed_base; } | |||
/** @endcond */ | |||
}; | |||
}; /* struct Ed448Goldilocks */ | |||
/** @cond internal */ | |||
inline SecureBuffer Ed448Goldilocks::Scalar::direct_scalarmul ( | |||
const Block &in, | |||
decaf_bool_t allow_identity, | |||
decaf_bool_t short_circuit | |||
) const throw(CryptoException) { | |||
SecureBuffer out(Ed448Goldilocks::Point::SER_BYTES); | |||
if (DECAF_SUCCESS != | |||
decaf_448_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit) | |||
) { | |||
throw CryptoException(); | |||
} | |||
return out; | |||
} | |||
/** endcond */ | |||
#undef NOEXCEPT | |||
} /* namespace decaf */ | |||
#endif /* __DECAF_448_HXX__ */ |