@@ -40,7 +40,7 @@ endif | |||||
WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \ | WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \ | ||||
-Wmissing-declarations -Wunused-function -Wno-overlength-strings $(EXWARN) | -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 | LANGFLAGS = -std=c99 -fno-strict-aliasing | ||||
LANGXXFLAGS = -fno-strict-aliasing | LANGXXFLAGS = -fno-strict-aliasing | ||||
GENFLAGS = -ffunction-sections -fdata-sections -fvisibility=hidden -fomit-frame-pointer -fPIC | GENFLAGS = -ffunction-sections -fdata-sections -fvisibility=hidden -fomit-frame-pointer -fPIC | ||||
@@ -79,10 +79,15 @@ SAGE ?= sage | |||||
SAGES= $(shell ls test/*.sage) | SAGES= $(shell ls test/*.sage) | ||||
BUILDPYS= $(SAGES:test/%.sage=$(BUILD_PY)/%.py) | 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)/% | .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") | HEADERSXX = $(HEADERS) $(shell find . -name "*.hxx") | ||||
# components needed by the lib | # components needed by the lib | ||||
@@ -123,6 +128,11 @@ $(BUILD_OBJ)/timestamp: | |||||
$(BUILD_OBJ)/%.o: $(BUILD_ASM)/%.s | $(BUILD_OBJ)/%.o: $(BUILD_ASM)/%.s | ||||
$(ASM) $(ASFLAGS) -c -o $@ $< | $(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 | # 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_field,p448,arch_x86_64)) | ||||
$(eval $(call define_curve,ed448goldilocks,p448)) | $(eval $(call define_curve,ed448goldilocks,p448)) | ||||
# The shakesum utility is in the public bin directory. | # The shakesum utility is in the public bin directory. | ||||
$(BUILD_BIN)/shakesum: $(BUILD_OBJ)/shakesum.o $(BUILD_OBJ)/shake.o $(BUILD_OBJ)/utils.o | $(BUILD_BIN)/shakesum: $(BUILD_OBJ)/shakesum.o $(BUILD_OBJ)/shake.o $(BUILD_OBJ)/utils.o | ||||
$(LD) $(LDFLAGS) -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__ */ |