Browse Source

initial replace 448->255; doesnt compile yet

master
Mike Hamburg 9 years ago
parent
commit
40b1f8b85e
17 changed files with 3488 additions and 1506 deletions
  1. +1
    -1
      Makefile
  2. +4
    -647
      include/decaf.h
  3. +4
    -734
      include/decaf.hxx
  4. +651
    -0
      include/decaf_255.h
  5. +738
    -0
      include/decaf_255.hxx
  6. +651
    -0
      include/decaf_448.h
  7. +738
    -0
      include/decaf_448.hxx
  8. +64
    -64
      src/decaf_crypto.c
  9. +26
    -22
      src/decaf_fast.c
  10. +8
    -8
      src/decaf_gen_tables.c
  11. +1
    -0
      src/p25519/arch_ref64/arch_config.h
  12. +318
    -0
      src/p25519/arch_ref64/p25519.c
  13. +155
    -0
      src/p25519/arch_ref64/p25519.h
  14. +67
    -0
      src/p25519/f_arithmetic.c
  15. +32
    -0
      src/p25519/f_field.h
  16. +14
    -14
      test/bench_decaf.cxx
  17. +16
    -16
      test/test_decaf.cxx

+ 1
- 1
Makefile View File

@@ -25,7 +25,7 @@ else
ARCH ?= arch_arm_32
endif

FIELD ?= p448
FIELD ?= p255

WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \
-Wmissing-declarations -Wunused-function -Wno-overlength-strings $(EXWARN)


+ 4
- 647
include/decaf.h View File

@@ -1,651 +1,8 @@
/**
* @file decaf.h
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief A group of prime order p.
*
* The Decaf library implements cryptographic operations on a an elliptic curve
* group of prime order p. It accomplishes this by using a twisted Edwards
* curve (isogenous to Ed448-Goldilocks) and wiping out the cofactor.
*
* The formulas are all complete and have no special cases, except that
* decaf_448_decode can fail because not every sequence of bytes is a valid group
* element.
*
* The formulas contain no data-dependent branches, timing or memory accesses,
* except for decaf_448_base_double_scalarmul_non_secret.
*
* This library may support multiple curves eventually. The Ed448-Goldilocks
* specific identifiers are prefixed with DECAF_448 or decaf_448.
*/
#ifndef __DECAF_448_H__
#define __DECAF_448_H__ 1

#include <stdint.h>
#include <sys/types.h>
#ifndef __DECAF_H__
#define __DECAF_H__ 1

/* Goldilocks' build flags default to hidden and stripping executables. */
/** @cond internal */
#if defined(DOXYGEN) && !defined(__attribute__)
#define __attribute__((x))
#endif
#define API_VIS __attribute__((visibility("default")))
#define NOINLINE __attribute__((noinline))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
#define NONNULL4 __attribute__((nonnull(1,2,3,4)))
#define NONNULL5 __attribute__((nonnull(1,2,3,4,5)))
#include "decaf_255.h" // MAGIC

/* Internal word types */
#if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \
&& !defined(DECAF_FORCE_32_BIT)
#define DECAF_WORD_BITS 64
typedef uint64_t decaf_word_t, decaf_bool_t;
typedef __uint128_t decaf_dword_t;
#else
#define DECAF_WORD_BITS 32
typedef uint32_t decaf_word_t, decaf_bool_t;
typedef uint64_t decaf_dword_t;
#endif
#endif /* __DECAF_H__ */

#define DECAF_448_LIMBS (512/DECAF_WORD_BITS)
#define DECAF_448_SCALAR_BITS 446
#define DECAF_448_SCALAR_LIMBS (448/DECAF_WORD_BITS)

/** Galois field element internal structure */
typedef struct gf_s {
decaf_word_t limb[DECAF_448_LIMBS];
} __attribute__((aligned(32))) gf_s, gf[1];
/** @endcond */

/** Number of bytes in a serialized point. */
#define DECAF_448_SER_BYTES 56

/** Number of bytes in a serialized scalar. */
#define DECAF_448_SCALAR_BYTES 56

/** Twisted Edwards (-1,d-1) extended homogeneous coordinates */
typedef struct decaf_448_point_s { /**@cond internal*/gf x,y,z,t;/**@endcond*/ } decaf_448_point_t[1];

/** Precomputed table based on a point. Can be trivial implementation. */
struct decaf_448_precomputed_s;

/** Precomputed table based on a point. Can be trivial implementation. */
typedef struct decaf_448_precomputed_s decaf_448_precomputed_s;

/** Size and alignment of precomputed point tables. */
extern const size_t sizeof_decaf_448_precomputed_s API_VIS, alignof_decaf_448_precomputed_s API_VIS;

/** Scalar is stored packed, because we don't need the speed. */
typedef struct decaf_448_scalar_s {
/** @cond internal */
decaf_word_t limb[DECAF_448_SCALAR_LIMBS];
/** @endcond */
} decaf_448_scalar_t[1];

/** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0;

/** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */
static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/,
DECAF_FAILURE = 0 /*DECAF_FALSE*/;

/** A scalar equal to 1. */
extern const decaf_448_scalar_t decaf_448_scalar_one API_VIS;

/** A scalar equal to 0. */
extern const decaf_448_scalar_t decaf_448_scalar_zero API_VIS;

/** The identity point on the curve. */
extern const decaf_448_point_t decaf_448_point_identity API_VIS;

/**
* An arbitrarily chosen base point on the curve.
* Equal to Ed448-Goldilocks base point defined by DJB, except of course that
* it's on the twist in this case. TODO: choose a base point with nice encoding?
*/
extern const decaf_448_point_t decaf_448_point_base API_VIS;

/** Precomputed table for the base point on the curve. */
extern const struct decaf_448_precomputed_s *decaf_448_precomputed_base API_VIS;

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Read a scalar from wire format or from bytes.
*
* @param [in] ser Serialized form of a scalar.
* @param [out] out Deserialized form.
*
* @retval DECAF_SUCCESS The scalar was correctly encoded.
* @retval DECAF_FAILURE The scalar was greater than the modulus,
* and has been reduced modulo that modulus.
*/
decaf_bool_t decaf_448_scalar_decode (
decaf_448_scalar_t out,
const unsigned char ser[DECAF_448_SCALAR_BYTES]
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Read a scalar from wire format or from bytes. Reduces mod
* scalar prime.
*
* @param [in] ser Serialized form of a scalar.
* @param [in] ser_len Length of serialized form.
* @param [out] out Deserialized form.
*/
void decaf_448_scalar_decode_long (
decaf_448_scalar_t out,
const unsigned char *ser,
size_t ser_len
) API_VIS NONNULL2 NOINLINE;
/**
* @brief Serialize a scalar to wire format.
*
* @param [out] ser Serialized form of a scalar.
* @param [in] s Deserialized scalar.
*/
void decaf_448_scalar_encode (
unsigned char ser[DECAF_448_SCALAR_BYTES],
const decaf_448_scalar_t s
) API_VIS NONNULL2 NOINLINE NOINLINE;
/**
* @brief Add two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a+b.
*/
void decaf_448_scalar_add (
decaf_448_scalar_t out,
const decaf_448_scalar_t a,
const decaf_448_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Compare two scalars.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @retval DECAF_TRUE The scalars are equal.
* @retval DECAF_FALSE The scalars are not equal.
*/
decaf_bool_t decaf_448_scalar_eq (
const decaf_448_scalar_t a,
const decaf_448_scalar_t b
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Subtract two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a-b.
*/
void decaf_448_scalar_sub (
decaf_448_scalar_t out,
const decaf_448_scalar_t a,
const decaf_448_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a*b.
*/
void decaf_448_scalar_mul (
decaf_448_scalar_t out,
const decaf_448_scalar_t a,
const decaf_448_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Invert a scalar. When passed zero, return 0. The input and output may alias.
* @param [in] a A scalar.
* @param [out] out 1/a.
* @return DECAF_TRUE The input is nonzero.
*/
decaf_bool_t decaf_448_scalar_invert (
decaf_448_scalar_t out,
const decaf_448_scalar_t a
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Copy a scalar. The scalars may use the same memory, in which
* case this function does nothing.
* @param [in] a A scalar.
* @param [out] out Will become a copy of a.
*/
static inline void NONNULL2 decaf_448_scalar_copy (
decaf_448_scalar_t out,
const decaf_448_scalar_t a
) {
*out = *a;
}

/**
* @brief Set a scalar to an integer.
* @param [in] a An integer.
* @param [out] out Will become equal to a.
* @todo Make inline?
*/
void decaf_448_scalar_set(
decaf_448_scalar_t out,
decaf_word_t a
) API_VIS NONNULL1;

/**
* @brief Encode a point as a sequence of bytes.
*
* @param [out] ser The byte representation of the point.
* @param [in] pt The point to encode.
*/
void decaf_448_point_encode (
uint8_t ser[DECAF_448_SER_BYTES],
const decaf_448_point_t pt
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Decode a point from a sequence of bytes.
*
* Every point has a unique encoding, so not every
* sequence of bytes is a valid encoding. If an invalid
* encoding is given, the output is undefined.
*
* @param [out] pt The decoded point.
* @param [in] ser The serialized version of the point.
* @param [in] allow_identity DECAF_TRUE if the identity is a legal input.
* @retval DECAF_SUCCESS The decoding succeeded.
* @retval DECAF_FAILURE The decoding didn't succeed, because
* ser does not represent a point.
*/
decaf_bool_t decaf_448_point_decode (
decaf_448_point_t pt,
const uint8_t ser[DECAF_448_SER_BYTES],
decaf_bool_t allow_identity
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Copy a point. The input and output may alias,
* in which case this function does nothing.
*
* @param [out] a A copy of the point.
* @param [in] b Any point.
*/
static inline void NONNULL2 decaf_448_point_copy (
decaf_448_point_t a,
const decaf_448_point_t b
) {
*a=*b;
}

/**
* @brief Test whether two points are equal. If yes, return
* DECAF_TRUE, else return DECAF_FALSE.
*
* @param [in] a A point.
* @param [in] b Another point.
* @retval DECAF_TRUE The points are equal.
* @retval DECAF_FALSE The points are not equal.
*/
decaf_bool_t decaf_448_point_eq (
const decaf_448_point_t a,
const decaf_448_point_t b
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Add two points to produce a third point. The
* input points and output point can be pointers to the same
* memory.
*
* @param [out] sum The sum a+b.
* @param [in] a An addend.
* @param [in] b An addend.
*/
void decaf_448_point_add (
decaf_448_point_t sum,
const decaf_448_point_t a,
const decaf_448_point_t b
) API_VIS NONNULL3;

/**
* @brief Double a point. Equivalent to
* decaf_448_point_add(two_a,a,a), but potentially faster.
*
* @param [out] two_a The sum a+a.
* @param [in] a A point.
*/
void decaf_448_point_double (
decaf_448_point_t two_a,
const decaf_448_point_t a
) API_VIS NONNULL2;

/**
* @brief Subtract two points to produce a third point. The
* input points and output point can be pointers to the same
* memory.
*
* @param [out] diff The difference a-b.
* @param [in] a The minuend.
* @param [in] b The subtrahend.
*/
void decaf_448_point_sub (
decaf_448_point_t diff,
const decaf_448_point_t a,
const decaf_448_point_t b
) API_VIS NONNULL3;
/**
* @brief Negate a point to produce another point. The input
* and output points can use the same memory.
*
* @param [out] nega The negated input point
* @param [in] a The input point.
*/
void decaf_448_point_negate (
decaf_448_point_t nega,
const decaf_448_point_t a
) API_VIS NONNULL2;

/**
* @brief Multiply a base point by a scalar: scaled = scalar*base.
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
*/
void decaf_448_point_scalarmul (
decaf_448_point_t scaled,
const decaf_448_point_t base,
const decaf_448_scalar_t scalar
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply a base point by a scalar: scaled = scalar*base.
* This function operates directly on serialized forms.
*
* @warning This function is experimental. It may not be supported
* long-term.
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
* @param [in] allow_identity Allow the input to be the identity.
* @param [in] short_circuit Allow a fast return if the input is illegal.
*
* @retval DECAF_SUCCESS The scalarmul succeeded.
* @retval DECAF_FAILURE The scalarmul didn't succeed, because
* base does not represent a point.
*/
decaf_bool_t decaf_448_direct_scalarmul (
uint8_t scaled[DECAF_448_SER_BYTES],
const uint8_t base[DECAF_448_SER_BYTES],
const decaf_448_scalar_t scalar,
decaf_bool_t allow_identity,
decaf_bool_t short_circuit
) API_VIS NONNULL3 WARN_UNUSED NOINLINE;

/**
* @brief Precompute a table for fast scalar multiplication.
* Some implementations do not include precomputed points; for
* those implementations, this implementation simply copies the
* point.
*
* @param [out] a A precomputed table of multiples of the point.
* @param [in] b Any point.
*/
void decaf_448_precompute (
decaf_448_precomputed_s *a,
const decaf_448_point_t b
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Multiply a precomputed base point by a scalar:
* scaled = scalar*base.
* Some implementations do not include precomputed points; for
* those implementations, this function is the same as
* decaf_448_point_scalarmul
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
*
* @todo precomputed dsmul? const or variable time?
*/
void decaf_448_precomputed_scalarmul (
decaf_448_point_t scaled,
const decaf_448_precomputed_s *base,
const decaf_448_scalar_t scalar
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply two base points by two scalars:
* scaled = scalar1*base1 + scalar2*base2.
*
* Equivalent to two calls to decaf_448_point_scalarmul, but may be
* faster.
*
* @param [out] combo The linear combination scalar1*base1 + scalar2*base2.
* @param [in] base1 A first point to be scaled.
* @param [in] scalar1 A first scalar to multiply by.
* @param [in] base2 A second point to be scaled.
* @param [in] scalar2 A second scalar to multiply by.
*/
void decaf_448_point_double_scalarmul (
decaf_448_point_t combo,
const decaf_448_point_t base1,
const decaf_448_scalar_t scalar1,
const decaf_448_point_t base2,
const decaf_448_scalar_t scalar2
) API_VIS NONNULL5 NOINLINE;

/**
* @brief Multiply two base points by two scalars:
* scaled = scalar1*decaf_448_point_base + scalar2*base2.
*
* Otherwise equivalent to decaf_448_point_double_scalarmul, but may be
* faster at the expense of being variable time.
*
* @param [out] combo The linear combination scalar1*base + scalar2*base2.
* @param [in] scalar1 A first scalar to multiply by.
* @param [in] base2 A second point to be scaled.
* @param [in] scalar2 A second scalar to multiply by.
*
* @warning: This function takes variable time, and may leak the scalars
* used. It is designed for signature verification.
*/
void decaf_448_base_double_scalarmul_non_secret (
decaf_448_point_t combo,
const decaf_448_scalar_t scalar1,
const decaf_448_point_t base2,
const decaf_448_scalar_t scalar2
) API_VIS NONNULL4 NOINLINE;

/**
* @brief Test that a point is valid, for debugging purposes.
*
* @param [in] toTest The point to test.
* @retval DECAF_TRUE The point is valid.
* @retval DECAF_FALSE The point is invalid.
*/
decaf_bool_t decaf_448_point_valid (
const decaf_448_point_t toTest
) API_VIS WARN_UNUSED NONNULL1 NOINLINE;

/**
* @brief 2-torque a point, for debugging purposes.
*
* @param [out] q The point to torque.
* @param [in] p The point to torque.
*/
void decaf_448_point_debugging_2torque (
decaf_448_point_t q,
const decaf_448_point_t p
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Almost-Elligator-like hash to curve.
*
* Call this function with the output of a hash to make a hash to the curve.
*
* This function runs Elligator2 on the decaf_448 Jacobi quartic model. It then
* uses the isogeny to put the result in twisted Edwards form. As a result,
* it is safe (cannot produce points of order 4), and would be compatible with
* hypothetical other implementations of Decaf using a Montgomery or untwisted
* Edwards model.
*
* Unlike Elligator, this function may be up to 4:1 on [0,(p-1)/2]:
* A factor of 2 due to the isogeny.
* A factor of 2 because we quotient out the 2-torsion.
*
* This makes it about 8:1 overall.
*
* Negating the input (mod q) results in the same point. Inverting the input
* (mod q) results in the negative point. This is the same as Elligator.
*
* This function isn't quite indifferentiable from a random oracle.
* However, it is suitable for many protocols, including SPEKE and SPAKE2 EE.
* Furthermore, calling it twice with independent seeds and adding the results
* is indifferentiable from a random oracle.
*
* @param [in] hashed_data Output of some hash function.
* @param [out] pt The data hashed to the curve.
* @return A "hint" value which can be used to help invert the encoding.
*/
unsigned char
decaf_448_point_from_hash_nonuniform (
decaf_448_point_t pt,
const unsigned char hashed_data[DECAF_448_SER_BYTES]
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Inverse of elligator-like hash to curve.
*
* This function writes to the buffer, to make it so that
* decaf_448_point_from_hash_nonuniform(buffer) = pt,hint
* if possible.
*
* @param [out] recovered_hash Encoded data.
* @param [in] pt The point to encode.
* @param [in] hint The hint value returned from
* decaf_448_point_from_hash_nonuniform.
*
* @retval DECAF_SUCCESS The inverse succeeded.
* @retval DECAF_FAILURE The pt isn't the image of
* decaf_448_point_from_hash_nonuniform with the given hint.
*
* @warning The hinting system is subject to change, especially in corner cases.
* @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF.
*/
decaf_bool_t
decaf_448_invert_elligator_nonuniform (
unsigned char recovered_hash[DECAF_448_SER_BYTES],
const decaf_448_point_t pt,
unsigned char hint
) API_VIS NONNULL2 NOINLINE WARN_UNUSED;

/**
* @brief Inverse of elligator-like hash to curve, uniform.
*
* This function modifies the first DECAF_448_SER_BYTES of the
* buffer, to make it so that
* decaf_448_point_from_hash_uniform(buffer) = pt,hint
* if possible.
*
* @param [out] recovered_hash Encoded data.
* @param [in] pt The point to encode.
* @param [in] hint The hint value returned from
* decaf_448_point_from_hash_nonuniform.
*
* @retval DECAF_SUCCESS The inverse succeeded.
* @retval DECAF_FAILURE The pt isn't the image of
* decaf_448_point_from_hash_uniform with the given hint.
*
* @warning The hinting system is subject to change, especially in corner cases.
* @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF.
*/
decaf_bool_t
decaf_448_invert_elligator_uniform (
unsigned char recovered_hash[2*DECAF_448_SER_BYTES],
const decaf_448_point_t pt,
unsigned char hint
) API_VIS NONNULL2 NOINLINE WARN_UNUSED;

/**
* @brief Indifferentiable hash function encoding to curve.
*
* Equivalent to calling decaf_448_point_from_hash_nonuniform twice and adding.
*
* @param [in] hashed_data Output of some hash function.
* @param [out] pt The data hashed to the curve.
* @return A "hint" value which can be used to help invert the encoding.
*/
unsigned char decaf_448_point_from_hash_uniform (
decaf_448_point_t pt,
const unsigned char hashed_data[2*DECAF_448_SER_BYTES]
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Overwrite data with zeros. Uses memset_s if available.
*/
void decaf_bzero (
void *data,
size_t size
) NONNULL1 API_VIS NOINLINE;

/**
* @brief Compare two buffers, returning DECAF_TRUE if they are equal.
*/
decaf_bool_t decaf_memeq (
const void *data1,
const void *data2,
size_t size
) NONNULL2 WARN_UNUSED API_VIS NOINLINE;

/**
* @brief Overwrite scalar with zeros.
*/
void decaf_448_scalar_destroy (
decaf_448_scalar_t scalar
) NONNULL1 API_VIS;

/**
* @brief Overwrite point with zeros.
* @todo Use this internally.
*/
void decaf_448_point_destroy (
decaf_448_point_t point
) NONNULL1 API_VIS;

/**
* @brief Overwrite point with zeros.
* @todo Use this internally.
*/
void decaf_448_precomputed_destroy (
decaf_448_precomputed_s *pre
) NONNULL1 API_VIS;

/* TODO: functions to invert point_from_hash?? */

#undef API_VIS
#undef WARN_UNUSED
#undef NOINLINE
#undef NONNULL1
#undef NONNULL2
#undef NONNULL3
#undef NONNULL4
#undef NONNULL5

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __DECAF_448_H__ */

+ 4
- 734
include/decaf.hxx View File

@@ -1,738 +1,8 @@
/**
* @file decaf.hxx
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief A group of prime order p, C++ wrapper.
*
* The Decaf library implements cryptographic operations on a an elliptic curve
* group of prime order p. It accomplishes this by using a twisted Edwards
* curve (isogenous to Ed448-Goldilocks) and wiping out the cofactor.
*
* The formulas are all complete and have no special cases, except that
* decaf_448_decode can fail because not every sequence of bytes is a valid group
* element.
*
* The formulas contain no data-dependent branches, timing or memory accesses,
* except for decaf_448_base_double_scalarmul_non_secret.
*/
#ifndef __DECAF_448_HXX__
#define __DECAF_448_HXX__ 1

/** This code uses posix_memalign. */
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <string.h> /* for memcpy */
#ifndef __DECAF_HXX__
#define __DECAF_HXX__ 1

#include "decaf.h"
#include <string>
#include <sys/types.h>
#include <limits.h>
#include "decaf_255.hxx" // MAGIC

/* TODO: This is incomplete */
/* TODO: attribute nonnull */
#endif /* __DECAF_H__ */

/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#define EXPLICIT_CON explicit
#define GET_DATA(str) ((const unsigned char *)&(str)[0])
#else
#define NOEXCEPT throw()
#define EXPLICIT_CON
#define GET_DATA(str) ((const unsigned char *)((str).data()))
#endif
/** @endcond */

namespace decaf {

/** @brief An exception for when crypto (ie point decode) has failed. */
class CryptoException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "CryptoException"; }
};

/** @brief An exception for when crypto (ie point decode) has failed. */
class LengthException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "LengthException"; }
};

/**
* Securely erase contents of memory.
*/
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }

/** Block object */
class Block {
protected:
unsigned char *data_;
size_t size_;

public:
/** Empty init */
inline Block() NOEXCEPT : data_(NULL), size_(0) {}
/** Init from C string */
inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {}

/** Unowned init */
inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {}
/** Block from std::string */
inline Block(const std::string &s) : data_((unsigned char *)GET_DATA(s)), size_(s.size()) {}

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Get the size */
inline size_t size() const NOEXCEPT { return size_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Convert to C++ string */
inline std::string get_string() const {
return std::string((const char *)data_,size_);
}

/** Slice the buffer*/
inline Block slice(size_t off, size_t length) const throw(LengthException) {
if (off > size() || length > size() - off)
throw LengthException();
return Block(data()+off, length);
}

/** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */
inline virtual ~Block() {};
};

class TmpBuffer;

class Buffer : public Block {
public:
/** Null init */
inline Buffer() NOEXCEPT : Block() {}

/** Unowned init */
inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {}

/** Get unconst data */
inline unsigned char *data() NOEXCEPT { return data_; }

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Autocast to unsigned char */
inline operator unsigned char*() NOEXCEPT { return data_; }

/** Slice the buffer*/
inline TmpBuffer slice(size_t off, size_t length) throw(LengthException);
};

class TmpBuffer : public Buffer {
public:
/** Unowned init */
inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {}
};

TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) {
if (off > size() || length > size() - off) throw LengthException();
return TmpBuffer(data()+off, length);
}

/** A self-erasing block of data */
class SecureBuffer : public Buffer {
public:
/** Null secure block */
inline SecureBuffer() NOEXCEPT : Buffer() {}

/** Construct empty from size */
inline SecureBuffer(size_t size) {
data_ = new unsigned char[size_ = size];
memset(data_,0,size);
}

/** Construct from data */
inline SecureBuffer(const unsigned char *data, size_t size){
data_ = new unsigned char[size_ = size];
memcpy(data_, data, size);
}

/** Copy constructor */
inline SecureBuffer(const Block &copy) : Buffer() { *this = copy; }

/** Copy-assign constructor */
inline SecureBuffer& operator=(const Block &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Copy-assign constructor */
inline SecureBuffer& operator=(const SecureBuffer &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Destructor erases data */
~SecureBuffer() NOEXCEPT { clear(); }

/** Clear data */
inline void clear() NOEXCEPT {
if (data_ == NULL) return;
really_bzero(data_,size_);
delete[] data_;
data_ = NULL;
size_ = 0;
}

#if __cplusplus >= 201103L
/** Move constructor */
inline SecureBuffer(SecureBuffer &&move) { *this = move; }

/** Move non-constructor */
inline SecureBuffer(Block &&move) { *this = (Block &)move; }

/** Move-assign constructor. TODO: check that this actually gets used.*/
inline SecureBuffer& operator=(SecureBuffer &&move) {
clear();
data_ = move.data_; move.data_ = NULL;
size_ = move.size_; move.size_ = 0;
return *this;
}

/** C++11-only explicit cast */
inline explicit operator std::string() const { return get_string(); }
#endif
};


/** @brief Passed to constructors to avoid (conservative) initialization */
struct NOINIT {};

/**@cond internal*/
/** Forward-declare sponge RNG object */
class SpongeRng;
/**@endcond*/


/**
* @brief Ed448-Goldilocks/Decaf instantiation of group.
*/
struct Ed448 {

/** @cond internal */
class Point;
class Precomputed;
/** @endcond */

/**
* @brief A scalar modulo the curve order.
* Supports the usual arithmetic operations, all in constant time.
*/
class Scalar {
public:
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_448_SCALAR_BYTES;
/** @brief access to the underlying scalar object */
decaf_448_scalar_t s;
/** @brief Don't initialize. */
inline Scalar(const NOINIT &) NOEXCEPT {}
/** @brief Set to an unsigned word */
inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; }

/** @brief Set to a signed word */
inline Scalar(const int w) NOEXCEPT { *this = w; }
/** @brief Construct from RNG */
inline explicit Scalar(SpongeRng &rng) NOEXCEPT;
/** @brief Construct from decaf_scalar_t object. */
inline Scalar(const decaf_448_scalar_t &t = decaf_448_scalar_zero) NOEXCEPT { decaf_448_scalar_copy(s,t); }
/** @brief Copy constructor. */
inline Scalar(const Scalar &x) NOEXCEPT { *this = x; }
/** @brief Construct from arbitrary-length little-endian byte sequence. */
inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; }
/** @brief Assignment. */
inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; }
/** @brief Assign from unsigned word. */
inline Scalar& operator=(decaf_word_t w) NOEXCEPT { decaf_448_scalar_set(s,w); return *this; }
/** @brief Assign from signed int. */
inline Scalar& operator=(int w) NOEXCEPT {
Scalar t(-(decaf_word_t)INT_MIN);
decaf_448_scalar_set(s,(decaf_word_t)w - (decaf_word_t)INT_MIN);
*this -= t;
return *this;
}
/** Destructor securely erases the scalar. */
inline ~Scalar() NOEXCEPT { decaf_448_scalar_destroy(s); }
/** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */
inline Scalar &operator=(const Block &bl) NOEXCEPT {
decaf_448_scalar_decode_long(s,bl.data(),bl.size()); return *this;
}
/**
* @brief Decode from correct-length little-endian byte sequence.
* @return DECAF_FAILURE if the scalar is greater than or equal to the group order q.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const unsigned char buffer[SER_BYTES]
) NOEXCEPT {
return decaf_448_scalar_decode(sc.s,buffer);
}
/** @brief Decode from correct-length little-endian byte sequence in C++ string. */
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const Block &buffer
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_448_scalar_decode(sc.s,buffer);
}
/** @brief Encode to fixed-length string */
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
SecureBuffer buf(SER_BYTES); decaf_448_scalar_encode(buf,s); return buf;
}
/** @brief Encode to fixed-length buffer */
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
decaf_448_scalar_encode(buffer, s);
}
/** Add. */
inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_add(r.s,s,q.s); return r; }
/** Add to this. */
inline Scalar &operator+=(const Scalar &q) NOEXCEPT { decaf_448_scalar_add(s,s,q.s); return *this; }
/** Subtract. */
inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_sub(r.s,s,q.s); return r; }
/** Subtract from this. */
inline Scalar &operator-=(const Scalar &q) NOEXCEPT { decaf_448_scalar_sub(s,s,q.s); return *this; }
/** Multiply */
inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_mul(r.s,s,q.s); return r; }
/** Multiply into this. */
inline Scalar &operator*=(const Scalar &q) NOEXCEPT { decaf_448_scalar_mul(s,s,q.s); return *this; }
/** Negate */
inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_sub(r.s,decaf_448_scalar_zero,s); return r; }
/** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */
inline Scalar inverse() const NOEXCEPT { Scalar r; decaf_448_scalar_invert(r.s,s); return r; }
/** @brief Divide by inverting q. If q == 0, return 0. */
inline Scalar operator/ (const Scalar &q) const NOEXCEPT { return *this * q.inverse(); }
/** @brief Divide by inverting q. If q == 0, return 0. */
inline Scalar &operator/=(const Scalar &q) NOEXCEPT { return *this *= q.inverse(); }
/** @brief Compare in constant time */
inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); }
/** @brief Compare in constant time */
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_448_scalar_eq(s,q.s); }
/** @brief Scalarmul with scalar on left. */
inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); }
/** @brief Scalarmul-precomputed with scalar on left. */
inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); }
/** @brief Direct scalar multiplication. */
inline SecureBuffer direct_scalarmul(
const Block &in,
decaf_bool_t allow_identity=DECAF_FALSE,
decaf_bool_t short_circuit=DECAF_TRUE
) const throw(CryptoException) {
SecureBuffer out(/*FIXME Point::*/SER_BYTES);
if (!decaf_448_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit))
throw CryptoException();
return out;
}
};

