Compare commits

...

45 commits
v0.1 ... master

Author SHA1 Message Date
7c9a6f6af0 libuecc v7 2016-03-27 01:37:26 +01:00
3eb02ade40 Update CHANGELOG 2016-03-19 14:02:43 +01:00
b5b4697c1c Improve ecc_25519_scalarmult_base documentation 2016-03-19 13:59:30 +01:00
bb87f7b0e8 Optimize ecc_25519_scalarmult_base
We can elide one multiplication assuming that Z == 1 for the default base.
2016-03-19 00:51:39 +01:00
26cbc55f78 Switch internal point representation to the Ed25519 curve
The Ed25519 curve allows slightly more efficient addition.
2016-03-19 00:51:31 +01:00
5ade164170 Deprecate ecc_25519_work_base_ed25519 and ecc_25519_work_base_legacy
The deprecation of ecc_25519_work_default_base and
ecc_25519_scalarmult_base{,_bits} is reverted, as the Ed25519 and legacy
base points are represented in the same way now.
2016-03-18 15:12:46 +01:00
740355d5dd Unify legacy and Ed25519 base point by negating conversion factors 2016-03-18 15:03:46 +01:00
bb4fcb9328 libuecc v6 2015-10-25 16:01:42 +01:00
fd6b95b775 Add README and CHANGELOG 2015-10-23 19:00:41 +02:00
5f2814e261 Add support for the Ed25519 curve 2015-10-17 18:09:32 +02:00
5f143b1c29 Add _legacy suffix to functions accessing points in compressed/coordinate representation 2015-10-17 06:32:06 +02:00
256e972b36 Add Ed25519-compatible generator point
The old point is renamed, as it isn't the only default point anymore. The
old name and functions using the old point are deprecated now.
2015-10-17 06:32:06 +02:00
a0751e06dc Fix loading of packed points in edge case
The parity bit was not handled correctly when the squeezed value of Y is
not fully reduced.
2015-10-17 06:29:22 +02:00
a20ecf69d8 Fix another comment typo 2015-10-09 18:26:06 +02:00
c917cec3ef Use stdint types where reasonable
Using uint32_t instead of unsigned int for the unpacked work struct ensures
the code is working correctly on ABIs with ints narrower than 32 bits.

While this would constitute a API/ABI change on some systems in theory,
most likely all systems using libuecc so far have uint8_t == unsigned char
and uint32_t == unsigned int.

