Compare commits

..

No commits in common. "master" and "v0.1" have entirely different histories.
master ... v0.1

11 changed files with 255 additions and 3645 deletions

View file

@ -1,34 +0,0 @@
libuecc v7 (2016/03/27)
* Change conversion between Ed25519 and legacy representation. This should
not affect any operations unless Ed25519 and legacy load/store
functions are mixed when accessing a work structure. Doing so is now
officially supported, for example to convert a legacy public key to
Ed25519 format.
* The changed representation allows to use the same
ecc_25519_work_default_base for both Ed25519 and legacy.
ecc_25519_work_default_base and ecc_25519_scalarmult_base have been
undeprecated, ecc_25519_work_base_ed25519 and
ecc_25519_work_base_legacy are deprecated now.
* All points are now internally represented with Ed25519 coordinates, which
allows about 6% faster scalar multplication than the legacy
representation.
* ecc_25519_scalarmult_base has been further optimized, making it another
6% faster than normal ecc_25519_scalarmult.
libuecc v6 (2015/10/25)
* Fixes a bug which might have caused a point's y coordinate to be negated
in certain circumstances when the point was stored in packed
representation and loaded again. It is extremely improbable that this
has ever actually happened, as only a small range of coordinates was
affected.
* Use stdint types to clarify ABI and add support for systems with
sizeof(int) < 4 (this is not an ABI break in practise as all systems on
which libuecc has been used in the past should have int == int32_t)
* Add point negation and subtraction functions
* Rename all point access functions to bear a _legacy suffix (the old names
are still available, but marked as deprecated)
* Add new point access functions and a new generator point that are
compatible with Ed25519

View file