/**
* @brief Element of prime-order group.
*/
class Point {
public:
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_448_SER_BYTES;
/** @brief Size of a stegged element */
static const size_t STEG_BYTES = DECAF_448_SER_BYTES + 8;
/** @brief Bytes required for hash */
static const size_t HASH_BYTES = DECAF_448_SER_BYTES;
/** The c-level object. */
decaf_448_point_t p;
/** @brief Don't initialize. */
inline Point(const NOINIT &) NOEXCEPT {}
/** @brief Constructor sets to identity by default. */
inline Point(const decaf_448_point_t &q = decaf_448_point_identity) NOEXCEPT { decaf_448_point_copy(p,q); }
/** @brief Copy constructor. */
inline Point(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); }
/** @brief Assignment. */
inline Point& operator=(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); return *this; }
/** @brief Destructor securely erases the point. */
inline ~Point() NOEXCEPT { decaf_448_point_destroy(p); }
/** @brief Construct from RNG */
inline explicit Point(SpongeRng &rng, bool uniform = true) NOEXCEPT;
/**
* @brief Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
*
* @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE.
*/
inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) {
if (!decode(*this,s,allow_identity)) throw CryptoException();
}
/**
* @brief Initialize from C fixed-length byte string.
* The all-zero string maps to the identity.
*
* @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE.
*/
inline explicit Point(const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE)
throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); }
/**
* @brief Initialize from C fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string wasn't the encoding of a point, or was the identity
* and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
return decaf_448_point_decode(p.p,buffer,allow_identity);
}
/**
* @brief Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_448_point_decode(p.p,buffer.data(),allow_identity);
}
/**
* @brief Map uniformly to the curve from a hash buffer.
* The empty or all-zero string maps to the identity, as does the string "\x01".
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
*/
static inline Point from_hash ( const Block &s ) NOEXCEPT {
Point p((NOINIT())); p.set_to_hash(s); return p;
}

/**
* @brief Map to the curve from a hash buffer.
* The empty or all-zero string maps to the identity, as does the string "\x01".
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
*/
inline unsigned char set_to_hash( const Block &s ) NOEXCEPT {
if (s.size() < HASH_BYTES) {
SecureBuffer b(HASH_BYTES);
memcpy(b.data(), s.data(), s.size());
return decaf_448_point_from_hash_nonuniform(p,b);
} else if (s.size() == HASH_BYTES) {
return decaf_448_point_from_hash_nonuniform(p,s);
} else if (s.size() < 2*HASH_BYTES) {
SecureBuffer b(2*HASH_BYTES);
memcpy(b.data(), s.data(), s.size());
return decaf_448_point_from_hash_uniform(p,b);
} else {
return decaf_448_point_from_hash_uniform(p,s);
}
}
/**
* @brief Encode to string. The identity encodes to the all-zero string.
*/
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
SecureBuffer buffer(SER_BYTES);
decaf_448_point_encode(buffer, p);
return buffer;
}
/**
* @brief Encode to a C buffer. The identity encodes to all zeros.
*/
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
decaf_448_point_encode(buffer, p);
}
/** @brief Point add. */
inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_add(r.p,p,q.p); return r; }
/** @brief Point add. */
inline Point &operator+=(const Point &q) NOEXCEPT { decaf_448_point_add(p,p,q.p); return *this; }
/** @brief Point subtract. */
inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_sub(r.p,p,q.p); return r; }
/** @brief Point subtract. */
inline Point &operator-=(const Point &q) NOEXCEPT { decaf_448_point_sub(p,p,q.p); return *this; }
/** @brief Point negate. */
inline Point operator- () const NOEXCEPT { Point r((NOINIT())); decaf_448_point_negate(r.p,p); return r; }
/** @brief Double the point out of place. */
inline Point times_two () const NOEXCEPT { Point r((NOINIT())); decaf_448_point_double(r.p,p); return r; }
/** @brief Double the point in place. */
inline Point &double_in_place() NOEXCEPT { decaf_448_point_double(p,p); return *this; }
/** @brief Constant-time compare. */
inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_448_point_eq(p,q.p); }

/** @brief Constant-time compare. */
inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_448_point_eq(p,q.p); }
/** @brief Scalar multiply. */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_scalarmul(r.p,p,s.s); return r; }
/** @brief Scalar multiply in place. */
inline Point &operator*=(const Scalar &s) NOEXCEPT { decaf_448_point_scalarmul(p,p,s.s); return *this; }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point &operator/=(const Scalar &s) NOEXCEPT { return (*this) *= s.inverse(); }
/** @brief Validate / sanity check */
inline bool validate() const NOEXCEPT { return !!decaf_448_point_valid(p); }
/** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */
static inline Point double_scalarmul (
const Point &q, const Scalar &qs, const Point &r, const Scalar &rs
) NOEXCEPT {
Point p((NOINIT())); decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
}
/**
* @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster.
* For those who like their scalars before the point.
*/
static inline Point double_scalarmul (
const Scalar &qs, const Point &q, const Scalar &rs, const Point &r
) NOEXCEPT {
Point p((NOINIT())); decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
}
/**
* @brief Double-scalar multiply: this point by the first scalar and base by the second scalar.
* @warning This function takes variable time, and may leak the scalars (or points, but currently
* it doesn't).
*/
inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT {
Point r((NOINIT())); decaf_448_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r;
}
inline Point& debugging_torque_in_place() {
decaf_448_point_debugging_2torque(p,p);
return *this;
}
inline bool invert_elligator (
Buffer &buf, unsigned char hint
) const NOEXCEPT {
unsigned char buf2[2*HASH_BYTES];
memset(buf2,0,sizeof(buf2));
memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
decaf_bool_t ret;
if (buf.size() > HASH_BYTES) {
ret = decaf_448_invert_elligator_uniform(buf2, p, hint);
} else {
ret = decaf_448_invert_elligator_nonuniform(buf2, p, hint);
}
if (buf.size() < HASH_BYTES) {
ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size());
}
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
decaf_bzero(buf2,sizeof(buf2));
return !!ret;
}
/** @brief Steganographically encode this */
inline SecureBuffer steg_encode(SpongeRng &rng) const NOEXCEPT;
/** @brief Return the base point */
static inline const Point base() NOEXCEPT { return Point(decaf_448_point_base); }
/** @brief Return the identity point */
static inline const Point identity() NOEXCEPT { return Point(decaf_448_point_identity); }
};

/**
* @brief Precomputed table of points.
* Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is.
* Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to
* stack-allocate a 15kiB object anyway.
*/
class Precomputed {
private:
/** @cond internal */
union {
decaf_448_precomputed_s *mine;
const decaf_448_precomputed_s *yours;
} ours;
bool isMine;
inline void clear() NOEXCEPT {
if (isMine) {
decaf_448_precomputed_destroy(ours.mine);
free(ours.mine);
ours.yours = decaf_448_precomputed_base;
isMine = false;
}
}
inline void alloc() throw(std::bad_alloc) {
if (isMine) return;
int ret = posix_memalign((void**)&ours.mine, alignof_decaf_448_precomputed_s,sizeof_decaf_448_precomputed_s);
if (ret || !ours.mine) {
isMine = false;
throw std::bad_alloc();
}
isMine = true;
}
inline const decaf_448_precomputed_s *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; }
/** @endcond */
public:
/** Destructor securely erases the memory. */
inline ~Precomputed() NOEXCEPT { clear(); }
/**
* @brief Initialize from underlying type, declared as a reference to prevent
* it from being called with 0, thereby breaking override.
*
* The underlying object must remain valid throughout the lifetime of this one.
*
* By default, initializes to the table for the base point.
*
* @warning The empty initializer makes this equal to base, unlike the empty
* initializer for points which makes this equal to the identity.
*/
inline Precomputed(
const decaf_448_precomputed_s &yours = *decaf_448_precomputed_base
) NOEXCEPT {
ours.yours = &yours;
isMine = false;
}
/**
* @brief Assign. This may require an allocation and memcpy.
*/
inline Precomputed &operator=(const Precomputed &it) throw(std::bad_alloc) {
if (this == &it) return *this;
if (it.isMine) {
alloc();
memcpy(ours.mine,it.ours.mine,sizeof_decaf_448_precomputed_s);
} else {
clear();
ours.yours = it.ours.yours;
}
isMine = it.isMine;
return *this;
}
/**
* @brief Initilaize from point. Must allocate memory, and may throw.
*/
inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) {
alloc();
decaf_448_precompute(ours.mine,it.p);
return *this;
}
/**
* @brief Copy constructor.
*/
inline Precomputed(const Precomputed &it) throw(std::bad_alloc) : isMine(false) { *this = it; }
/**
* @brief Constructor which initializes from point.
*/
inline explicit Precomputed(const Point &it) throw(std::bad_alloc) : isMine(false) { *this = it; }
#if __cplusplus >= 201103L
inline Precomputed &operator=(Precomputed &&it) NOEXCEPT {
if (this == &it) return *this;
clear();
ours = it.ours;
isMine = it.isMine;
it.isMine = false;
it.ours.yours = decaf_448_precomputed_base;
return *this;
}
inline Precomputed(Precomputed &&it) NOEXCEPT : isMine(false) { *this = it; }
#endif
/** @brief Fixed base scalarmul. */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_448_precomputed_scalarmul(r.p,get(),s.s); return r; }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); }
/** @brief Return the table for the base point. */
static inline const Precomputed base() NOEXCEPT { return Precomputed(*decaf_448_precomputed_base); }
};

}; /* struct Decaf448 */