Also, coding style cleanup.
2015-10-06 21:16:36 +02:00
89f8a35c71 Remove some unnecessary squeeze() calls
As only the subtrahend in a sub() call needs to be squeezed, the squeeze
can be skipped in these cases.
2015-10-03 18:57:41 +02:00
320daa4838 Improve documenation of internal functions 2015-10-03 18:57:27 +02:00
55178f5f41 Fix typo in comment 2015-10-03 15:40:23 +02:00
16636d4f90 Add comments clarifying when subtractions without squeeze are valid 2015-10-03 13:35:59 +02:00
962888f03f Add functions for point negation and subtraction 2015-10-02 20:57:19 +09:00
a68abb34c2 Move documentation comments for public API to the public header
This makes the documentation more accessible, as the header now contains
all information regarding the usage of the API, and it is not necessary to
generate the Doxygen documentation anymore for that.
2015-10-02 20:07:45 +09:00
0a08c04b0d libuecc v5 2015-01-26 19:41:00 +01:00
ceddc2c2ce Update doxygen support 2015-01-26 19:40:28 +01:00
1591dbfc4d Make default base and identity points accessible 2015-01-26 06:00:20 +01:00
2320e02317 Add a better explanation to ecc_25519_gf_sanitize_secret() 2015-01-26 05:53:39 +01:00
68821f6b8f Update copyright years 2015-01-26 05:45:45 +01:00
1a5fdede16 Add reduced-bitlength scalar multiplication 2015-01-22 21:25:25 +01:00
caf543ccfd libuecc v4 2013-12-26 22:06:39 +01:00
f2ca23547e Use LIB_SUFFIX in pkg-config information 2013-12-26 06:01:01 +01:00
85aa5199d2 Add -Wall to COMPILE_FLAGS 2013-10-28 00:16:38 +01:00
38f32789b1 Update Doxyfile.in 2013-10-27 19:12:44 +01:00
baebc99c0b Remove deprecated definitions 2013-10-27 19:09:02 +01:00
894ecf6913 Respect LIB_SUFFIX 2013-10-27 19:04:57 +01:00
32d40ef190 Build a shared library as well 2013-10-27 19:04:13 +01:00
c30aa7087c libuecc v3 2013-01-09 10:19:30 +01:00
a88af14481 Check points for validity on load 2013-01-09 10:18:39 +01:00
131597e511 Add pkg-config file, prepare release 2 2012-12-23 19:37:56 +01:00
9d875f0418 Lots of code documentation 2012-12-23 19:17:28 +01:00
9c832519c6 Change type names to follow the _t convention, add `deprecated' attribute 2012-12-22 22:12:03 +01:00
c6f33a891f Fix ecc_25519_gf_is_zero 2012-12-09 03:55:33 +01:00
d072ec9de1 Add the order of the base point to the public API 2012-12-08 12:15:49 +01:00
5dff3b368f Add some Doxygen documentation 2012-12-08 12:11:28 +01:00
9aae1f4177 Reduce before reciprocation 2012-12-07 20:47:51 +01:00
80db8a2f72 Add GF reciprocal function 2012-12-07 20:11:54 +01:00
bccf64ec1b Reworked the API 2012-12-07 19:07:37 +01:00
11 changed files with 3650 additions and 260 deletions

34
CHANGELOG Normal file
View file

@ -0,0 +1,34 @@
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,9 +1,20 @@
cmake_minimum_required(VERSION 2.6)
project(LIBUECC C)
set(PROJECT_VERSION 7)
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)
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")
install(FILES ${include_files} DESTINATION include/libuecc)
install(FILES ${include_files} DESTINATION "include/libuecc-${PROJECT_VERSION}/libuecc")

View file

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

2363
Doxyfile.in Normal file

File diff suppressed because it is too large Load diff

30
README Normal file
View file

@ -0,0 +1,30 @@
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.

149
UseDoxygen.cmake Normal file
View file

@ -0,0 +1,149 @@
# - 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, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2012-2015, Matthias Schiffer <mschiffer@universe-factory.net>
Partly based on public domain code by Matthew Dempsky and D. J. Bernstein.
All rights reserved.
@ -27,36 +27,307 @@
#ifndef _LIBUECC_ECC_H_
#define _LIBUECC_ECC_H_
typedef struct _ecc_public_key_256 {
unsigned char p[32];
} ecc_public_key_256;
#ifndef DEPRECATED
#define DEPRECATED __attribute__((deprecated))
#endif
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 {
unsigned int X[32];
unsigned int Y[32];
unsigned int Z[32];
unsigned int T[32];
} ecc_25519_work;
uint32_t X[32];
uint32_t Y[32];
uint32_t Z[32];
uint32_t T[32];
} ecc_25519_work_t;
/**
* \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);
void ecc_25519_store(ecc_public_key_256 *out, const ecc_25519_work *in);
/**
* The Ed25519 default generator point
*
* \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);
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);
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);
/**
* The Ed25519 default generator point
*
* \deprecated Use the equivalent \ref ecc_25519_work_default_base instead.
*/
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);
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);
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);
/**
* The Ed25519 default generator point
*
* The order of the base point is \f$ 2^{252} + 27742317777372353535851937790883648493 \f$.
*/
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_ */

10
libuecc.pc.in Normal file
View file

@ -0,0 +1,10 @@
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,7 +1,24 @@
include_directories(${LIBUECC_SOURCE_DIR}/include)
add_library(uecc STATIC ec25519.c ec25519_secret.c)
set(UECC_SRC ec25519.c ec25519_gf.c)
set(UECC_ABI 0)
install(TARGETS uecc
ARCHIVE DESTINATION lib
add_library(uecc_shared SHARED ${UECC_SRC})
set_target_properties(uecc_shared PROPERTIES
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, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2012-2015, Matthias Schiffer <mschiffer@universe-factory.net>
Partly based on public domain code by Matthew Dempsky and D. J. Bernstein.
All rights reserved.
@ -24,119 +24,325 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
EC group operations for Twisted Edwards Curve ax^2 + y^2 = 1 + dx^2y^2 with
a = 486664
d = 486660
on prime field p = 2^255 - 19.
The curve is 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
*/
/** \file
* EC group operations for Twisted Edwards Curve \f$ ax^2 + y^2 = 1 + dx^2y^2 \f$
* on prime field \f$ p = 2^{255} - 19 \f$.
*
* Two different (isomorphic) sets of curve parameters are supported:
*
* \f$ a = 486664 \f$ and
* \f$ d = 486660 \f$
* 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.
*
* 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>
static void add(unsigned int out[32], const unsigned int a[32], const unsigned int b[32]) {
unsigned int j;
unsigned int u;
u = 0;
for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; }
u += a[31] + b[31]; out[31] = u;
}
const ecc_25519_work_t ecc_25519_work_identity = {{0}, {1}, {1}, {0}};
static void sub(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 u;
u = 218;
for (j = 0;j < 31;++j) {
u += a[j] + 65280 - b[j];
uint32_t u;
u = 0;
for (j = 0; j < 31; j++) {
u += a[j] + b[j];
out[j] = u & 255;
u >>= 8;
}
u += a[31] + b[31];
out[31] = u;
}
/**
* 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;
uint32_t u;
u = 218;
for (j = 0;j < 31;++j) {
u += a[j] + UINT32_C(65280) - b[j];
out[j] = u & 255;
u >>= 8;
}
u += a[31] - b[31];
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 u;
uint32_t u;
u = 0;
for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
u += a[31]; a[31] = u & 127;
for (j = 0;j < 31;++j) {
u += a[j];
a[j] = u & 255;
u >>= 8;
}
u += a[31];
a[31] = u & 127;
u = 19 * (u >> 7);
for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
u += a[31]; a[31] = u;
for (j = 0;j < 31;++j) {
u += a[j];
a[j] = u & 255;
u >>= 8;
}
u += a[31];
a[31] = u;
}
static void freeze(unsigned int a[32]) {
static const unsigned int minusp[32] = {
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, 128
};
unsigned int aorig[32];
static const uint32_t minusp[32] = {
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, 128
};
/**
* 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 negative;
uint32_t negative;
for (j = 0; j < 32; j++) aorig[j] = a[j];
for (j = 0; j < 32; j++)
aorig[j] = a[j];
add(a, a, minusp);
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]) {
unsigned int i;
unsigned int j;
unsigned int u;
/**
* Returns the parity (lowest bit of the fully reduced value) of a
*
* The input must be \em squeezed.
*/
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) {
u = 0;
for (j = 0;j <= i;++j) u += a[j] * b[i - j];
for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j];
for (j = 0; j <= i; 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;
}
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 u;
uint32_t u;
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 = 19 * (u >> 7);
for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; }
u += out[j]; out[j] = u;
for (j = 0; j < 31; j++) {
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]) {
unsigned int i;
unsigned int j;
unsigned int u;
/**
* Squares an unpacked integer
*
* The result will be sqeezed.
*/
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;
for (j = 0;j < i - j;++j) u += a[j] * a[i - j];
for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j];
for (j = 0; j < i - j; 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;
if ((i & 1) == 0) {
u += a[i / 2] * a[i / 2];
u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
}
out[i] = u;
}
squeeze(out);
}
static int check_equal(const unsigned int x[32], const unsigned int y[32]) {
unsigned int differentbits = 0;
/** Checks for the equality of two unpacked integers */
static int check_equal(const uint32_t x[32], const uint32_t y[32]) {
uint32_t differentbits = 0;
int i;
for (i = 0; i < 32; i++) {
@ -147,9 +353,13 @@ static int check_equal(const unsigned int x[32], const unsigned int y[32]) {
return (1 & ((differentbits - 1) >> 16));
}
static int check_zero(const unsigned int x[32]) {
static const unsigned int zero[32] = {0};
static const unsigned int p[32] = {
/**
* Checks if an unpacked integer equals zero (modulo p)
*
* 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,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@ -159,10 +369,11 @@ static int check_zero(const unsigned int x[32]) {
return (check_equal(x, zero) | check_equal(x, p));
}
static void selectw(ecc_25519_work *out, const ecc_25519_work *r, const ecc_25519_work *s, unsigned int b) {
/** Copies r to out when b == 0, s when b == 1 */
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 t;
unsigned int bminus1;
uint32_t t;
uint32_t bminus1;
bminus1 = b - 1;
for (j = 0; j < 32; ++j) {
@ -180,10 +391,11 @@ static void selectw(ecc_25519_work *out, const ecc_25519_work *r, const ecc_2551
}
}
static void select(unsigned int out[32], const unsigned int r[32], const unsigned int s[32], unsigned int b) {
/** Copies r to out when b == 0, s when b == 1 */
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 t;
unsigned int bminus1;
uint32_t t;
uint32_t bminus1;
bminus1 = b - 1;
for (j = 0;j < 32;++j) {
@ -192,15 +404,13 @@ static void select(unsigned int out[32], const unsigned int r[32], const unsigne
}
}
static void square_root(unsigned int out[32], const unsigned int z[32]) {
static const unsigned int 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
};
static const unsigned int rho_s[32] = {
/**
* Computes the square root of an unpacked integer (in the prime field modulo p)
*
* If the given integer has no square root, 0 is returned, 1 otherwise.
*/
static int square_root(uint32_t out[32], const uint32_t z[32]) {
static const uint32_t rho_s[32] = {
0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4,
0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f,
0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b,
@ -209,18 +419,18 @@ static void square_root(unsigned int out[32], const unsigned int z[32]) {
/* raise z to power (2^252-2), check if power (2^253-5) equals -1 */
unsigned int z2[32];
unsigned int z9[32];
unsigned int z11[32];
unsigned int z2_5_0[32];
unsigned int z2_10_0[32];
unsigned int z2_20_0[32];
unsigned int z2_50_0[32];
unsigned int z2_100_0[32];
unsigned int t0[32];
unsigned int t1[32];
unsigned int z2_252_1[32];
unsigned int z2_252_1_rho_s[32];
uint32_t z2[32];
uint32_t z9[32];
uint32_t z11[32];
uint32_t z2_5_0[32];
uint32_t z2_10_0[32];
uint32_t z2_20_0[32];
uint32_t z2_50_0[32];
uint32_t z2_100_0[32];
uint32_t t0[32];
uint32_t t1[32];
uint32_t z2_252_1[32];
uint32_t z2_252_1_rho_s[32];
int i;
/* 2 */ square(z2, z);
@ -279,19 +489,24 @@ static void square_root(unsigned int out[32], const unsigned int z[32]) {
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));
/* Check the root */
square(t0, out);
return check_equal(t0, z);
}
static void recip(unsigned int out[32], const unsigned int z[32]) {
unsigned int z2[32];
unsigned int z9[32];
unsigned int z11[32];
unsigned int z2_5_0[32];
unsigned int z2_10_0[32];
unsigned int z2_20_0[32];
unsigned int z2_50_0[32];
unsigned int z2_100_0[32];
unsigned int t0[32];
unsigned int t1[32];
/** Computes the reciprocal of an unpacked integer (in the prime field modulo p) */
static void recip(uint32_t out[32], const uint32_t z[32]) {
uint32_t z2[32];
uint32_t z9[32];
uint32_t z11[32];
uint32_t z2_5_0[32];
uint32_t z2_10_0[32];
uint32_t z2_20_0[32];
uint32_t z2_50_0[32];
uint32_t z2_100_0[32];
uint32_t t0[32];
uint32_t t1[32];
int i;
/* 2 */ square(z2, z);
@ -347,58 +562,207 @@ static void recip(unsigned int out[32], const unsigned int z[32]) {
/* 2^255 - 21 */ mult(out, t1, z11);
}
void ecc_25519_load(ecc_25519_work *out, const ecc_public_key_256 *in) {
static const unsigned int zero[32] = {0};
static const unsigned int one[32] = {1};
/**
* Checks if the X and Y coordinates of a work structure represent a valid point of the curve
*
* 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;
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++) {
out->X[i] = in->p[i];
out->X[i] = x->p[i];
out->Y[i] = y->p[i];
out->Z[i] = (i == 0);
}
out->X[31] &= 0x7f;
return check_load_xy(out);
}
square(X2, out->X);
mult_int(aX2, 486664, X2);
mult_int(dX2, 486660, X2);
int ecc_25519_load_xy_legacy(ecc_25519_work_t *out, const ecc_int256_t *x, const ecc_int256_t *y) {
int i;
uint32_t tmp[32];
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_dX2, one, dX2);
recip(_1_1_dX2, _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);
select(out->Y, Y, Yt, (in->p[31] >> 7) ^ (Y[0] & 1));
select(out->Y, Y, Yt, (in->p[31] >> 7) ^ parity(Y));
mult(out->X, X_legacy, legacy_to_ed25519);
mult(out->T, out->X, out->Y);
return 1;
}
void ecc_25519_store(ecc_public_key_256 *out, const ecc_25519_work *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);
int ecc_25519_load_packed(ecc_25519_work_t *out, const ecc_int256_t *in) {
return ecc_25519_load_packed_legacy(out, in);
}
static const ecc_25519_work id = {{0}, {1}, {1}, {0}};
int ecc_25519_is_identity(const ecc_25519_work *in) {
unsigned int Y_Z[32];
void ecc_25519_store_packed_ed25519(ecc_int256_t *out, const ecc_25519_work_t *in) {
ecc_int256_t x;
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);
squeeze(Y_Z);
@ -406,57 +770,127 @@ int ecc_25519_is_identity(const ecc_25519_work *in) {
return (check_zero(in->X)&check_zero(Y_Z));
}
void ecc_25519_double(ecc_25519_work *out, const ecc_25519_work *in) {
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];
void ecc_25519_negate(ecc_25519_work_t *out, const ecc_25519_work_t *in) {
int i;
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(B, in->Y);
square(t0, in->Z);
mult_int(C, 2, t0);
mult_int(D, 486664, A);
add(t1, in->X, in->Y);
square(t2, t1);
sub(t3, t2, A); squeeze(t3);
sub(E, t3, B);
add(G, D, B); squeeze(G);
sub(D, zero, A);
add(t0, in->X, in->Y);
square(t1, t0);
sub(t0, t1, A);
sub(E, t0, B);
add(G, D, B);
sub(F, G, C);
sub(H, D, B);
mult(out->X, E, F);
mult(out->Y, G, H);
mult(out->T, E, H);
mult(out->Z, F, G);
}
void ecc_25519_add(ecc_25519_work *out, const ecc_25519_work *in1, const ecc_25519_work *in2) {
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];
void ecc_25519_add(ecc_25519_work_t *out, const ecc_25519_work_t *in1, const ecc_25519_work_t *in2) {
const uint32_t j = UINT32_C(60833);
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];
mult(A, in1->X, in2->X);
mult(B, in1->Y, in2->Y);
mult_int(t0, 486660, in2->T);
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(D, in1->Z, in2->Z);
add(t1, in1->X, in1->Y);
add(t2, in2->X, in2->Y);
mult(t3, t1, t2);
sub(t4, t3, A); squeeze(t4);
sub(E, t4, B);
sub(F, D, C);
add(G, D, C);
mult_int(t5, 486664, A);
sub(H, B, t5);
mult_int(t0, 2*j, in2->Z);
mult(D, in1->Z, t0);
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_scalarmult(ecc_25519_work *out, const ecc_secret_key_256 *n, const ecc_25519_work *base) {
ecc_25519_work Q2, Q2p;
ecc_25519_work cur = id;
/** Adds two points of the Elliptic Curve, assuming that in2->Z == 1 */
static void ecc_25519_add1(ecc_25519_work_t *out, const ecc_25519_work_t *in1, const ecc_25519_work_t *in2) {
const uint32_t j = UINT32_C(60833);
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;
for (pos = 255; pos >= 0; --pos) {
b = n->s[pos / 8] >> (pos & 7);
if (bits > 256)
bits = 256;
for (pos = bits - 1; pos >= 0; --pos) {
b = n->p[pos / 8] >> (pos & 7);
b &= 1;
ecc_25519_double(&Q2, &cur);
@ -467,22 +901,30 @@ void ecc_25519_scalarmult(ecc_25519_work *out, const ecc_secret_key_256 *n, cons
*out = cur;
}
static const ecc_25519_work default_base = {
{0xd4, 0x6b, 0xfe, 0x7f, 0x39, 0xfa, 0x8c, 0x22,
0xe1, 0x96, 0x23, 0xeb, 0x26, 0xb7, 0x8e, 0x6a,
0x34, 0x74, 0x8b, 0x66, 0xd6, 0xa3, 0x26, 0xdd,
0x19, 0x5e, 0x9f, 0x21, 0x50, 0x43, 0x7c, 0x54},
{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},
{0x47, 0x56, 0x98, 0x99, 0xc7, 0x61, 0x0a, 0x82,
0x1a, 0xdf, 0x82, 0x22, 0x1f, 0x2c, 0x72, 0x88,
0xc3, 0x29, 0x09, 0x52, 0x78, 0xe9, 0x1e, 0xe4,
0x47, 0x4b, 0x4c, 0x81, 0xa6, 0x02, 0xfd, 0x29}
};
void ecc_25519_scalarmult_base(ecc_25519_work *out, const ecc_secret_key_256 *n) {
ecc_25519_scalarmult(out, n, &default_base);
void ecc_25519_scalarmult(ecc_25519_work_t *out, const ecc_int256_t *n, const ecc_25519_work_t *base) {
ecc_25519_scalarmult_bits(out, n, base, 256);
}
void ecc_25519_scalarmult_base_bits(ecc_25519_work_t *out, const ecc_int256_t *n, unsigned bits) {
ecc_25519_work_t Q2, Q2p;
ecc_25519_work_t cur = ecc_25519_work_identity;
int b, pos;
if (bits > 256)
bits = 256;
for (pos = bits - 1; pos >= 0; --pos) {
b = n->p[pos / 8] >> (pos & 7);
b &= 1;
ecc_25519_double(&Q2, &cur);
ecc_25519_add1(&Q2p, &Q2, &ecc_25519_work_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, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2012-2015, Matthias Schiffer <mschiffer@universe-factory.net>
Partly based on public domain code by Matthew Dempsky and D. J. Bernstein.
All rights reserved.
@ -24,31 +24,41 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Simple finite field operations on the prime field F_q for
q = 2^252 + 27742317777372353535851937790883648493, which
is the order of the base point used for ec25519
*/
/** \file
* Simple finite field operations on the prime field \f$ F_q \f$ for
* \f$ q = 2^{252} + 27742317777372353535851937790883648493 \f$, which
* 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>
/** Checks if the highest bit of an uint32_teger is set */
#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)))
static const unsigned char q[32] = {
const ecc_int256_t ecc_25519_gf_order = {{
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 t;
unsigned int bminus1;
uint8_t t;
uint8_t bminus1;
bminus1 = b - 1;
for (j = 0;j < 32;++j) {
@ -57,52 +67,53 @@ static void select(unsigned char out[32], const unsigned char r[32], const unsig
}
}
int ecc_25519_secret_is_zero(const ecc_secret_key_256 *in) {
int ecc_25519_gf_is_zero(const ecc_int256_t *in) {
int i;
ecc_secret_key_256 r;
unsigned int bits;
ecc_int256_t r;
uint32_t bits = 0;
ecc_25519_secret_reduce(&r, in);
ecc_25519_gf_reduce(&r, in);
for (i = 0; i < 32; i++)
bits |= r.s[i];
bits |= r.p[i];
return (((bits-1)>>8) & 1);
}
void ecc_25519_secret_add(ecc_secret_key_256 *out, const ecc_secret_key_256 *in1, const ecc_secret_key_256 *in2) {
void ecc_25519_gf_add(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2) {
unsigned int j;
unsigned int u;
int nq = 1 - (in1->s[31]>>4) - (in2->s[31]>>4);
uint32_t u;
int nq = 1 - (in1->p[31]>>4) - (in2->p[31]>>4);
u = 0;
for (j = 0; j < 32; ++j) {
u += in1->s[j] + in2->s[j] + nq*q[j];
u += in1->p[j] + in2->p[j] + nq*q[j];
out->s[j] = u;
out->p[j] = u;
u = ASR(u, 8);
}
}
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_gf_sub(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2) {
unsigned int j;
unsigned int u;
int nq = 8 - (in1->s[31]>>4) + (in2->s[31]>>4);
uint32_t u;
int nq = 8 - (in1->p[31]>>4) + (in2->p[31]>>4);
u = 0;
for (j = 0; j < 32; ++j) {
u += in1->s[j] - in2->s[j] + nq*q[j];
u += in1->p[j] - in2->p[j] + nq*q[j];
out->s[j] = u;
out->p[j] = u;
u = ASR(u, 8);
}
}
static void reduce(unsigned char a[32]) {
/** Reduces an integer to a unique representation in the range \f$ [0,q-1] \f$ */
static void reduce(uint8_t a[32]) {
unsigned int j;
unsigned int nq = a[31] >> 4;
unsigned int u1, u2;
unsigned char out1[32], out2[32];
uint32_t nq = a[31] >> 4;
uint32_t u1, u2;
uint8_t out1[32], out2[32];
u1 = u2 = 0;
for (j = 0; j < 31; ++j) {
@ -120,20 +131,20 @@ static void reduce(unsigned char a[32]) {
select(a, out1, out2, IS_NEGATIVE(u1));
}
void ecc_25519_secret_reduce(ecc_secret_key_256 *out, const ecc_secret_key_256 *in) {
void ecc_25519_gf_reduce(ecc_int256_t *out, const ecc_int256_t *in) {
int i;
for (i = 0; i < 32; i++)
out->s[i] = in->s[i];
out->p[i] = in->p[i];
reduce(out->s);
reduce(out->p);
}
/* Montgomery modular multiplication algorithm */
static void montgomery(unsigned char out[32], const unsigned char a[32], const unsigned char b[32]) {
/** Montgomery modular multiplication algorithm */
static void montgomery(uint8_t out[32], const uint8_t a[32], const uint8_t b[32]) {
unsigned int i, j;
unsigned int nq;
unsigned int u;
uint32_t nq;
uint32_t u;
for (i = 0; i < 32; i++)
out[i] = 0;
@ -153,36 +164,88 @@ static void montgomery(unsigned char out[32], const unsigned char a[32], const u
}
}
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_gf_mult(ecc_int256_t *out, const ecc_int256_t *in1, const ecc_int256_t *in2) {
/* 2^512 mod q */
static const unsigned char C[32] = {
static const uint8_t C[32] = {
0x01, 0x0f, 0x9c, 0x44, 0xe3, 0x11, 0x06, 0xa4,
0x47, 0x93, 0x85, 0x68, 0xa7, 0x1b, 0x0e, 0xd0,
0x65, 0xbe, 0xf5, 0x17, 0xd2, 0x73, 0xec, 0xce,
0x3d, 0x9a, 0x30, 0x7c, 0x1b, 0x41, 0x99, 0x03
};
unsigned char B[32];
unsigned char R[32];
uint8_t B[32];
uint8_t R[32];
unsigned int i;
for (i = 0; i < 32; i++)
B[i] = in2->s[i];
B[i] = in2->p[i];
reduce(B);
montgomery(R, in1->s, B);
montgomery(out->s, R, C);
montgomery(R, in1->p, B);
montgomery(out->p, R, C);
}
void ecc_25519_secret_sanitize(ecc_secret_key_256 *out, const ecc_secret_key_256 *in) {
void ecc_25519_gf_recip(ecc_int256_t *out, const ecc_int256_t *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;
for (i = 0; i < 32; i++)
out->s[i] = in->s[i];
out->p[i] = in->p[i];
out->s[0] &= 0xf8;
out->s[31] &= 0x7f;
out->s[31] |= 0x40;
out->p[0] &= 0xf8;
out->p[31] &= 0x7f;
out->p[31] |= 0x40;
}