@ -1,20 +1,9 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
project(LIBUECC C) project(LIBUECC C)
set(PROJECT_VERSION 7)
set(CMAKE_MODULE_PATH ${LIBUECC_SOURCE_DIR}) set(CMAKE_MODULE_PATH ${LIBUECC_SOURCE_DIR})
set(DOXYFILE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
set(DOXYFILE_EXTRA_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/include")
include(UseDoxygen OPTIONAL)
set(LIBDIR "lib${LIB_SUFFIX}")
add_subdirectory(src) add_subdirectory(src)
configure_file(${LIBUECC_SOURCE_DIR}/libuecc.pc.in ${LIBUECC_BINARY_DIR}/libuecc.pc @ONLY)
install(FILES ${LIBUECC_BINARY_DIR}/libuecc.pc DESTINATION "${LIBDIR}/pkgconfig")
FILE(GLOB include_files "${CMAKE_CURRENT_SOURCE_DIR}/include/libuecc/*.h") FILE(GLOB include_files "${CMAKE_CURRENT_SOURCE_DIR}/include/libuecc/*.h")
install(FILES ${include_files} DESTINATION "include/libuecc-${PROJECT_VERSION}/libuecc") install(FILES ${include_files} DESTINATION include/libuecc)

View file

@ -1,4 +1,4 @@
Copyright (c) 2012-2015, Matthias Schiffer <mschiffer@universe-factory.net> Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
Partly based on public domain code by Matthew Dempsky and D. J. Bernstein. Partly based on public domain code by Matthew Dempsky and D. J. Bernstein.
All rights reserved. All rights reserved.

File diff suppressed because it is too large Load diff

30
README
View file

@ -1,30 +0,0 @@
libuecc is a very small generic-purpose Elliptic Curve Cryptography library
compatible with Ed25519.
Most documentation can be found as Doxygen comments in the ecc.h header
file. You can use `make doxygen` after running CMake to create HTML
documenation from it.
There are two sets of functions converting between libuecc's internal point
representation and coordinates or compressed representation. The functions
ending with _ed25519 use the same representation as original Ed25519
implementation and should be used by new software. The functions with the
suffix _legacy are provided for compatiblity with libuecc version before
v6.
Ed25519 and the legacy representation are isomorphic, they use a Twisted
Edwards Curve
ax^2 + y^2 = 1 + dx^2y^2
over the prime field for p = 2^255 - 19.
Ed25519 uses the parameters
a = -1 and
d = -(121665/121666),
while the legacy curve has
a = 486664
d = 486660.

View file

@ -1,149 +0,0 @@
# - Run Doxygen
#
# Adds a doxygen target that runs doxygen to generate the html
# and optionally the LaTeX API documentation.
# The doxygen target is added to the doc target as a dependency.
# i.e.: the API documentation is built with:
# make doc
#
# USAGE: GLOBAL INSTALL
#
# Install it with:
# cmake ./ && sudo make install
# Add the following to the CMakeLists.txt of your project:
# include(UseDoxygen OPTIONAL)
# Optionally copy Doxyfile.in in the directory of CMakeLists.txt and edit it.
#
# USAGE: INCLUDE IN PROJECT
#
# set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# include(UseDoxygen)
# Add the Doxyfile.in and UseDoxygen.cmake files to the projects source directory.
#
#
# CONFIGURATION
#
# To configure Doxygen you can edit Doxyfile.in and set some variables in cmake.
# Variables you may define are:
# DOXYFILE_SOURCE_DIR - Path where the Doxygen input files are.
# Defaults to the current source directory.
# DOXYFILE_EXTRA_SOURCES - Additional source diretories/files for Doxygen to scan.
# The Paths should be in double quotes and separated by space. e.g.:
# "${CMAKE_CURRENT_BINARY_DIR}/foo.c" "${CMAKE_CURRENT_BINARY_DIR}/bar/"
#
# DOXYFILE_OUTPUT_DIR - Path where the Doxygen output is stored.
# Defaults to "${CMAKE_CURRENT_BINARY_DIR}/doxygen".
#
# DOXYFILE_LATEX - ON/OFF; Set to "ON" if you want the LaTeX documentation
# to be built.
# DOXYFILE_LATEX_DIR - Directory relative to DOXYFILE_OUTPUT_DIR where
# the Doxygen LaTeX output is stored. Defaults to "latex".
#
# DOXYFILE_HTML_DIR - Directory relative to DOXYFILE_OUTPUT_DIR where
# the Doxygen html output is stored. Defaults to "html".
#
#
# Copyright (c) 2009, 2010, 2011 Tobias Rautenkranz <tobias@rautenkranz.ch>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
macro(usedoxygen_set_default name value type docstring)
if(NOT DEFINED "${name}")
set("${name}" "${value}" CACHE "${type}" "${docstring}")
endif()
endmacro()
if(ANDROID)
find_host_package(Doxygen)
else(ANDROID)
find_package(Doxygen)
endif(ANDROID)
if(DOXYGEN_FOUND)
if(ANDROID)
# android-cmake doesn't provide a find_host_file and here's the workaround
set(_save_root_path ${CMAKE_FIND_ROOT_PATH})
set(CMAKE_FIND_ROOT_PATH)
endif(ANDROID)
find_file(DOXYFILE_IN "Doxyfile.in"
PATHS "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_ROOT}/Modules/"
NO_DEFAULT_PATH
DOC "Path to the doxygen configuration template file")
if(ANDROID)
set(CMAKE_FIND_ROOT_PATH $_save_root_path)
endif(ANDROID)
set(DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DOXYFILE_IN DEFAULT_MSG "DOXYFILE_IN")
endif()
if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND)
usedoxygen_set_default(DOXYFILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doxygen"
PATH "Doxygen output directory")
usedoxygen_set_default(DOXYFILE_HTML_DIR "html"
STRING "Doxygen HTML output directory")
usedoxygen_set_default(DOXYFILE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
PATH "Input files source directory")
usedoxygen_set_default(DOXYFILE_EXTRA_SOURCE_DIRS ""
STRING "Additional source files/directories separated by space")
set(DOXYFILE_SOURCE_DIRS "\"${DOXYFILE_SOURCE_DIR}\" ${DOXYFILE_EXTRA_SOURCES}")
usedoxygen_set_default(DOXYFILE_LATEX YES BOOL "Generate LaTeX API documentation" OFF)
usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex" STRING "LaTex output directory")
mark_as_advanced(DOXYFILE_OUTPUT_DIR DOXYFILE_HTML_DIR DOXYFILE_LATEX_DIR
DOXYFILE_SOURCE_DIR DOXYFILE_EXTRA_SOURCE_DIRS DOXYFILE_IN)
set_property(DIRECTORY
APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_HTML_DIR}")
add_custom_target(doxygen
COMMAND "${DOXYGEN_EXECUTABLE}"
"${DOXYFILE}"
COMMENT "Writing documentation to ${DOXYFILE_OUTPUT_DIR}..."
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
set(DOXYFILE_DOT "NO")
if(DOXYGEN_DOT_EXECUTABLE)
set(DOXYFILE_DOT "YES")
endif()
## LaTeX
set(DOXYFILE_PDFLATEX "NO")
set_property(DIRECTORY APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
if(DOXYFILE_LATEX STREQUAL "ON")
set(DOXYFILE_GENERATE_LATEX "YES")
find_package(LATEX)
find_program(DOXYFILE_MAKE make)
mark_as_advanced(DOXYFILE_MAKE)
if(LATEX_COMPILER AND MAKEINDEX_COMPILER AND DOXYFILE_MAKE)
if(PDFLATEX_COMPILER)
set(DOXYFILE_PDFLATEX "YES")
endif()
add_custom_command(TARGET doxygen
POST_BUILD
COMMAND "${DOXYFILE_MAKE}"
COMMENT "Running LaTeX for Doxygen documentation in ${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}..."
WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
else()
set(DOXYGEN_LATEX "NO")
endif()
else()
set(DOXYFILE_GENERATE_LATEX "NO")
endif()
configure_file("${DOXYFILE_IN}" "${DOXYFILE}" @ONLY)
endif()

View file

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2012-2015, Matthias Schiffer <mschiffer@universe-factory.net> Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
Partly based on public domain code by Matthew Dempsky and D. J. Bernstein. Partly based on public domain code by Matthew Dempsky and D. J. Bernstein.
All rights reserved. All rights reserved.
@ -27,307 +27,36 @@
#ifndef _LIBUECC_ECC_H_ #ifndef _LIBUECC_ECC_H_
#define _LIBUECC_ECC_H_ #define _LIBUECC_ECC_H_
#ifndef DEPRECATED typedef struct _ecc_public_key_256 {
#define DEPRECATED __attribute__((deprecated)) unsigned char p[32];
#endif } ecc_public_key_256;
typedef struct _ecc_secret_key_256 {
unsigned char s[32];
} ecc_secret_key_256;
#include <stdint.h>
/**
* A 256 bit integer
*
* All functions of libuecc treat \ref ecc_int256_t as unsigned little-endian.
*/
typedef union _ecc_int256 {
/** Data bytes */
uint8_t p[32];
} ecc_int256_t;
/**
* A point on the curve unpacked for efficient calculation
*
* The internal representation of an unpacked point isn't unique, so for serialization
* it should always be packed.
*/
typedef struct _ecc_25519_work { typedef struct _ecc_25519_work {
uint32_t X[32]; unsigned int X[32];
uint32_t Y[32]; unsigned int Y[32];
uint32_t Z[32]; unsigned int Z[32];
uint32_t T[32]; unsigned int T[32];
} ecc_25519_work_t; } ecc_25519_work;
/**
* \defgroup curve_ops Operations on points of the Elliptic Curve
* @{
*/
/** The identity element */
extern const ecc_25519_work_t ecc_25519_work_identity;
/** void ecc_25519_load(ecc_25519_work *out, const ecc_public_key_256 *in);
* The Ed25519 default generator point void ecc_25519_store(ecc_public_key_256 *out, const ecc_25519_work *in);
*
* \deprecated Use the equivalent \ref ecc_25519_work_default_base instead.
*
**/
DEPRECATED extern const ecc_25519_work_t ecc_25519_work_base_ed25519;
/** int ecc_25519_is_identity(const ecc_25519_work *in);
* The Ed25519 default generator point void ecc_25519_add(ecc_25519_work *out, const ecc_25519_work *in1, const ecc_25519_work *in2);
* void ecc_25519_double(ecc_25519_work *out, const ecc_25519_work *in);
* \deprecated Use the equivalent \ref ecc_25519_work_default_base instead. void ecc_25519_scalarmult(ecc_25519_work *out, const ecc_secret_key_256 *n, const ecc_25519_work *base);
*/ void ecc_25519_scalarmult_base(ecc_25519_work *out, const ecc_secret_key_256 *n);
DEPRECATED extern const ecc_25519_work_t ecc_25519_work_base_legacy;
int ecc_25519_secret_is_zero(const ecc_secret_key_256 *in);
/** void ecc_25519_secret_add(ecc_secret_key_256 *out, const ecc_secret_key_256 *in1, const ecc_secret_key_256 *in2);
* The Ed25519 default generator point void ecc_25519_secret_sub(ecc_secret_key_256 *out, const ecc_secret_key_256 *in1, const ecc_secret_key_256 *in2);
* void ecc_25519_secret_reduce(ecc_secret_key_256 *out, const ecc_secret_key_256 *in);
* The order of the base point is \f$ 2^{252} + 27742317777372353535851937790883648493 \f$. void ecc_25519_secret_mult(ecc_secret_key_256 *out, const ecc_secret_key_256 *in1, const ecc_secret_key_256 *in2);
*/ void ecc_25519_secret_sanitize(ecc_secret_key_256 *out, const ecc_secret_key_256 *in);
extern const ecc_25519_work_t ecc_25519_work_default_base;
/** Loads a point of the Ed25519 curve with given coordinates into its unpacked representation */
int ecc_25519_load_xy_ed25519(ecc_25519_work_t *out, const ecc_int256_t *x, const ecc_int256_t *y);
/**
* Loads a point of the legacy curve with given coordinates into its unpacked representation
*
* New software should use \ref ecc_25519_load_xy_ed25519, which uses the same curve as the Ed25519 algorithm.
*/
int ecc_25519_load_xy_legacy(ecc_25519_work_t *out, const ecc_int256_t *x, const ecc_int256_t *y);
/**
* Loads a point of the legacy curve with given coordinates into its unpacked representation
*
* \deprecated Use \ref ecc_25519_load_xy_legacy
*/
DEPRECATED int ecc_25519_load_xy(ecc_25519_work_t *out, const ecc_int256_t *x, const ecc_int256_t *y);
/**
* Stores the x and y coordinates of a point of the Ed25519 curve
*
* \param x Returns the x coordinate of the point. May be NULL.
* \param y Returns the y coordinate of the point. May be NULL.
* \param in The unpacked point to store.
*/
void ecc_25519_store_xy_ed25519(ecc_int256_t *x, ecc_int256_t *y, const ecc_25519_work_t *in);
/**
* Stores the x and y coordinates of a point of the legacy curve
*
* New software should use \ref ecc_25519_store_xy_ed25519, which uses the same curve as the Ed25519 algorithm.
*
* \param x Returns the x coordinate of the point. May be NULL.
* \param y Returns the y coordinate of the point. May be NULL.
* \param in The unpacked point to store.
*/
void ecc_25519_store_xy_legacy(ecc_int256_t *x, ecc_int256_t *y, const ecc_25519_work_t *in);
/**
* Stores a point's x and y coordinates
*
* \param x Returns the x coordinate of the point. May be NULL.
* \param y Returns the y coordinate of the point. May be NULL.
* \param in The unpacked point to store.
*
* \deprecated Use \ref ecc_25519_store_xy_legacy
*/
DEPRECATED void ecc_25519_store_xy(ecc_int256_t *x, ecc_int256_t *y, const ecc_25519_work_t *in);
/**
* Loads a packed point of the Ed25519 curve into its unpacked representation
*
* The packed format is different from the legacy one: the legacy format contains that X coordinate and the parity of the Y coordinate,
* Ed25519 uses the Y coordinate and the parity of the X coordinate.
*/
int ecc_25519_load_packed_ed25519(ecc_25519_work_t *out, const ecc_int256_t *in);
/**
* Loads a packed point of the legacy curve into its unpacked representation
*
* New software should use \ref ecc_25519_load_packed_ed25519, which uses the same curve and packed representation as the Ed25519 algorithm.
*
* The packed format is different from the Ed25519 one: the legacy format contains that X coordinate and the parity of the Y coordinate,
* Ed25519 uses the Y coordinate and the parity of the X coordinate.
*/
int ecc_25519_load_packed_legacy(ecc_25519_work_t *out, const ecc_int256_t *in);
/**
* Loads a packed point of the legacy curve into its unpacked representation
*
* \deprecated Use \ref ecc_25519_load_packed_legacy
*/
DEPRECATED int ecc_25519_load_packed(ecc_25519_work_t *out, const ecc_int256_t *in);
/**
* Stores a point of the Ed25519 curve into its packed representation
*
* The packed format is different from the Ed25519 one: the legacy format contains that X coordinate and the parity of the Y coordinate,
* Ed25519 uses the Y coordinate and the parity of the X coordinate.
*/
void ecc_25519_store_packed_ed25519(ecc_int256_t *out, const ecc_25519_work_t *in);
/**
* Stores a point of the legacy curve into its packed representation
*
* New software should use \ref ecc_25519_store_packed_ed25519, which uses the same curve and packed representation as the Ed25519 algorithm.
*
* The packed format is different from the Ed25519 one: the legacy format contains that X coordinate and the parity of the Y coordinate,
* Ed25519 uses the Y coordinate and the parity of the X coordinate.
*/
void ecc_25519_store_packed_legacy(ecc_int256_t *out, const ecc_25519_work_t *in);
/**
* Stores a point of the legacy curve into its packed representation
*
* \deprecated Use \ref ecc_25519_store_packed_legacy
*/
DEPRECATED void ecc_25519_store_packed(ecc_int256_t *out, const ecc_25519_work_t *in);
/** Checks if a point is the identity element of the Elliptic Curve group */
int ecc_25519_is_identity(const ecc_25519_work_t *in);
/**
* Negates a point of the Elliptic Curve
*
* The same pointer may be given for input and output
*/
void ecc_25519_negate(ecc_25519_work_t *out, const ecc_25519_work_t *in);
/**
* Doubles a point of the Elliptic Curve
*
* ecc_25519_double(out, in) is equivalent to ecc_25519_add(out, in, in), but faster.
*
* The same pointer may be given for input and output.
*/
void ecc_25519_double(ecc_25519_work_t *out, const ecc_25519_work_t *in);
/**
* Adds two points of the Elliptic Curve
*
* The same pointers may be given for input and output.
*/
void ecc_25519_add(ecc_25519_work_t *out, const ecc_25519_work_t *in1, const ecc_25519_work_t *in2);
/**
* Subtracts two points of the Elliptic Curve
*
* The same pointers may be given for input and output.
*/
void ecc_25519_sub(ecc_25519_work_t *out, const ecc_25519_work_t *in1, const ecc_25519_work_t *in2);
/**
* Does a scalar multiplication of a point of the Elliptic Curve with an integer of a given bit length
*
* To speed up scalar multiplication when it is known that not the whole 256 bits of the scalar
* are used. The bit length should always be a constant and not computed at runtime to ensure
* that no timing attacks are possible.
*
* The same pointer may be given for input and output.
**/
void ecc_25519_scalarmult_bits(ecc_25519_work_t *out, const ecc_int256_t *n, const ecc_25519_work_t *base, unsigned bits);
/**
* Does a scalar multiplication of a point of the Elliptic Curve with an integer
*
* The same pointer may be given for input and output.
**/
void ecc_25519_scalarmult(ecc_25519_work_t *out, const ecc_int256_t *n, const ecc_25519_work_t *base);
/**
* Does a scalar multiplication of the default base point (generator element) of the Elliptic Curve with an integer of a given bit length
*
* The order of the base point is \f$ 2^{252} + 27742317777372353535851937790883648493 \f$.
*
* ecc_25519_scalarmult_base_bits(out, n, bits) is faster than ecc_25519_scalarmult_bits(out, n, &ecc_25519_work_default_base, bits).
*
* See the notes about \ref ecc_25519_scalarmult_bits before using this function.
*/
void ecc_25519_scalarmult_base_bits(ecc_25519_work_t *out, const ecc_int256_t *n, unsigned bits);
/**
* Does a scalar multiplication of the default base point (generator element) of the Elliptic Curve with an integer
*
* The order of the base point is \f$ 2^{252} + 27742317777372353535851937790883648493 \f$.
*
* ecc_25519_scalarmult_base(out, n) is faster than ecc_25519_scalarmult(out, n, &ecc_25519_work_default_base).
*/
void ecc_25519_scalarmult_base(ecc_25519_work_t *out, const ecc_int256_t *n);
/**@}*/
/**
* \defgroup gf_ops Prime field operations for the order of the base point of the Elliptic Curve
* @{
*/
/**
* The order of the prime field
*
* The order is \f$ 2^{252} + 27742317777372353535851937790883648493 \f$.
*/
extern const ecc_int256_t ecc_25519_gf_order;
/** Checks if an integer is equal to zero (after reduction) */
int ecc_25519_gf_is_zero(const ecc_int256_t *in);
/**
* Adds two integers as Galois field elements
*
* The same pointers may be given for input and output.
*/
void ecc_25519_gf_add(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2);
/**
* Subtracts two integers as Galois field elements
*
* The same pointers may be given for input and output.
*/
void ecc_25519_gf_sub(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2);
/**
* Reduces an integer to a unique representation in the range \f$ [0,q-1] \f$
*
* The same pointer may be given for input and output.
*/
void ecc_25519_gf_reduce(ecc_int256_t *out, const ecc_int256_t *in);
/**
* Multiplies two integers as Galois field elements
*
* The same pointers may be given for input and output.
*/
void ecc_25519_gf_mult(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2);
/**
* Computes the reciprocal of a Galois field element
*
* The same pointers may be given for input and output.
*/
void ecc_25519_gf_recip(ecc_int256_t *out, const ecc_int256_t *in);
/**
* Ensures some properties of a Galois field element to make it fit for use as a secret key
*
* This sets the 255th bit and clears the 256th and the bottom three bits (so the key
* will be a multiple of 8). See Daniel J. Bernsteins paper "Curve25519: new Diffie-Hellman speed records."
* for the rationale of this.
*
* The same pointer may be given for input and output.
*/
void ecc_25519_gf_sanitize_secret(ecc_int256_t *out, const ecc_int256_t *in);
/**@}*/
#endif /* _LIBUECC_ECC_H_ */ #endif /* _LIBUECC_ECC_H_ */

View file

@ -1,10 +0,0 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/@LIBDIR@
includedir=${prefix}/include
Name: libuecc
Description: Very small Elliptic Curve Cryptography library
Version: @PROJECT_VERSION@
Libs: -L${libdir} -luecc
Cflags: -I${includedir}/libuecc-@PROJECT_VERSION@

View file

@ -1,24 +1,7 @@
include_directories(${LIBUECC_SOURCE_DIR}/include) include_directories(${LIBUECC_SOURCE_DIR}/include)
set(UECC_SRC ec25519.c ec25519_gf.c) add_library(uecc STATIC ec25519.c ec25519_secret.c)
set(UECC_ABI 0)
add_library(uecc_shared SHARED ${UECC_SRC}) install(TARGETS uecc
set_target_properties(uecc_shared PROPERTIES ARCHIVE DESTINATION lib
OUTPUT_NAME uecc
SOVERSION ${UECC_ABI}
VERSION ${UECC_ABI}.${PROJECT_VERSION}
COMPILE_FLAGS -Wall
)
add_library(uecc_static STATIC ${UECC_SRC})
set_target_properties(uecc_static PROPERTIES
OUTPUT_NAME uecc
COMPILE_FLAGS -Wall
)
install(TARGETS uecc_shared uecc_static
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION bin
) )

View file

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2012-2015, Matthias Schiffer <mschiffer@universe-factory.net> Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
Partly based on public domain code by Matthew Dempsky and D. J. Bernstein. Partly based on public domain code by Matthew Dempsky and D. J. Bernstein.
All rights reserved. All rights reserved.
@ -24,325 +24,119 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/** \file /*
* EC group operations for Twisted Edwards Curve \f$ ax^2 + y^2 = 1 + dx^2y^2 \f$ EC group operations for Twisted Edwards Curve ax^2 + y^2 = 1 + dx^2y^2 with
* on prime field \f$ p = 2^{255} - 19 \f$. a = 486664
* d = 486660
* Two different (isomorphic) sets of curve parameters are supported: on prime field p = 2^255 - 19.
*
* \f$ a = 486664 \f$ and The curve is equivalent to the Montgomery Curve used in D. J. Bernstein's
* \f$ d = 486660 \f$ Curve25519 Diffie-Hellman algorithm
* are the parameters used by the original libuecc implementation (till v5).
* To use points on this curve, use the functions with the suffix \em legacy. See http://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html for add and
* double operations
* The other supported curve uses the parameters */
* \f$ a = -1 \f$ and
* \f$ d = -(121665/121666) \f$,
* which is the curve used by the Ed25519 algorithm. The functions for this curve
* have the suffix \em ed25519.
*
* Internally, libuecc always uses the latter representation for its \em work structure.
*
* The curves are equivalent to the Montgomery Curve used in D. J. Bernstein's
* Curve25519 Diffie-Hellman algorithm.
*
* See http://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html for add and
* double operations.
*
* Doxygen comments for public APIs can be found in the public header file.
*
* Invariant that must be held by all public API: the components of an
* \ref ecc_25519_work_t are always in the range \f$ [0, 2p) \f$.
* Integers in this range will be called \em squeezed in the following.
*/
#include <libuecc/ecc.h> #include <libuecc/ecc.h>
const ecc_25519_work_t ecc_25519_work_identity = {{0}, {1}, {1}, {0}}; static void add(unsigned int out[32], const unsigned int a[32], const unsigned int b[32]) {
const ecc_25519_work_t ecc_25519_work_base_legacy = {
{0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9,
0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69,
0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21},
{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66},
{1},
{0xa3, 0xdd, 0xb7, 0xa5, 0xb3, 0x8a, 0xde, 0x6d,
0xf5, 0x52, 0x51, 0x77, 0x80, 0x9f, 0xf0, 0x20,
0x7d, 0xe3, 0xab, 0x64, 0x8e, 0x4e, 0xea, 0x66,
0x65, 0x76, 0x8b, 0xd7, 0x0f, 0x5f, 0x87, 0x67},
};
const ecc_25519_work_t ecc_25519_work_default_base = {
{0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9,
0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69,
0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21},
{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66},
{1},
{0xa3, 0xdd, 0xb7, 0xa5, 0xb3, 0x8a, 0xde, 0x6d,
0xf5, 0x52, 0x51, 0x77, 0x80, 0x9f, 0xf0, 0x20,
0x7d, 0xe3, 0xab, 0x64, 0x8e, 0x4e, 0xea, 0x66,
0x65, 0x76, 0x8b, 0xd7, 0x0f, 0x5f, 0x87, 0x67},
};
const ecc_25519_work_t ecc_25519_work_base_ed25519 = {
{0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9,
0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69,
0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21},
{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66},
{1},
{0xa3, 0xdd, 0xb7, 0xa5, 0xb3, 0x8a, 0xde, 0x6d,
0xf5, 0x52, 0x51, 0x77, 0x80, 0x9f, 0xf0, 0x20,
0x7d, 0xe3, 0xab, 0x64, 0x8e, 0x4e, 0xea, 0x66,
0x65, 0x76, 0x8b, 0xd7, 0x0f, 0x5f, 0x87, 0x67},
};
static const uint32_t zero[32] = {0};
static const uint32_t one[32] = {1};
static const uint32_t minus1[32] = {
0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
};
/** Ed25519 parameter -(121665/121666) */
static const uint32_t d[32] = {
0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52,
};
/** Factor to multiply the X coordinate with to convert from the legacy to the Ed25519 curve */
static const uint32_t legacy_to_ed25519[32] = {
0xe7, 0x81, 0xba, 0x00, 0x55, 0xfb, 0x91, 0x33,
0x7d, 0xe5, 0x82, 0xb4, 0x2e, 0x2c, 0x5e, 0x3a,
0x81, 0xb0, 0x03, 0xfc, 0x23, 0xf7, 0x84, 0x2d,
0x44, 0xf9, 0x5f, 0x9f, 0x0b, 0x12, 0xd9, 0x70,
};
/** Factor to multiply the X coordinate with to convert from the Ed25519 to the legacy curve */
static const uint32_t ed25519_to_legacy[32] = {
0xe9, 0x68, 0x42, 0xdb, 0xaf, 0x04, 0xb4, 0x40,
0xa1, 0xd5, 0x43, 0xf2, 0xf9, 0x38, 0x31, 0x28,
0x01, 0x17, 0x05, 0x67, 0x9b, 0x81, 0x61, 0xf8,
0xa9, 0x5b, 0x3e, 0x6a, 0x20, 0x67, 0x4b, 0x24,
};
/** Adds two unpacked integers (modulo p) */
static void add(uint32_t out[32], const uint32_t a[32], const uint32_t b[32]) {
unsigned int j; unsigned int j;
uint32_t u; unsigned int u;
u = 0; u = 0;
for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; }
for (j = 0; j < 31; j++) { u += a[31] + b[31]; out[31] = u;
u += a[j] + b[j];
out[j] = u & 255;
u >>= 8;
}
u += a[31] + b[31];
out[31] = u;
} }
/** static void sub(unsigned int out[32], const unsigned int a[32], const unsigned int b[32]) {
* Subtracts two unpacked integers (modulo p)
*
* b must be \em squeezed.
*/
static void sub(uint32_t out[32], const uint32_t a[32], const uint32_t b[32]) {
unsigned int j; unsigned int j;
uint32_t u; unsigned int u;
u = 218; u = 218;
for (j = 0;j < 31;++j) { for (j = 0;j < 31;++j) {
u += a[j] + UINT32_C(65280) - b[j]; u += a[j] + 65280 - b[j];
out[j] = u & 255; out[j] = u & 255;
u >>= 8; u >>= 8;
} }
u += a[31] - b[31]; u += a[31] - b[31];
out[31] = u; out[31] = u;
} }
/** static void squeeze(unsigned int a[32]) {
* Performs carry and reduce on an unpacked integer
*
* The result is not always fully reduced, but it will be significantly smaller than \f$ 2p \f$.
*/
static void squeeze(uint32_t a[32]) {
unsigned int j; unsigned int j;
uint32_t u; unsigned int u;
u = 0; u = 0;
for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
for (j = 0;j < 31;++j) { u += a[31]; a[31] = u & 127;
u += a[j];
a[j] = u & 255;
u >>= 8;
}
u += a[31];
a[31] = u & 127;
u = 19 * (u >> 7); u = 19 * (u >> 7);
for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
for (j = 0;j < 31;++j) { u += a[31]; a[31] = u;
u += a[j];
a[j] = u & 255;
u >>= 8;
}
u += a[31];
a[31] = u;
} }
static void freeze(unsigned int a[32]) {
static const uint32_t minusp[32] = { static const unsigned int minusp[32] = {
19, 0, 0, 0, 0, 0, 0, 0, 19, 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, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 128 0, 0, 0, 0, 0, 0, 0, 128
}; };
/** unsigned int aorig[32];
* Ensures that the output of a previous \ref squeeze is fully reduced
*
* After a \ref freeze, only the lower byte of each integer part holds a meaningful value.
*/
static void freeze(uint32_t a[32]) {
uint32_t aorig[32];
unsigned int j; unsigned int j;
uint32_t negative; unsigned int negative;
for (j = 0; j < 32; j++) for (j = 0; j < 32; j++) aorig[j] = a[j];
aorig[j] = a[j];
add(a, a, minusp); add(a, a, minusp);
negative = -((a[31] >> 7) & 1); negative = -((a[31] >> 7) & 1);
for (j = 0; j < 32; j++) a[j] ^= negative & (aorig[j] ^ a[j]);
for (j = 0; j < 32; j++)
a[j] ^= negative & (aorig[j] ^ a[j]);
} }
/** static void mult(unsigned int out[32], const unsigned int a[32], const unsigned int b[32]) {
* Returns the parity (lowest bit of the fully reduced value) of a unsigned int i;
* unsigned int j;
* The input must be \em squeezed. unsigned int u;
*/
static int parity(const uint32_t a[32]) {
uint32_t b[32];
add(b, a, minusp);
return (a[0] ^ (b[31] >> 7) ^ 1) & 1;
}
/**
* Multiplies two unpacked integers (modulo p)
*
* The result will be \em squeezed.
*/
static void mult(uint32_t out[32], const uint32_t a[32], const uint32_t b[32]) {
unsigned int i, j;
uint32_t u;
for (i = 0; i < 32; ++i) { for (i = 0; i < 32; ++i) {
u = 0; u = 0;
for (j = 0;j <= i;++j) u += a[j] * b[i - j];
for (j = 0; j <= i; j++) for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j];
u += a[j] * b[i - j];
for (j = i + 1; j < 32; j++)
u += 38 * a[j] * b[i + 32 - j];
out[i] = u; out[i] = u;
} }
squeeze(out); squeeze(out);
} }
/** static void mult_int(unsigned int out[32], const unsigned int n, const unsigned int a[32]) {
* Multiplies an unpacked integer with a small integer (modulo p)
*
* The result will be \em squeezed.
*/
static void mult_int(uint32_t out[32], uint32_t n, const uint32_t a[32]) {
unsigned int j; unsigned int j;
uint32_t u; unsigned int u;
u = 0; u = 0;
for (j = 0;j < 31;++j) { u += n * a[j]; out[j] = u & 255; u >>= 8; }
for (j = 0; j < 31; j++) {
u += n * a[j];
out[j] = u & 255;
u >>= 8;
}
u += n * a[31]; out[31] = u & 127; u += n * a[31]; out[31] = u & 127;
u = 19 * (u >> 7); u = 19 * (u >> 7);
for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; }
for (j = 0; j < 31; j++) { u += out[j]; out[j] = u;
u += out[j];
out[j] = u & 255;
u >>= 8;
}
u += out[j];
out[j] = u;
} }
/** static void square(unsigned int out[32], const unsigned int a[32]) {
* Squares an unpacked integer unsigned int i;
* unsigned int j;
* The result will be sqeezed. unsigned int u;
*/
static void square(uint32_t out[32], const uint32_t a[32]) {
unsigned int i, j;
uint32_t u;
for (i = 0; i < 32; i++) { for (i = 0; i < 32; ++i) {
u = 0; u = 0;
for (j = 0;j < i - j;++j) u += a[j] * a[i - j];
for (j = 0; j < i - j; j++) for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j];
u += a[j] * a[i - j];
for (j = i + 1; j < i + 32 - j; j++)
u += 38 * a[j] * a[i + 32 - j];
u *= 2; u *= 2;
if ((i & 1) == 0) { if ((i & 1) == 0) {
u += a[i / 2] * a[i / 2]; u += a[i / 2] * a[i / 2];
u += 38 * a[i / 2 + 16] * a[i / 2 + 16]; u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
} }
out[i] = u; out[i] = u;
} }
squeeze(out); squeeze(out);
} }
/** Checks for the equality of two unpacked integers */ static int check_equal(const unsigned int x[32], const unsigned int y[32]) {
static int check_equal(const uint32_t x[32], const uint32_t y[32]) { unsigned int differentbits = 0;
uint32_t differentbits = 0;
int i; int i;
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
@ -353,13 +147,9 @@ static int check_equal(const uint32_t x[32], const uint32_t y[32]) {
return (1 & ((differentbits - 1) >> 16)); return (1 & ((differentbits - 1) >> 16));
} }
/** static int check_zero(const unsigned int x[32]) {
* Checks if an unpacked integer equals zero (modulo p) static const unsigned int zero[32] = {0};
* static const unsigned int p[32] = {
* The integer must be squeezed before.
*/
static int check_zero(const uint32_t x[32]) {
static const uint32_t p[32] = {
0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@ -369,11 +159,10 @@ static int check_zero(const uint32_t x[32]) {
return (check_equal(x, zero) | check_equal(x, p)); return (check_equal(x, zero) | check_equal(x, p));
} }
/** Copies r to out when b == 0, s when b == 1 */ static void selectw(ecc_25519_work *out, const ecc_25519_work *r, const ecc_25519_work *s, unsigned int b) {
static void selectw(ecc_25519_work_t *out, const ecc_25519_work_t *r, const ecc_25519_work_t *s, uint32_t b) {
unsigned int j; unsigned int j;
uint32_t t; unsigned int t;
uint32_t bminus1; unsigned int bminus1;
bminus1 = b - 1; bminus1 = b - 1;
for (j = 0; j < 32; ++j) { for (j = 0; j < 32; ++j) {
@ -391,11 +180,10 @@ static void selectw(ecc_25519_work_t *out, const ecc_25519_work_t *r, const ecc_
} }
} }
/** Copies r to out when b == 0, s when b == 1 */ static void select(unsigned int out[32], const unsigned int r[32], const unsigned int s[32], unsigned int b) {
static void select(uint32_t out[32], const uint32_t r[32], const uint32_t s[32], uint32_t b) {
unsigned int j; unsigned int j;
uint32_t t; unsigned int t;
uint32_t bminus1; unsigned int bminus1;
bminus1 = b - 1; bminus1 = b - 1;
for (j = 0;j < 32;++j) { for (j = 0;j < 32;++j) {
@ -404,13 +192,15 @@ static void select(uint32_t out[32], const uint32_t r[32], const uint32_t s[32],
} }
} }
/** static void square_root(unsigned int out[32], const unsigned int z[32]) {
* Computes the square root of an unpacked integer (in the prime field modulo p) static const unsigned int minus1[32] = {
* 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
* If the given integer has no square root, 0 is returned, 1 otherwise. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
static int square_root(uint32_t out[32], const uint32_t z[32]) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
static const uint32_t rho_s[32] = { };
static const unsigned int rho_s[32] = {
0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4, 0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4,
0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f, 0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f,
0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b, 0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b,
@ -419,18 +209,18 @@ static int square_root(uint32_t out[32], const uint32_t z[32]) {
/* raise z to power (2^252-2), check if power (2^253-5) equals -1 */ /* raise z to power (2^252-2), check if power (2^253-5) equals -1 */
uint32_t z2[32]; unsigned int z2[32];
uint32_t z9[32]; unsigned int z9[32];
uint32_t z11[32]; unsigned int z11[32];
uint32_t z2_5_0[32]; unsigned int z2_5_0[32];
uint32_t z2_10_0[32]; unsigned int z2_10_0[32];
uint32_t z2_20_0[32]; unsigned int z2_20_0[32];
uint32_t z2_50_0[32]; unsigned int z2_50_0[32];
uint32_t z2_100_0[32]; unsigned int z2_100_0[32];
uint32_t t0[32]; unsigned int t0[32];
uint32_t t1[32]; unsigned int t1[32];
uint32_t z2_252_1[32]; unsigned int z2_252_1[32];
uint32_t z2_252_1_rho_s[32]; unsigned int z2_252_1_rho_s[32];
int i; int i;
/* 2 */ square(z2, z); /* 2 */ square(z2, z);
@ -489,24 +279,19 @@ static int square_root(uint32_t out[32], const uint32_t z[32]) {
mult(z2_252_1_rho_s, z2_252_1, rho_s); mult(z2_252_1_rho_s, z2_252_1, rho_s);
select(out, z2_252_1, z2_252_1_rho_s, check_equal(t1, minus1)); select(out, z2_252_1, z2_252_1_rho_s, check_equal(t1, minus1));
/* Check the root */
square(t0, out);
return check_equal(t0, z);
} }
/** Computes the reciprocal of an unpacked integer (in the prime field modulo p) */ static void recip(unsigned int out[32], const unsigned int z[32]) {
static void recip(uint32_t out[32], const uint32_t z[32]) { unsigned int z2[32];
uint32_t z2[32]; unsigned int z9[32];
uint32_t z9[32]; unsigned int z11[32];
uint32_t z11[32]; unsigned int z2_5_0[32];
uint32_t z2_5_0[32]; unsigned int z2_10_0[32];
uint32_t z2_10_0[32]; unsigned int z2_20_0[32];
uint32_t z2_20_0[32]; unsigned int z2_50_0[32];
uint32_t z2_50_0[32]; unsigned int z2_100_0[32];
uint32_t z2_100_0[32]; unsigned int t0[32];
uint32_t t0[32]; unsigned int t1[32];
uint32_t t1[32];
int i; int i;
/* 2 */ square(z2, z); /* 2 */ square(z2, z);
@ -562,207 +347,58 @@ static void recip(uint32_t out[32], const uint32_t z[32]) {
/* 2^255 - 21 */ mult(out, t1, z11); /* 2^255 - 21 */ mult(out, t1, z11);
} }
/** void ecc_25519_load(ecc_25519_work *out, const ecc_public_key_256 *in) {
* Checks if the X and Y coordinates of a work structure represent a valid point of the curve static const unsigned int zero[32] = {0};
* static const unsigned int one[32] = {1};
* Also fills in the T coordinate.
*/
static int check_load_xy(ecc_25519_work_t *val) {
uint32_t X2[32], Y2[32], dX2[32], dX2Y2[32], Y2_X2[32], Y2_X2_1[32], r[32];
/* Check validity */
square(X2, val->X);
square(Y2, val->Y);
mult(dX2, d, X2);
mult(dX2Y2, dX2, Y2);
sub(Y2_X2, Y2, X2);
sub(Y2_X2_1, Y2_X2, one);
sub(r, Y2_X2_1, dX2Y2);
squeeze(r);
if (!check_zero(r))
return 0;
mult(val->T, val->X, val->Y);
return 1;
}
int ecc_25519_load_xy_ed25519(ecc_25519_work_t *out, const ecc_int256_t *x, const ecc_int256_t *y) {
int i; int i;
unsigned int X2[32] /* X^2 */, aX2[32] /* aX^2 */, dX2[32] /* dX^2 */, _1_aX2[32] /* 1-aX^2 */, _1_dX2[32] /* 1-aX^2 */;
unsigned int _1_1_dX2[32] /* 1/(1-aX^2) */, Y2[32] /* Y^2 */, Y[32], Yt[32];
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
out->X[i] = x->p[i]; out->X[i] = in->p[i];
out->Y[i] = y->p[i];
out->Z[i] = (i == 0); out->Z[i] = (i == 0);
} }
return check_load_xy(out); out->X[31] &= 0x7f;
}
int ecc_25519_load_xy_legacy(ecc_25519_work_t *out, const ecc_int256_t *x, const ecc_int256_t *y) { square(X2, out->X);
int i; mult_int(aX2, 486664, X2);
uint32_t tmp[32]; mult_int(dX2, 486660, X2);
for (i = 0; i < 32; i++) {
tmp[i] = x->p[i];
out->Y[i] = y->p[i];
out->Z[i] = (i == 0);
}
mult(out->X, tmp, legacy_to_ed25519);
return check_load_xy(out);
}
int ecc_25519_load_xy(ecc_25519_work_t *out, const ecc_int256_t *x, const ecc_int256_t *y) {
return ecc_25519_load_xy_legacy(out, x, y);
}
void ecc_25519_store_xy_ed25519(ecc_int256_t *x, ecc_int256_t *y, const ecc_25519_work_t *in) {
uint32_t X[32], Y[32], Z[32];
int i;
recip(Z, in->Z);
if (x) {
mult(X, Z, in->X);
freeze(X);
for (i = 0; i < 32; i++)
x->p[i] = X[i];
}
if (y) {
mult(Y, Z, in->Y);
freeze(Y);
for (i = 0; i < 32; i++)
y->p[i] = Y[i];
}
}
void ecc_25519_store_xy_legacy(ecc_int256_t *x, ecc_int256_t *y, const ecc_25519_work_t *in) {
uint32_t X[32], tmp[32], Y[32], Z[32];
int i;
recip(Z, in->Z);
if (x) {
mult(tmp, Z, in->X);
mult(X, tmp, ed25519_to_legacy);
freeze(X);
for (i = 0; i < 32; i++)
x->p[i] = X[i];
}
if (y) {
mult(Y, Z, in->Y);
freeze(Y);
for (i = 0; i < 32; i++)
y->p[i] = Y[i];
}
}
void ecc_25519_store_xy(ecc_int256_t *x, ecc_int256_t *y, const ecc_25519_work_t *in) {
ecc_25519_store_xy_legacy(x, y, in);
}
int ecc_25519_load_packed_ed25519(ecc_25519_work_t *out, const ecc_int256_t *in) {
int i;
uint32_t Y2[32] /* Y^2 */, dY2[32] /* dY^2 */, Y2_1[32] /* Y^2-1 */, dY2_1[32] /* dY^2+1 */, _1_dY2_1[32] /* 1/(dY^2+1) */;
uint32_t X2[32] /* X^2 */, X[32], Xt[32];
for (i = 0; i < 32; i++) {
out->Y[i] = in->p[i];
out->Z[i] = (i == 0);
}
out->Y[31] &= 0x7f;
square(Y2, out->Y);
mult(dY2, d, Y2);
sub(Y2_1, Y2, one);
add(dY2_1, dY2, one);
recip(_1_dY2_1, dY2_1);
mult(X2, Y2_1, _1_dY2_1);
if (!square_root(X, X2))
return 0;
/* No squeeze is necessary after subtractions from zero if the subtrahend is squeezed */
sub(Xt, zero, X);
select(out->X, X, Xt, (in->p[31] >> 7) ^ parity(X));
mult(out->T, out->X, out->Y);
return 1;
}
int ecc_25519_load_packed_legacy(ecc_25519_work_t *out, const ecc_int256_t *in) {
int i;
uint32_t X2[32] /* X^2 */, aX2[32] /* aX^2 */, dX2[32] /* dX^2 */, _1_aX2[32] /* 1-aX^2 */, _1_dX2[32] /* 1-aX^2 */;
uint32_t _1_1_dX2[32] /* 1/(1-aX^2) */, Y2[32] /* Y^2 */, Y[32], Yt[32], X_legacy[32];
for (i = 0; i < 32; i++) {
X_legacy[i] = in->p[i];
out->Z[i] = (i == 0);
}
X_legacy[31] &= 0x7f;
square(X2, X_legacy);
mult_int(aX2, UINT32_C(486664), X2);
mult_int(dX2, UINT32_C(486660), X2);
sub(_1_aX2, one, aX2); sub(_1_aX2, one, aX2);
sub(_1_dX2, one, dX2); sub(_1_dX2, one, dX2);
recip(_1_1_dX2, _1_dX2); recip(_1_1_dX2, _1_dX2);
mult(Y2, _1_aX2, _1_1_dX2); mult(Y2, _1_aX2, _1_1_dX2);
square_root(Y, Y2);
if (!square_root(Y, Y2))
return 0;
/* No squeeze is necessary after subtractions from zero if the subtrahend is squeezed */
sub(Yt, zero, Y); sub(Yt, zero, Y);
select(out->Y, Y, Yt, (in->p[31] >> 7) ^ parity(Y)); select(out->Y, Y, Yt, (in->p[31] >> 7) ^ (Y[0] & 1));
mult(out->X, X_legacy, legacy_to_ed25519);
mult(out->T, out->X, out->Y); mult(out->T, out->X, out->Y);
return 1;
} }
int ecc_25519_load_packed(ecc_25519_work_t *out, const ecc_int256_t *in) { void ecc_25519_store(ecc_public_key_256 *out, const ecc_25519_work *in) {
return ecc_25519_load_packed_legacy(out, in); unsigned int x[32], y[32], z[32];
int i;
recip(z, in->Z);
mult(x, z, in->X);
mult(y, z, in->Y);
freeze(x);
freeze(y);
for (i = 0; i < 32; i++)
out->p[i] = x[i];
out->p[31] |= (y[0] << 7);
} }
static const ecc_25519_work id = {{0}, {1}, {1}, {0}};
void ecc_25519_store_packed_ed25519(ecc_int256_t *out, const ecc_25519_work_t *in) { int ecc_25519_is_identity(const ecc_25519_work *in) {
ecc_int256_t x; unsigned int Y_Z[32];
ecc_25519_store_xy_ed25519(&x, out, in);
out->p[31] |= (x.p[0] << 7);
}
void ecc_25519_store_packed_legacy(ecc_int256_t *out, const ecc_25519_work_t *in) {
ecc_int256_t y;
ecc_25519_store_xy_legacy(out, &y, in);
out->p[31] |= (y.p[0] << 7);
}
void ecc_25519_store_packed(ecc_int256_t *out, const ecc_25519_work_t *in) {
ecc_25519_store_packed_legacy(out, in);
}
int ecc_25519_is_identity(const ecc_25519_work_t *in) {
uint32_t Y_Z[32];
sub(Y_Z, in->Y, in->Z); sub(Y_Z, in->Y, in->Z);
squeeze(Y_Z); squeeze(Y_Z);
@ -770,127 +406,57 @@ int ecc_25519_is_identity(const ecc_25519_work_t *in) {
return (check_zero(in->X)&check_zero(Y_Z)); return (check_zero(in->X)&check_zero(Y_Z));
} }
void ecc_25519_negate(ecc_25519_work_t *out, const ecc_25519_work_t *in) { void ecc_25519_double(ecc_25519_work *out, const ecc_25519_work *in) {
int i; unsigned int A[32], B[32], C[32], D[32], E[32], F[32], G[32], H[32], t0[32], t1[32], t2[32], t3[32];
for (i = 0; i < 32; i++) {
out->Y[i] = in->Y[i];
out->Z[i] = in->Z[i];
}
/* No squeeze is necessary after subtractions from zero if the subtrahend is squeezed */
sub(out->X, zero, in->X);
sub(out->T, zero, in->T);
}
void ecc_25519_double(ecc_25519_work_t *out, const ecc_25519_work_t *in) {
uint32_t A[32], B[32], C[32], D[32], E[32], F[32], G[32], H[32], t0[32], t1[32];
square(A, in->X); square(A, in->X);
square(B, in->Y); square(B, in->Y);
square(t0, in->Z); square(t0, in->Z);
mult_int(C, 2, t0); mult_int(C, 2, t0);
mult_int(D, 486664, A);
sub(D, zero, A); add(t1, in->X, in->Y);
square(t2, t1);
add(t0, in->X, in->Y); sub(t3, t2, A); squeeze(t3);
square(t1, t0); sub(E, t3, B);
sub(t0, t1, A); add(G, D, B); squeeze(G);
sub(E, t0, B);
add(G, D, B);
sub(F, G, C); sub(F, G, C);
sub(H, D, B); sub(H, D, B);
mult(out->X, E, F); mult(out->X, E, F);
mult(out->Y, G, H); mult(out->Y, G, H);
mult(out->T, E, H); mult(out->T, E, H);
mult(out->Z, F, G); mult(out->Z, F, G);
} }
void ecc_25519_add(ecc_25519_work_t *out, const ecc_25519_work_t *in1, const ecc_25519_work_t *in2) { void ecc_25519_add(ecc_25519_work *out, const ecc_25519_work *in1, const ecc_25519_work *in2) {
const uint32_t j = UINT32_C(60833); unsigned int A[32], B[32], C[32], D[32], E[32], F[32], G[32], H[32], t0[32], t1[32], t2[32], t3[32], t4[32], t5[32];
const uint32_t k = UINT32_C(121665);
uint32_t A[32], B[32], C[32], D[32], E[32], F[32], G[32], H[32], t0[32], t1[32];
sub(t0, in1->Y, in1->X); mult(A, in1->X, in2->X);
mult_int(t1, j, t0); mult(B, in1->Y, in2->Y);
sub(t0, in2->Y, in2->X); mult_int(t0, 486660, in2->T);
mult(A, t0, t1);
add(t0, in1->Y, in1->X);
mult_int(t1, j, t0);
add(t0, in2->Y, in2->X);
mult(B, t0, t1);
mult_int(t0, k, in2->T);
mult(C, in1->T, t0); mult(C, in1->T, t0);
mult(D, in1->Z, in2->Z);
mult_int(t0, 2*j, in2->Z); add(t1, in1->X, in1->Y);
mult(D, in1->Z, t0); add(t2, in2->X, in2->Y);
mult(t3, t1, t2);
sub(E, B, A); sub(t4, t3, A); squeeze(t4);
add(F, D, C); sub(E, t4, B);
sub(G, D, C); sub(F, D, C);
add(H, B, A); add(G, D, C);
mult_int(t5, 486664, A);
sub(H, B, t5);
mult(out->X, E, F); mult(out->X, E, F);
mult(out->Y, G, H); mult(out->Y, G, H);
mult(out->T, E, H); mult(out->T, E, H);
mult(out->Z, F, G); mult(out->Z, F, G);
} }
/** Adds two points of the Elliptic Curve, assuming that in2->Z == 1 */ void ecc_25519_scalarmult(ecc_25519_work *out, const ecc_secret_key_256 *n, const ecc_25519_work *base) {
static void ecc_25519_add1(ecc_25519_work_t *out, const ecc_25519_work_t *in1, const ecc_25519_work_t *in2) { ecc_25519_work Q2, Q2p;
const uint32_t j = UINT32_C(60833); ecc_25519_work cur = id;
const uint32_t k = UINT32_C(121665);
uint32_t A[32], B[32], C[32], D[32], E[32], F[32], G[32], H[32], t0[32], t1[32];
sub(t0, in1->Y, in1->X);
mult_int(t1, j, t0);
sub(t0, in2->Y, in2->X);
mult(A, t0, t1);
add(t0, in1->Y, in1->X);
mult_int(t1, j, t0);
add(t0, in2->Y, in2->X);
mult(B, t0, t1);
mult_int(t0, k, in2->T);
mult(C, in1->T, t0);
mult_int(D, 2*j, in1->Z);
sub(E, B, A);
add(F, D, C);
sub(G, D, C);
add(H, B, A);
mult(out->X, E, F);
mult(out->Y, G, H);
mult(out->T, E, H);
mult(out->Z, F, G);
}
void ecc_25519_sub(ecc_25519_work_t *out, const ecc_25519_work_t *in1, const ecc_25519_work_t *in2) {
ecc_25519_work_t in2_neg;
ecc_25519_negate(&in2_neg, in2);
ecc_25519_add(out, in1, &in2_neg);
}
void ecc_25519_scalarmult_bits(ecc_25519_work_t *out, const ecc_int256_t *n, const ecc_25519_work_t *base, unsigned bits) {
ecc_25519_work_t Q2, Q2p;
ecc_25519_work_t cur = ecc_25519_work_identity;
int b, pos; int b, pos;
if (bits > 256) for (pos = 255; pos >= 0; --pos) {
bits = 256; b = n->s[pos / 8] >> (pos & 7);
for (pos = bits - 1; pos >= 0; --pos) {
b = n->p[pos / 8] >> (pos & 7);
b &= 1; b &= 1;
ecc_25519_double(&Q2, &cur); ecc_25519_double(&Q2, &cur);
@ -901,30 +467,22 @@ void ecc_25519_scalarmult_bits(ecc_25519_work_t *out, const ecc_int256_t *n, con
*out = cur; *out = cur;
} }
void ecc_25519_scalarmult(ecc_25519_work_t *out, const ecc_int256_t *n, const ecc_25519_work_t *base) { static const ecc_25519_work default_base = {
ecc_25519_scalarmult_bits(out, n, base, 256); {0xd4, 0x6b, 0xfe, 0x7f, 0x39, 0xfa, 0x8c, 0x22,
} 0xe1, 0x96, 0x23, 0xeb, 0x26, 0xb7, 0x8e, 0x6a,
0x34, 0x74, 0x8b, 0x66, 0xd6, 0xa3, 0x26, 0xdd,
void ecc_25519_scalarmult_base_bits(ecc_25519_work_t *out, const ecc_int256_t *n, unsigned bits) { 0x19, 0x5e, 0x9f, 0x21, 0x50, 0x43, 0x7c, 0x54},
ecc_25519_work_t Q2, Q2p; {0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
ecc_25519_work_t cur = ecc_25519_work_identity; 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
int b, pos; 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66},
if (bits > 256) {1},
bits = 256; {0x47, 0x56, 0x98, 0x99, 0xc7, 0x61, 0x0a, 0x82,
0x1a, 0xdf, 0x82, 0x22, 0x1f, 0x2c, 0x72, 0x88,
for (pos = bits - 1; pos >= 0; --pos) { 0xc3, 0x29, 0x09, 0x52, 0x78, 0xe9, 0x1e, 0xe4,
b = n->p[pos / 8] >> (pos & 7); 0x47, 0x4b, 0x4c, 0x81, 0xa6, 0x02, 0xfd, 0x29}
b &= 1; };
ecc_25519_double(&Q2, &cur); void ecc_25519_scalarmult_base(ecc_25519_work *out, const ecc_secret_key_256 *n) {
ecc_25519_add1(&Q2p, &Q2, &ecc_25519_work_default_base); ecc_25519_scalarmult(out, n, &default_base);
selectw(&cur, &Q2, &Q2p, b);
}
*out = cur;
}
void ecc_25519_scalarmult_base(ecc_25519_work_t *out, const ecc_int256_t *n) {
ecc_25519_scalarmult_base_bits(out, n, 256);
} }

View file

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2012-2015, Matthias Schiffer <mschiffer@universe-factory.net> Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
Partly based on public domain code by Matthew Dempsky and D. J. Bernstein. Partly based on public domain code by Matthew Dempsky and D. J. Bernstein.
All rights reserved. All rights reserved.
@ -24,41 +24,31 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/** \file /*
* Simple finite field operations on the prime field \f$ F_q \f$ for Simple finite field operations on the prime field F_q for
* \f$ q = 2^{252} + 27742317777372353535851937790883648493 \f$, which q = 2^252 + 27742317777372353535851937790883648493, which
* is the order of the base point used for ec25519 is the order of the base point used for ec25519
* */
* Doxygen comments for public APIs can be found in the public header file.
*/
#include <libuecc/ecc.h> #include <libuecc/ecc.h>
/** Checks if the highest bit of an uint32_teger is set */
#define IS_NEGATIVE(n) ((int)((((unsigned)n) >> (8*sizeof(n)-1))&1)) #define IS_NEGATIVE(n) ((int)((((unsigned)n) >> (8*sizeof(n)-1))&1))
/** Performs an arithmetic right shift */
#define ASR(n,s) (((n) >> s)|(IS_NEGATIVE(n)*((unsigned)-1) << (8*sizeof(n)-s))) #define ASR(n,s) (((n) >> s)|(IS_NEGATIVE(n)*((unsigned)-1) << (8*sizeof(n)-s)))
const ecc_int256_t ecc_25519_gf_order = {{ static const unsigned char q[32] = {
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
}}; };
/** An internal alias for \ref ecc_25519_gf_order */
static const uint8_t *q = ecc_25519_gf_order.p;
/** static void select(unsigned char out[32], const unsigned char r[32], const unsigned char s[32], unsigned int b) {
* Copies the content of r into out if b == 0, the contents of s if b == 1
*/
static void select(uint8_t out[32], const uint8_t r[32], const uint8_t s[32], uint32_t b) {
unsigned int j; unsigned int j;
uint8_t t; unsigned int t;
uint8_t bminus1; unsigned int bminus1;
bminus1 = b - 1; bminus1 = b - 1;
for (j = 0;j < 32;++j) { for (j = 0;j < 32;++j) {
@ -67,53 +57,52 @@ static void select(uint8_t out[32], const uint8_t r[32], const uint8_t s[32], ui
} }
} }
int ecc_25519_gf_is_zero(const ecc_int256_t *in) { int ecc_25519_secret_is_zero(const ecc_secret_key_256 *in) {
int i; int i;
ecc_int256_t r; ecc_secret_key_256 r;
uint32_t bits = 0; unsigned int bits;
ecc_25519_gf_reduce(&r, in); ecc_25519_secret_reduce(&r, in);
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
bits |= r.p[i]; bits |= r.s[i];
return (((bits-1)>>8) & 1); return (((bits-1)>>8) & 1);
} }
void ecc_25519_gf_add(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2) { void ecc_25519_secret_add(ecc_secret_key_256 *out, const ecc_secret_key_256 *in1, const ecc_secret_key_256 *in2) {
unsigned int j; unsigned int j;
uint32_t u; unsigned int u;
int nq = 1 - (in1->p[31]>>4) - (in2->p[31]>>4); int nq = 1 - (in1->s[31]>>4) - (in2->s[31]>>4);
u = 0; u = 0;
for (j = 0; j < 32; ++j) { for (j = 0; j < 32; ++j) {
u += in1->p[j] + in2->p[j] + nq*q[j]; u += in1->s[j] + in2->s[j] + nq*q[j];
out->p[j] = u; out->s[j] = u;
u = ASR(u, 8); u = ASR(u, 8);
} }
} }
void ecc_25519_gf_sub(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2) { void ecc_25519_secret_sub(ecc_secret_key_256 *out, const ecc_secret_key_256 *in1, const ecc_secret_key_256 *in2) {
unsigned int j; unsigned int j;
uint32_t u; unsigned int u;
int nq = 8 - (in1->p[31]>>4) + (in2->p[31]>>4); int nq = 8 - (in1->s[31]>>4) + (in2->s[31]>>4);
u = 0; u = 0;
for (j = 0; j < 32; ++j) { for (j = 0; j < 32; ++j) {
u += in1->p[j] - in2->p[j] + nq*q[j]; u += in1->s[j] - in2->s[j] + nq*q[j];
out->p[j] = u; out->s[j] = u;
u = ASR(u, 8); u = ASR(u, 8);
} }
} }
/** Reduces an integer to a unique representation in the range \f$ [0,q-1] \f$ */ static void reduce(unsigned char a[32]) {
static void reduce(uint8_t a[32]) {
unsigned int j; unsigned int j;
uint32_t nq = a[31] >> 4; unsigned int nq = a[31] >> 4;
uint32_t u1, u2; unsigned int u1, u2;
uint8_t out1[32], out2[32]; unsigned char out1[32], out2[32];
u1 = u2 = 0; u1 = u2 = 0;
for (j = 0; j < 31; ++j) { for (j = 0; j < 31; ++j) {
@ -131,20 +120,20 @@ static void reduce(uint8_t a[32]) {
select(a, out1, out2, IS_NEGATIVE(u1)); select(a, out1, out2, IS_NEGATIVE(u1));
} }
void ecc_25519_gf_reduce(ecc_int256_t *out, const ecc_int256_t *in) { void ecc_25519_secret_reduce(ecc_secret_key_256 *out, const ecc_secret_key_256 *in) {
int i; int i;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
out->p[i] = in->p[i]; out->s[i] = in->s[i];
reduce(out->p); reduce(out->s);
} }
/** Montgomery modular multiplication algorithm */ /* Montgomery modular multiplication algorithm */
static void montgomery(uint8_t out[32], const uint8_t a[32], const uint8_t b[32]) { static void montgomery(unsigned char out[32], const unsigned char a[32], const unsigned char b[32]) {
unsigned int i, j; unsigned int i, j;
uint32_t nq; unsigned int nq;
uint32_t u; unsigned int u;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
out[i] = 0; out[i] = 0;
@ -164,88 +153,36 @@ static void montgomery(uint8_t out[32], const uint8_t a[32], const uint8_t b[32]
} }
} }
void ecc_25519_gf_mult(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2) {
void ecc_25519_secret_mult(ecc_secret_key_256 *out, const ecc_secret_key_256 *in1, const ecc_secret_key_256 *in2) {
/* 2^512 mod q */ /* 2^512 mod q */
static const uint8_t C[32] = { static const unsigned char C[32] = {
0x01, 0x0f, 0x9c, 0x44, 0xe3, 0x11, 0x06, 0xa4, 0x01, 0x0f, 0x9c, 0x44, 0xe3, 0x11, 0x06, 0xa4,
0x47, 0x93, 0x85, 0x68, 0xa7, 0x1b, 0x0e, 0xd0, 0x47, 0x93, 0x85, 0x68, 0xa7, 0x1b, 0x0e, 0xd0,
0x65, 0xbe, 0xf5, 0x17, 0xd2, 0x73, 0xec, 0xce, 0x65, 0xbe, 0xf5, 0x17, 0xd2, 0x73, 0xec, 0xce,
0x3d, 0x9a, 0x30, 0x7c, 0x1b, 0x41, 0x99, 0x03 0x3d, 0x9a, 0x30, 0x7c, 0x1b, 0x41, 0x99, 0x03
}; };
uint8_t B[32]; unsigned char B[32];
uint8_t R[32]; unsigned char R[32];
unsigned int i; unsigned int i;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
B[i] = in2->p[i]; B[i] = in2->s[i];
reduce(B); reduce(B);
montgomery(R, in1->p, B); montgomery(R, in1->s, B);
montgomery(out->p, R, C); montgomery(out->s, R, C);
} }
void ecc_25519_gf_recip(ecc_int256_t *out, const ecc_int256_t *in) { void ecc_25519_secret_sanitize(ecc_secret_key_256 *out, const ecc_secret_key_256 *in) {
static const uint8_t C[32] = {
0x01
};
uint8_t A[32], B[32];
uint8_t R1[32], R2[32];
int use_r2 = 0;
unsigned int i, j;
for (i = 0; i < 32; i++) {
R1[i] = (i == 0);
A[i] = in->p[i];
}
reduce(A);
for (i = 0; i < 32; i++) {
uint8_t c;
if (i == 0)
c = 0xeb; /* q[0] - 2 */
else
c = q[i];
for (j = 0; j < 8; j+=2) {
if (c & (1 << j)) {
if (use_r2)
montgomery(R1, R2, A);
else
montgomery(R2, R1, A);
use_r2 = !use_r2;
}
montgomery(B, A, A);
if (c & (2 << j)) {
if (use_r2)
montgomery(R1, R2, B);
else
montgomery(R2, R1, B);
use_r2 = !use_r2;
}
montgomery(A, B, B);
}
}
montgomery(out->p, R2, C);
}
void ecc_25519_gf_sanitize_secret(ecc_int256_t *out, const ecc_int256_t *in) {
int i; int i;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
out->p[i] = in->p[i]; out->s[i] = in->s[i];
out->p[0] &= 0xf8; out->s[0] &= 0xf8;
out->p[31] &= 0x7f; out->s[31] &= 0x7f;
out->p[31] |= 0x40; out->s[31] |= 0x40;
} }