#undef NOEXCEPT
#undef EXPLICIT_CON
#undef GET_DATA
} /* namespace decaf */

#endif /* __DECAF_448_HXX__ */

+ 651
- 0
include/decaf_255.h View File

@@ -0,0 +1,651 @@
/**
* @file decaf_255.h
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief A group of prime order p.
*
* The Decaf library implements cryptographic operations on a an elliptic curve
* group of prime order p. It accomplishes this by using a twisted Edwards
* curve (isogenous to Ed255-Goldilocks) and wiping out the cofactor.
*
* The formulas are all complete and have no special cases, except that
* decaf_255_decode can fail because not every sequence of bytes is a valid group
* element.
*
* The formulas contain no data-dependent branches, timing or memory accesses,
* except for decaf_255_base_double_scalarmul_non_secret.
*
* This library may support multiple curves eventually. The Ed255-Goldilocks
* specific identifiers are prefixed with DECAF_255 or decaf_255.
*/
#ifndef __DECAF_255_H__
#define __DECAF_255_H__ 1

#include <stdint.h>
#include <sys/types.h>

/* Goldilocks' build flags default to hidden and stripping executables. */
/** @cond internal */
#if defined(DOXYGEN) && !defined(__attribute__)
#define __attribute__((x))
#endif
#define API_VIS __attribute__((visibility("default")))
#define NOINLINE __attribute__((noinline))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
#define NONNULL4 __attribute__((nonnull(1,2,3,4)))
#define NONNULL5 __attribute__((nonnull(1,2,3,4,5)))

/* Internal word types */
#if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \
&& !defined(DECAF_FORCE_32_BIT)
#define DECAF_WORD_BITS 64
typedef uint64_t decaf_word_t, decaf_bool_t;
typedef __uint128_t decaf_dword_t;
#else
#define DECAF_WORD_BITS 32
typedef uint32_t decaf_word_t, decaf_bool_t;
typedef uint64_t decaf_dword_t;
#endif

#define DECAF_255_LIMBS (320/DECAF_WORD_BITS)
#define DECAF_255_SCALAR_BITS 252
#define DECAF_255_SCALAR_LIMBS (256/DECAF_WORD_BITS)

/** Galois field element internal structure */
typedef struct gf_s {
decaf_word_t limb[DECAF_255_LIMBS];
} __attribute__((aligned(32))) gf_s, gf[1];
/** @endcond */

/** Number of bytes in a serialized point. */
#define DECAF_255_SER_BYTES 32

/** Number of bytes in a serialized scalar. */
#define DECAF_255_SCALAR_BYTES 32

/** Twisted Edwards (-1,d-1) extended homogeneous coordinates */
typedef struct decaf_255_point_s { /**@cond internal*/gf x,y,z,t;/**@endcond*/ } decaf_255_point_t[1];

/** Precomputed table based on a point. Can be trivial implementation. */
struct decaf_255_precomputed_s;

/** Precomputed table based on a point. Can be trivial implementation. */
typedef struct decaf_255_precomputed_s decaf_255_precomputed_s;

/** Size and alignment of precomputed point tables. */
extern const size_t sizeof_decaf_255_precomputed_s API_VIS, alignof_decaf_255_precomputed_s API_VIS;

/** Scalar is stored packed, because we don't need the speed. */
typedef struct decaf_255_scalar_s {
/** @cond internal */
decaf_word_t limb[DECAF_255_SCALAR_LIMBS];
/** @endcond */
} decaf_255_scalar_t[1];

/** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0;

/** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */
static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/,
DECAF_FAILURE = 0 /*DECAF_FALSE*/;

/** A scalar equal to 1. */
extern const decaf_255_scalar_t decaf_255_scalar_one API_VIS;

/** A scalar equal to 0. */
extern const decaf_255_scalar_t decaf_255_scalar_zero API_VIS;

/** The identity point on the curve. */
extern const decaf_255_point_t decaf_255_point_identity API_VIS;

/**
* An arbitrarily chosen base point on the curve.
* Equal to Ed255-Goldilocks base point defined by DJB, except of course that
* it's on the twist in this case. TODO: choose a base point with nice encoding?
*/
extern const decaf_255_point_t decaf_255_point_base API_VIS;

/** Precomputed table for the base point on the curve. */
extern const struct decaf_255_precomputed_s *decaf_255_precomputed_base API_VIS;

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Read a scalar from wire format or from bytes.
*
* @param [in] ser Serialized form of a scalar.
* @param [out] out Deserialized form.
*
* @retval DECAF_SUCCESS The scalar was correctly encoded.
* @retval DECAF_FAILURE The scalar was greater than the modulus,
* and has been reduced modulo that modulus.
*/
decaf_bool_t decaf_255_scalar_decode (
decaf_255_scalar_t out,
const unsigned char ser[DECAF_255_SCALAR_BYTES]
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Read a scalar from wire format or from bytes. Reduces mod
* scalar prime.
*
* @param [in] ser Serialized form of a scalar.
* @param [in] ser_len Length of serialized form.
* @param [out] out Deserialized form.
*/
void decaf_255_scalar_decode_long (
decaf_255_scalar_t out,
const unsigned char *ser,
size_t ser_len
) API_VIS NONNULL2 NOINLINE;
/**
* @brief Serialize a scalar to wire format.
*
* @param [out] ser Serialized form of a scalar.
* @param [in] s Deserialized scalar.
*/
void decaf_255_scalar_encode (
unsigned char ser[DECAF_255_SCALAR_BYTES],
const decaf_255_scalar_t s
) API_VIS NONNULL2 NOINLINE NOINLINE;
/**
* @brief Add two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a+b.
*/
void decaf_255_scalar_add (
decaf_255_scalar_t out,
const decaf_255_scalar_t a,
const decaf_255_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Compare two scalars.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @retval DECAF_TRUE The scalars are equal.
* @retval DECAF_FALSE The scalars are not equal.
*/
decaf_bool_t decaf_255_scalar_eq (
const decaf_255_scalar_t a,
const decaf_255_scalar_t b
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Subtract two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a-b.
*/
void decaf_255_scalar_sub (
decaf_255_scalar_t out,
const decaf_255_scalar_t a,
const decaf_255_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a*b.
*/
void decaf_255_scalar_mul (
decaf_255_scalar_t out,
const decaf_255_scalar_t a,
const decaf_255_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Invert a scalar. When passed zero, return 0. The input and output may alias.
* @param [in] a A scalar.
* @param [out] out 1/a.
* @return DECAF_TRUE The input is nonzero.
*/
decaf_bool_t decaf_255_scalar_invert (
decaf_255_scalar_t out,
const decaf_255_scalar_t a
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Copy a scalar. The scalars may use the same memory, in which
* case this function does nothing.
* @param [in] a A scalar.
* @param [out] out Will become a copy of a.
*/
static inline void NONNULL2 decaf_255_scalar_copy (
decaf_255_scalar_t out,
const decaf_255_scalar_t a
) {
*out = *a;
}

/**
* @brief Set a scalar to an integer.
* @param [in] a An integer.
* @param [out] out Will become equal to a.
* @todo Make inline?
*/
void decaf_255_scalar_set(
decaf_255_scalar_t out,
decaf_word_t a
) API_VIS NONNULL1;

/**
* @brief Encode a point as a sequence of bytes.
*
* @param [out] ser The byte representation of the point.
* @param [in] pt The point to encode.
*/
void decaf_255_point_encode (
uint8_t ser[DECAF_255_SER_BYTES],
const decaf_255_point_t pt
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Decode a point from a sequence of bytes.
*
* Every point has a unique encoding, so not every
* sequence of bytes is a valid encoding. If an invalid
* encoding is given, the output is undefined.
*
* @param [out] pt The decoded point.
* @param [in] ser The serialized version of the point.
* @param [in] allow_identity DECAF_TRUE if the identity is a legal input.
* @retval DECAF_SUCCESS The decoding succeeded.
* @retval DECAF_FAILURE The decoding didn't succeed, because
* ser does not represent a point.
*/
decaf_bool_t decaf_255_point_decode (
decaf_255_point_t pt,
const uint8_t ser[DECAF_255_SER_BYTES],
decaf_bool_t allow_identity
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Copy a point. The input and output may alias,
* in which case this function does nothing.
*
* @param [out] a A copy of the point.
* @param [in] b Any point.
*/
static inline void NONNULL2 decaf_255_point_copy (
decaf_255_point_t a,
const decaf_255_point_t b
) {
*a=*b;
}

/**
* @brief Test whether two points are equal. If yes, return
* DECAF_TRUE, else return DECAF_FALSE.
*
* @param [in] a A point.
* @param [in] b Another point.
* @retval DECAF_TRUE The points are equal.
* @retval DECAF_FALSE The points are not equal.
*/
decaf_bool_t decaf_255_point_eq (
const decaf_255_point_t a,
const decaf_255_point_t b
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Add two points to produce a third point. The
* input points and output point can be pointers to the same
* memory.
*
* @param [out] sum The sum a+b.
* @param [in] a An addend.
* @param [in] b An addend.
*/
void decaf_255_point_add (
decaf_255_point_t sum,
const decaf_255_point_t a,
const decaf_255_point_t b
) API_VIS NONNULL3;

/**
* @brief Double a point. Equivalent to
* decaf_255_point_add(two_a,a,a), but potentially faster.
*
* @param [out] two_a The sum a+a.
* @param [in] a A point.
*/
void decaf_255_point_double (
decaf_255_point_t two_a,
const decaf_255_point_t a
) API_VIS NONNULL2;

/**
* @brief Subtract two points to produce a third point. The
* input points and output point can be pointers to the same
* memory.
*
* @param [out] diff The difference a-b.
* @param [in] a The minuend.
* @param [in] b The subtrahend.
*/
void decaf_255_point_sub (
decaf_255_point_t diff,
const decaf_255_point_t a,
const decaf_255_point_t b
) API_VIS NONNULL3;
/**
* @brief Negate a point to produce another point. The input
* and output points can use the same memory.
*
* @param [out] nega The negated input point
* @param [in] a The input point.
*/
void decaf_255_point_negate (
decaf_255_point_t nega,
const decaf_255_point_t a
) API_VIS NONNULL2;

/**
* @brief Multiply a base point by a scalar: scaled = scalar*base.
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
*/
void decaf_255_point_scalarmul (
decaf_255_point_t scaled,
const decaf_255_point_t base,
const decaf_255_scalar_t scalar
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply a base point by a scalar: scaled = scalar*base.
* This function operates directly on serialized forms.
*
* @warning This function is experimental. It may not be supported
* long-term.
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
* @param [in] allow_identity Allow the input to be the identity.
* @param [in] short_circuit Allow a fast return if the input is illegal.
*
* @retval DECAF_SUCCESS The scalarmul succeeded.
* @retval DECAF_FAILURE The scalarmul didn't succeed, because
* base does not represent a point.
*/
decaf_bool_t decaf_255_direct_scalarmul (
uint8_t scaled[DECAF_255_SER_BYTES],
const uint8_t base[DECAF_255_SER_BYTES],
const decaf_255_scalar_t scalar,
decaf_bool_t allow_identity,
decaf_bool_t short_circuit
) API_VIS NONNULL3 WARN_UNUSED NOINLINE;

/**
* @brief Precompute a table for fast scalar multiplication.
* Some implementations do not include precomputed points; for
* those implementations, this implementation simply copies the
* point.
*
* @param [out] a A precomputed table of multiples of the point.
* @param [in] b Any point.
*/
void decaf_255_precompute (
decaf_255_precomputed_s *a,
const decaf_255_point_t b
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Multiply a precomputed base point by a scalar:
* scaled = scalar*base.
* Some implementations do not include precomputed points; for
* those implementations, this function is the same as
* decaf_255_point_scalarmul
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
*
* @todo precomputed dsmul? const or variable time?
*/
void decaf_255_precomputed_scalarmul (
decaf_255_point_t scaled,
const decaf_255_precomputed_s *base,
const decaf_255_scalar_t scalar
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply two base points by two scalars:
* scaled = scalar1*base1 + scalar2*base2.
*
* Equivalent to two calls to decaf_255_point_scalarmul, but may be
* faster.
*
* @param [out] combo The linear combination scalar1*base1 + scalar2*base2.
* @param [in] base1 A first point to be scaled.
* @param [in] scalar1 A first scalar to multiply by.
* @param [in] base2 A second point to be scaled.
* @param [in] scalar2 A second scalar to multiply by.
*/
void decaf_255_point_double_scalarmul (
decaf_255_point_t combo,
const decaf_255_point_t base1,
const decaf_255_scalar_t scalar1,
const decaf_255_point_t base2,
const decaf_255_scalar_t scalar2
) API_VIS NONNULL5 NOINLINE;

/**
* @brief Multiply two base points by two scalars:
* scaled = scalar1*decaf_255_point_base + scalar2*base2.
*
* Otherwise equivalent to decaf_255_point_double_scalarmul, but may be
* faster at the expense of being variable time.
*
* @param [out] combo The linear combination scalar1*base + scalar2*base2.
* @param [in] scalar1 A first scalar to multiply by.
* @param [in] base2 A second point to be scaled.
* @param [in] scalar2 A second scalar to multiply by.
*
* @warning: This function takes variable time, and may leak the scalars
* used. It is designed for signature verification.
*/
void decaf_255_base_double_scalarmul_non_secret (
decaf_255_point_t combo,
const decaf_255_scalar_t scalar1,
const decaf_255_point_t base2,
const decaf_255_scalar_t scalar2
) API_VIS NONNULL4 NOINLINE;

/**
* @brief Test that a point is valid, for debugging purposes.
*
* @param [in] toTest The point to test.
* @retval DECAF_TRUE The point is valid.
* @retval DECAF_FALSE The point is invalid.
*/
decaf_bool_t decaf_255_point_valid (
const decaf_255_point_t toTest
) API_VIS WARN_UNUSED NONNULL1 NOINLINE;

/**
* @brief 2-torque a point, for debugging purposes.
*
* @param [out] q The point to torque.
* @param [in] p The point to torque.
*/
void decaf_255_point_debugging_2torque (
decaf_255_point_t q,
const decaf_255_point_t p
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Almost-Elligator-like hash to curve.
*
* Call this function with the output of a hash to make a hash to the curve.
*
* This function runs Elligator2 on the decaf_255 Jacobi quartic model. It then
* uses the isogeny to put the result in twisted Edwards form. As a result,
* it is safe (cannot produce points of order 4), and would be compatible with
* hypothetical other implementations of Decaf using a Montgomery or untwisted
* Edwards model.
*
* Unlike Elligator, this function may be up to 4:1 on [0,(p-1)/2]:
* A factor of 2 due to the isogeny.
* A factor of 2 because we quotient out the 2-torsion.
*
* This makes it about 8:1 overall.
*
* Negating the input (mod q) results in the same point. Inverting the input
* (mod q) results in the negative point. This is the same as Elligator.
*
* This function isn't quite indifferentiable from a random oracle.
* However, it is suitable for many protocols, including SPEKE and SPAKE2 EE.
* Furthermore, calling it twice with independent seeds and adding the results
* is indifferentiable from a random oracle.
*
* @param [in] hashed_data Output of some hash function.
* @param [out] pt The data hashed to the curve.
* @return A "hint" value which can be used to help invert the encoding.
*/
unsigned char
decaf_255_point_from_hash_nonuniform (
decaf_255_point_t pt,
const unsigned char hashed_data[DECAF_255_SER_BYTES]
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Inverse of elligator-like hash to curve.
*
* This function writes to the buffer, to make it so that
* decaf_255_point_from_hash_nonuniform(buffer) = pt,hint
* if possible.
*
* @param [out] recovered_hash Encoded data.
* @param [in] pt The point to encode.
* @param [in] hint The hint value returned from
* decaf_255_point_from_hash_nonuniform.
*
* @retval DECAF_SUCCESS The inverse succeeded.
* @retval DECAF_FAILURE The pt isn't the image of
* decaf_255_point_from_hash_nonuniform with the given hint.
*
* @warning The hinting system is subject to change, especially in corner cases.
* @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF.
*/
decaf_bool_t
decaf_255_invert_elligator_nonuniform (
unsigned char recovered_hash[DECAF_255_SER_BYTES],
const decaf_255_point_t pt,
unsigned char hint
) API_VIS NONNULL2 NOINLINE WARN_UNUSED;

/**
* @brief Inverse of elligator-like hash to curve, uniform.
*
* This function modifies the first DECAF_255_SER_BYTES of the
* buffer, to make it so that
* decaf_255_point_from_hash_uniform(buffer) = pt,hint
* if possible.
*
* @param [out] recovered_hash Encoded data.
* @param [in] pt The point to encode.
* @param [in] hint The hint value returned from
* decaf_255_point_from_hash_nonuniform.
*
* @retval DECAF_SUCCESS The inverse succeeded.
* @retval DECAF_FAILURE The pt isn't the image of
* decaf_255_point_from_hash_uniform with the given hint.
*
* @warning The hinting system is subject to change, especially in corner cases.
* @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF.
*/
decaf_bool_t
decaf_255_invert_elligator_uniform (
unsigned char recovered_hash[2*DECAF_255_SER_BYTES],
const decaf_255_point_t pt,
unsigned char hint
) API_VIS NONNULL2 NOINLINE WARN_UNUSED;

/**
* @brief Indifferentiable hash function encoding to curve.
*
* Equivalent to calling decaf_255_point_from_hash_nonuniform twice and adding.
*
* @param [in] hashed_data Output of some hash function.
* @param [out] pt The data hashed to the curve.
* @return A "hint" value which can be used to help invert the encoding.
*/
unsigned char decaf_255_point_from_hash_uniform (
decaf_255_point_t pt,
const unsigned char hashed_data[2*DECAF_255_SER_BYTES]
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Overwrite data with zeros. Uses memset_s if available.
*/
void decaf_bzero (
void *data,
size_t size
) NONNULL1 API_VIS NOINLINE;

/**
* @brief Compare two buffers, returning DECAF_TRUE if they are equal.
*/
decaf_bool_t decaf_memeq (
const void *data1,
const void *data2,
size_t size
) NONNULL2 WARN_UNUSED API_VIS NOINLINE;

/**
* @brief Overwrite scalar with zeros.
*/
void decaf_255_scalar_destroy (
decaf_255_scalar_t scalar
) NONNULL1 API_VIS;

/**
* @brief Overwrite point with zeros.
* @todo Use this internally.
*/
void decaf_255_point_destroy (
decaf_255_point_t point
) NONNULL1 API_VIS;

/**
* @brief Overwrite point with zeros.
* @todo Use this internally.
*/
void decaf_255_precomputed_destroy (
decaf_255_precomputed_s *pre
) NONNULL1 API_VIS;

/* TODO: functions to invert point_from_hash?? */

#undef API_VIS
#undef WARN_UNUSED
#undef NOINLINE
#undef NONNULL1
#undef NONNULL2
#undef NONNULL3
#undef NONNULL4
#undef NONNULL5

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __DECAF_255_H__ */

+ 738
- 0
include/decaf_255.hxx View File

@@ -0,0 +1,738 @@
/**
* @file decaf_255.hxx
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief A group of prime order p, C++ wrapper.
*
* The Decaf library implements cryptographic operations on a an elliptic curve
* group of prime order p. It accomplishes this by using a twisted Edwards
* curve (isogenous to Ed255-Goldilocks) and wiping out the cofactor.
*
* The formulas are all complete and have no special cases, except that
* decaf_255_decode can fail because not every sequence of bytes is a valid group
* element.
*
* The formulas contain no data-dependent branches, timing or memory accesses,
* except for decaf_255_base_double_scalarmul_non_secret.
*/
#ifndef __DECAF_255_HXX__
#define __DECAF_255_HXX__ 1

/** This code uses posix_memalign. */
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <string.h> /* for memcpy */

#include "decaf.h"
#include <string>
#include <sys/types.h>
#include <limits.h>

/* TODO: This is incomplete */
/* TODO: attribute nonnull */

/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#define EXPLICIT_CON explicit
#define GET_DATA(str) ((const unsigned char *)&(str)[0])
#else
#define NOEXCEPT throw()
#define EXPLICIT_CON
#define GET_DATA(str) ((const unsigned char *)((str).data()))
#endif
/** @endcond */

namespace decaf {

/** @brief An exception for when crypto (ie point decode) has failed. */
class CryptoException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "CryptoException"; }
};

/** @brief An exception for when crypto (ie point decode) has failed. */
class LengthException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "LengthException"; }
};

/**
* Securely erase contents of memory.
*/
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }

/** Block object */
class Block {
protected:
unsigned char *data_;
size_t size_;

public:
/** Empty init */
inline Block() NOEXCEPT : data_(NULL), size_(0) {}
/** Init from C string */
inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {}

/** Unowned init */
inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {}
/** Block from std::string */
inline Block(const std::string &s) : data_((unsigned char *)GET_DATA(s)), size_(s.size()) {}

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Get the size */
inline size_t size() const NOEXCEPT { return size_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Convert to C++ string */
inline std::string get_string() const {
return std::string((const char *)data_,size_);
}

/** Slice the buffer*/
inline Block slice(size_t off, size_t length) const throw(LengthException) {
if (off > size() || length > size() - off)
throw LengthException();
return Block(data()+off, length);
}

/** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */
inline virtual ~Block() {};
};

class TmpBuffer;

class Buffer : public Block {
public:
/** Null init */
inline Buffer() NOEXCEPT : Block() {}

/** Unowned init */
inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {}

/** Get unconst data */
inline unsigned char *data() NOEXCEPT { return data_; }

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Autocast to unsigned char */
inline operator unsigned char*() NOEXCEPT { return data_; }

/** Slice the buffer*/
inline TmpBuffer slice(size_t off, size_t length) throw(LengthException);
};

class TmpBuffer : public Buffer {
public:
/** Unowned init */
inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {}
};

TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) {
if (off > size() || length > size() - off) throw LengthException();
return TmpBuffer(data()+off, length);
}

/** A self-erasing block of data */
class SecureBuffer : public Buffer {
public:
/** Null secure block */
inline SecureBuffer() NOEXCEPT : Buffer() {}

/** Construct empty from size */
inline SecureBuffer(size_t size) {
data_ = new unsigned char[size_ = size];
memset(data_,0,size);
}

/** Construct from data */
inline SecureBuffer(const unsigned char *data, size_t size){
data_ = new unsigned char[size_ = size];
memcpy(data_, data, size);
}

/** Copy constructor */
inline SecureBuffer(const Block &copy) : Buffer() { *this = copy; }

/** Copy-assign constructor */
inline SecureBuffer& operator=(const Block &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Copy-assign constructor */
inline SecureBuffer& operator=(const SecureBuffer &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Destructor erases data */
~SecureBuffer() NOEXCEPT { clear(); }

/** Clear data */
inline void clear() NOEXCEPT {
if (data_ == NULL) return;
really_bzero(data_,size_);
delete[] data_;
data_ = NULL;
size_ = 0;
}

#if __cplusplus >= 201103L
/** Move constructor */
inline SecureBuffer(SecureBuffer &&move) { *this = move; }

/** Move non-constructor */
inline SecureBuffer(Block &&move) { *this = (Block &)move; }

/** Move-assign constructor. TODO: check that this actually gets used.*/
inline SecureBuffer& operator=(SecureBuffer &&move) {
clear();
data_ = move.data_; move.data_ = NULL;
size_ = move.size_; move.size_ = 0;
return *this;
}

/** C++11-only explicit cast */
inline explicit operator std::string() const { return get_string(); }
#endif
};


/** @brief Passed to constructors to avoid (conservative) initialization */
struct NOINIT {};

/**@cond internal*/
/** Forward-declare sponge RNG object */
class SpongeRng;
/**@endcond*/


/**
* @brief Ed255-Goldilocks/Decaf instantiation of group.
*/
struct Ed255 {

/** @cond internal */
class Point;
class Precomputed;
/** @endcond */

/**
* @brief A scalar modulo the curve order.
* Supports the usual arithmetic operations, all in constant time.
*/
class Scalar {
public:
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_255_SCALAR_BYTES;
/** @brief access to the underlying scalar object */
decaf_255_scalar_t s;
/** @brief Don't initialize. */
inline Scalar(const NOINIT &) NOEXCEPT {}
/** @brief Set to an unsigned word */
inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; }

/** @brief Set to a signed word */
inline Scalar(const int w) NOEXCEPT { *this = w; }
/** @brief Construct from RNG */
inline explicit Scalar(SpongeRng &rng) NOEXCEPT;
/** @brief Construct from decaf_scalar_t object. */
inline Scalar(const decaf_255_scalar_t &t = decaf_255_scalar_zero) NOEXCEPT { decaf_255_scalar_copy(s,t); }
/** @brief Copy constructor. */
inline Scalar(const Scalar &x) NOEXCEPT { *this = x; }
/** @brief Construct from arbitrary-length little-endian byte sequence. */
inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; }
/** @brief Assignment. */
inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_255_scalar_copy(s,x.s); return *this; }
/** @brief Assign from unsigned word. */
inline Scalar& operator=(decaf_word_t w) NOEXCEPT { decaf_255_scalar_set(s,w); return *this; }
/** @brief Assign from signed int. */
inline Scalar& operator=(int w) NOEXCEPT {
Scalar t(-(decaf_word_t)INT_MIN);
decaf_255_scalar_set(s,(decaf_word_t)w - (decaf_word_t)INT_MIN);
*this -= t;
return *this;
}
/** Destructor securely erases the scalar. */
inline ~Scalar() NOEXCEPT { decaf_255_scalar_destroy(s); }
/** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */
inline Scalar &operator=(const Block &bl) NOEXCEPT {
decaf_255_scalar_decode_long(s,bl.data(),bl.size()); return *this;
}
/**
* @brief Decode from correct-length little-endian byte sequence.
* @return DECAF_FAILURE if the scalar is greater than or equal to the group order q.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const unsigned char buffer[SER_BYTES]
) NOEXCEPT {
return decaf_255_scalar_decode(sc.s,buffer);
}
/** @brief Decode from correct-length little-endian byte sequence in C++ string. */
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const Block &buffer
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_255_scalar_decode(sc.s,buffer);
}
/** @brief Encode to fixed-length string */
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
SecureBuffer buf(SER_BYTES); decaf_255_scalar_encode(buf,s); return buf;
}
/** @brief Encode to fixed-length buffer */
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
decaf_255_scalar_encode(buffer, s);
}
/** Add. */
inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_add(r.s,s,q.s); return r; }
/** Add to this. */
inline Scalar &operator+=(const Scalar &q) NOEXCEPT { decaf_255_scalar_add(s,s,q.s); return *this; }
/** Subtract. */
inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_sub(r.s,s,q.s); return r; }
/** Subtract from this. */
inline Scalar &operator-=(const Scalar &q) NOEXCEPT { decaf_255_scalar_sub(s,s,q.s); return *this; }
/** Multiply */
inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_mul(r.s,s,q.s); return r; }
/** Multiply into this. */
inline Scalar &operator*=(const Scalar &q) NOEXCEPT { decaf_255_scalar_mul(s,s,q.s); return *this; }
/** Negate */
inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_sub(r.s,decaf_255_scalar_zero,s); return r; }
/** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */
inline Scalar inverse() const NOEXCEPT { Scalar r; decaf_255_scalar_invert(r.s,s); return r; }
/** @brief Divide by inverting q. If q == 0, return 0. */
inline Scalar operator/ (const Scalar &q) const NOEXCEPT { return *this * q.inverse(); }
/** @brief Divide by inverting q. If q == 0, return 0. */
inline Scalar &operator/=(const Scalar &q) NOEXCEPT { return *this *= q.inverse(); }
/** @brief Compare in constant time */
inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); }
/** @brief Compare in constant time */
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_255_scalar_eq(s,q.s); }
/** @brief Scalarmul with scalar on left. */
inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); }
/** @brief Scalarmul-precomputed with scalar on left. */
inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); }
/** @brief Direct scalar multiplication. */
inline SecureBuffer direct_scalarmul(
const Block &in,
decaf_bool_t allow_identity=DECAF_FALSE,
decaf_bool_t short_circuit=DECAF_TRUE
) const throw(CryptoException) {
SecureBuffer out(/*FIXME Point::*/SER_BYTES);
if (!decaf_255_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit))
throw CryptoException();
return out;
}
};

/**
* @brief Element of prime-order group.
*/
class Point {
public:
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_255_SER_BYTES;
/** @brief Size of a stegged element */
static const size_t STEG_BYTES = DECAF_255_SER_BYTES + 8;
/** @brief Bytes required for hash */
static const size_t HASH_BYTES = DECAF_255_SER_BYTES;
/** The c-level object. */
decaf_255_point_t p;
/** @brief Don't initialize. */
inline Point(const NOINIT &) NOEXCEPT {}
/** @brief Constructor sets to identity by default. */
inline Point(const decaf_255_point_t &q = decaf_255_point_identity) NOEXCEPT { decaf_255_point_copy(p,q); }
/** @brief Copy constructor. */
inline Point(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); }
/** @brief Assignment. */
inline Point& operator=(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); return *this; }
/** @brief Destructor securely erases the point. */
inline ~Point() NOEXCEPT { decaf_255_point_destroy(p); }
/** @brief Construct from RNG */
inline explicit Point(SpongeRng &rng, bool uniform = true) NOEXCEPT;
/**
* @brief Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
*
* @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE.
*/
inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) {
if (!decode(*this,s,allow_identity)) throw CryptoException();
}
/**
* @brief Initialize from C fixed-length byte string.
* The all-zero string maps to the identity.
*
* @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE.
*/
inline explicit Point(const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE)
throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); }
/**
* @brief Initialize from C fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string wasn't the encoding of a point, or was the identity
* and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
return decaf_255_point_decode(p.p,buffer,allow_identity);
}
/**
* @brief Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_255_point_decode(p.p,buffer.data(),allow_identity);
}
/**
* @brief Map uniformly to the curve from a hash buffer.
* The empty or all-zero string maps to the identity, as does the string "\x01".
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
*/
static inline Point from_hash ( const Block &s ) NOEXCEPT {
Point p((NOINIT())); p.set_to_hash(s); return p;
}

/**
* @brief Map to the curve from a hash buffer.
* The empty or all-zero string maps to the identity, as does the string "\x01".
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
*/
inline unsigned char set_to_hash( const Block &s ) NOEXCEPT {
if (s.size() < HASH_BYTES) {
SecureBuffer b(HASH_BYTES);
memcpy(b.data(), s.data(), s.size());
return decaf_255_point_from_hash_nonuniform(p,b);
} else if (s.size() == HASH_BYTES) {
return decaf_255_point_from_hash_nonuniform(p,s);
} else if (s.size() < 2*HASH_BYTES) {
SecureBuffer b(2*HASH_BYTES);
memcpy(b.data(), s.data(), s.size());
return decaf_255_point_from_hash_uniform(p,b);
} else {
return decaf_255_point_from_hash_uniform(p,s);
}
}
/**
* @brief Encode to string. The identity encodes to the all-zero string.
*/
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
SecureBuffer buffer(SER_BYTES);
decaf_255_point_encode(buffer, p);
return buffer;
}
/**
* @brief Encode to a C buffer. The identity encodes to all zeros.
*/
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
decaf_255_point_encode(buffer, p);
}
/** @brief Point add. */
inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_add(r.p,p,q.p); return r; }
/** @brief Point add. */
inline Point &operator+=(const Point &q) NOEXCEPT { decaf_255_point_add(p,p,q.p); return *this; }
/** @brief Point subtract. */
inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_sub(r.p,p,q.p); return r; }
/** @brief Point subtract. */
inline Point &operator-=(const Point &q) NOEXCEPT { decaf_255_point_sub(p,p,q.p); return *this; }
/** @brief Point negate. */
inline Point operator- () const NOEXCEPT { Point r((NOINIT())); decaf_255_point_negate(r.p,p); return r; }
/** @brief Double the point out of place. */
inline Point times_two () const NOEXCEPT { Point r((NOINIT())); decaf_255_point_double(r.p,p); return r; }
/** @brief Double the point in place. */
inline Point &double_in_place() NOEXCEPT { decaf_255_point_double(p,p); return *this; }
/** @brief Constant-time compare. */
inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_255_point_eq(p,q.p); }

/** @brief Constant-time compare. */
inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_255_point_eq(p,q.p); }
/** @brief Scalar multiply. */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_scalarmul(r.p,p,s.s); return r; }
/** @brief Scalar multiply in place. */
inline Point &operator*=(const Scalar &s) NOEXCEPT { decaf_255_point_scalarmul(p,p,s.s); return *this; }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point &operator/=(const Scalar &s) NOEXCEPT { return (*this) *= s.inverse(); }
/** @brief Validate / sanity check */
inline bool validate() const NOEXCEPT { return !!decaf_255_point_valid(p); }
/** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */
static inline Point double_scalarmul (
const Point &q, const Scalar &qs, const Point &r, const Scalar &rs
) NOEXCEPT {
Point p((NOINIT())); decaf_255_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
}
/**
* @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster.
* For those who like their scalars before the point.
*/
static inline Point double_scalarmul (
const Scalar &qs, const Point &q, const Scalar &rs, const Point &r
) NOEXCEPT {
Point p((NOINIT())); decaf_255_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
}
/**
* @brief Double-scalar multiply: this point by the first scalar and base by the second scalar.
* @warning This function takes variable time, and may leak the scalars (or points, but currently
* it doesn't).
*/
inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT {
Point r((NOINIT())); decaf_255_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r;
}
inline Point& debugging_torque_in_place() {
decaf_255_point_debugging_2torque(p,p);
return *this;
}
inline bool invert_elligator (
Buffer &buf, unsigned char hint
) const NOEXCEPT {
unsigned char buf2[2*HASH_BYTES];
memset(buf2,0,sizeof(buf2));
memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
decaf_bool_t ret;
if (buf.size() > HASH_BYTES) {
ret = decaf_255_invert_elligator_uniform(buf2, p, hint);
} else {
ret = decaf_255_invert_elligator_nonuniform(buf2, p, hint);
}
if (buf.size() < HASH_BYTES) {
ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size());
}
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
decaf_bzero(buf2,sizeof(buf2));
return !!ret;
}
/** @brief Steganographically encode this */
inline SecureBuffer steg_encode(SpongeRng &rng) const NOEXCEPT;
/** @brief Return the base point */
static inline const Point base() NOEXCEPT { return Point(decaf_255_point_base); }
/** @brief Return the identity point */
static inline const Point identity() NOEXCEPT { return Point(decaf_255_point_identity); }
};

/**
* @brief Precomputed table of points.
* Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is.
* Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to
* stack-allocate a 15kiB object anyway.
*/
class Precomputed {
private:
/** @cond internal */
union {
decaf_255_precomputed_s *mine;
const decaf_255_precomputed_s *yours;
} ours;
bool isMine;
inline void clear() NOEXCEPT {
if (isMine) {
decaf_255_precomputed_destroy(ours.mine);
free(ours.mine);
ours.yours = decaf_255_precomputed_base;
isMine = false;
}
}
inline void alloc() throw(std::bad_alloc) {
if (isMine) return;
int ret = posix_memalign((void**)&ours.mine, alignof_decaf_255_precomputed_s,sizeof_decaf_255_precomputed_s);
if (ret || !ours.mine) {
isMine = false;
throw std::bad_alloc();
}
isMine = true;
}
inline const decaf_255_precomputed_s *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; }
/** @endcond */
public:
/** Destructor securely erases the memory. */
inline ~Precomputed() NOEXCEPT { clear(); }
/**
* @brief Initialize from underlying type, declared as a reference to prevent
* it from being called with 0, thereby breaking override.
*
* The underlying object must remain valid throughout the lifetime of this one.
*
* By default, initializes to the table for the base point.
*
* @warning The empty initializer makes this equal to base, unlike the empty
* initializer for points which makes this equal to the identity.
*/
inline Precomputed(
const decaf_255_precomputed_s &yours = *decaf_255_precomputed_base
) NOEXCEPT {
ours.yours = &yours;
isMine = false;
}
/**
* @brief Assign. This may require an allocation and memcpy.
*/
inline Precomputed &operator=(const Precomputed &it) throw(std::bad_alloc) {
if (this == &it) return *this;
if (it.isMine) {
alloc();
memcpy(ours.mine,it.ours.mine,sizeof_decaf_255_precomputed_s);
} else {
clear();
ours.yours = it.ours.yours;
}
isMine = it.isMine;
return *this;
}
/**
* @brief Initilaize from point. Must allocate memory, and may throw.
*/
inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) {
alloc();
decaf_255_precompute(ours.mine,it.p);
return *this;
}
/**
* @brief Copy constructor.
*/
inline Precomputed(const Precomputed &it) throw(std::bad_alloc) : isMine(false) { *this = it; }
/**
* @brief Constructor which initializes from point.
*/
inline explicit Precomputed(const Point &it) throw(std::bad_alloc) : isMine(false) { *this = it; }
#if __cplusplus >= 201103L
inline Precomputed &operator=(Precomputed &&it) NOEXCEPT {
if (this == &it) return *this;
clear();
ours = it.ours;
isMine = it.isMine;
it.isMine = false;
it.ours.yours = decaf_255_precomputed_base;
return *this;
}
inline Precomputed(Precomputed &&it) NOEXCEPT : isMine(false) { *this = it; }
#endif
/** @brief Fixed base scalarmul. */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_255_precomputed_scalarmul(r.p,get(),s.s); return r; }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); }
/** @brief Return the table for the base point. */
static inline const Precomputed base() NOEXCEPT { return Precomputed(*decaf_255_precomputed_base); }
};

}; /* struct Decaf255 */

#undef NOEXCEPT
#undef EXPLICIT_CON
#undef GET_DATA
} /* namespace decaf */

#endif /* __DECAF_255_HXX__ */

+ 651
- 0
include/decaf_448.h View File

@@ -0,0 +1,651 @@
/**
* @file decaf_448.h
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief A group of prime order p.
*
* The Decaf library implements cryptographic operations on a an elliptic curve
* group of prime order p. It accomplishes this by using a twisted Edwards
* curve (isogenous to Ed448-Goldilocks) and wiping out the cofactor.
*
* The formulas are all complete and have no special cases, except that
* decaf_448_decode can fail because not every sequence of bytes is a valid group
* element.
*
* The formulas contain no data-dependent branches, timing or memory accesses,
* except for decaf_448_base_double_scalarmul_non_secret.
*
* This library may support multiple curves eventually. The Ed448-Goldilocks
* specific identifiers are prefixed with DECAF_448 or decaf_448.
*/
#ifndef __DECAF_448_H__
#define __DECAF_448_H__ 1

#include <stdint.h>
#include <sys/types.h>

/* Goldilocks' build flags default to hidden and stripping executables. */
/** @cond internal */
#if defined(DOXYGEN) && !defined(__attribute__)
#define __attribute__((x))
#endif
#define API_VIS __attribute__((visibility("default")))
#define NOINLINE __attribute__((noinline))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
#define NONNULL4 __attribute__((nonnull(1,2,3,4)))
#define NONNULL5 __attribute__((nonnull(1,2,3,4,5)))

/* Internal word types */
#if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \
&& !defined(DECAF_FORCE_32_BIT)
#define DECAF_WORD_BITS 64
typedef uint64_t decaf_word_t, decaf_bool_t;
typedef __uint128_t decaf_dword_t;
#else
#define DECAF_WORD_BITS 32
typedef uint32_t decaf_word_t, decaf_bool_t;
typedef uint64_t decaf_dword_t;
#endif

#define DECAF_448_LIMBS (512/DECAF_WORD_BITS)
#define DECAF_448_SCALAR_BITS 446
#define DECAF_448_SCALAR_LIMBS (448/DECAF_WORD_BITS)

/** Galois field element internal structure */
typedef struct gf_s {
decaf_word_t limb[DECAF_448_LIMBS];
} __attribute__((aligned(32))) gf_s, gf[1];
/** @endcond */

/** Number of bytes in a serialized point. */
#define DECAF_448_SER_BYTES 56

/** Number of bytes in a serialized scalar. */
#define DECAF_448_SCALAR_BYTES 56

/** Twisted Edwards (-1,d-1) extended homogeneous coordinates */
typedef struct decaf_448_point_s { /**@cond internal*/gf x,y,z,t;/**@endcond*/ } decaf_448_point_t[1];

/** Precomputed table based on a point. Can be trivial implementation. */
struct decaf_448_precomputed_s;

/** Precomputed table based on a point. Can be trivial implementation. */
typedef struct decaf_448_precomputed_s decaf_448_precomputed_s;

/** Size and alignment of precomputed point tables. */
extern const size_t sizeof_decaf_448_precomputed_s API_VIS, alignof_decaf_448_precomputed_s API_VIS;

/** Scalar is stored packed, because we don't need the speed. */
typedef struct decaf_448_scalar_s {
/** @cond internal */
decaf_word_t limb[DECAF_448_SCALAR_LIMBS];
/** @endcond */
} decaf_448_scalar_t[1];

/** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0;

/** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */
static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/,
DECAF_FAILURE = 0 /*DECAF_FALSE*/;

/** A scalar equal to 1. */
extern const decaf_448_scalar_t decaf_448_scalar_one API_VIS;

/** A scalar equal to 0. */
extern const decaf_448_scalar_t decaf_448_scalar_zero API_VIS;

/** The identity point on the curve. */
extern const decaf_448_point_t decaf_448_point_identity API_VIS;

/**
* An arbitrarily chosen base point on the curve.
* Equal to Ed448-Goldilocks base point defined by DJB, except of course that
* it's on the twist in this case. TODO: choose a base point with nice encoding?
*/
extern const decaf_448_point_t decaf_448_point_base API_VIS;

/** Precomputed table for the base point on the curve. */
extern const struct decaf_448_precomputed_s *decaf_448_precomputed_base API_VIS;

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Read a scalar from wire format or from bytes.
*
* @param [in] ser Serialized form of a scalar.
* @param [out] out Deserialized form.
*
* @retval DECAF_SUCCESS The scalar was correctly encoded.
* @retval DECAF_FAILURE The scalar was greater than the modulus,
* and has been reduced modulo that modulus.
*/
decaf_bool_t decaf_448_scalar_decode (
decaf_448_scalar_t out,
const unsigned char ser[DECAF_448_SCALAR_BYTES]
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Read a scalar from wire format or from bytes. Reduces mod
* scalar prime.
*
* @param [in] ser Serialized form of a scalar.
* @param [in] ser_len Length of serialized form.
* @param [out] out Deserialized form.
*/
void decaf_448_scalar_decode_long (
decaf_448_scalar_t out,
const unsigned char *ser,
size_t ser_len
) API_VIS NONNULL2 NOINLINE;
/**
* @brief Serialize a scalar to wire format.
*
* @param [out] ser Serialized form of a scalar.
* @param [in] s Deserialized scalar.
*/
void decaf_448_scalar_encode (
unsigned char ser[DECAF_448_SCALAR_BYTES],
const decaf_448_scalar_t s
) API_VIS NONNULL2 NOINLINE NOINLINE;
/**
* @brief Add two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a+b.
*/
void decaf_448_scalar_add (
decaf_448_scalar_t out,
const decaf_448_scalar_t a,
const decaf_448_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Compare two scalars.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @retval DECAF_TRUE The scalars are equal.
* @retval DECAF_FALSE The scalars are not equal.
*/
decaf_bool_t decaf_448_scalar_eq (
const decaf_448_scalar_t a,
const decaf_448_scalar_t b
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Subtract two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a-b.
*/
void decaf_448_scalar_sub (
decaf_448_scalar_t out,
const decaf_448_scalar_t a,
const decaf_448_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @param [out] out a*b.
*/
void decaf_448_scalar_mul (
decaf_448_scalar_t out,
const decaf_448_scalar_t a,
const decaf_448_scalar_t b
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Invert a scalar. When passed zero, return 0. The input and output may alias.
* @param [in] a A scalar.
* @param [out] out 1/a.
* @return DECAF_TRUE The input is nonzero.
*/
decaf_bool_t decaf_448_scalar_invert (
decaf_448_scalar_t out,
const decaf_448_scalar_t a
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Copy a scalar. The scalars may use the same memory, in which
* case this function does nothing.
* @param [in] a A scalar.
* @param [out] out Will become a copy of a.
*/
static inline void NONNULL2 decaf_448_scalar_copy (
decaf_448_scalar_t out,
const decaf_448_scalar_t a
) {
*out = *a;
}

/**
* @brief Set a scalar to an integer.
* @param [in] a An integer.
* @param [out] out Will become equal to a.
* @todo Make inline?
*/
void decaf_448_scalar_set(
decaf_448_scalar_t out,
decaf_word_t a
) API_VIS NONNULL1;

/**
* @brief Encode a point as a sequence of bytes.
*
* @param [out] ser The byte representation of the point.
* @param [in] pt The point to encode.
*/
void decaf_448_point_encode (
uint8_t ser[DECAF_448_SER_BYTES],
const decaf_448_point_t pt
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Decode a point from a sequence of bytes.
*
* Every point has a unique encoding, so not every
* sequence of bytes is a valid encoding. If an invalid
* encoding is given, the output is undefined.
*
* @param [out] pt The decoded point.
* @param [in] ser The serialized version of the point.
* @param [in] allow_identity DECAF_TRUE if the identity is a legal input.
* @retval DECAF_SUCCESS The decoding succeeded.
* @retval DECAF_FAILURE The decoding didn't succeed, because
* ser does not represent a point.
*/
decaf_bool_t decaf_448_point_decode (
decaf_448_point_t pt,
const uint8_t ser[DECAF_448_SER_BYTES],
decaf_bool_t allow_identity
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Copy a point. The input and output may alias,
* in which case this function does nothing.
*
* @param [out] a A copy of the point.
* @param [in] b Any point.
*/
static inline void NONNULL2 decaf_448_point_copy (
decaf_448_point_t a,
const decaf_448_point_t b
) {
*a=*b;
}

/**
* @brief Test whether two points are equal. If yes, return
* DECAF_TRUE, else return DECAF_FALSE.
*
* @param [in] a A point.
* @param [in] b Another point.
* @retval DECAF_TRUE The points are equal.
* @retval DECAF_FALSE The points are not equal.
*/
decaf_bool_t decaf_448_point_eq (
const decaf_448_point_t a,
const decaf_448_point_t b
) API_VIS WARN_UNUSED NONNULL2 NOINLINE;

/**
* @brief Add two points to produce a third point. The
* input points and output point can be pointers to the same
* memory.
*
* @param [out] sum The sum a+b.
* @param [in] a An addend.
* @param [in] b An addend.
*/
void decaf_448_point_add (
decaf_448_point_t sum,
const decaf_448_point_t a,
const decaf_448_point_t b
) API_VIS NONNULL3;

/**
* @brief Double a point. Equivalent to
* decaf_448_point_add(two_a,a,a), but potentially faster.
*
* @param [out] two_a The sum a+a.
* @param [in] a A point.
*/
void decaf_448_point_double (
decaf_448_point_t two_a,
const decaf_448_point_t a
) API_VIS NONNULL2;

/**
* @brief Subtract two points to produce a third point. The
* input points and output point can be pointers to the same
* memory.
*
* @param [out] diff The difference a-b.
* @param [in] a The minuend.
* @param [in] b The subtrahend.
*/
void decaf_448_point_sub (
decaf_448_point_t diff,
const decaf_448_point_t a,
const decaf_448_point_t b
) API_VIS NONNULL3;
/**
* @brief Negate a point to produce another point. The input
* and output points can use the same memory.
*
* @param [out] nega The negated input point
* @param [in] a The input point.
*/
void decaf_448_point_negate (
decaf_448_point_t nega,
const decaf_448_point_t a
) API_VIS NONNULL2;

/**
* @brief Multiply a base point by a scalar: scaled = scalar*base.
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
*/
void decaf_448_point_scalarmul (
decaf_448_point_t scaled,
const decaf_448_point_t base,
const decaf_448_scalar_t scalar
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply a base point by a scalar: scaled = scalar*base.
* This function operates directly on serialized forms.
*
* @warning This function is experimental. It may not be supported
* long-term.
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
* @param [in] allow_identity Allow the input to be the identity.
* @param [in] short_circuit Allow a fast return if the input is illegal.
*
* @retval DECAF_SUCCESS The scalarmul succeeded.
* @retval DECAF_FAILURE The scalarmul didn't succeed, because
* base does not represent a point.
*/
decaf_bool_t decaf_448_direct_scalarmul (
uint8_t scaled[DECAF_448_SER_BYTES],
const uint8_t base[DECAF_448_SER_BYTES],
const decaf_448_scalar_t scalar,
decaf_bool_t allow_identity,
decaf_bool_t short_circuit
) API_VIS NONNULL3 WARN_UNUSED NOINLINE;

/**
* @brief Precompute a table for fast scalar multiplication.
* Some implementations do not include precomputed points; for
* those implementations, this implementation simply copies the
* point.
*
* @param [out] a A precomputed table of multiples of the point.
* @param [in] b Any point.
*/
void decaf_448_precompute (
decaf_448_precomputed_s *a,
const decaf_448_point_t b
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Multiply a precomputed base point by a scalar:
* scaled = scalar*base.
* Some implementations do not include precomputed points; for
* those implementations, this function is the same as
* decaf_448_point_scalarmul
*
* @param [out] scaled The scaled point base*scalar
* @param [in] base The point to be scaled.
* @param [in] scalar The scalar to multiply by.
*
* @todo precomputed dsmul? const or variable time?
*/
void decaf_448_precomputed_scalarmul (
decaf_448_point_t scaled,
const decaf_448_precomputed_s *base,
const decaf_448_scalar_t scalar
) API_VIS NONNULL3 NOINLINE;

/**
* @brief Multiply two base points by two scalars:
* scaled = scalar1*base1 + scalar2*base2.
*
* Equivalent to two calls to decaf_448_point_scalarmul, but may be
* faster.
*
* @param [out] combo The linear combination scalar1*base1 + scalar2*base2.
* @param [in] base1 A first point to be scaled.
* @param [in] scalar1 A first scalar to multiply by.
* @param [in] base2 A second point to be scaled.
* @param [in] scalar2 A second scalar to multiply by.
*/
void decaf_448_point_double_scalarmul (
decaf_448_point_t combo,
const decaf_448_point_t base1,
const decaf_448_scalar_t scalar1,
const decaf_448_point_t base2,
const decaf_448_scalar_t scalar2
) API_VIS NONNULL5 NOINLINE;

/**
* @brief Multiply two base points by two scalars:
* scaled = scalar1*decaf_448_point_base + scalar2*base2.
*
* Otherwise equivalent to decaf_448_point_double_scalarmul, but may be
* faster at the expense of being variable time.
*
* @param [out] combo The linear combination scalar1*base + scalar2*base2.
* @param [in] scalar1 A first scalar to multiply by.
* @param [in] base2 A second point to be scaled.
* @param [in] scalar2 A second scalar to multiply by.
*
* @warning: This function takes variable time, and may leak the scalars
* used. It is designed for signature verification.
*/
void decaf_448_base_double_scalarmul_non_secret (
decaf_448_point_t combo,
const decaf_448_scalar_t scalar1,
const decaf_448_point_t base2,
const decaf_448_scalar_t scalar2
) API_VIS NONNULL4 NOINLINE;

/**
* @brief Test that a point is valid, for debugging purposes.
*
* @param [in] toTest The point to test.
* @retval DECAF_TRUE The point is valid.
* @retval DECAF_FALSE The point is invalid.
*/
decaf_bool_t decaf_448_point_valid (
const decaf_448_point_t toTest
) API_VIS WARN_UNUSED NONNULL1 NOINLINE;

/**
* @brief 2-torque a point, for debugging purposes.
*
* @param [out] q The point to torque.
* @param [in] p The point to torque.
*/
void decaf_448_point_debugging_2torque (
decaf_448_point_t q,
const decaf_448_point_t p
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Almost-Elligator-like hash to curve.
*
* Call this function with the output of a hash to make a hash to the curve.
*
* This function runs Elligator2 on the decaf_448 Jacobi quartic model. It then
* uses the isogeny to put the result in twisted Edwards form. As a result,
* it is safe (cannot produce points of order 4), and would be compatible with
* hypothetical other implementations of Decaf using a Montgomery or untwisted
* Edwards model.
*
* Unlike Elligator, this function may be up to 4:1 on [0,(p-1)/2]:
* A factor of 2 due to the isogeny.
* A factor of 2 because we quotient out the 2-torsion.
*
* This makes it about 8:1 overall.
*
* Negating the input (mod q) results in the same point. Inverting the input
* (mod q) results in the negative point. This is the same as Elligator.
*
* This function isn't quite indifferentiable from a random oracle.
* However, it is suitable for many protocols, including SPEKE and SPAKE2 EE.
* Furthermore, calling it twice with independent seeds and adding the results
* is indifferentiable from a random oracle.
*
* @param [in] hashed_data Output of some hash function.
* @param [out] pt The data hashed to the curve.
* @return A "hint" value which can be used to help invert the encoding.
*/
unsigned char
decaf_448_point_from_hash_nonuniform (
decaf_448_point_t pt,
const unsigned char hashed_data[DECAF_448_SER_BYTES]
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Inverse of elligator-like hash to curve.
*
* This function writes to the buffer, to make it so that
* decaf_448_point_from_hash_nonuniform(buffer) = pt,hint
* if possible.
*
* @param [out] recovered_hash Encoded data.
* @param [in] pt The point to encode.
* @param [in] hint The hint value returned from
* decaf_448_point_from_hash_nonuniform.
*
* @retval DECAF_SUCCESS The inverse succeeded.
* @retval DECAF_FAILURE The pt isn't the image of
* decaf_448_point_from_hash_nonuniform with the given hint.
*
* @warning The hinting system is subject to change, especially in corner cases.
* @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF.
*/
decaf_bool_t
decaf_448_invert_elligator_nonuniform (
unsigned char recovered_hash[DECAF_448_SER_BYTES],
const decaf_448_point_t pt,
unsigned char hint
) API_VIS NONNULL2 NOINLINE WARN_UNUSED;

/**
* @brief Inverse of elligator-like hash to curve, uniform.
*
* This function modifies the first DECAF_448_SER_BYTES of the
* buffer, to make it so that
* decaf_448_point_from_hash_uniform(buffer) = pt,hint
* if possible.
*
* @param [out] recovered_hash Encoded data.
* @param [in] pt The point to encode.
* @param [in] hint The hint value returned from
* decaf_448_point_from_hash_nonuniform.
*
* @retval DECAF_SUCCESS The inverse succeeded.
* @retval DECAF_FAILURE The pt isn't the image of
* decaf_448_point_from_hash_uniform with the given hint.
*
* @warning The hinting system is subject to change, especially in corner cases.
* @warning FIXME The hinting system doesn't work for certain inputs which have many 0xFF.
*/
decaf_bool_t
decaf_448_invert_elligator_uniform (
unsigned char recovered_hash[2*DECAF_448_SER_BYTES],
const decaf_448_point_t pt,
unsigned char hint
) API_VIS NONNULL2 NOINLINE WARN_UNUSED;

/**
* @brief Indifferentiable hash function encoding to curve.
*
* Equivalent to calling decaf_448_point_from_hash_nonuniform twice and adding.
*
* @param [in] hashed_data Output of some hash function.
* @param [out] pt The data hashed to the curve.
* @return A "hint" value which can be used to help invert the encoding.
*/
unsigned char decaf_448_point_from_hash_uniform (
decaf_448_point_t pt,
const unsigned char hashed_data[2*DECAF_448_SER_BYTES]
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Overwrite data with zeros. Uses memset_s if available.
*/
void decaf_bzero (
void *data,
size_t size
) NONNULL1 API_VIS NOINLINE;

/**
* @brief Compare two buffers, returning DECAF_TRUE if they are equal.
*/
decaf_bool_t decaf_memeq (
const void *data1,
const void *data2,
size_t size
) NONNULL2 WARN_UNUSED API_VIS NOINLINE;

/**
* @brief Overwrite scalar with zeros.
*/
void decaf_448_scalar_destroy (
decaf_448_scalar_t scalar
) NONNULL1 API_VIS;

/**
* @brief Overwrite point with zeros.
* @todo Use this internally.
*/
void decaf_448_point_destroy (
decaf_448_point_t point
) NONNULL1 API_VIS;

/**
* @brief Overwrite point with zeros.
* @todo Use this internally.
*/
void decaf_448_precomputed_destroy (
decaf_448_precomputed_s *pre
) NONNULL1 API_VIS;

/* TODO: functions to invert point_from_hash?? */

#undef API_VIS
#undef WARN_UNUSED
#undef NOINLINE
#undef NONNULL1
#undef NONNULL2
#undef NONNULL3
#undef NONNULL4
#undef NONNULL5

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __DECAF_448_H__ */

+ 738
- 0
include/decaf_448.hxx View File

@@ -0,0 +1,738 @@
/**
* @file decaf_448.hxx
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief A group of prime order p, C++ wrapper.
*
* The Decaf library implements cryptographic operations on a an elliptic curve
* group of prime order p. It accomplishes this by using a twisted Edwards
* curve (isogenous to Ed448-Goldilocks) and wiping out the cofactor.
*
* The formulas are all complete and have no special cases, except that
* decaf_448_decode can fail because not every sequence of bytes is a valid group
* element.
*
* The formulas contain no data-dependent branches, timing or memory accesses,
* except for decaf_448_base_double_scalarmul_non_secret.
*/
#ifndef __DECAF_448_HXX__
#define __DECAF_448_HXX__ 1

/** This code uses posix_memalign. */
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <string.h> /* for memcpy */

#include "decaf.h"
#include <string>
#include <sys/types.h>
#include <limits.h>

/* TODO: This is incomplete */
/* TODO: attribute nonnull */

/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#define EXPLICIT_CON explicit
#define GET_DATA(str) ((const unsigned char *)&(str)[0])
#else
#define NOEXCEPT throw()
#define EXPLICIT_CON
#define GET_DATA(str) ((const unsigned char *)((str).data()))
#endif
/** @endcond */

namespace decaf {

/** @brief An exception for when crypto (ie point decode) has failed. */
class CryptoException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "CryptoException"; }
};

/** @brief An exception for when crypto (ie point decode) has failed. */
class LengthException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "LengthException"; }
};

/**
* Securely erase contents of memory.
*/
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }

/** Block object */
class Block {
protected:
unsigned char *data_;
size_t size_;

public:
/** Empty init */
inline Block() NOEXCEPT : data_(NULL), size_(0) {}
/** Init from C string */
inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {}

/** Unowned init */
inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {}
/** Block from std::string */
inline Block(const std::string &s) : data_((unsigned char *)GET_DATA(s)), size_(s.size()) {}

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Get the size */
inline size_t size() const NOEXCEPT { return size_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Convert to C++ string */
inline std::string get_string() const {
return std::string((const char *)data_,size_);
}

/** Slice the buffer*/
inline Block slice(size_t off, size_t length) const throw(LengthException) {
if (off > size() || length > size() - off)
throw LengthException();
return Block(data()+off, length);
}

/** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */
inline virtual ~Block() {};
};

class TmpBuffer;

class Buffer : public Block {
public:
/** Null init */
inline Buffer() NOEXCEPT : Block() {}

/** Unowned init */
inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {}

/** Get unconst data */
inline unsigned char *data() NOEXCEPT { return data_; }

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Autocast to unsigned char */
inline operator unsigned char*() NOEXCEPT { return data_; }

/** Slice the buffer*/
inline TmpBuffer slice(size_t off, size_t length) throw(LengthException);
};

class TmpBuffer : public Buffer {
public:
/** Unowned init */
inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {}
};

TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) {
if (off > size() || length > size() - off) throw LengthException();
return TmpBuffer(data()+off, length);
}

/** A self-erasing block of data */
class SecureBuffer : public Buffer {
public:
/** Null secure block */
inline SecureBuffer() NOEXCEPT : Buffer() {}

/** Construct empty from size */
inline SecureBuffer(size_t size) {
data_ = new unsigned char[size_ = size];
memset(data_,0,size);
}

/** Construct from data */
inline SecureBuffer(const unsigned char *data, size_t size){
data_ = new unsigned char[size_ = size];
memcpy(data_, data, size);
}

/** Copy constructor */
inline SecureBuffer(const Block &copy) : Buffer() { *this = copy; }

/** Copy-assign constructor */
inline SecureBuffer& operator=(const Block &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Copy-assign constructor */
inline SecureBuffer& operator=(const SecureBuffer &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Destructor erases data */
~SecureBuffer() NOEXCEPT { clear(); }

/** Clear data */
inline void clear() NOEXCEPT {
if (data_ == NULL) return;
really_bzero(data_,size_);
delete[] data_;
data_ = NULL;
size_ = 0;
}

#if __cplusplus >= 201103L
/** Move constructor */
inline SecureBuffer(SecureBuffer &&move) { *this = move; }

/** Move non-constructor */
inline SecureBuffer(Block &&move) { *this = (Block &)move; }

/** Move-assign constructor. TODO: check that this actually gets used.*/
inline SecureBuffer& operator=(SecureBuffer &&move) {
clear();
data_ = move.data_; move.data_ = NULL;
size_ = move.size_; move.size_ = 0;
return *this;
}

/** C++11-only explicit cast */
inline explicit operator std::string() const { return get_string(); }
#endif
};


/** @brief Passed to constructors to avoid (conservative) initialization */
struct NOINIT {};

/**@cond internal*/
/** Forward-declare sponge RNG object */
class SpongeRng;
/**@endcond*/


/**
* @brief Ed448-Goldilocks/Decaf instantiation of group.
*/
struct Ed448 {

/** @cond internal */
class Point;
class Precomputed;
/** @endcond */

/**
* @brief A scalar modulo the curve order.
* Supports the usual arithmetic operations, all in constant time.
*/
class Scalar {
public:
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_448_SCALAR_BYTES;
/** @brief access to the underlying scalar object */
decaf_448_scalar_t s;
/** @brief Don't initialize. */
inline Scalar(const NOINIT &) NOEXCEPT {}
/** @brief Set to an unsigned word */
inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; }

/** @brief Set to a signed word */
inline Scalar(const int w) NOEXCEPT { *this = w; }
/** @brief Construct from RNG */
inline explicit Scalar(SpongeRng &rng) NOEXCEPT;
/** @brief Construct from decaf_scalar_t object. */
inline Scalar(const decaf_448_scalar_t &t = decaf_448_scalar_zero) NOEXCEPT { decaf_448_scalar_copy(s,t); }
/** @brief Copy constructor. */
inline Scalar(const Scalar &x) NOEXCEPT { *this = x; }
/** @brief Construct from arbitrary-length little-endian byte sequence. */
inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; }
/** @brief Assignment. */
inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; }
/** @brief Assign from unsigned word. */
inline Scalar& operator=(decaf_word_t w) NOEXCEPT { decaf_448_scalar_set(s,w); return *this; }
/** @brief Assign from signed int. */
inline Scalar& operator=(int w) NOEXCEPT {
Scalar t(-(decaf_word_t)INT_MIN);
decaf_448_scalar_set(s,(decaf_word_t)w - (decaf_word_t)INT_MIN);
*this -= t;
return *this;
}
/** Destructor securely erases the scalar. */
inline ~Scalar() NOEXCEPT { decaf_448_scalar_destroy(s); }
/** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */
inline Scalar &operator=(const Block &bl) NOEXCEPT {
decaf_448_scalar_decode_long(s,bl.data(),bl.size()); return *this;
}
/**
* @brief Decode from correct-length little-endian byte sequence.
* @return DECAF_FAILURE if the scalar is greater than or equal to the group order q.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const unsigned char buffer[SER_BYTES]
) NOEXCEPT {
return decaf_448_scalar_decode(sc.s,buffer);
}
/** @brief Decode from correct-length little-endian byte sequence in C++ string. */
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const Block &buffer
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_448_scalar_decode(sc.s,buffer);
}
/** @brief Encode to fixed-length string */
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
SecureBuffer buf(SER_BYTES); decaf_448_scalar_encode(buf,s); return buf;
}
/** @brief Encode to fixed-length buffer */
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
decaf_448_scalar_encode(buffer, s);
}
/** Add. */
inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_add(r.s,s,q.s); return r; }
/** Add to this. */
inline Scalar &operator+=(const Scalar &q) NOEXCEPT { decaf_448_scalar_add(s,s,q.s); return *this; }
/** Subtract. */
inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_sub(r.s,s,q.s); return r; }
/** Subtract from this. */
inline Scalar &operator-=(const Scalar &q) NOEXCEPT { decaf_448_scalar_sub(s,s,q.s); return *this; }
/** Multiply */
inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_mul(r.s,s,q.s); return r; }
/** Multiply into this. */
inline Scalar &operator*=(const Scalar &q) NOEXCEPT { decaf_448_scalar_mul(s,s,q.s); return *this; }
/** Negate */
inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_sub(r.s,decaf_448_scalar_zero,s); return r; }
/** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */
inline Scalar inverse() const NOEXCEPT { Scalar r; decaf_448_scalar_invert(r.s,s); return r; }
/** @brief Divide by inverting q. If q == 0, return 0. */
inline Scalar operator/ (const Scalar &q) const NOEXCEPT { return *this * q.inverse(); }
/** @brief Divide by inverting q. If q == 0, return 0. */
inline Scalar &operator/=(const Scalar &q) NOEXCEPT { return *this *= q.inverse(); }
/** @brief Compare in constant time */
inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); }
/** @brief Compare in constant time */
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_448_scalar_eq(s,q.s); }
/** @brief Scalarmul with scalar on left. */
inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); }
/** @brief Scalarmul-precomputed with scalar on left. */
inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); }
/** @brief Direct scalar multiplication. */
inline SecureBuffer direct_scalarmul(
const Block &in,
decaf_bool_t allow_identity=DECAF_FALSE,
decaf_bool_t short_circuit=DECAF_TRUE
) const throw(CryptoException) {
SecureBuffer out(/*FIXME Point::*/SER_BYTES);
if (!decaf_448_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit))
throw CryptoException();
return out;
}
};

/**
* @brief Element of prime-order group.
*/
class Point {
public:
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_448_SER_BYTES;
/** @brief Size of a stegged element */
static const size_t STEG_BYTES = DECAF_448_SER_BYTES + 8;
/** @brief Bytes required for hash */
static const size_t HASH_BYTES = DECAF_448_SER_BYTES;
/** The c-level object. */
decaf_448_point_t p;
/** @brief Don't initialize. */
inline Point(const NOINIT &) NOEXCEPT {}
/** @brief Constructor sets to identity by default. */
inline Point(const decaf_448_point_t &q = decaf_448_point_identity) NOEXCEPT { decaf_448_point_copy(p,q); }
/** @brief Copy constructor. */
inline Point(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); }
/** @brief Assignment. */
inline Point& operator=(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); return *this; }
/** @brief Destructor securely erases the point. */
inline ~Point() NOEXCEPT { decaf_448_point_destroy(p); }
/** @brief Construct from RNG */
inline explicit Point(SpongeRng &rng, bool uniform = true) NOEXCEPT;
/**
* @brief Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
*
* @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE.
*/
inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) {
if (!decode(*this,s,allow_identity)) throw CryptoException();
}
/**
* @brief Initialize from C fixed-length byte string.
* The all-zero string maps to the identity.
*
* @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE.
*/
inline explicit Point(const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE)
throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); }
/**
* @brief Initialize from C fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string wasn't the encoding of a point, or was the identity
* and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
return decaf_448_point_decode(p.p,buffer,allow_identity);
}
/**
* @brief Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point,
* or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_448_point_decode(p.p,buffer.data(),allow_identity);
}
/**
* @brief Map uniformly to the curve from a hash buffer.
* The empty or all-zero string maps to the identity, as does the string "\x01".
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
*/
static inline Point from_hash ( const Block &s ) NOEXCEPT {
Point p((NOINIT())); p.set_to_hash(s); return p;
}

/**
* @brief Map to the curve from a hash buffer.
* The empty or all-zero string maps to the identity, as does the string "\x01".
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
*/
inline unsigned char set_to_hash( const Block &s ) NOEXCEPT {
if (s.size() < HASH_BYTES) {
SecureBuffer b(HASH_BYTES);
memcpy(b.data(), s.data(), s.size());
return decaf_448_point_from_hash_nonuniform(p,b);
} else if (s.size() == HASH_BYTES) {
return decaf_448_point_from_hash_nonuniform(p,s);
} else if (s.size() < 2*HASH_BYTES) {
SecureBuffer b(2*HASH_BYTES);
memcpy(b.data(), s.data(), s.size());
return decaf_448_point_from_hash_uniform(p,b);
} else {
return decaf_448_point_from_hash_uniform(p,s);
}
}
/**
* @brief Encode to string. The identity encodes to the all-zero string.
*/
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
SecureBuffer buffer(SER_BYTES);
decaf_448_point_encode(buffer, p);
return buffer;
}
/**
* @brief Encode to a C buffer. The identity encodes to all zeros.
*/
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
decaf_448_point_encode(buffer, p);
}
/** @brief Point add. */
inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_add(r.p,p,q.p); return r; }
/** @brief Point add. */
inline Point &operator+=(const Point &q) NOEXCEPT { decaf_448_point_add(p,p,q.p); return *this; }
/** @brief Point subtract. */
inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_sub(r.p,p,q.p); return r; }
/** @brief Point subtract. */
inline Point &operator-=(const Point &q) NOEXCEPT { decaf_448_point_sub(p,p,q.p); return *this; }
/** @brief Point negate. */
inline Point operator- () const NOEXCEPT { Point r((NOINIT())); decaf_448_point_negate(r.p,p); return r; }
/** @brief Double the point out of place. */
inline Point times_two () const NOEXCEPT { Point r((NOINIT())); decaf_448_point_double(r.p,p); return r; }
/** @brief Double the point in place. */
inline Point &double_in_place() NOEXCEPT { decaf_448_point_double(p,p); return *this; }
/** @brief Constant-time compare. */
inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_448_point_eq(p,q.p); }

/** @brief Constant-time compare. */
inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_448_point_eq(p,q.p); }
/** @brief Scalar multiply. */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); decaf_448_point_scalarmul(r.p,p,s.s); return r; }
/** @brief Scalar multiply in place. */
inline Point &operator*=(const Scalar &s) NOEXCEPT { decaf_448_point_scalarmul(p,p,s.s); return *this; }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point &operator/=(const Scalar &s) NOEXCEPT { return (*this) *= s.inverse(); }
/** @brief Validate / sanity check */
inline bool validate() const NOEXCEPT { return !!decaf_448_point_valid(p); }
/** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */
static inline Point double_scalarmul (
const Point &q, const Scalar &qs, const Point &r, const Scalar &rs
) NOEXCEPT {
Point p((NOINIT())); decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
}
/**
* @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster.
* For those who like their scalars before the point.
*/
static inline Point double_scalarmul (
const Scalar &qs, const Point &q, const Scalar &rs, const Point &r
) NOEXCEPT {
Point p((NOINIT())); decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
}
/**
* @brief Double-scalar multiply: this point by the first scalar and base by the second scalar.
* @warning This function takes variable time, and may leak the scalars (or points, but currently
* it doesn't).
*/
inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT {
Point r((NOINIT())); decaf_448_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r;
}
inline Point& debugging_torque_in_place() {
decaf_448_point_debugging_2torque(p,p);
return *this;
}
inline bool invert_elligator (
Buffer &buf, unsigned char hint
) const NOEXCEPT {
unsigned char buf2[2*HASH_BYTES];
memset(buf2,0,sizeof(buf2));
memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
decaf_bool_t ret;
if (buf.size() > HASH_BYTES) {
ret = decaf_448_invert_elligator_uniform(buf2, p, hint);
} else {
ret = decaf_448_invert_elligator_nonuniform(buf2, p, hint);
}
if (buf.size() < HASH_BYTES) {
ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size());
}
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
decaf_bzero(buf2,sizeof(buf2));
return !!ret;
}
/** @brief Steganographically encode this */
inline SecureBuffer steg_encode(SpongeRng &rng) const NOEXCEPT;
/** @brief Return the base point */
static inline const Point base() NOEXCEPT { return Point(decaf_448_point_base); }
/** @brief Return the identity point */
static inline const Point identity() NOEXCEPT { return Point(decaf_448_point_identity); }
};

/**
* @brief Precomputed table of points.
* Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is.
* Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to
* stack-allocate a 15kiB object anyway.
*/
class Precomputed {
private:
/** @cond internal */
union {
decaf_448_precomputed_s *mine;
const decaf_448_precomputed_s *yours;
} ours;
bool isMine;
inline void clear() NOEXCEPT {
if (isMine) {
decaf_448_precomputed_destroy(ours.mine);
free(ours.mine);
ours.yours = decaf_448_precomputed_base;
isMine = false;
}
}
inline void alloc() throw(std::bad_alloc) {
if (isMine) return;
int ret = posix_memalign((void**)&ours.mine, alignof_decaf_448_precomputed_s,sizeof_decaf_448_precomputed_s);
if (ret || !ours.mine) {
isMine = false;
throw std::bad_alloc();
}
isMine = true;
}
inline const decaf_448_precomputed_s *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; }
/** @endcond */
public:
/** Destructor securely erases the memory. */
inline ~Precomputed() NOEXCEPT { clear(); }
/**
* @brief Initialize from underlying type, declared as a reference to prevent
* it from being called with 0, thereby breaking override.
*
* The underlying object must remain valid throughout the lifetime of this one.
*
* By default, initializes to the table for the base point.
*
* @warning The empty initializer makes this equal to base, unlike the empty
* initializer for points which makes this equal to the identity.
*/
inline Precomputed(
const decaf_448_precomputed_s &yours = *decaf_448_precomputed_base
) NOEXCEPT {
ours.yours = &yours;
isMine = false;
}
/**
* @brief Assign. This may require an allocation and memcpy.
*/
inline Precomputed &operator=(const Precomputed &it) throw(std::bad_alloc) {
if (this == &it) return *this;
if (it.isMine) {
alloc();
memcpy(ours.mine,it.ours.mine,sizeof_decaf_448_precomputed_s);
} else {
clear();
ours.yours = it.ours.yours;
}
isMine = it.isMine;
return *this;
}
/**
* @brief Initilaize from point. Must allocate memory, and may throw.
*/
inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) {
alloc();
decaf_448_precompute(ours.mine,it.p);
return *this;
}
/**
* @brief Copy constructor.
*/
inline Precomputed(const Precomputed &it) throw(std::bad_alloc) : isMine(false) { *this = it; }
/**
* @brief Constructor which initializes from point.
*/
inline explicit Precomputed(const Point &it) throw(std::bad_alloc) : isMine(false) { *this = it; }
#if __cplusplus >= 201103L
inline Precomputed &operator=(Precomputed &&it) NOEXCEPT {
if (this == &it) return *this;
clear();
ours = it.ours;
isMine = it.isMine;
it.isMine = false;
it.ours.yours = decaf_448_precomputed_base;
return *this;
}
inline Precomputed(Precomputed &&it) NOEXCEPT : isMine(false) { *this = it; }
#endif
/** @brief Fixed base scalarmul. */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_448_precomputed_scalarmul(r.p,get(),s.s); return r; }
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); }
/** @brief Return the table for the base point. */
static inline const Precomputed base() NOEXCEPT { return Precomputed(*decaf_448_precomputed_base); }
};

}; /* struct Decaf448 */

#undef NOEXCEPT
#undef EXPLICIT_CON
#undef GET_DATA
} /* namespace decaf */

#endif /* __DECAF_448_HXX__ */

+ 64
- 64
src/decaf_crypto.c View File

@@ -11,60 +11,60 @@
#include "decaf_crypto.h"
#include <string.h>

static const unsigned int DECAF_448_SCALAR_OVERKILL_BYTES = DECAF_448_SCALAR_BYTES + 8;
static const unsigned int DECAF_255_SCALAR_OVERKILL_BYTES = DECAF_255_SCALAR_BYTES + 8;

void decaf_448_derive_private_key (
decaf_448_private_key_t priv,
const decaf_448_symmetric_key_t proto
void decaf_255_derive_private_key (
decaf_255_private_key_t priv,
const decaf_255_symmetric_key_t proto
) {
const char *magic = "decaf_448_derive_private_key";
uint8_t encoded_scalar[DECAF_448_SCALAR_OVERKILL_BYTES];
decaf_448_point_t pub;
const char *magic = "decaf_255_derive_private_key";
uint8_t encoded_scalar[DECAF_255_SCALAR_OVERKILL_BYTES];
decaf_255_point_t pub;

keccak_sponge_t sponge;
shake256_init(sponge);
shake256_update(sponge, proto, sizeof(decaf_448_symmetric_key_t));
shake256_update(sponge, proto, sizeof(decaf_255_symmetric_key_t));
shake256_update(sponge, (const unsigned char *)magic, strlen(magic));
shake256_final(sponge, encoded_scalar, sizeof(encoded_scalar));
shake256_destroy(sponge);
memcpy(priv->sym, proto, sizeof(decaf_448_symmetric_key_t));
decaf_448_scalar_decode_long(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar));
memcpy(priv->sym, proto, sizeof(decaf_255_symmetric_key_t));
decaf_255_scalar_decode_long(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar));
decaf_448_precomputed_scalarmul(pub, decaf_448_precomputed_base, priv->secret_scalar);
decaf_448_point_encode(priv->pub, pub);
decaf_255_precomputed_scalarmul(pub, decaf_255_precomputed_base, priv->secret_scalar);
decaf_255_point_encode(priv->pub, pub);
decaf_bzero(encoded_scalar, sizeof(encoded_scalar));
}

void
decaf_448_destroy_private_key (
decaf_448_private_key_t priv
decaf_255_destroy_private_key (
decaf_255_private_key_t priv
) {
decaf_bzero((void*)priv, sizeof(decaf_448_private_key_t));
decaf_bzero((void*)priv, sizeof(decaf_255_private_key_t));
}

void decaf_448_private_to_public (
decaf_448_public_key_t pub,
const decaf_448_private_key_t priv
void decaf_255_private_to_public (
decaf_255_public_key_t pub,
const decaf_255_private_key_t priv
) {
memcpy(pub, priv->pub, sizeof(decaf_448_public_key_t));
memcpy(pub, priv->pub, sizeof(decaf_255_public_key_t));
}

decaf_bool_t
decaf_448_shared_secret (
decaf_255_shared_secret (
uint8_t *shared,
size_t shared_bytes,
const decaf_448_private_key_t my_privkey,
const decaf_448_public_key_t your_pubkey
const decaf_255_private_key_t my_privkey,
const decaf_255_public_key_t your_pubkey
) {
uint8_t ss_ser[DECAF_448_SER_BYTES];
const char *nope = "decaf_448_ss_invalid";
uint8_t ss_ser[DECAF_255_SER_BYTES];
const char *nope = "decaf_255_ss_invalid";
unsigned i;
/* Lexsort keys. Less will be -1 if mine is less, and 0 otherwise. */
uint16_t less = 0;
for (i=0; i<DECAF_448_SER_BYTES; i++) {
for (i=0; i<DECAF_255_SER_BYTES; i++) {
uint16_t delta = my_privkey->pub[i];
delta -= your_pubkey[i];
/* Case:
@@ -92,7 +92,7 @@ decaf_448_shared_secret (
}
shake256_update(sponge, ss_ser, sizeof(ss_ser));
decaf_bool_t ret = decaf_448_direct_scalarmul(ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE);
decaf_bool_t ret = decaf_255_direct_scalarmul(ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE);
/* If invalid, then replace ... */
for (i=0; i<sizeof(ss_ser); i++) {
ss_ser[i] &= ret;
@@ -114,16 +114,16 @@ decaf_448_shared_secret (
}

void
decaf_448_sign_shake (
decaf_448_signature_t sig,
const decaf_448_private_key_t priv,
decaf_255_sign_shake (
decaf_255_signature_t sig,
const decaf_255_private_key_t priv,
const keccak_sponge_t shake
) {
const char *magic = "decaf_448_sign_shake";
const char *magic = "decaf_255_sign_shake";

uint8_t overkill[DECAF_448_SCALAR_OVERKILL_BYTES], encoded[DECAF_448_SER_BYTES];
decaf_448_point_t point;
decaf_448_scalar_t nonce, challenge;
uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES], encoded[DECAF_255_SER_BYTES];
decaf_255_point_t point;
decaf_255_scalar_t nonce, challenge;
/* Derive nonce */
keccak_sponge_t ctx;
@@ -132,9 +132,9 @@ decaf_448_sign_shake (
shake256_update(ctx, (const unsigned char *)magic, strlen(magic));
shake256_final(ctx, overkill, sizeof(overkill));
decaf_448_scalar_decode_long(nonce, overkill, sizeof(overkill));
decaf_448_precomputed_scalarmul(point, decaf_448_precomputed_base, nonce);
decaf_448_point_encode(encoded, point);
decaf_255_scalar_decode_long(nonce, overkill, sizeof(overkill));
decaf_255_precomputed_scalarmul(point, decaf_255_precomputed_base, nonce);
decaf_255_point_encode(encoded, point);

/* Derive challenge */
memcpy(ctx, shake, sizeof(ctx));
@@ -142,83 +142,83 @@ decaf_448_sign_shake (
shake256_update(ctx, encoded, sizeof(encoded));
shake256_final(ctx, overkill, sizeof(overkill));
shake256_destroy(ctx);
decaf_448_scalar_decode_long(challenge, overkill, sizeof(overkill));
decaf_255_scalar_decode_long(challenge, overkill, sizeof(overkill));
/* Respond */
decaf_448_scalar_mul(challenge, challenge, priv->secret_scalar);
decaf_448_scalar_sub(nonce, nonce, challenge);
decaf_255_scalar_mul(challenge, challenge, priv->secret_scalar);
decaf_255_scalar_sub(nonce, nonce, challenge);
/* Save results */
memcpy(sig, encoded, sizeof(encoded));
decaf_448_scalar_encode(&sig[sizeof(encoded)], nonce);
decaf_255_scalar_encode(&sig[sizeof(encoded)], nonce);
/* Clean up */
decaf_448_scalar_destroy(nonce);
decaf_448_scalar_destroy(challenge);
decaf_255_scalar_destroy(nonce);
decaf_255_scalar_destroy(challenge);
decaf_bzero(overkill,sizeof(overkill));
decaf_bzero(encoded,sizeof(encoded));
}

decaf_bool_t
decaf_448_verify_shake (
const decaf_448_signature_t sig,
const decaf_448_public_key_t pub,
decaf_255_verify_shake (
const decaf_255_signature_t sig,
const decaf_255_public_key_t pub,
const keccak_sponge_t shake
) {
decaf_bool_t ret;

uint8_t overkill[DECAF_448_SCALAR_OVERKILL_BYTES];
decaf_448_point_t point, pubpoint;
decaf_448_scalar_t challenge, response;
uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES];
decaf_255_point_t point, pubpoint;
decaf_255_scalar_t challenge, response;
/* Derive challenge */
keccak_sponge_t ctx;
memcpy(ctx, shake, sizeof(ctx));
shake256_update(ctx, pub, sizeof(decaf_448_public_key_t));
shake256_update(ctx, sig, DECAF_448_SER_BYTES);
shake256_update(ctx, pub, sizeof(decaf_255_public_key_t));
shake256_update(ctx, sig, DECAF_255_SER_BYTES);
shake256_final(ctx, overkill, sizeof(overkill));
shake256_destroy(ctx);
decaf_448_scalar_decode_long(challenge, overkill, sizeof(overkill));
decaf_255_scalar_decode_long(challenge, overkill, sizeof(overkill));

/* Decode points. */
ret = decaf_448_point_decode(point, sig, DECAF_TRUE);
ret &= decaf_448_point_decode(pubpoint, pub, DECAF_FALSE);
ret &= decaf_448_scalar_decode(response, &sig[DECAF_448_SER_BYTES]);
ret = decaf_255_point_decode(point, sig, DECAF_TRUE);
ret &= decaf_255_point_decode(pubpoint, pub, DECAF_FALSE);
ret &= decaf_255_scalar_decode(response, &sig[DECAF_255_SER_BYTES]);

decaf_448_base_double_scalarmul_non_secret (
decaf_255_base_double_scalarmul_non_secret (
pubpoint, response, pubpoint, challenge
);

ret &= decaf_448_point_eq(pubpoint, point);
ret &= decaf_255_point_eq(pubpoint, point);
return ret;
}

void
decaf_448_sign (
decaf_448_signature_t sig,
const decaf_448_private_key_t priv,
decaf_255_sign (
decaf_255_signature_t sig,
const decaf_255_private_key_t priv,
const unsigned char *message,
size_t message_len
) {
keccak_sponge_t ctx;
shake256_init(ctx);
shake256_update(ctx, message, message_len);
decaf_448_sign_shake(sig, priv, ctx);
decaf_255_sign_shake(sig, priv, ctx);
shake256_destroy(ctx);
}

decaf_bool_t
decaf_448_verify (
const decaf_448_signature_t sig,
const decaf_448_public_key_t pub,
decaf_255_verify (
const decaf_255_signature_t sig,
const decaf_255_public_key_t pub,
const unsigned char *message,
size_t message_len
) {
keccak_sponge_t ctx;
shake256_init(ctx);
shake256_update(ctx, message, message_len);
decaf_bool_t ret = decaf_448_verify_shake(sig, pub, ctx);
decaf_bool_t ret = decaf_255_verify_shake(sig, pub, ctx);
shake256_destroy(ctx);
return ret;
}

+ 26
- 22
src/decaf_fast.c View File

@@ -13,20 +13,20 @@
#include "decaf.h"
#include <string.h>
#include "field.h"
#include "decaf_448_config.h"
#include "decaf_255_config.h"

#define WBITS DECAF_WORD_BITS

/* Rename table for eventual factoring into .c.inc, MSR ECC style */
#define SCALAR_LIMBS DECAF_448_SCALAR_LIMBS
#define SCALAR_BITS DECAF_448_SCALAR_BITS
#define NLIMBS DECAF_448_LIMBS
#define API_NS(_id) decaf_448_##_id
#define API_NS2(_pref,_id) _pref##_decaf_448_##_id
#define scalar_t decaf_448_scalar_t
#define point_t decaf_448_point_t
#define precomputed_s decaf_448_precomputed_s
#define SER_BYTES DECAF_448_SER_BYTES
#define SCALAR_LIMBS DECAF_255_SCALAR_LIMBS
#define SCALAR_BITS DECAF_255_SCALAR_BITS
#define NLIMBS DECAF_255_LIMBS
#define API_NS(_id) decaf_255_##_id
#define API_NS2(_pref,_id) _pref##_decaf_255_##_id
#define scalar_t decaf_255_scalar_t
#define point_t decaf_255_point_t
#define precomputed_s decaf_255_precomputed_s
#define SER_BYTES DECAF_255_SER_BYTES

#if WBITS == 64
typedef __int128_t decaf_sdword_t;
@@ -45,25 +45,23 @@ typedef int64_t decaf_sdword_t;
#define siv static inline void __attribute__((always_inline))
static const gf ZERO = {{{0}}}, ONE = {{{1}}}, TWO = {{{2}}};

static const int EDWARDS_D = -39081;
static const int EDWARDS_D = 121665;

static const scalar_t sc_p = {{{
SC_LIMB(0x2378c292ab5844f3),
SC_LIMB(0x216cc2728dc58f55),
SC_LIMB(0xc44edb49aed63690),
SC_LIMB(0xffffffff7cca23e9),
SC_LIMB(0xffffffffffffffff),
SC_LIMB(0xffffffffffffffff),
SC_LIMB(0x3fffffffffffffff)
SC_LIMB(0x5812631a5cf5d3ed),
SC_LIMB(0x14def9dea2f79cd6),
SC_LIMB(0),
SC_LIMB(0),
SC_LIMB(0x1000000000000000)
}}};

const scalar_t API_NS(scalar_one) = {{{1}}}, API_NS(scalar_zero) = {{{0}}};
extern const scalar_t sc_r2;
extern const decaf_word_t MONTGOMERY_FACTOR;

/* sqrt(5) = 2phi-1 from the curve spec. Not exported, but used by pregen tool. */
/* sqrt(9) = 3 from the curve spec. Not exported, but used by pregen tool. */
const unsigned char base_point_ser_for_pregen[SER_BYTES] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1
3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};

extern const point_t API_NS(point_base);
@@ -324,7 +322,8 @@ decaf_bool_t API_NS(scalar_invert) (
scalar_t out,
const scalar_t a
) {
/* FIELD MAGIC */
#if 0
/* FIELD MAGIC. FIXME: not updated for 25519 */
scalar_t chain[7], tmp;
sc_montmul(chain[0],a,sc_r2);
@@ -371,6 +370,11 @@ decaf_bool_t API_NS(scalar_invert) (
API_NS(scalar_destroy)(chain[i]);
}
return ~API_NS(scalar_eq)(out,API_NS(scalar_zero));
#else
(void)out;
(void)a;
return 0;
#endif
}

void API_NS(scalar_sub) (
@@ -1067,7 +1071,7 @@ unsigned char API_NS(point_from_hash_nonuniform) (

decaf_bool_t
API_NS(invert_elligator_nonuniform) (
unsigned char recovered_hash[DECAF_448_SER_BYTES],
unsigned char recovered_hash[DECAF_255_SER_BYTES],
const point_t p,
unsigned char hint
) {


+ 8
- 8
src/decaf_gen_tables.c View File

@@ -12,11 +12,11 @@
#include <stdio.h>
#include <stdlib.h>
#include "decaf.h"
#include "decaf_448_config.h" /* MAGIC */
#include "decaf_255_config.h" /* MAGIC */
#include "field.h"

#define API_NS(_id) decaf_448_##_id
#define API_NS2(_pref,_id) _pref##_decaf_448_##_id
#define API_NS(_id) decaf_255_##_id
#define API_NS2(_pref,_id) _pref##_decaf_255_##_id

/* To satisfy linker. */
const field_t API_NS(precomputed_base_as_fe)[1];
@@ -24,7 +24,7 @@ const API_NS(scalar_t) API_NS(precomputed_scalarmul_adjustment);
const API_NS(scalar_t) API_NS(point_scalarmul_adjustment);
const API_NS(scalar_t) sc_r2 = {{{0}}};
const decaf_word_t MONTGOMERY_FACTOR = 0;
const unsigned char base_point_ser_for_pregen[DECAF_448_SER_BYTES];
const unsigned char base_point_ser_for_pregen[DECAF_255_SER_BYTES];

const API_NS(point_t) API_NS(point_base);

@@ -94,8 +94,8 @@ int main(int argc, char **argv) {
printf("/** @warning: this file was automatically generated. */\n");
printf("#include \"field.h\"\n\n");
printf("#include \"decaf.h\"\n\n");
printf("#define API_NS(_id) decaf_448_##_id\n");
printf("#define API_NS2(_pref,_id) _pref##_decaf_448_##_id\n");
printf("#define API_NS(_id) decaf_255_##_id\n");
printf("#define API_NS2(_pref,_id) _pref##_decaf_255_##_id\n");
output = (const field_t *)real_point_base;
printf("const API_NS(point_t) API_NS(point_base) = {{\n");
@@ -138,8 +138,8 @@ int main(int argc, char **argv) {
scalar_print("API_NS(precomputed_scalarmul_adjustment)", smadj);
API_NS(scalar_copy)(smadj,API_NS(scalar_one));
for (i=0; i<DECAF_448_SCALAR_BITS-1 + DECAF_WINDOW_BITS
- ((DECAF_448_SCALAR_BITS-1)%DECAF_WINDOW_BITS); i++) {
for (i=0; i<DECAF_255_SCALAR_BITS-1 + DECAF_WINDOW_BITS
- ((DECAF_255_SCALAR_BITS-1)%DECAF_WINDOW_BITS); i++) {
API_NS(scalar_add)(smadj,smadj,smadj);
}
API_NS(scalar_sub)(smadj, smadj, API_NS(scalar_one));


+ 1
- 0
src/p25519/arch_ref64/arch_config.h View File

@@ -0,0 +1 @@
#define WORD_BITS 64

+ 318
- 0
src/p25519/arch_ref64/p25519.c View File

@@ -0,0 +1,318 @@
/* Copyright (c) 2014 Cryptography Research, Inc.
* Released under the MIT License. See LICENSE.txt for license information.
*/

#include "p25519.h"

static __inline__ __uint128_t widemul(
const uint64_t a,
const uint64_t b
) {
return ((__uint128_t)a) * ((__uint128_t)b);
}

static __inline__ uint64_t is_zero(uint64_t a) {
/* let's hope the compiler isn't clever enough to optimize this. */
return (((__uint128_t)a)-1)>>64;
}

void
p255_mul (
p255_t *__restrict__ cs,
const p255_t *as,
const p255_t *bs
) {
const uint64_t *a = as->limb, *b = bs->limb;
uint64_t *c = cs->limb;

__uint128_t accum0 = 0, accum1 = 0, accum2;
uint64_t mask = (1ull<<51) - 1;

uint64_t aa[4], bb[4], bbb[4];

unsigned int i;
for (i=0; i<4; i++) {
aa[i] = a[i] + a[i+4];
bb[i] = b[i] + b[i+4];
bbb[i] = bb[i] + b[i+4];
}

int I_HATE_UNROLLED_LOOPS = 0;

if (I_HATE_UNROLLED_LOOPS) {
/* The compiler probably won't unroll this,
* so it's like 80% slower.
*/
for (i=0; i<4; i++) {
accum2 = 0;

unsigned int j;
for (j=0; j<=i; j++) {
accum2 += widemul(a[j], b[i-j]);
accum1 += widemul(aa[j], bb[i-j]);
accum0 += widemul(a[j+4], b[i-j+4]);
}
for (; j<4; j++) {
accum2 += widemul(a[j], b[i-j+8]);
accum1 += widemul(aa[j], bbb[i-j+4]);
accum0 += widemul(a[j+4], bb[i-j+4]);
}

accum1 -= accum2;
accum0 += accum2;

c[i] = ((uint64_t)(accum0)) & mask;
c[i+4] = ((uint64_t)(accum1)) & mask;

accum0 >>= 56;
accum1 >>= 56;
}
} else {
accum2 = widemul(a[0], b[0]);
accum1 += widemul(aa[0], bb[0]);
accum0 += widemul(a[4], b[4]);

accum2 += widemul(a[1], b[7]);
accum1 += widemul(aa[1], bbb[3]);
accum0 += widemul(a[5], bb[3]);

accum2 += widemul(a[2], b[6]);
accum1 += widemul(aa[2], bbb[2]);
accum0 += widemul(a[6], bb[2]);

accum2 += widemul(a[3], b[5]);
accum1 += widemul(aa[3], bbb[1]);
accum0 += widemul(a[7], bb[1]);

accum1 -= accum2;
accum0 += accum2;

c[0] = ((uint64_t)(accum0)) & mask;
c[4] = ((uint64_t)(accum1)) & mask;

accum0 >>= 56;
accum1 >>= 56;

accum2 = widemul(a[0], b[1]);
accum1 += widemul(aa[0], bb[1]);
accum0 += widemul(a[4], b[5]);

accum2 += widemul(a[1], b[0]);
accum1 += widemul(aa[1], bb[0]);
accum0 += widemul(a[5], b[4]);

accum2 += widemul(a[2], b[7]);
accum1 += widemul(aa[2], bbb[3]);
accum0 += widemul(a[6], bb[3]);

accum2 += widemul(a[3], b[6]);
accum1 += widemul(aa[3], bbb[2]);
accum0 += widemul(a[7], bb[2]);

accum1 -= accum2;
accum0 += accum2;

c[1] = ((uint64_t)(accum0)) & mask;
c[5] = ((uint64_t)(accum1)) & mask;

accum0 >>= 56;
accum1 >>= 56;

accum2 = widemul(a[0], b[2]);
accum1 += widemul(aa[0], bb[2]);
accum0 += widemul(a[4], b[6]);

accum2 += widemul(a[1], b[1]);
accum1 += widemul(aa[1], bb[1]);
accum0 += widemul(a[5], b[5]);

accum2 += widemul(a[2], b[0]);
accum1 += widemul(aa[2], bb[0]);
accum0 += widemul(a[6], b[4]);

accum2 += widemul(a[3], b[7]);
accum1 += widemul(aa[3], bbb[3]);
accum0 += widemul(a[7], bb[3]);

accum1 -= accum2;
accum0 += accum2;

c[2] = ((uint64_t)(accum0)) & mask;
c[6] = ((uint64_t)(accum1)) & mask;

accum0 >>= 56;
accum1 >>= 56;

accum2 = widemul(a[0], b[3]);
accum1 += widemul(aa[0], bb[3]);
accum0 += widemul(a[4], b[7]);

accum2 += widemul(a[1], b[2]);
accum1 += widemul(aa[1], bb[2]);
accum0 += widemul(a[5], b[6]);

accum2 += widemul(a[2], b[1]);
accum1 += widemul(aa[2], bb[1]);
accum0 += widemul(a[6], b[5]);

accum2 += widemul(a[3], b[0]);
accum1 += widemul(aa[3], bb[0]);
accum0 += widemul(a[7], b[4]);

accum1 -= accum2;
accum0 += accum2;

c[3] = ((uint64_t)(accum0)) & mask;
c[7] = ((uint64_t)(accum1)) & mask;

accum0 >>= 56;
accum1 >>= 56;
} /* !I_HATE_UNROLLED_LOOPS */

accum0 += accum1;
accum0 += c[4];
accum1 += c[0];
c[4] = ((uint64_t)(accum0)) & mask;
c[0] = ((uint64_t)(accum1)) & mask;

accum0 >>= 56;
accum1 >>= 56;

c[5] += ((uint64_t)(accum0));
c[1] += ((uint64_t)(accum1));
}

void
p255_mulw (
p255_t *__restrict__ cs,
const p255_t *as,
uint64_t b
) {
const uint64_t *a = as->limb;
uint64_t *c = cs->limb;

__uint128_t accum0 = 0, accum4 = 0;
uint64_t mask = (1ull<<56) - 1;

int i;
for (i=0; i<4; i++) {
accum0 += widemul(b, a[i]);
accum4 += widemul(b, a[i+4]);
c[i] = accum0 & mask; accum0 >>= 56;
c[i+4] = accum4 & mask; accum4 >>= 56;
}
accum0 += accum4 + c[4];
c[4] = accum0 & mask;
c[5] += accum0 >> 56;

accum4 += c[0];
c[0] = accum4 & mask;
c[1] += accum4 >> 56;
}

void
p255_sqr (
p255_t *__restrict__ cs,
const p255_t *as
) {
p255_mul(cs,as,as); // TODO
}

void
p255_strong_reduce (
p255_t *a
) {
uint64_t mask = (1ull<<56)-1;

/* first, clear high */
a->limb[4] += a->limb[7]>>56;
a->limb[0] += a->limb[7]>>56;
a->limb[7] &= mask;

/* now the total is less than 2^255 - 2^(255-56) + 2^(255-56+8) < 2p */

/* compute total_value - p. No need to reduce mod p. */

__int128_t scarry = 0;
int i;
for (i=0; i<8; i++) {
scarry = scarry + a->limb[i] - ((i==4)?mask-1:mask);
a->limb[i] = scarry & mask;
scarry >>= 56;
}

/* uncommon case: it was >= p, so now scarry = 0 and this = x
* common case: it was < p, so now scarry = -1 and this = x - p + 2^255
* so let's add back in p. will carry back off the top for 2^255.
*/

assert(is_zero(scarry) | is_zero(scarry+1));

uint64_t scarry_mask = scarry & mask;
__uint128_t carry = 0;

/* add it back */
for (i=0; i<8; i++) {
carry = carry + a->limb[i] + ((i==4)?(scarry_mask&~1):scarry_mask);
a->limb[i] = carry & mask;
carry >>= 56;
}

assert(is_zero(carry + scarry));
}

void
p255_serialize (
uint8_t serial[32],
const struct p255_t *x
) {
int i,j;
p255_t red;
p255_copy(&red, x);
p255_strong_reduce(&red);
for (i=0; i<8; i++) {
for (j=0; j<7; j++) {
serial[7*i+j] = red.limb[i];
red.limb[i] >>= 8;
}
assert(red.limb[i] == 0);
}
}

mask_t
p255_deserialize (
p255_t *x,
const uint8_t serial[32]
) {
int i,j;
for (i=0; i<8; i++) {
uint64_t out = 0;
for (j=0; j<7; j++) {
out |= ((uint64_t)serial[7*i+j])<<(8*j);
}
x->limb[i] = out;
}
/* Check for reduction.
*
* The idea is to create a variable ge which is all ones (rather, 56 ones)
* if and only if the low $i$ words of $x$ are >= those of p.
*
* Remember p = little_endian(1111,1111,1111,1111,1110,1111,1111,1111)
*/
uint64_t ge = -1, mask = (1ull<<56)-1;
for (i=0; i<4; i++) {
ge &= x->limb[i];
}
/* At this point, ge = 1111 iff bottom are all 1111. Now propagate if 1110, or set if 1111 */
ge = (ge & (x->limb[4] + 1)) | is_zero(x->limb[4] ^ mask);
/* Propagate the rest */
for (i=5; i<8; i++) {
ge &= x->limb[i];
}
return ~is_zero(ge ^ mask);
}

+ 155
- 0
src/p25519/arch_ref64/p25519.h View File

@@ -0,0 +1,155 @@
/* Copyright (c) 2014 Cryptography Research, Inc.
* Released under the MIT License. See LICENSE.txt for license information.
*/
#ifndef __P255_H__
#define __P255_H__ 1

#include <stdint.h>
#include <assert.h>
#include <string.h>

#include "word.h"

typedef struct p255_t {
uint64_t limb[5];
} p255_t;

#define LBITS 51
#define FIELD_LITERAL(a,b,c,d,e) {{a,b,c,d,e}}

#ifdef __cplusplus
extern "C" {
#endif

static __inline__ void
p255_add_RAW (
p255_t *out,
const p255_t *a,
const p255_t *b
) __attribute__((unused));
static __inline__ void
p255_sub_RAW (
p255_t *out,
const p255_t *a,
const p255_t *b
) __attribute__((unused));
static __inline__ void
p255_copy (
p255_t *out,
const p255_t *a
) __attribute__((unused));
static __inline__ void
p255_weak_reduce (
p255_t *inout
) __attribute__((unused));
void
p255_strong_reduce (
p255_t *inout
);

static __inline__ void
p255_bias (
p255_t *inout,
int amount
) __attribute__((unused));
void
p255_mul (
p255_t *__restrict__ out,
const p255_t *a,
const p255_t *b
);

void
p255_mulw (
p255_t *__restrict__ out,
const p255_t *a,
uint64_t b
);

void
p255_sqr (
p255_t *__restrict__ out,
const p255_t *a
);

void
p255_serialize (
uint8_t serial[32],
const struct p255_t *x
);

mask_t
p255_deserialize (
p255_t *x,
const uint8_t serial[32]
);

/* -------------- Inline functions begin here -------------- */

void
p255_add_RAW (
p255_t *out,
const p255_t *a,
const p255_t *b
) {
unsigned int i;
for (i=0; i<5; i++) {
out->limb[i] = a->limb[i] + b->limb[i];
}
p255_weak_reduce(out);
}

void
p255_sub_RAW (
p255_t *out,
const p255_t *a,
const p255_t *b
) {
unsigned int i;
uint64_t co1 = ((1ull<<51)-1)*2, co2 = co1-36;
for (i=0; i<5; i++) {
out->limb[i] = a->limb[i] - b->limb[i] + ((i==0) ? co2 : co1);
}
p255_weak_reduce(out);
}

void
p255_copy (
p255_t *out,
const p255_t *a
) {
memcpy(out,a,sizeof(*a));
}

void
p255_bias (
p255_t *a,
int amt
) {
(void) a;
(void) amt;
}

void
p255_weak_reduce (
p255_t *a
) {
uint64_t mask = (1ull<<51) - 1;
uint64_t tmp = a->limb[5] >> 51;
int i;
for (i=7; i>0; i--) {
a->limb[i] = (a->limb[i] & mask) + (a->limb[i-1]>>51);
}
a->limb[0] = (a->limb[0] & mask) + tmp*19;
}

#ifdef __cplusplus
}; /* extern "C" */
#endif

#endif /* __P255_H__ */

+ 67
- 0
src/p25519/f_arithmetic.c View File

@@ -0,0 +1,67 @@
/**
* @cond internal
* @file f_arithmetic.c
* @copyright
* Copyright (c) 2014 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
* @brief Field-specific arithmetic.
*/

#include "field.h"

extern field_a_t ONE; // TODO

static const field_a_t SQRT_MINUS_ONE = FIELD_LITERAL( // FIXME goes elsewhere?
0x61b274a0ea0b0,
0x0d5a5fc8f189d,
0x7ef5e9cbd0c60,
0x78595a6804c9e,
0x2b8324804fc1d
);

void
field_isr (
field_a_t a,
const field_a_t x
) {
field_a_t st[3], tmp1, tmp2;
const struct { unsigned char sh, idx } ops[] = {
{1,2},{1,2},{3,1},{6,0},{1,2},{12,1},{25,1},{25,1},{50,0},{125,0},{2,2},{1,2}
};
field_cpy(st[0],x);
field_cpy(st[1],x);
field_cpy(st[2],x);
int i;
for (i=0; i<sizeof(ops)/sizeof(ops[0]); i++) {
field_sqrn(tmp1, st[1^i&1], ops[i].sh);
field_mul(tmp2, tmp1, st[ops[i].idx]);
field_cpy(st[i&1], tmp2);
}
mask_t m = field_eq(st[1], ONE);
cond_sel(tmp1,SQRT_MINUS_ONE,ONE,m);
field_mul(a,tmp1,st[0]);
};

void
field_isr (
field_a_t a,
const field_a_t x
) {
field_a_t st[3], tmp1, tmp2;
const struct { unsigned char sh, idx } ops[] = {
{1,2},{1,2},{3,1},{6,0},{1,2},{12,1},{25,1},{25,1},{50,0},{125,0},{2,2},{1,2}
};
field_cpy(st[0],x);
field_cpy(st[1],x);
field_cpy(st[2],x);
int i;
for (i=0; i<sizeof(ops)/sizeof(ops[0]); i++) {
field_sqrn(tmp1, st[1^i&1], ops[i].sh);
field_mul(tmp2, tmp1, st[ops[i].idx]);
field_cpy(st[i&1], tmp2);
}
mask_t m = field_eq(st[1], ONE);
}

+ 32
- 0
src/p25519/f_field.h View File

@@ -0,0 +1,32 @@
/**
* @file f_field.h
* @brief Field-specific code.
* @copyright
* Copyright (c) 2014 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
*/
#ifndef __F_FIELD_H__
#define __F_FIELD_H__ 1

#include "constant_time.h"
#include <string.h>

#include "p25519.h"
#define FIELD_LIT_LIMB_BITS 51
#define FIELD_BITS 255
#define field_t p255_t
#define field_mul p255_mul
#define field_sqr p255_sqr
#define field_add_RAW p255_add_RAW
#define field_sub_RAW p255_sub_RAW
#define field_mulw p255_mulw
#define field_bias p255_bias
#define field_isr p255_isr
#define field_inverse p255_inverse
#define field_weak_reduce p255_weak_reduce
#define field_strong_reduce p255_strong_reduce
#define field_serialize p255_serialize
#define field_deserialize p255_deserialize

#endif /* __F_FIELD_H__ */

+ 14
- 14
test/bench_decaf.cxx View File

@@ -21,9 +21,9 @@
#include <algorithm>

using namespace decaf;
typedef Ed448::Scalar Scalar;
typedef Ed448::Point Point;
typedef Ed448::Precomputed Precomputed;
typedef Ed255::Scalar Scalar;
typedef Ed255::Point Point;
typedef Ed255::Precomputed Precomputed;


static __inline__ void __attribute__((unused)) ignore_result ( int result ) { (void)result; }
@@ -281,10 +281,10 @@ int main(int argc, char **argv) {
if (argc >= 2 && !strcmp(argv[1], "--micro"))
micro = true;
decaf_448_public_key_t p1,p2;
decaf_448_private_key_t s1,s2;
decaf_448_symmetric_key_t r1,r2;
decaf_448_signature_t sig1;
decaf_255_public_key_t p1,p2;
decaf_255_private_key_t s1,s2;
decaf_255_symmetric_key_t r1,r2;
decaf_255_signature_t sig1;
unsigned char ss[32];
memset(r1,1,sizeof(r1));
@@ -348,25 +348,25 @@ int main(int argc, char **argv) {

printf("\nMacro-benchmarks:\n");
for (Benchmark b("Keygen"); b.iter(); ) {
decaf_448_derive_private_key(s1,r1);
decaf_255_derive_private_key(s1,r1);
}
decaf_448_private_to_public(p1,s1);
decaf_448_derive_private_key(s2,r2);
decaf_448_private_to_public(p2,s2);
decaf_255_private_to_public(p1,s1);
decaf_255_derive_private_key(s2,r2);
decaf_255_private_to_public(p2,s2);
for (Benchmark b("Shared secret"); b.iter(); ) {
decaf_bool_t ret = decaf_448_shared_secret(ss,sizeof(ss),s1,p2);
decaf_bool_t ret = decaf_255_shared_secret(ss,sizeof(ss),s1,p2);
ignore_result(ret);
assert(ret);
}
for (Benchmark b("Sign"); b.iter(); ) {
decaf_448_sign(sig1,s1,umessage,lmessage);
decaf_255_sign(sig1,s1,umessage,lmessage);
}
for (Benchmark b("Verify"); b.iter(); ) {
decaf_bool_t ret = decaf_448_verify(sig1,p1,umessage,lmessage);
decaf_bool_t ret = decaf_255_verify(sig1,p1,umessage,lmessage);
umessage[0]++;
umessage[1]^=umessage[0];
ignore_result(ret);


+ 16
- 16
test/test_decaf.cxx View File

@@ -127,7 +127,7 @@ static void test_arithmetic() {
for (int i=0; i<NTESTS*10 && test.passing_now; i++) {
/* TODO: pathological cases */
size_t sob = DECAF_448_SCALAR_BYTES + 8 - (i%16);
size_t sob = DECAF_255_SCALAR_BYTES + 8 - (i%16);
Scalar x(rng.read(sob));
Scalar y(rng.read(sob));
Scalar z(rng.read(sob));
@@ -244,31 +244,31 @@ static void test_decaf() {
Test test("Sample crypto");
decaf::SpongeRng rng(decaf::Block("test_decaf"));

decaf_448_symmetric_key_t proto1,proto2;
decaf_448_private_key_t s1,s2;
decaf_448_public_key_t p1,p2;
decaf_448_signature_t sig;
decaf_255_symmetric_key_t proto1,proto2;
decaf_255_private_key_t s1,s2;
decaf_255_public_key_t p1,p2;
decaf_255_signature_t sig;
unsigned char shared1[1234],shared2[1234];
const char *message = "Hello, world!";

for (int i=0; i<NTESTS && test.passing_now; i++) {
rng.read(decaf::TmpBuffer(proto1,sizeof(proto1)));
rng.read(decaf::TmpBuffer(proto2,sizeof(proto2)));
decaf_448_derive_private_key(s1,proto1);
decaf_448_private_to_public(p1,s1);
decaf_448_derive_private_key(s2,proto2);
decaf_448_private_to_public(p2,s2);
if (!decaf_448_shared_secret (shared1,sizeof(shared1),s1,p2)) {
decaf_255_derive_private_key(s1,proto1);
decaf_255_private_to_public(p1,s1);
decaf_255_derive_private_key(s2,proto2);
decaf_255_private_to_public(p2,s2);
if (!decaf_255_shared_secret (shared1,sizeof(shared1),s1,p2)) {
test.fail(); printf("Fail ss12\n");
}
if (!decaf_448_shared_secret (shared2,sizeof(shared2),s2,p1)) {
if (!decaf_255_shared_secret (shared2,sizeof(shared2),s2,p1)) {
test.fail(); printf("Fail ss21\n");
}
if (memcmp(shared1,shared2,sizeof(shared1))) {
test.fail(); printf("Fail ss21 == ss12\n");
}
decaf_448_sign (sig,s1,(const unsigned char *)message,strlen(message));
if (!decaf_448_verify (sig,p1,(const unsigned char *)message,strlen(message))) {
decaf_255_sign (sig,s1,(const unsigned char *)message,strlen(message));
if (!decaf_255_verify (sig,p1,(const unsigned char *)message,strlen(message))) {
test.fail(); printf("Fail sig ver\n");
}
}
@@ -277,9 +277,9 @@ static void test_decaf() {
int main(int argc, char **argv) {
(void) argc; (void) argv;
Tests<decaf::Ed448>::test_arithmetic();
Tests<decaf::Ed448>::test_elligator();
Tests<decaf::Ed448>::test_ec();
Tests<decaf::Ed255>::test_arithmetic();
Tests<decaf::Ed255>::test_elligator();
Tests<decaf::Ed255>::test_ec();
test_decaf();
if (passing) printf("Passed all tests.\n");


Loading…
Cancel
Save