mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
Ed25519 signature algorithm
This commit is contained in:
parent
a936aa3e4a
commit
786e52f923
@ -32,7 +32,7 @@
|
|||||||
\li Authenticated encryption with associated data (AEAD): ChaChaPoly, GCM
|
\li Authenticated encryption with associated data (AEAD): ChaChaPoly, GCM
|
||||||
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
|
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
|
||||||
\li Message authenticators: Poly1305, GHASH
|
\li Message authenticators: Poly1305, GHASH
|
||||||
\li Public key algorithms: Curve25519
|
\li Public key algorithms: Curve25519, Ed25519
|
||||||
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource
|
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource
|
||||||
|
|
||||||
All cryptographic algorithms have been optimized for 8-bit Arduino platforms
|
All cryptographic algorithms have been optimized for 8-bit Arduino platforms
|
||||||
@ -96,6 +96,9 @@ Ardunino Mega 2560 running at 16 MHz are similar:
|
|||||||
<tr><td>Curve25519::eval()</td><td align="right">3119ms</td><td colspan="3">Raw curve evaluation</td></tr>
|
<tr><td>Curve25519::eval()</td><td align="right">3119ms</td><td colspan="3">Raw curve evaluation</td></tr>
|
||||||
<tr><td>Curve25519::dh1()</td><td align="right">3121ms</td><td colspan="3">First half of Diffie-Hellman key agreement</td></tr>
|
<tr><td>Curve25519::dh1()</td><td align="right">3121ms</td><td colspan="3">First half of Diffie-Hellman key agreement</td></tr>
|
||||||
<tr><td>Curve25519::dh2()</td><td align="right">3120ms</td><td colspan="3">Second half of Diffie-Hellman key agreement</td></tr>
|
<tr><td>Curve25519::dh2()</td><td align="right">3120ms</td><td colspan="3">Second half of Diffie-Hellman key agreement</td></tr>
|
||||||
|
<tr><td>Ed25519::sign()</td><td align="right">5688ms</td><td colspan="3">Digital signature generation</td></tr>
|
||||||
|
<tr><td>Ed25519::verify()</td><td align="right">9030ms</td><td colspan="3">Digital signature verification</td></tr>
|
||||||
|
<tr><td>Ed25519::derivePublicKey()</td><td align="right">5642ms</td><td colspan="3">Derive a public key from a private key</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
Where a cipher supports more than one key size (such as ChaCha), the values
|
Where a cipher supports more than one key size (such as ChaCha), the values
|
||||||
|
@ -97,7 +97,7 @@ realtime clock and the LCD library to implement an alarm clock.
|
|||||||
\li Authenticated encryption with associated data (AEAD): ChaChaPoly, GCM
|
\li Authenticated encryption with associated data (AEAD): ChaChaPoly, GCM
|
||||||
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
|
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
|
||||||
\li Message authenticators: Poly1305, GHASH
|
\li Message authenticators: Poly1305, GHASH
|
||||||
\li Public key algorithms: Curve25519
|
\li Public key algorithms: Curve25519, Ed25519
|
||||||
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource
|
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource
|
||||||
|
|
||||||
More information can be found on the \ref crypto "Cryptographic Library" page.
|
More information can be found on the \ref crypto "Cryptographic Library" page.
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "BigNumberUtil.h"
|
#include "BigNumberUtil.h"
|
||||||
#include "utility/EndianUtil.h"
|
#include "utility/EndianUtil.h"
|
||||||
|
#include "utility/LimbUtil.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -363,3 +364,273 @@ void BigNumberUtil::packBE(uint8_t *bytes, size_t len,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds two big numbers.
|
||||||
|
*
|
||||||
|
* \param result The result of the addition. This can be the same
|
||||||
|
* as either \a x or \a y.
|
||||||
|
* \param x The first big number.
|
||||||
|
* \param y The second big number.
|
||||||
|
* \param size The size of the values in limbs.
|
||||||
|
*
|
||||||
|
* \return Returns 1 if there was a carry out or 0 if there was no carry out.
|
||||||
|
*
|
||||||
|
* \sa sub(), mul()
|
||||||
|
*/
|
||||||
|
limb_t BigNumberUtil::add(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size)
|
||||||
|
{
|
||||||
|
dlimb_t carry = 0;
|
||||||
|
while (size > 0) {
|
||||||
|
carry += *x++;
|
||||||
|
carry += *y++;
|
||||||
|
*result++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
return (limb_t)carry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Subtracts one big number from another.
|
||||||
|
*
|
||||||
|
* \param result The result of the subtraction. This can be the same
|
||||||
|
* as either \a x or \a y.
|
||||||
|
* \param x The first big number.
|
||||||
|
* \param y The second big number to subtract from \a x.
|
||||||
|
* \param size The size of the values in limbs.
|
||||||
|
*
|
||||||
|
* \return Returns 1 if there was a borrow, or 0 if there was no borrow.
|
||||||
|
*
|
||||||
|
* \sa add(), mul()
|
||||||
|
*/
|
||||||
|
limb_t BigNumberUtil::sub(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size)
|
||||||
|
{
|
||||||
|
dlimb_t borrow = 0;
|
||||||
|
while (size > 0) {
|
||||||
|
borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
|
||||||
|
*result++ = (limb_t)borrow;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Multiplies two big numbers.
|
||||||
|
*
|
||||||
|
* \param result The result of the multiplication. The array must be
|
||||||
|
* \a xcount + \a ycount limbs in size.
|
||||||
|
* \param x Points to the first value to multiply.
|
||||||
|
* \param xcount The number of limbs in \a x.
|
||||||
|
* \param y Points to the second value to multiply.
|
||||||
|
* \param ycount The number of limbs in \a y.
|
||||||
|
*
|
||||||
|
* \sa mul_P()
|
||||||
|
*/
|
||||||
|
void BigNumberUtil::mul(limb_t *result, const limb_t *x, size_t xcount,
|
||||||
|
const limb_t *y, size_t ycount)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
dlimb_t carry;
|
||||||
|
limb_t word;
|
||||||
|
const limb_t *xx;
|
||||||
|
limb_t *rr;
|
||||||
|
|
||||||
|
// Multiply the lowest limb of y by x.
|
||||||
|
carry = 0;
|
||||||
|
word = y[0];
|
||||||
|
xx = x;
|
||||||
|
rr = result;
|
||||||
|
for (i = 0; i < xcount; ++i) {
|
||||||
|
carry += ((dlimb_t)(*xx++)) * word;
|
||||||
|
*rr++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
}
|
||||||
|
*rr = (limb_t)carry;
|
||||||
|
|
||||||
|
// Multiply and add the remaining limbs of y by x.
|
||||||
|
for (i = 1; i < ycount; ++i) {
|
||||||
|
word = y[i];
|
||||||
|
carry = 0;
|
||||||
|
xx = x;
|
||||||
|
rr = result + i;
|
||||||
|
for (j = 0; j < xcount; ++j) {
|
||||||
|
carry += ((dlimb_t)(*xx++)) * word;
|
||||||
|
carry += *rr;
|
||||||
|
*rr++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
}
|
||||||
|
*rr = (limb_t)carry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reduces \a x modulo \a y using subtraction.
|
||||||
|
*
|
||||||
|
* \param result The result of the reduction. This can be the
|
||||||
|
* same as \a x.
|
||||||
|
* \param x The number to be reduced.
|
||||||
|
* \param y The base to use for the modulo reduction.
|
||||||
|
* \param size The size of the values in limbs.
|
||||||
|
*
|
||||||
|
* It is assumed that \a x is less than \a y * 2 so that a single
|
||||||
|
* conditional subtraction will bring it down below \a y. The reduction
|
||||||
|
* is performed in constant time.
|
||||||
|
*
|
||||||
|
* \sa reduceQuick_P()
|
||||||
|
*/
|
||||||
|
void BigNumberUtil::reduceQuick(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size)
|
||||||
|
{
|
||||||
|
// Subtract "y" from "x" and turn the borrow into an AND mask.
|
||||||
|
limb_t mask = sub(result, x, y, size);
|
||||||
|
mask = (~mask) + 1;
|
||||||
|
|
||||||
|
// Add "y" back to the result if the mask is non-zero.
|
||||||
|
dlimb_t carry = 0;
|
||||||
|
while (size > 0) {
|
||||||
|
carry += *result;
|
||||||
|
carry += (*y++ & mask);
|
||||||
|
*result++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds two big numbers where one of them is in program memory.
|
||||||
|
*
|
||||||
|
* \param result The result of the addition. This can be the same as \a x.
|
||||||
|
* \param x The first big number.
|
||||||
|
* \param y The second big number. This must point into program memory.
|
||||||
|
* \param size The size of the values in limbs.
|
||||||
|
*
|
||||||
|
* \return Returns 1 if there was a carry out or 0 if there was no carry out.
|
||||||
|
*
|
||||||
|
* \sa sub_P(), mul_P()
|
||||||
|
*/
|
||||||
|
limb_t BigNumberUtil::add_P(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size)
|
||||||
|
{
|
||||||
|
dlimb_t carry = 0;
|
||||||
|
while (size > 0) {
|
||||||
|
carry += *x++;
|
||||||
|
carry += pgm_read_limb(y++);
|
||||||
|
*result++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
return (limb_t)carry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Subtracts one big number from another where one is in program memory.
|
||||||
|
*
|
||||||
|
* \param result The result of the subtraction. This can be the same as \a x.
|
||||||
|
* \param x The first big number.
|
||||||
|
* \param y The second big number to subtract from \a x. This must point
|
||||||
|
* into program memory.
|
||||||
|
* \param size The size of the values in limbs.
|
||||||
|
*
|
||||||
|
* \return Returns 1 if there was a borrow, or 0 if there was no borrow.
|
||||||
|
*
|
||||||
|
* \sa add_P(), mul_P()
|
||||||
|
*/
|
||||||
|
limb_t BigNumberUtil::sub_P(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size)
|
||||||
|
{
|
||||||
|
dlimb_t borrow = 0;
|
||||||
|
while (size > 0) {
|
||||||
|
borrow = ((dlimb_t)(*x++)) - pgm_read_limb(y++) - ((borrow >> LIMB_BITS) & 0x01);
|
||||||
|
*result++ = (limb_t)borrow;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Multiplies two big numbers where one is in program memory.
|
||||||
|
*
|
||||||
|
* \param result The result of the multiplication. The array must be
|
||||||
|
* \a xcount + \a ycount limbs in size.
|
||||||
|
* \param x Points to the first value to multiply.
|
||||||
|
* \param xcount The number of limbs in \a x.
|
||||||
|
* \param y Points to the second value to multiply. This must point
|
||||||
|
* into program memory.
|
||||||
|
* \param ycount The number of limbs in \a y.
|
||||||
|
*
|
||||||
|
* \sa mul()
|
||||||
|
*/
|
||||||
|
void BigNumberUtil::mul_P(limb_t *result, const limb_t *x, size_t xcount,
|
||||||
|
const limb_t *y, size_t ycount)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
dlimb_t carry;
|
||||||
|
limb_t word;
|
||||||
|
const limb_t *xx;
|
||||||
|
limb_t *rr;
|
||||||
|
|
||||||
|
// Multiply the lowest limb of y by x.
|
||||||
|
carry = 0;
|
||||||
|
word = pgm_read_limb(&(y[0]));
|
||||||
|
xx = x;
|
||||||
|
rr = result;
|
||||||
|
for (i = 0; i < xcount; ++i) {
|
||||||
|
carry += ((dlimb_t)(*xx++)) * word;
|
||||||
|
*rr++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
}
|
||||||
|
*rr = (limb_t)carry;
|
||||||
|
|
||||||
|
// Multiply and add the remaining limb of y by x.
|
||||||
|
for (i = 1; i < ycount; ++i) {
|
||||||
|
word = pgm_read_limb(&(y[i]));
|
||||||
|
carry = 0;
|
||||||
|
xx = x;
|
||||||
|
rr = result + i;
|
||||||
|
for (j = 0; j < xcount; ++j) {
|
||||||
|
carry += ((dlimb_t)(*xx++)) * word;
|
||||||
|
carry += *rr;
|
||||||
|
*rr++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
}
|
||||||
|
*rr = (limb_t)carry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reduces \a x modulo \a y using subtraction where \a y is
|
||||||
|
* in program memory.
|
||||||
|
*
|
||||||
|
* \param result The result of the reduction. This can be the
|
||||||
|
* same as \a x.
|
||||||
|
* \param x The number to be reduced.
|
||||||
|
* \param y The base to use for the modulo reduction. This must point
|
||||||
|
* into program memory.
|
||||||
|
* \param size The size of the values in limbs.
|
||||||
|
*
|
||||||
|
* It is assumed that \a x is less than \a y * 2 so that a single
|
||||||
|
* conditional subtraction will bring it down below \a y. The reduction
|
||||||
|
* is performed in constant time.
|
||||||
|
*
|
||||||
|
* \sa reduceQuick()
|
||||||
|
*/
|
||||||
|
void BigNumberUtil::reduceQuick_P(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size)
|
||||||
|
{
|
||||||
|
// Subtract "y" from "x" and turn the borrow into an AND mask.
|
||||||
|
limb_t mask = sub_P(result, x, y, size);
|
||||||
|
mask = (~mask) + 1;
|
||||||
|
|
||||||
|
// Add "y" back to the result if the mask is non-zero.
|
||||||
|
dlimb_t carry = 0;
|
||||||
|
while (size > 0) {
|
||||||
|
carry += *result;
|
||||||
|
carry += (pgm_read_limb(y++) & mask);
|
||||||
|
*result++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -61,6 +61,24 @@ public:
|
|||||||
static void packBE(uint8_t *bytes, size_t len,
|
static void packBE(uint8_t *bytes, size_t len,
|
||||||
const limb_t *limbs, size_t count);
|
const limb_t *limbs, size_t count);
|
||||||
|
|
||||||
|
static limb_t add(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size);
|
||||||
|
static limb_t sub(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size);
|
||||||
|
static void mul(limb_t *result, const limb_t *x, size_t xcount,
|
||||||
|
const limb_t *y, size_t ycount);
|
||||||
|
static void reduceQuick(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size);
|
||||||
|
|
||||||
|
static limb_t add_P(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size);
|
||||||
|
static limb_t sub_P(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size);
|
||||||
|
static void mul_P(limb_t *result, const limb_t *x, size_t xcount,
|
||||||
|
const limb_t *y, size_t ycount);
|
||||||
|
static void reduceQuick_P(limb_t *result, const limb_t *x,
|
||||||
|
const limb_t *y, size_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Constructor and destructor are private - cannot instantiate this class.
|
// Constructor and destructor are private - cannot instantiate this class.
|
||||||
BigNumberUtil() {}
|
BigNumberUtil() {}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include "Curve25519.h"
|
#include "Curve25519.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "RNG.h"
|
#include "RNG.h"
|
||||||
#include "utility/ProgMemUtil.h"
|
#include "utility/LimbUtil.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,15 +37,10 @@
|
|||||||
*
|
*
|
||||||
* References: http://cr.yp.to/ecdh.html
|
* References: http://cr.yp.to/ecdh.html
|
||||||
* https://tools.ietf.org/html/draft-irtf-cfrg-curves-02
|
* https://tools.ietf.org/html/draft-irtf-cfrg-curves-02
|
||||||
|
*
|
||||||
|
* \sa Ed25519
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Number of limbs in a value from the field modulo 2^255 - 19.
|
|
||||||
// We assume that sizeof(limb_t) is a power of 2: 1, 2, 4, etc.
|
|
||||||
#define NUM_LIMBS (32 / sizeof(limb_t))
|
|
||||||
|
|
||||||
// Number of bits in limb_t.
|
|
||||||
#define LIMB_BITS (8 * sizeof(limb_t))
|
|
||||||
|
|
||||||
// The overhead of clean() calls in mul(), reduceQuick(), etc can
|
// The overhead of clean() calls in mul(), reduceQuick(), etc can
|
||||||
// add up to a lot of processing time during eval(). Only do such
|
// add up to a lot of processing time during eval(). Only do such
|
||||||
// cleanups if strict mode has been enabled. Other implementations
|
// cleanups if strict mode has been enabled. Other implementations
|
||||||
@ -78,20 +73,20 @@
|
|||||||
*/
|
*/
|
||||||
bool Curve25519::eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32])
|
bool Curve25519::eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32])
|
||||||
{
|
{
|
||||||
limb_t x_1[NUM_LIMBS];
|
limb_t x_1[NUM_LIMBS_256BIT];
|
||||||
limb_t x_2[NUM_LIMBS];
|
limb_t x_2[NUM_LIMBS_256BIT];
|
||||||
limb_t x_3[NUM_LIMBS];
|
limb_t x_3[NUM_LIMBS_256BIT];
|
||||||
limb_t z_2[NUM_LIMBS];
|
limb_t z_2[NUM_LIMBS_256BIT];
|
||||||
limb_t z_3[NUM_LIMBS];
|
limb_t z_3[NUM_LIMBS_256BIT];
|
||||||
limb_t A[NUM_LIMBS];
|
limb_t A[NUM_LIMBS_256BIT];
|
||||||
limb_t B[NUM_LIMBS];
|
limb_t B[NUM_LIMBS_256BIT];
|
||||||
limb_t C[NUM_LIMBS];
|
limb_t C[NUM_LIMBS_256BIT];
|
||||||
limb_t D[NUM_LIMBS];
|
limb_t D[NUM_LIMBS_256BIT];
|
||||||
limb_t E[NUM_LIMBS];
|
limb_t E[NUM_LIMBS_256BIT];
|
||||||
limb_t AA[NUM_LIMBS];
|
limb_t AA[NUM_LIMBS_256BIT];
|
||||||
limb_t BB[NUM_LIMBS];
|
limb_t BB[NUM_LIMBS_256BIT];
|
||||||
limb_t DA[NUM_LIMBS];
|
limb_t DA[NUM_LIMBS_256BIT];
|
||||||
limb_t CB[NUM_LIMBS];
|
limb_t CB[NUM_LIMBS_256BIT];
|
||||||
uint8_t mask;
|
uint8_t mask;
|
||||||
uint8_t sposn;
|
uint8_t sposn;
|
||||||
uint8_t select;
|
uint8_t select;
|
||||||
@ -102,8 +97,8 @@ bool Curve25519::eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[3
|
|||||||
// which also masks off the high bit. NULL means 9.
|
// which also masks off the high bit. NULL means 9.
|
||||||
if (x) {
|
if (x) {
|
||||||
// x1 = x
|
// x1 = x
|
||||||
BigNumberUtil::unpackLE(x_1, NUM_LIMBS, x, 32);
|
BigNumberUtil::unpackLE(x_1, NUM_LIMBS_256BIT, x, 32);
|
||||||
x_1[NUM_LIMBS - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
x_1[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
||||||
} else {
|
} else {
|
||||||
memset(x_1, 0, sizeof(x_1)); // x_1 = 9
|
memset(x_1, 0, sizeof(x_1)); // x_1 = 9
|
||||||
x_1[0] = 9;
|
x_1[0] = 9;
|
||||||
@ -178,7 +173,7 @@ bool Curve25519::eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[3
|
|||||||
mul(x_2, x_2, z_3);
|
mul(x_2, x_2, z_3);
|
||||||
|
|
||||||
// Pack the result into the return array.
|
// Pack the result into the return array.
|
||||||
BigNumberUtil::packLE(result, 32, x_2, NUM_LIMBS);
|
BigNumberUtil::packLE(result, 32, x_2, NUM_LIMBS_256BIT);
|
||||||
|
|
||||||
// Clean up and exit.
|
// Clean up and exit.
|
||||||
clean(x_1);
|
clean(x_1);
|
||||||
@ -354,13 +349,13 @@ uint8_t Curve25519::isWeakPoint(const uint8_t k[32])
|
|||||||
* \brief Reduces a number modulo 2^255 - 19.
|
* \brief Reduces a number modulo 2^255 - 19.
|
||||||
*
|
*
|
||||||
* \param result The array that will contain the result when the
|
* \param result The array that will contain the result when the
|
||||||
* function exits. Must be NUM_LIMBS limbs in size.
|
* function exits. Must be NUM_LIMBS_256BIT limbs in size.
|
||||||
* \param x The number to be reduced, which must be NUM_LIMBS * 2 limbs in
|
* \param x The number to be reduced, which must be NUM_LIMBS_512BIT
|
||||||
* size and less than or equal to square(2^255 - 19 - 1). This array will
|
* limbs in size and less than or equal to square(2^255 - 19 - 1).
|
||||||
* be modified by the reduction process.
|
* This array will be modified by the reduction process.
|
||||||
* \param size The size of the high order half of \a x. This indicates
|
* \param size The size of the high order half of \a x. This indicates
|
||||||
* the size of \a x in limbs. If it is shorter than NUM_LIMBS then the
|
* the size of \a x in limbs. If it is shorter than NUM_LIMBS_256BIT
|
||||||
* reduction can be performed quicker.
|
* then the reduction can be performed quicker.
|
||||||
*/
|
*/
|
||||||
void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
|
void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
|
||||||
{
|
{
|
||||||
@ -411,18 +406,18 @@ void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
|
|||||||
// Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
|
// Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
|
||||||
// either produce the answer we want or it will produce a
|
// either produce the answer we want or it will produce a
|
||||||
// value of the form "answer + j * (2^255 - 19)".
|
// value of the form "answer + j * (2^255 - 19)".
|
||||||
carry = ((dlimb_t)(x[NUM_LIMBS - 1] >> (LIMB_BITS - 1))) * 19U;
|
carry = ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
|
||||||
x[NUM_LIMBS - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
||||||
for (posn = 0; posn < size; ++posn) {
|
for (posn = 0; posn < size; ++posn) {
|
||||||
carry += ((dlimb_t)(x[posn + NUM_LIMBS])) * 38U;
|
carry += ((dlimb_t)(x[posn + NUM_LIMBS_256BIT])) * 38U;
|
||||||
carry += x[posn];
|
carry += x[posn];
|
||||||
x[posn] = (limb_t)carry;
|
x[posn] = (limb_t)carry;
|
||||||
carry >>= LIMB_BITS;
|
carry >>= LIMB_BITS;
|
||||||
}
|
}
|
||||||
if (size < NUM_LIMBS) {
|
if (size < NUM_LIMBS_256BIT) {
|
||||||
// The high order half of the number is short; e.g. for mulA24().
|
// The high order half of the number is short; e.g. for mulA24().
|
||||||
// Propagate the carry through the rest of the low order part.
|
// Propagate the carry through the rest of the low order part.
|
||||||
for (posn = size; posn < NUM_LIMBS; ++posn) {
|
for (posn = size; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
carry += x[posn];
|
carry += x[posn];
|
||||||
x[posn] = (limb_t)carry;
|
x[posn] = (limb_t)carry;
|
||||||
carry >>= LIMB_BITS;
|
carry >>= LIMB_BITS;
|
||||||
@ -434,9 +429,9 @@ void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
|
|||||||
// then this won't do any harm but we must still do the calculation
|
// then this won't do any harm but we must still do the calculation
|
||||||
// to preserve the overall timing.
|
// to preserve the overall timing.
|
||||||
carry *= 38U;
|
carry *= 38U;
|
||||||
carry += ((dlimb_t)(x[NUM_LIMBS - 1] >> (LIMB_BITS - 1))) * 19U;
|
carry += ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
|
||||||
x[NUM_LIMBS - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
||||||
for (posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
carry += x[posn];
|
carry += x[posn];
|
||||||
x[posn] = (limb_t)carry;
|
x[posn] = (limb_t)carry;
|
||||||
carry >>= LIMB_BITS;
|
carry >>= LIMB_BITS;
|
||||||
@ -448,9 +443,9 @@ void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
|
|||||||
// trial answer into the top-most limbs of the original "x" array.
|
// trial answer into the top-most limbs of the original "x" array.
|
||||||
// We add 19 here; the subtraction of 2^255 occurs in the next step.
|
// We add 19 here; the subtraction of 2^255 occurs in the next step.
|
||||||
carry = 19U;
|
carry = 19U;
|
||||||
for (posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
carry += x[posn];
|
carry += x[posn];
|
||||||
x[posn + NUM_LIMBS] = (limb_t)carry;
|
x[posn + NUM_LIMBS_256BIT] = (limb_t)carry;
|
||||||
carry >>= LIMB_BITS;
|
carry >>= LIMB_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,22 +455,22 @@ void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
|
|||||||
// it in a way that instruction timing will not reveal which value
|
// it in a way that instruction timing will not reveal which value
|
||||||
// was selected. Borrow will occur if the high bit of the previous
|
// was selected. Borrow will occur if the high bit of the previous
|
||||||
// result is 0: turn the high bit into a selection mask.
|
// result is 0: turn the high bit into a selection mask.
|
||||||
limb_t mask = (limb_t)(((slimb_t)(x[NUM_LIMBS * 2 - 1])) >> (LIMB_BITS - 1));
|
limb_t mask = (limb_t)(((slimb_t)(x[NUM_LIMBS_512BIT - 1])) >> (LIMB_BITS - 1));
|
||||||
limb_t nmask = ~mask;
|
limb_t nmask = ~mask;
|
||||||
x[NUM_LIMBS * 2 - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
x[NUM_LIMBS_512BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
||||||
for (posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
result[posn] = (x[posn] & nmask) | (x[posn + NUM_LIMBS] & mask);
|
result[posn] = (x[posn] & nmask) | (x[posn + NUM_LIMBS_256BIT] & mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Quickly reduces a number modulo 2^255 - 19.
|
* \brief Quickly reduces a number modulo 2^255 - 19.
|
||||||
*
|
*
|
||||||
* \param x The number to be reduced, which must be NUM_LIMBS limbs in size
|
* \param x The number to be reduced, which must be NUM_LIMBS_256BIT
|
||||||
* and less than or equal to 2 * (2^255 - 19 - 1).
|
( limbs in size and less than or equal to 2 * (2^255 - 19 - 1).
|
||||||
* \return Zero if \a x was greater than or equal to (2^255 - 19).
|
* \return Zero if \a x was greater than or equal to (2^255 - 19).
|
||||||
*
|
*
|
||||||
* The answer is also put into \a x and will consist of NUM_LIMBS limbs.
|
* The answer is also put into \a x and will consist of NUM_LIMBS_256BIT limbs.
|
||||||
*
|
*
|
||||||
* This function is intended for reducing the result of additions where
|
* This function is intended for reducing the result of additions where
|
||||||
* the caller knows that \a x is within the described range. A single
|
* the caller knows that \a x is within the described range. A single
|
||||||
@ -483,7 +478,7 @@ void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
|
|||||||
*/
|
*/
|
||||||
limb_t Curve25519::reduceQuick(limb_t *x)
|
limb_t Curve25519::reduceQuick(limb_t *x)
|
||||||
{
|
{
|
||||||
limb_t temp[NUM_LIMBS];
|
limb_t temp[NUM_LIMBS_256BIT];
|
||||||
dlimb_t carry;
|
dlimb_t carry;
|
||||||
uint8_t posn;
|
uint8_t posn;
|
||||||
limb_t *xx;
|
limb_t *xx;
|
||||||
@ -495,7 +490,7 @@ limb_t Curve25519::reduceQuick(limb_t *x)
|
|||||||
carry = 19U;
|
carry = 19U;
|
||||||
xx = x;
|
xx = x;
|
||||||
tt = temp;
|
tt = temp;
|
||||||
for (posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
carry += *xx++;
|
carry += *xx++;
|
||||||
*tt++ = (limb_t)carry;
|
*tt++ = (limb_t)carry;
|
||||||
carry >>= LIMB_BITS;
|
carry >>= LIMB_BITS;
|
||||||
@ -506,12 +501,12 @@ limb_t Curve25519::reduceQuick(limb_t *x)
|
|||||||
// correct answer but do it in a way that instruction timing will not
|
// correct answer but do it in a way that instruction timing will not
|
||||||
// reveal which value was selected. Borrow will occur if the high bit
|
// reveal which value was selected. Borrow will occur if the high bit
|
||||||
// of "temp" is 0: turn the high bit into a selection mask.
|
// of "temp" is 0: turn the high bit into a selection mask.
|
||||||
limb_t mask = (limb_t)(((slimb_t)(temp[NUM_LIMBS - 1])) >> (LIMB_BITS - 1));
|
limb_t mask = (limb_t)(((slimb_t)(temp[NUM_LIMBS_256BIT - 1])) >> (LIMB_BITS - 1));
|
||||||
limb_t nmask = ~mask;
|
limb_t nmask = ~mask;
|
||||||
temp[NUM_LIMBS - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
temp[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
|
||||||
xx = x;
|
xx = x;
|
||||||
tt = temp;
|
tt = temp;
|
||||||
for (posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
*xx = ((*xx) & nmask) | ((*tt++) & mask);
|
*xx = ((*xx) & nmask) | ((*tt++) & mask);
|
||||||
++xx;
|
++xx;
|
||||||
}
|
}
|
||||||
@ -524,53 +519,68 @@ limb_t Curve25519::reduceQuick(limb_t *x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Multiplies two values and then reduces the result modulo 2^255 - 19.
|
* \brief Multiplies two 256-bit values to produce a 512-bit result.
|
||||||
*
|
*
|
||||||
* \param result The result, which must be NUM_LIMBS limbs in size and can
|
* \param result The result, which must be NUM_LIMBS_512BIT limbs in size
|
||||||
* be the same array as \a x or \a y.
|
* and must not overlap with \a x or \a y.
|
||||||
* \param x The first value to multiply, which must be NUM_LIMBS limbs in size
|
* \param x The first value to multiply, which must be NUM_LIMBS_256BIT
|
||||||
* and less than 2^255 - 19.
|
* limbs in size.
|
||||||
* \param y The second value to multiply, which must be NUM_LIMBS limbs in size
|
* \param y The second value to multiply, which must be NUM_LIMBS_256BIT
|
||||||
* and less than 2^255 - 19. This can be the same array as \a x.
|
* limbs in size.
|
||||||
|
*
|
||||||
|
* \sa mul()
|
||||||
*/
|
*/
|
||||||
void Curve25519::mul(limb_t *result, const limb_t *x, const limb_t *y)
|
void Curve25519::mulNoReduce(limb_t *result, const limb_t *x, const limb_t *y)
|
||||||
{
|
{
|
||||||
limb_t temp[NUM_LIMBS * 2];
|
|
||||||
uint8_t i, j;
|
uint8_t i, j;
|
||||||
dlimb_t carry;
|
dlimb_t carry;
|
||||||
limb_t word;
|
limb_t word;
|
||||||
const limb_t *yy;
|
const limb_t *yy;
|
||||||
limb_t *tt;
|
limb_t *rr;
|
||||||
|
|
||||||
// Multiply the lowest word of x by y.
|
// Multiply the lowest word of x by y.
|
||||||
carry = 0;
|
carry = 0;
|
||||||
word = x[0];
|
word = x[0];
|
||||||
yy = y;
|
yy = y;
|
||||||
tt = temp;
|
rr = result;
|
||||||
for (i = 0; i < NUM_LIMBS; ++i) {
|
for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
|
||||||
carry += ((dlimb_t)(*yy++)) * word;
|
carry += ((dlimb_t)(*yy++)) * word;
|
||||||
*tt++ = (limb_t)carry;
|
*rr++ = (limb_t)carry;
|
||||||
carry >>= LIMB_BITS;
|
carry >>= LIMB_BITS;
|
||||||
}
|
}
|
||||||
*tt = (limb_t)carry;
|
*rr = (limb_t)carry;
|
||||||
|
|
||||||
// Multiply and add the remaining words of x by y.
|
// Multiply and add the remaining words of x by y.
|
||||||
for (i = 1; i < NUM_LIMBS; ++i) {
|
for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
|
||||||
word = x[i];
|
word = x[i];
|
||||||
carry = 0;
|
carry = 0;
|
||||||
yy = y;
|
yy = y;
|
||||||
tt = temp + i;
|
rr = result + i;
|
||||||
for (j = 0; j < NUM_LIMBS; ++j) {
|
for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
|
||||||
carry += ((dlimb_t)(*yy++)) * word;
|
carry += ((dlimb_t)(*yy++)) * word;
|
||||||
carry += *tt;
|
carry += *rr;
|
||||||
*tt++ = (limb_t)carry;
|
*rr++ = (limb_t)carry;
|
||||||
carry >>= LIMB_BITS;
|
carry >>= LIMB_BITS;
|
||||||
}
|
}
|
||||||
*tt = (limb_t)carry;
|
*rr = (limb_t)carry;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reduce the intermediate result modulo 2^255 - 19.
|
/**
|
||||||
reduce(result, temp, NUM_LIMBS);
|
* \brief Multiplies two values and then reduces the result modulo 2^255 - 19.
|
||||||
|
*
|
||||||
|
* \param result The result, which must be NUM_LIMBS_256BIT limbs in size
|
||||||
|
* and can be the same array as \a x or \a y.
|
||||||
|
* \param x The first value to multiply, which must be NUM_LIMBS_256BIT limbs
|
||||||
|
* in size and less than 2^255 - 19.
|
||||||
|
* \param y The second value to multiply, which must be NUM_LIMBS_256BIT limbs
|
||||||
|
* in size and less than 2^255 - 19. This can be the same array as \a x.
|
||||||
|
*/
|
||||||
|
void Curve25519::mul(limb_t *result, const limb_t *x, const limb_t *y)
|
||||||
|
{
|
||||||
|
limb_t temp[NUM_LIMBS_512BIT];
|
||||||
|
mulNoReduce(temp, x, y);
|
||||||
|
reduce(result, temp, NUM_LIMBS_256BIT);
|
||||||
strict_clean(temp);
|
strict_clean(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,9 +588,9 @@ void Curve25519::mul(limb_t *result, const limb_t *x, const limb_t *y)
|
|||||||
* \fn void Curve25519::square(limb_t *result, const limb_t *x)
|
* \fn void Curve25519::square(limb_t *result, const limb_t *x)
|
||||||
* \brief Squares a value and then reduces it modulo 2^255 - 19.
|
* \brief Squares a value and then reduces it modulo 2^255 - 19.
|
||||||
*
|
*
|
||||||
* \param result The result, which must be NUM_LIMBS limbs in size and
|
* \param result The result, which must be NUM_LIMBS_256BIT limbs in size and
|
||||||
* can be the same array as \a x.
|
* can be the same array as \a x.
|
||||||
* \param x The value to square, which must be NUM_LIMBS limbs in size
|
* \param x The value to square, which must be NUM_LIMBS_256BIT limbs in size
|
||||||
* and less than 2^255 - 19.
|
* and less than 2^255 - 19.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -588,36 +598,33 @@ void Curve25519::mul(limb_t *result, const limb_t *x, const limb_t *y)
|
|||||||
* \brief Multiplies a value by the a24 constant and then reduces the result
|
* \brief Multiplies a value by the a24 constant and then reduces the result
|
||||||
* modulo 2^255 - 19.
|
* modulo 2^255 - 19.
|
||||||
*
|
*
|
||||||
* \param result The result, which must be NUM_LIMBS limbs in size and can
|
* \param result The result, which must be NUM_LIMBS_256BIT limbs in size
|
||||||
* be the same array as \a x.
|
* and can be the same array as \a x.
|
||||||
* \param x The value to multiply by a24, which must be NUM_LIMBS limbs in size
|
* \param x The value to multiply by a24, which must be NUM_LIMBS_256BIT
|
||||||
* and less than 2^255 - 19.
|
* limbs in size and less than 2^255 - 19.
|
||||||
*/
|
*/
|
||||||
void Curve25519::mulA24(limb_t *result, const limb_t *x)
|
void Curve25519::mulA24(limb_t *result, const limb_t *x)
|
||||||
{
|
{
|
||||||
// The constant a24 = 121665 (0x1DB41) as a limb array.
|
// The constant a24 = 121665 (0x1DB41) as a limb array.
|
||||||
#if BIGNUMBER_LIMB_8BIT
|
#if BIGNUMBER_LIMB_8BIT
|
||||||
static limb_t const a24[3] PROGMEM = {0x41, 0xDB, 0x01};
|
static limb_t const a24[3] PROGMEM = {0x41, 0xDB, 0x01};
|
||||||
#define pgm_read_a24(index) (pgm_read_byte(&(a24[(index)])))
|
|
||||||
#elif BIGNUMBER_LIMB_16BIT
|
#elif BIGNUMBER_LIMB_16BIT
|
||||||
static limb_t const a24[2] PROGMEM = {0xDB41, 0x0001};
|
static limb_t const a24[2] PROGMEM = {0xDB41, 0x0001};
|
||||||
#define pgm_read_a24(index) (pgm_read_word(&(a24[(index)])))
|
|
||||||
#elif BIGNUMBER_LIMB_32BIT
|
#elif BIGNUMBER_LIMB_32BIT
|
||||||
static limb_t const a24[1] PROGMEM = {0x0001DB41};
|
static limb_t const a24[1] PROGMEM = {0x0001DB41};
|
||||||
#define pgm_read_a24(index) (pgm_read_dword(&(a24[(index)])))
|
|
||||||
#else
|
#else
|
||||||
#error "limb_t must be 8, 16, or 32 bits in size"
|
#error "limb_t must be 8, 16, or 32 bits in size"
|
||||||
#endif
|
#endif
|
||||||
#define NUM_A24_LIMBS (sizeof(a24) / sizeof(limb_t))
|
#define NUM_A24_LIMBS (sizeof(a24) / sizeof(limb_t))
|
||||||
|
|
||||||
// Multiply the lowest limb of a24 by x and zero-extend into the result.
|
// Multiply the lowest limb of a24 by x and zero-extend into the result.
|
||||||
limb_t temp[NUM_LIMBS * 2];
|
limb_t temp[NUM_LIMBS_512BIT];
|
||||||
uint8_t i, j;
|
uint8_t i, j;
|
||||||
dlimb_t carry = 0;
|
dlimb_t carry = 0;
|
||||||
limb_t word = pgm_read_a24(0);
|
limb_t word = pgm_read_limb(&(a24[0]));
|
||||||
const limb_t *xx = x;
|
const limb_t *xx = x;
|
||||||
limb_t *tt = temp;
|
limb_t *tt = temp;
|
||||||
for (i = 0; i < NUM_LIMBS; ++i) {
|
for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
|
||||||
carry += ((dlimb_t)(*xx++)) * word;
|
carry += ((dlimb_t)(*xx++)) * word;
|
||||||
*tt++ = (limb_t)carry;
|
*tt++ = (limb_t)carry;
|
||||||
carry >>= LIMB_BITS;
|
carry >>= LIMB_BITS;
|
||||||
@ -626,11 +633,11 @@ void Curve25519::mulA24(limb_t *result, const limb_t *x)
|
|||||||
|
|
||||||
// Multiply and add the remaining limbs of a24.
|
// Multiply and add the remaining limbs of a24.
|
||||||
for (i = 1; i < NUM_A24_LIMBS; ++i) {
|
for (i = 1; i < NUM_A24_LIMBS; ++i) {
|
||||||
word = pgm_read_a24(i);
|
word = pgm_read_limb(&(a24[i]));
|
||||||
carry = 0;
|
carry = 0;
|
||||||
xx = x;
|
xx = x;
|
||||||
tt = temp + i;
|
tt = temp + i;
|
||||||
for (j = 0; j < NUM_LIMBS; ++j) {
|
for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
|
||||||
carry += ((dlimb_t)(*xx++)) * word;
|
carry += ((dlimb_t)(*xx++)) * word;
|
||||||
carry += *tt;
|
carry += *tt;
|
||||||
*tt++ = (limb_t)carry;
|
*tt++ = (limb_t)carry;
|
||||||
@ -644,15 +651,69 @@ void Curve25519::mulA24(limb_t *result, const limb_t *x)
|
|||||||
strict_clean(temp);
|
strict_clean(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Multiplies two values and then reduces the result modulo 2^255 - 19,
|
||||||
|
* where one of the values is in program memory.
|
||||||
|
*
|
||||||
|
* \param result The result, which must be NUM_LIMBS_256BIT limbs in size
|
||||||
|
* and can be the same array as \a x or \a y.
|
||||||
|
* \param x The first value to multiply, which must be NUM_LIMBS_256BIT limbs
|
||||||
|
* in size and less than 2^255 - 19.
|
||||||
|
* \param y The second value to multiply, which must be NUM_LIMBS_256BIT limbs
|
||||||
|
* in size and less than 2^255 - 19. This array must be in program memory.
|
||||||
|
*/
|
||||||
|
void Curve25519::mul_P(limb_t *result, const limb_t *x, const limb_t *y)
|
||||||
|
{
|
||||||
|
limb_t temp[NUM_LIMBS_512BIT];
|
||||||
|
uint8_t i, j;
|
||||||
|
dlimb_t carry;
|
||||||
|
limb_t word;
|
||||||
|
const limb_t *yy;
|
||||||
|
limb_t *tt;
|
||||||
|
|
||||||
|
// Multiply the lowest word of x by y.
|
||||||
|
carry = 0;
|
||||||
|
word = x[0];
|
||||||
|
yy = y;
|
||||||
|
tt = temp;
|
||||||
|
for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
|
||||||
|
carry += ((dlimb_t)(pgm_read_limb(yy))) * word;
|
||||||
|
*tt++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
++yy;
|
||||||
|
}
|
||||||
|
*tt = (limb_t)carry;
|
||||||
|
|
||||||
|
// Multiply and add the remaining words of x by y.
|
||||||
|
for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
|
||||||
|
word = x[i];
|
||||||
|
carry = 0;
|
||||||
|
yy = y;
|
||||||
|
tt = temp + i;
|
||||||
|
for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
|
||||||
|
carry += ((dlimb_t)(pgm_read_limb(yy))) * word;
|
||||||
|
carry += *tt;
|
||||||
|
*tt++ = (limb_t)carry;
|
||||||
|
carry >>= LIMB_BITS;
|
||||||
|
++yy;
|
||||||
|
}
|
||||||
|
*tt = (limb_t)carry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce the intermediate result modulo 2^255 - 19.
|
||||||
|
reduce(result, temp, NUM_LIMBS_256BIT);
|
||||||
|
strict_clean(temp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Adds two values and then reduces the result modulo 2^255 - 19.
|
* \brief Adds two values and then reduces the result modulo 2^255 - 19.
|
||||||
*
|
*
|
||||||
* \param result The result, which must be NUM_LIMBS limbs in size and can
|
* \param result The result, which must be NUM_LIMBS_256BIT limbs in size
|
||||||
* be the same array as \a x or \a y.
|
* and can be the same array as \a x or \a y.
|
||||||
* \param x The first value to multiply, which must be NUM_LIMBS limbs in size
|
* \param x The first value to multiply, which must be NUM_LIMBS_256BIT
|
||||||
* and less than 2^255 - 19.
|
* limbs in size and less than 2^255 - 19.
|
||||||
* \param y The second value to multiply, which must be NUM_LIMBS limbs in size
|
* \param y The second value to multiply, which must be NUM_LIMBS_256BIT
|
||||||
* and less than 2^255 - 19.
|
* limbs in size and less than 2^255 - 19.
|
||||||
*/
|
*/
|
||||||
void Curve25519::add(limb_t *result, const limb_t *x, const limb_t *y)
|
void Curve25519::add(limb_t *result, const limb_t *x, const limb_t *y)
|
||||||
{
|
{
|
||||||
@ -661,7 +722,7 @@ void Curve25519::add(limb_t *result, const limb_t *x, const limb_t *y)
|
|||||||
limb_t *rr = result;
|
limb_t *rr = result;
|
||||||
|
|
||||||
// Add the two arrays to obtain the intermediate result.
|
// Add the two arrays to obtain the intermediate result.
|
||||||
for (posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
carry += *x++;
|
carry += *x++;
|
||||||
carry += *y++;
|
carry += *y++;
|
||||||
*rr++ = (limb_t)carry;
|
*rr++ = (limb_t)carry;
|
||||||
@ -675,12 +736,12 @@ void Curve25519::add(limb_t *result, const limb_t *x, const limb_t *y)
|
|||||||
/**
|
/**
|
||||||
* \brief Subtracts two values and then reduces the result modulo 2^255 - 19.
|
* \brief Subtracts two values and then reduces the result modulo 2^255 - 19.
|
||||||
*
|
*
|
||||||
* \param result The result, which must be NUM_LIMBS limbs in size and can
|
* \param result The result, which must be NUM_LIMBS_256BIT limbs in size
|
||||||
* be the same array as \a x or \a y.
|
* and can be the same array as \a x or \a y.
|
||||||
* \param x The first value to multiply, which must be NUM_LIMBS limbs in size
|
* \param x The first value to multiply, which must be NUM_LIMBS_256BIT
|
||||||
* and less than 2^255 - 19.
|
* limbs in size and less than 2^255 - 19.
|
||||||
* \param y The second value to multiply, which must be NUM_LIMBS limbs in size
|
* \param y The second value to multiply, which must be NUM_LIMBS_256BIT
|
||||||
* and less than 2^255 - 19.
|
* limbs in size and less than 2^255 - 19.
|
||||||
*/
|
*/
|
||||||
void Curve25519::sub(limb_t *result, const limb_t *x, const limb_t *y)
|
void Curve25519::sub(limb_t *result, const limb_t *x, const limb_t *y)
|
||||||
{
|
{
|
||||||
@ -690,7 +751,7 @@ void Curve25519::sub(limb_t *result, const limb_t *x, const limb_t *y)
|
|||||||
|
|
||||||
// Subtract y from x to generate the intermediate result.
|
// Subtract y from x to generate the intermediate result.
|
||||||
borrow = 0;
|
borrow = 0;
|
||||||
for (posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
|
borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
|
||||||
*rr++ = (limb_t)borrow;
|
*rr++ = (limb_t)borrow;
|
||||||
}
|
}
|
||||||
@ -704,7 +765,7 @@ void Curve25519::sub(limb_t *result, const limb_t *x, const limb_t *y)
|
|||||||
borrow = (borrow >> LIMB_BITS) & 19U;
|
borrow = (borrow >> LIMB_BITS) & 19U;
|
||||||
borrow = ((dlimb_t)(*rr)) - borrow;
|
borrow = ((dlimb_t)(*rr)) - borrow;
|
||||||
*rr++ = (limb_t)borrow;
|
*rr++ = (limb_t)borrow;
|
||||||
for (posn = 1; posn < NUM_LIMBS; ++posn) {
|
for (posn = 1; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
borrow = ((dlimb_t)(*rr)) - ((borrow >> LIMB_BITS) & 0x01);
|
borrow = ((dlimb_t)(*rr)) - ((borrow >> LIMB_BITS) & 0x01);
|
||||||
*rr++ = (limb_t)borrow;
|
*rr++ = (limb_t)borrow;
|
||||||
}
|
}
|
||||||
@ -720,8 +781,10 @@ void Curve25519::sub(limb_t *result, const limb_t *x, const limb_t *y)
|
|||||||
*
|
*
|
||||||
* The swap is performed in a way that it should take the same amount of
|
* The swap is performed in a way that it should take the same amount of
|
||||||
* time irrespective of the value of \a select.
|
* time irrespective of the value of \a select.
|
||||||
|
*
|
||||||
|
* \sa cmove()
|
||||||
*/
|
*/
|
||||||
void Curve25519::cswap(uint8_t select, limb_t *x, limb_t *y)
|
void Curve25519::cswap(limb_t select, limb_t *x, limb_t *y)
|
||||||
{
|
{
|
||||||
uint8_t posn;
|
uint8_t posn;
|
||||||
limb_t dummy;
|
limb_t dummy;
|
||||||
@ -734,7 +797,7 @@ void Curve25519::cswap(uint8_t select, limb_t *x, limb_t *y)
|
|||||||
|
|
||||||
// Swap the two values based on "select". Algorithm from:
|
// Swap the two values based on "select". Algorithm from:
|
||||||
// https://tools.ietf.org/html/draft-irtf-cfrg-curves-02
|
// https://tools.ietf.org/html/draft-irtf-cfrg-curves-02
|
||||||
for (posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
dummy = sel & (x[posn] ^ y[posn]);
|
dummy = sel & (x[posn] ^ y[posn]);
|
||||||
x[posn] ^= dummy;
|
x[posn] ^= dummy;
|
||||||
y[posn] ^= dummy;
|
y[posn] ^= dummy;
|
||||||
@ -742,20 +805,48 @@ void Curve25519::cswap(uint8_t select, limb_t *x, limb_t *y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Computes the reciprocal of a number modulo 2^255 - 19.
|
* \brief Conditionally moves \a y into \a x if a selection value is non-zero.
|
||||||
*
|
*
|
||||||
* \param result The result as a array of NUM_LIMBS limbs in size. This can
|
* \param select Non-zero to move \a y into \a x, zero to leave \a x unchanged.
|
||||||
* be the same array as \a x.
|
* \param x The destination to move into.
|
||||||
* \param x The number to compute the reciprocal for.
|
* \param y The value to conditionally move.
|
||||||
|
*
|
||||||
|
* The move is performed in a way that it should take the same amount of
|
||||||
|
* time irrespective of the value of \a select.
|
||||||
|
*
|
||||||
|
* \sa cswap()
|
||||||
*/
|
*/
|
||||||
void Curve25519::recip(limb_t *result, const limb_t *x)
|
void Curve25519::cmove(limb_t select, limb_t *x, const limb_t *y)
|
||||||
{
|
{
|
||||||
limb_t t1[NUM_LIMBS];
|
uint8_t posn;
|
||||||
|
limb_t dummy;
|
||||||
|
limb_t sel;
|
||||||
|
|
||||||
|
// Turn "select" into an all-zeroes or all-ones mask. We don't care
|
||||||
|
// which bit or bits is set in the original "select" value.
|
||||||
|
sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
|
||||||
|
--sel;
|
||||||
|
|
||||||
|
// Move y into x based on "select". Similar to conditional swap above.
|
||||||
|
for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
|
||||||
|
dummy = sel & (x[posn] ^ y[posn]);
|
||||||
|
x[posn] ^= dummy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Raise x to the power of (2^250 - 1).
|
||||||
|
*
|
||||||
|
* \param result The result array, which must be NUM_LIMBS_256BIT limbs in size.
|
||||||
|
* \param x The value to raise.
|
||||||
|
*/
|
||||||
|
void Curve25519::pow250(limb_t *result, const limb_t *x)
|
||||||
|
{
|
||||||
|
limb_t t1[NUM_LIMBS_256BIT];
|
||||||
uint8_t i, j;
|
uint8_t i, j;
|
||||||
|
|
||||||
// The reciprocal is the same as x ^ (p - 2) where p = 2^255 - 19.
|
// The big-endian hexadecimal expansion of (2^250 - 1) is:
|
||||||
// The big-endian hexadecimal expansion of (p - 2) is:
|
// 03FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
|
||||||
// 7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFEB
|
|
||||||
//
|
//
|
||||||
// The naive implementation needs to do 2 multiplications per 1 bit and
|
// The naive implementation needs to do 2 multiplications per 1 bit and
|
||||||
// 1 multiplication per 0 bit. We can improve upon this by creating a
|
// 1 multiplication per 0 bit. We can improve upon this by creating a
|
||||||
@ -786,6 +877,25 @@ void Curve25519::recip(limb_t *result, const limb_t *x)
|
|||||||
mul(result, result, t1);
|
mul(result, result, t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up and exit.
|
||||||
|
clean(t1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Computes the reciprocal of a number modulo 2^255 - 19.
|
||||||
|
*
|
||||||
|
* \param result The result as a array of NUM_LIMBS_256BIT limbs in size.
|
||||||
|
* This cannot be the same array as \a x.
|
||||||
|
* \param x The number to compute the reciprocal for.
|
||||||
|
*/
|
||||||
|
void Curve25519::recip(limb_t *result, const limb_t *x)
|
||||||
|
{
|
||||||
|
// The reciprocal is the same as x ^ (p - 2) where p = 2^255 - 19.
|
||||||
|
// The big-endian hexadecimal expansion of (p - 2) is:
|
||||||
|
// 7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFEB
|
||||||
|
// Start with the 250 upper bits of the expansion of (p - 2).
|
||||||
|
pow250(result, x);
|
||||||
|
|
||||||
// Deal with the 5 lowest bits of (p - 2), 01011, from highest to lowest.
|
// Deal with the 5 lowest bits of (p - 2), 01011, from highest to lowest.
|
||||||
square(result, result);
|
square(result, result);
|
||||||
square(result, result);
|
square(result, result);
|
||||||
@ -795,7 +905,59 @@ void Curve25519::recip(limb_t *result, const limb_t *x)
|
|||||||
mul(result, result, x);
|
mul(result, result, x);
|
||||||
square(result, result);
|
square(result, result);
|
||||||
mul(result, result, x);
|
mul(result, result, x);
|
||||||
|
}
|
||||||
// Clean up and exit.
|
|
||||||
clean(t1);
|
/**
|
||||||
|
* \brief Computes the square root of a number modulo 2^255 - 19.
|
||||||
|
*
|
||||||
|
* \param result The result as a array of NUM_LIMBS_256BIT limbs in size.
|
||||||
|
* This must not overlap with \a x.
|
||||||
|
* \param x The number to compute the square root for.
|
||||||
|
*
|
||||||
|
* For any number \a x, there are two square roots: positive and negative.
|
||||||
|
* For example, both 2 and -2 are square roots of 4 because 2 * 2 = -2 * -2.
|
||||||
|
* This function will return one or the other. Callers must determine which
|
||||||
|
* square root they are interested in and invert the result as necessary.
|
||||||
|
*
|
||||||
|
* \note This function is not constant time so it should only be used
|
||||||
|
* on publicly-known values.
|
||||||
|
*/
|
||||||
|
bool Curve25519::sqrt(limb_t *result, const limb_t *x)
|
||||||
|
{
|
||||||
|
// sqrt(-1) mod (2^255 - 19).
|
||||||
|
static limb_t const numSqrtM1[NUM_LIMBS_256BIT] PROGMEM = {
|
||||||
|
LIMB(0x4A0EA0B0), LIMB(0xC4EE1B27), LIMB(0xAD2FE478), LIMB(0x2F431806),
|
||||||
|
LIMB(0x3DFBD7A7), LIMB(0x2B4D0099), LIMB(0x4FC1DF0B), LIMB(0x2B832480)
|
||||||
|
};
|
||||||
|
limb_t y[NUM_LIMBS_256BIT];
|
||||||
|
|
||||||
|
// Algorithm from:
|
||||||
|
// https://tools.ietf.org/id/draft-josefsson-eddsa-ed25519-02.txt
|
||||||
|
|
||||||
|
// Compute a candidate root: result = x^((p + 3) / 8) mod p.
|
||||||
|
// (p + 3) / 8 = (2^252 - 2) which is 251 one bits followed by a zero:
|
||||||
|
// 0FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE
|
||||||
|
pow250(result, x);
|
||||||
|
square(result, result);
|
||||||
|
mul(result, result, x);
|
||||||
|
square(result, result);
|
||||||
|
|
||||||
|
// Did we get the square root immediately?
|
||||||
|
square(y, result);
|
||||||
|
if (memcmp(x, y, sizeof(y)) == 0) {
|
||||||
|
clean(y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply the result by sqrt(-1) and check again.
|
||||||
|
mul_P(result, result, numSqrtM1);
|
||||||
|
square(y, result);
|
||||||
|
if (memcmp(x, y, sizeof(y)) == 0) {
|
||||||
|
clean(y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The number does not have a square root.
|
||||||
|
clean(y);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include "BigNumberUtil.h"
|
#include "BigNumberUtil.h"
|
||||||
|
|
||||||
|
class Ed25519;
|
||||||
|
|
||||||
class Curve25519
|
class Curve25519
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -43,6 +45,8 @@ private:
|
|||||||
static void reduce(limb_t *result, limb_t *x, uint8_t size);
|
static void reduce(limb_t *result, limb_t *x, uint8_t size);
|
||||||
static limb_t reduceQuick(limb_t *x);
|
static limb_t reduceQuick(limb_t *x);
|
||||||
|
|
||||||
|
static void mulNoReduce(limb_t *result, const limb_t *x, const limb_t *y);
|
||||||
|
|
||||||
static void mul(limb_t *result, const limb_t *x, const limb_t *y);
|
static void mul(limb_t *result, const limb_t *x, const limb_t *y);
|
||||||
static void square(limb_t *result, const limb_t *x)
|
static void square(limb_t *result, const limb_t *x)
|
||||||
{
|
{
|
||||||
@ -51,16 +55,23 @@ private:
|
|||||||
|
|
||||||
static void mulA24(limb_t *result, const limb_t *x);
|
static void mulA24(limb_t *result, const limb_t *x);
|
||||||
|
|
||||||
|
static void mul_P(limb_t *result, const limb_t *x, const limb_t *y);
|
||||||
|
|
||||||
static void add(limb_t *result, const limb_t *x, const limb_t *y);
|
static void add(limb_t *result, const limb_t *x, const limb_t *y);
|
||||||
static void sub(limb_t *result, const limb_t *x, const limb_t *y);
|
static void sub(limb_t *result, const limb_t *x, const limb_t *y);
|
||||||
|
|
||||||
static void cswap(uint8_t select, limb_t *x, limb_t *y);
|
static void cswap(limb_t select, limb_t *x, limb_t *y);
|
||||||
|
static void cmove(limb_t select, limb_t *x, const limb_t *y);
|
||||||
|
|
||||||
|
static void pow250(limb_t *result, const limb_t *x);
|
||||||
static void recip(limb_t *result, const limb_t *x);
|
static void recip(limb_t *result, const limb_t *x);
|
||||||
|
static bool sqrt(limb_t *result, const limb_t *x);
|
||||||
|
|
||||||
// Constructor and destructor are private - cannot instantiate this class.
|
// Constructor and destructor are private - cannot instantiate this class.
|
||||||
Curve25519() {}
|
Curve25519() {}
|
||||||
~Curve25519() {}
|
~Curve25519() {}
|
||||||
|
|
||||||
|
friend class Ed25519;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
643
libraries/Crypto/Ed25519.cpp
Normal file
643
libraries/Crypto/Ed25519.cpp
Normal file
@ -0,0 +1,643 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Ed25519.h"
|
||||||
|
#include "Curve25519.h"
|
||||||
|
#include "Crypto.h"
|
||||||
|
#include "RNG.h"
|
||||||
|
#include "utility/LimbUtil.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class Ed25519 Ed25519.h <Ed25519.h>
|
||||||
|
* \brief Digital signatures based on the elliptic curve modulo 2^255 - 19.
|
||||||
|
*
|
||||||
|
* The first step in creating a digital signature with Ed25519 is to
|
||||||
|
* generate a key pair:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* uint8_t privateKey[32];
|
||||||
|
* uint8_t publicKey[32];
|
||||||
|
*
|
||||||
|
* Ed25519::generatePrivateKey(privateKey);
|
||||||
|
* Ed25519::derivePublicKey(publicKey, privateKey);
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* The application can store both the private and public key for later
|
||||||
|
* signing operations. Or it can store just the private key and then
|
||||||
|
* derive the public key at the point where signing is to occur.
|
||||||
|
*
|
||||||
|
* Message signing produces a 64-byte signature as follows:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* uint8_t message[N];
|
||||||
|
* uint8_t signature[64];
|
||||||
|
*
|
||||||
|
* Ed25519::sign(signature, privateKey, publicKey, message, N);
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* And then to verify the signature:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* if (!Ed25519::verify(signature, publicKey, message, N)) {
|
||||||
|
* // The signature is invalid.
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* \note The public functions in this class need a substantial amount of
|
||||||
|
* stack space to store intermediate results while the curve function is
|
||||||
|
* being evaluated. About 1.5k of free stack space is recommended for safety.
|
||||||
|
*
|
||||||
|
* References: https://tools.ietf.org/id/draft-josefsson-eddsa-ed25519-02.txt
|
||||||
|
*
|
||||||
|
* \sa Curve25519
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @cond */
|
||||||
|
|
||||||
|
// 37095705934669439343138083508754565189542113879843219016388785533085940283555
|
||||||
|
static limb_t const numD[NUM_LIMBS_256BIT] PROGMEM = {
|
||||||
|
LIMB(0x135978A3), LIMB(0x75EB4DCA), LIMB(0x4141D8AB), LIMB(0x00700A4D),
|
||||||
|
LIMB(0x7779E898), LIMB(0x8CC74079), LIMB(0x2B6FFE73), LIMB(0x52036CEE)
|
||||||
|
};
|
||||||
|
|
||||||
|
// d * 2
|
||||||
|
static limb_t const numDx2[NUM_LIMBS_256BIT] PROGMEM = {
|
||||||
|
LIMB(0x26B2F159), LIMB(0xEBD69B94), LIMB(0x8283B156), LIMB(0x00E0149A),
|
||||||
|
LIMB(0xEEF3D130), LIMB(0x198E80F2), LIMB(0x56DFFCE7), LIMB(0x2406D9DC)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extended homogenous co-ordinates for the base point.
|
||||||
|
static limb_t const numBx[NUM_LIMBS_256BIT] PROGMEM = {
|
||||||
|
LIMB(0x8F25D51A), LIMB(0xC9562D60), LIMB(0x9525A7B2), LIMB(0x692CC760),
|
||||||
|
LIMB(0xFDD6DC5C), LIMB(0xC0A4E231), LIMB(0xCD6E53FE), LIMB(0x216936D3)
|
||||||
|
};
|
||||||
|
static limb_t const numBy[NUM_LIMBS_256BIT] PROGMEM = {
|
||||||
|
LIMB(0x66666658), LIMB(0x66666666), LIMB(0x66666666), LIMB(0x66666666),
|
||||||
|
LIMB(0x66666666), LIMB(0x66666666), LIMB(0x66666666), LIMB(0x66666666)
|
||||||
|
};
|
||||||
|
static limb_t const numBz[NUM_LIMBS_256BIT] PROGMEM = {
|
||||||
|
LIMB(0x00000001), LIMB(0x00000000), LIMB(0x00000000), LIMB(0x00000000),
|
||||||
|
LIMB(0x00000000), LIMB(0x00000000), LIMB(0x00000000), LIMB(0x00000000)
|
||||||
|
};
|
||||||
|
static limb_t const numBt[NUM_LIMBS_256BIT] PROGMEM = {
|
||||||
|
LIMB(0xA5B7DDA3), LIMB(0x6DDE8AB3), LIMB(0x775152F5), LIMB(0x20F09F80),
|
||||||
|
LIMB(0x64ABE37D), LIMB(0x66EA4E8E), LIMB(0xD78B7665), LIMB(0x67875F0F)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2^252 + 27742317777372353535851937790883648493
|
||||||
|
static limb_t const numQ[NUM_LIMBS_256BIT] PROGMEM = {
|
||||||
|
LIMB(0x5CF5D3ED), LIMB(0x5812631A), LIMB(0xA2F79CD6), LIMB(0x14DEF9DE),
|
||||||
|
LIMB(0x00000000), LIMB(0x00000000), LIMB(0x00000000), LIMB(0x10000000)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Signs a message using a specific Ed25519 private key.
|
||||||
|
*
|
||||||
|
* \param signature The signature value.
|
||||||
|
* \param privateKey The private key to use to sign the message.
|
||||||
|
* \param publicKey The public key corresponding to \a privateKey.
|
||||||
|
* \param message Points to the message to be signed.
|
||||||
|
* \param len The length of the \a message to be signed.
|
||||||
|
*
|
||||||
|
* \sa verify(), derivePublicKey()
|
||||||
|
*/
|
||||||
|
void Ed25519::sign(uint8_t signature[64], const uint8_t privateKey[32],
|
||||||
|
const uint8_t publicKey[32], const void *message, size_t len)
|
||||||
|
{
|
||||||
|
SHA512 hash;
|
||||||
|
uint8_t *buf = (uint8_t *)(hash.state.w); // Reuse hash buffer to save memory.
|
||||||
|
limb_t a[NUM_LIMBS_256BIT];
|
||||||
|
limb_t r[NUM_LIMBS_256BIT];
|
||||||
|
limb_t k[NUM_LIMBS_256BIT];
|
||||||
|
limb_t t[NUM_LIMBS_512BIT + 1];
|
||||||
|
Point rB;
|
||||||
|
|
||||||
|
// Derive the secret scalar a and the message prefix from the private key.
|
||||||
|
deriveKeys(&hash, a, privateKey);
|
||||||
|
|
||||||
|
// Hash the prefix and the message to derive r.
|
||||||
|
hash.reset();
|
||||||
|
hash.update(buf + 32, 32);
|
||||||
|
hash.update(message, len);
|
||||||
|
hash.finalize(buf, 0);
|
||||||
|
reduceQFromBuffer(r, buf, t);
|
||||||
|
|
||||||
|
// Encode rB into the first half of the signature buffer as R.
|
||||||
|
mul(rB, r);
|
||||||
|
encodePoint(signature, rB);
|
||||||
|
|
||||||
|
// Hash R, A, and the message to get k.
|
||||||
|
hash.reset();
|
||||||
|
hash.update(signature, 32); // R
|
||||||
|
hash.update(publicKey, 32); // A
|
||||||
|
hash.update(message, len);
|
||||||
|
hash.finalize(buf, 0);
|
||||||
|
reduceQFromBuffer(k, buf, t);
|
||||||
|
|
||||||
|
// Compute s = (r + k * a) mod q.
|
||||||
|
Curve25519::mulNoReduce(t, k, a);
|
||||||
|
t[NUM_LIMBS_512BIT] = 0;
|
||||||
|
reduceQ(t, t);
|
||||||
|
BigNumberUtil::add(t, t, r, NUM_LIMBS_256BIT);
|
||||||
|
BigNumberUtil::reduceQuick_P(t, t, numQ, NUM_LIMBS_256BIT);
|
||||||
|
BigNumberUtil::packLE(signature + 32, 32, t, NUM_LIMBS_256BIT);
|
||||||
|
|
||||||
|
// Clean up.
|
||||||
|
clean(a);
|
||||||
|
clean(r);
|
||||||
|
clean(k);
|
||||||
|
clean(t);
|
||||||
|
clean(rB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Verifies a signature using a specific Ed25519 public key.
|
||||||
|
*
|
||||||
|
* \param signature The signature value to be verified.
|
||||||
|
* \param publicKey The public key to use to verify the signature.
|
||||||
|
* \param message The message whose signature is to be verified.
|
||||||
|
* \param len The length of the \a message to be verified.
|
||||||
|
*
|
||||||
|
* \return Returns true if the \a signature is valid for \a message;
|
||||||
|
* or false if the \a signature is not valid.
|
||||||
|
*
|
||||||
|
* \sa sign()
|
||||||
|
*/
|
||||||
|
bool Ed25519::verify(const uint8_t signature[64], const uint8_t publicKey[32],
|
||||||
|
const void *message, size_t len)
|
||||||
|
{
|
||||||
|
SHA512 hash;
|
||||||
|
Point A;
|
||||||
|
Point R;
|
||||||
|
Point sB;
|
||||||
|
Point kA;
|
||||||
|
uint8_t *k = (uint8_t *)(hash.state.w); // Reuse hash buffer to save memory.
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
// Decode the public key and the R component of the signature.
|
||||||
|
if (decodePoint(A, publicKey) && decodePoint(R, signature)) {
|
||||||
|
// Reconstruct the k value from the signing step.
|
||||||
|
hash.reset();
|
||||||
|
hash.update(signature, 32);
|
||||||
|
hash.update(publicKey, 32);
|
||||||
|
hash.update(message, len);
|
||||||
|
hash.finalize(k, 0);
|
||||||
|
|
||||||
|
// Calculate s * B. The s value is stored temporarily in kA.t.
|
||||||
|
BigNumberUtil::unpackLE(kA.t, NUM_LIMBS_256BIT, signature + 32, 32);
|
||||||
|
mul(sB, kA.t, false);
|
||||||
|
|
||||||
|
// Calculate R + k * A. We don't need sB.t in equal() below,
|
||||||
|
// so we reuse that as a temporary buffer when reducing k.
|
||||||
|
reduceQFromBuffer(sB.t, k, kA.x);
|
||||||
|
mul(kA, sB.t, A, false);
|
||||||
|
add(R, kA);
|
||||||
|
|
||||||
|
// Compare s * B and R + k * A for equality.
|
||||||
|
result = equal(sB, R);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up and exit.
|
||||||
|
clean(A);
|
||||||
|
clean(R);
|
||||||
|
clean(sB);
|
||||||
|
clean(kA);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generates a private key for Ed25519 signing operations.
|
||||||
|
*
|
||||||
|
* \param privateKey The resulting private key.
|
||||||
|
*
|
||||||
|
* The private key is generated with \link RNGClass::rand() RNG.rand()\endlink.
|
||||||
|
* It is the caller's responsibility to ensure that the global random number
|
||||||
|
* pool has sufficient entropy to generate the 32 bytes of the key safely
|
||||||
|
* before calling this function.
|
||||||
|
*
|
||||||
|
* \sa derivePublicKey()
|
||||||
|
*/
|
||||||
|
void Ed25519::generatePrivateKey(uint8_t privateKey[32])
|
||||||
|
{
|
||||||
|
RNG.rand(privateKey, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Derives the public key from a private key.
|
||||||
|
*
|
||||||
|
* \param publicKey The public key.
|
||||||
|
* \param privateKey The private key.
|
||||||
|
*
|
||||||
|
* \sa generatePrivateKey()
|
||||||
|
*/
|
||||||
|
void Ed25519::derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32])
|
||||||
|
{
|
||||||
|
SHA512 hash;
|
||||||
|
uint8_t *buf = (uint8_t *)(hash.state.w);
|
||||||
|
limb_t a[NUM_LIMBS_256BIT];
|
||||||
|
Point ptA;
|
||||||
|
|
||||||
|
// Derive the secret scalar a from the private key.
|
||||||
|
deriveKeys(&hash, a, privateKey);
|
||||||
|
|
||||||
|
// Compute the point A = aB and encode it.
|
||||||
|
mul(ptA, a);
|
||||||
|
encodePoint(publicKey, ptA);
|
||||||
|
|
||||||
|
// Clean up and exit.
|
||||||
|
clean(a);
|
||||||
|
clean(ptA);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reduces a number modulo q that was specified in a 512 bit buffer.
|
||||||
|
*
|
||||||
|
* \param result The result array, which must be NUM_LIMBS_256BIT limbs in size.
|
||||||
|
* \param buf The buffer containing the value to reduce in little-endian order.
|
||||||
|
* \param temp A temporary buffer of at least NUM_LIMBS_512BIT + 1 in size.
|
||||||
|
*
|
||||||
|
* \sa reduceQ()
|
||||||
|
*/
|
||||||
|
void Ed25519::reduceQFromBuffer(limb_t *result, const uint8_t buf[64], limb_t *temp)
|
||||||
|
{
|
||||||
|
BigNumberUtil::unpackLE(temp, NUM_LIMBS_512BIT, buf, 64);
|
||||||
|
temp[NUM_LIMBS_512BIT] = 0;
|
||||||
|
reduceQ(result, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reduces a number modulo q.
|
||||||
|
*
|
||||||
|
* \param result The result array, which must be NUM_LIMBS_256BIT limbs in size.
|
||||||
|
* \param r The value to reduce, which must be NUM_LIMBS_512BIT + 1
|
||||||
|
* limbs in size.
|
||||||
|
*
|
||||||
|
* The \a r array will be modified by this function as a side effect of
|
||||||
|
* the division. It is allowed for \a result to be the same as \a r.
|
||||||
|
*
|
||||||
|
* \sa reduceQFromBuffer()
|
||||||
|
*/
|
||||||
|
void Ed25519::reduceQ(limb_t *result, limb_t *r)
|
||||||
|
{
|
||||||
|
// Algorithm from: http://en.wikipedia.org/wiki/Barrett_reduction
|
||||||
|
//
|
||||||
|
// We assume that r is less than or equal to (q - 1)^2.
|
||||||
|
//
|
||||||
|
// We want to compute result = r mod q. Find the smallest k such
|
||||||
|
// that 2^k > q. In our case, k = 253. Then set m = floor(4^k / q)
|
||||||
|
// and let r = r - q * floor(m * r / 4^k). This will be the result
|
||||||
|
// or it will be at most one subtraction of q away from the result.
|
||||||
|
//
|
||||||
|
// Note: 4^k = 4^253 = 2^506 = 2^512/2^6. We can more easily compute
|
||||||
|
// the result we want if we set m = floor(4^k * 2^6 / q) instead and
|
||||||
|
// then r = r - q * floor(m * r / 2^512). Because the slight extra
|
||||||
|
// precision in m, r is at most two subtractions of q away from the
|
||||||
|
// final result.
|
||||||
|
static limb_t const numM[NUM_LIMBS_256BIT + 1] PROGMEM = {
|
||||||
|
LIMB(0x0A2C131B), LIMB(0xED9CE5A3), LIMB(0x086329A7), LIMB(0x2106215D),
|
||||||
|
LIMB(0xFFFFFFEB), LIMB(0xFFFFFFFF), LIMB(0xFFFFFFFF), LIMB(0xFFFFFFFF),
|
||||||
|
0x0F
|
||||||
|
};
|
||||||
|
limb_t temp[NUM_LIMBS_512BIT + NUM_LIMBS_256BIT + 1];
|
||||||
|
|
||||||
|
// Multiply r by m.
|
||||||
|
BigNumberUtil::mul_P(temp, r, NUM_LIMBS_512BIT, numM, NUM_LIMBS_256BIT + 1);
|
||||||
|
|
||||||
|
// Multiply (m * r) / 2^512 by q and subtract it from r.
|
||||||
|
// We can ignore the high words of the subtraction result
|
||||||
|
// because they will all turn into zero after the subtraction.
|
||||||
|
BigNumberUtil::mul_P(temp, temp + NUM_LIMBS_512BIT, NUM_LIMBS_256BIT + 1,
|
||||||
|
numQ, NUM_LIMBS_256BIT);
|
||||||
|
BigNumberUtil::sub(r, r, temp, NUM_LIMBS_256BIT);
|
||||||
|
|
||||||
|
// Perform two subtractions of q from the result to reduce it.
|
||||||
|
BigNumberUtil::reduceQuick_P(result, r, numQ, NUM_LIMBS_256BIT);
|
||||||
|
BigNumberUtil::reduceQuick_P(result, result, numQ, NUM_LIMBS_256BIT);
|
||||||
|
|
||||||
|
// Clean up and exit.
|
||||||
|
clean(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Multiplies a value by a curve point.
|
||||||
|
*
|
||||||
|
* \param result The result of the multiplication.
|
||||||
|
* \param s The value, which must be NUM_LIMBS_256BIT limbs in size.
|
||||||
|
* \param p The curve point, which will be modified by this function.
|
||||||
|
* \param constTime Set to true if the evaluation must be constant-time
|
||||||
|
* because \a s is a secret value.
|
||||||
|
*/
|
||||||
|
void Ed25519::mul(Point &result, const limb_t *s, Point &p, bool constTime)
|
||||||
|
{
|
||||||
|
Point q;
|
||||||
|
limb_t A[NUM_LIMBS_256BIT];
|
||||||
|
limb_t B[NUM_LIMBS_256BIT];
|
||||||
|
limb_t C[NUM_LIMBS_256BIT];
|
||||||
|
limb_t D[NUM_LIMBS_256BIT];
|
||||||
|
limb_t mask, select;
|
||||||
|
uint8_t sposn, t;
|
||||||
|
|
||||||
|
// Initialize the result to (0, 1, 1, 0).
|
||||||
|
memset(&result, 0, sizeof(Point));
|
||||||
|
result.y[0] = 1;
|
||||||
|
result.z[0] = 1;
|
||||||
|
|
||||||
|
// Iterate over the 255 bits of "s" to calculate "s * p".
|
||||||
|
mask = 1;
|
||||||
|
sposn = 0;
|
||||||
|
for (t = 255; t > 0; --t) {
|
||||||
|
// Add p to the result to produce q. The specification refers
|
||||||
|
// to temporary variables A to H. We can dispense with E to H
|
||||||
|
// by using B, D, q.z, and q.t to hold those values temporarily.
|
||||||
|
select = s[sposn] & mask;
|
||||||
|
if (constTime || select) {
|
||||||
|
Curve25519::sub(A, result.y, result.x);
|
||||||
|
Curve25519::sub(C, p.y, p.x);
|
||||||
|
Curve25519::mul(A, A, C);
|
||||||
|
Curve25519::add(B, result.y, result.x);
|
||||||
|
Curve25519::add(C, p.y, p.x);
|
||||||
|
Curve25519::mul(B, B, C);
|
||||||
|
Curve25519::mul(C, result.t, p.t);
|
||||||
|
Curve25519::mul_P(C, C, numDx2);
|
||||||
|
Curve25519::mul(D, result.z, p.z);
|
||||||
|
Curve25519::add(D, D, D);
|
||||||
|
Curve25519::sub(q.t, B, A); // E = B - A
|
||||||
|
Curve25519::sub(q.z, D, C); // F = D - C
|
||||||
|
Curve25519::add(D, D, C); // G = D + C
|
||||||
|
Curve25519::add(B, B, A); // H = B + A
|
||||||
|
if (constTime) {
|
||||||
|
// Put the intermediate value into q.
|
||||||
|
Curve25519::mul(q.x, q.t, q.z); // q.x = E * F
|
||||||
|
Curve25519::mul(q.y, D, B); // q.y = G * H
|
||||||
|
Curve25519::mul(q.z, q.z, D); // q.z = F * G
|
||||||
|
Curve25519::mul(q.t, q.t, B); // q.t = E * H
|
||||||
|
|
||||||
|
// Copy q into the result if the current bit of s is 1.
|
||||||
|
Curve25519::cmove(select, result.x, q.x);
|
||||||
|
Curve25519::cmove(select, result.y, q.y);
|
||||||
|
Curve25519::cmove(select, result.z, q.z);
|
||||||
|
Curve25519::cmove(select, result.t, q.t);
|
||||||
|
} else {
|
||||||
|
// Put the intermediate value directly into the result.
|
||||||
|
Curve25519::mul(result.x, q.t, q.z); // q.x = E * F
|
||||||
|
Curve25519::mul(result.y, D, B); // q.y = G * H
|
||||||
|
Curve25519::mul(result.z, q.z, D); // q.z = F * G
|
||||||
|
Curve25519::mul(result.t, q.t, B); // q.t = E * H
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double p for the next iteration.
|
||||||
|
Curve25519::sub(A, p.y, p.x);
|
||||||
|
Curve25519::square(A, A);
|
||||||
|
Curve25519::add(B, p.y, p.x);
|
||||||
|
Curve25519::square(B, B);
|
||||||
|
Curve25519::square(C, p.t);
|
||||||
|
Curve25519::mul_P(C, C, numDx2);
|
||||||
|
Curve25519::square(D, p.z);
|
||||||
|
Curve25519::add(D, D, D);
|
||||||
|
Curve25519::sub(p.t, B, A); // E = B - A
|
||||||
|
Curve25519::sub(p.z, D, C); // F = D - C
|
||||||
|
Curve25519::add(D, D, C); // G = D + C
|
||||||
|
Curve25519::add(B, B, A); // H = B + A
|
||||||
|
Curve25519::mul(p.x, p.t, p.z); // p.x = E * F
|
||||||
|
Curve25519::mul(p.y, D, B); // p.y = G * H
|
||||||
|
Curve25519::mul(p.z, p.z, D); // p.z = F * G
|
||||||
|
Curve25519::mul(p.t, p.t, B); // p.t = E * H
|
||||||
|
|
||||||
|
// Move onto the next bit of s from lowest to highest.
|
||||||
|
if (mask != (((limb_t)1) << (LIMB_BITS - 1))) {
|
||||||
|
mask <<= 1;
|
||||||
|
} else {
|
||||||
|
++sposn;
|
||||||
|
mask = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up.
|
||||||
|
clean(q);
|
||||||
|
clean(A);
|
||||||
|
clean(B);
|
||||||
|
clean(C);
|
||||||
|
clean(D);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Multiplies a value by the base point of the curve.
|
||||||
|
*
|
||||||
|
* \param result The result of the multiplication.
|
||||||
|
* \param s The value, which must be NUM_LIMBS_256BIT limbs in size.
|
||||||
|
* \param constTime Set to true if the evaluation must be constant-time
|
||||||
|
* because \a s is a secret values.
|
||||||
|
*/
|
||||||
|
void Ed25519::mul(Point &result, const limb_t *s, bool constTime)
|
||||||
|
{
|
||||||
|
Point P;
|
||||||
|
memcpy_P(P.x, numBx, sizeof(P.x));
|
||||||
|
memcpy_P(P.y, numBy, sizeof(P.y));
|
||||||
|
memcpy_P(P.z, numBz, sizeof(P.z));
|
||||||
|
memcpy_P(P.t, numBt, sizeof(P.t));
|
||||||
|
mul(result, s, P, constTime);
|
||||||
|
clean(P);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds two curve points.
|
||||||
|
*
|
||||||
|
* \param p The first point and the result.
|
||||||
|
* \param q The second point.
|
||||||
|
*/
|
||||||
|
void Ed25519::add(Point &p, const Point &q)
|
||||||
|
{
|
||||||
|
limb_t A[NUM_LIMBS_256BIT];
|
||||||
|
limb_t B[NUM_LIMBS_256BIT];
|
||||||
|
limb_t C[NUM_LIMBS_256BIT];
|
||||||
|
limb_t D[NUM_LIMBS_256BIT];
|
||||||
|
|
||||||
|
Curve25519::sub(A, p.y, p.x);
|
||||||
|
Curve25519::sub(C, q.y, q.x);
|
||||||
|
Curve25519::mul(A, A, C);
|
||||||
|
Curve25519::add(B, p.y, p.x);
|
||||||
|
Curve25519::add(C, q.y, q.x);
|
||||||
|
Curve25519::mul(B, B, C);
|
||||||
|
Curve25519::mul(C, p.t, q.t);
|
||||||
|
Curve25519::mul_P(C, C, numDx2);
|
||||||
|
Curve25519::mul(D, p.z, q.z);
|
||||||
|
Curve25519::add(D, D, D);
|
||||||
|
Curve25519::sub(p.t, B, A); // E = B - A
|
||||||
|
Curve25519::sub(p.z, D, C); // F = D - C
|
||||||
|
Curve25519::add(D, D, C); // G = D + C
|
||||||
|
Curve25519::add(B, B, A); // H = B + A
|
||||||
|
Curve25519::mul(p.x, p.t, p.z); // p.x = E * F
|
||||||
|
Curve25519::mul(p.y, D, B); // p.y = G * H
|
||||||
|
Curve25519::mul(p.z, p.z, D); // p.z = F * G
|
||||||
|
Curve25519::mul(p.t, p.t, B); // p.t = E * H
|
||||||
|
|
||||||
|
clean(A);
|
||||||
|
clean(B);
|
||||||
|
clean(C);
|
||||||
|
clean(D);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Determine if two curve points are equal.
|
||||||
|
*
|
||||||
|
* \param p The first curve point.
|
||||||
|
* \param q The second curve point.
|
||||||
|
*
|
||||||
|
* \return Returns true if \a p and \a q are equal; false otherwise.
|
||||||
|
*/
|
||||||
|
bool Ed25519::equal(const Point &p, const Point &q)
|
||||||
|
{
|
||||||
|
limb_t a[NUM_LIMBS_256BIT];
|
||||||
|
limb_t b[NUM_LIMBS_256BIT];
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
Curve25519::mul(a, p.x, q.z);
|
||||||
|
Curve25519::mul(b, q.x, p.z);
|
||||||
|
result &= secure_compare(a, b, sizeof(a));
|
||||||
|
|
||||||
|
Curve25519::mul(a, p.y, q.z);
|
||||||
|
Curve25519::mul(b, q.y, p.z);
|
||||||
|
result &= secure_compare(a, b, sizeof(a));
|
||||||
|
|
||||||
|
clean(a);
|
||||||
|
clean(b);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Encodes a curve point into a 32-byte buffer.
|
||||||
|
*
|
||||||
|
* \param buf The buffer to encode into.
|
||||||
|
* \param point The curve point to encode. This value will be modified
|
||||||
|
* the function and effectively destroyed.
|
||||||
|
*
|
||||||
|
* \sa decodePoint()
|
||||||
|
*/
|
||||||
|
void Ed25519::encodePoint(uint8_t *buf, Point &point)
|
||||||
|
{
|
||||||
|
// Convert the homogeneous coordinates into plain (x, y) coordinates:
|
||||||
|
// zinv = z^(-1) mod p
|
||||||
|
// x = x * zinv mod p
|
||||||
|
// y = y * zinv mod p
|
||||||
|
// We don't need the t coordinate, so use that to store zinv temporarily.
|
||||||
|
Curve25519::recip(point.t, point.z);
|
||||||
|
Curve25519::mul(point.x, point.x, point.t);
|
||||||
|
Curve25519::mul(point.y, point.y, point.t);
|
||||||
|
|
||||||
|
// Copy the lowest bit of x to the highest bit of y.
|
||||||
|
point.y[NUM_LIMBS_256BIT - 1] |= (point.x[0] << (LIMB_BITS - 1));
|
||||||
|
|
||||||
|
// Convert y into little-endian in the return buffer.
|
||||||
|
BigNumberUtil::packLE(buf, 32, point.y, NUM_LIMBS_256BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decodes a curve point from a 32-byte buffer.
|
||||||
|
*
|
||||||
|
* \param point The curve point that was decoded from the buffer.
|
||||||
|
* \param buf The buffer to decode.
|
||||||
|
*
|
||||||
|
* \return Returns true if the point was decoded or false if the contents
|
||||||
|
* of the buffer do not correspond to a legitimate curve point.
|
||||||
|
*
|
||||||
|
* \note This function is not constant time so it should only be used
|
||||||
|
* on publicly-known values.
|
||||||
|
*/
|
||||||
|
bool Ed25519::decodePoint(Point &point, const uint8_t *buf)
|
||||||
|
{
|
||||||
|
limb_t temp[NUM_LIMBS_256BIT];
|
||||||
|
|
||||||
|
// Convert the input buffer from little-endian into the limbs of y.
|
||||||
|
BigNumberUtil::unpackLE(point.y, NUM_LIMBS_256BIT, buf, 32);
|
||||||
|
|
||||||
|
// The high bit of y is the sign bit for x.
|
||||||
|
limb_t sign = point.y[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1);
|
||||||
|
point.y[NUM_LIMBS_256BIT - 1] &= ~(((limb_t)1) << (LIMB_BITS - 1));
|
||||||
|
|
||||||
|
// Set z to 1.
|
||||||
|
memcpy_P(point.z, numBz, sizeof(point.z));
|
||||||
|
|
||||||
|
// Compute t = (y * y - 1) * modinv(d * y * y + 1).
|
||||||
|
Curve25519::square(point.t, point.y);
|
||||||
|
Curve25519::sub(point.x, point.t, point.z);
|
||||||
|
Curve25519::mul_P(point.t, point.t, numD);
|
||||||
|
Curve25519::add(point.t, point.t, point.z);
|
||||||
|
Curve25519::recip(temp, point.t);
|
||||||
|
Curve25519::mul(point.t, point.x, temp);
|
||||||
|
clean(temp);
|
||||||
|
|
||||||
|
// Check for t = 0.
|
||||||
|
limb_t check = point.t[0];
|
||||||
|
for (uint8_t posn = 1; posn < NUM_LIMBS_256BIT; ++posn)
|
||||||
|
check |= point.t[posn];
|
||||||
|
if (!check) {
|
||||||
|
// If the sign bit is set, then decoding has failed.
|
||||||
|
// Otherwise x is zero and we're done.
|
||||||
|
if (sign)
|
||||||
|
return false;
|
||||||
|
memset(point.x, 0, sizeof(point.x));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recover x by taking the sqrt of t and flipping the sign if necessary.
|
||||||
|
if (!Curve25519::sqrt(point.x, point.t))
|
||||||
|
return false;
|
||||||
|
if (sign != (point.x[0] & ((limb_t)1))) {
|
||||||
|
// The signs are different so we want the other square root.
|
||||||
|
memset(point.t, 0, sizeof(point.t));
|
||||||
|
Curve25519::sub(point.x, point.t, point.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, t = x * y.
|
||||||
|
Curve25519::mul(point.t, point.x, point.y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Derive key material from a 32-byte private key.
|
||||||
|
*
|
||||||
|
* \param hash SHA512 hash object from the caller for use in this function.
|
||||||
|
* The 64-byte output buffer within this hash object will contain the
|
||||||
|
* hash prefix on exit.
|
||||||
|
* \param a The secret scalar derived from \a privateKey. This must be
|
||||||
|
* NUM_LIMBS_256BIT limbs in size.
|
||||||
|
* \param privateKey The 32-byte private key to derive all other values from.
|
||||||
|
*/
|
||||||
|
void Ed25519::deriveKeys(SHA512 *hash, limb_t *a, const uint8_t privateKey[32])
|
||||||
|
{
|
||||||
|
// Hash the private key to get the "a" scalar and the message prefix.
|
||||||
|
uint8_t *buf = (uint8_t *)(hash->state.w); // Reuse hash buffer to save memory.
|
||||||
|
hash->reset();
|
||||||
|
hash->update(privateKey, 32);
|
||||||
|
hash->finalize(buf, 0);
|
||||||
|
buf[0] &= 0xF8;
|
||||||
|
buf[31] &= 0x7F;
|
||||||
|
buf[31] |= 0x40;
|
||||||
|
|
||||||
|
// Unpack the first half of the hash value into "a".
|
||||||
|
BigNumberUtil::unpackLE(a, NUM_LIMBS_256BIT, buf, 32);
|
||||||
|
}
|
71
libraries/Crypto/Ed25519.h
Normal file
71
libraries/Crypto/Ed25519.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRYPTO_ED25519_h
|
||||||
|
#define CRYPTO_ED25519_h
|
||||||
|
|
||||||
|
#include "BigNumberUtil.h"
|
||||||
|
#include "SHA512.h"
|
||||||
|
|
||||||
|
class Ed25519
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void sign(uint8_t signature[64], const uint8_t privateKey[32],
|
||||||
|
const uint8_t publicKey[32], const void *message,
|
||||||
|
size_t len);
|
||||||
|
static bool verify(const uint8_t signature[64], const uint8_t publicKey[32],
|
||||||
|
const void *message, size_t len);
|
||||||
|
|
||||||
|
static void generatePrivateKey(uint8_t privateKey[32]);
|
||||||
|
static void derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32]);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Constructor and destructor are private - cannot instantiate this class.
|
||||||
|
Ed25519();
|
||||||
|
~Ed25519();
|
||||||
|
|
||||||
|
// Curve point represented in extended homogeneous coordinates.
|
||||||
|
struct Point
|
||||||
|
{
|
||||||
|
limb_t x[32 / sizeof(limb_t)];
|
||||||
|
limb_t y[32 / sizeof(limb_t)];
|
||||||
|
limb_t z[32 / sizeof(limb_t)];
|
||||||
|
limb_t t[32 / sizeof(limb_t)];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void reduceQFromBuffer(limb_t *result, const uint8_t buf[64], limb_t *temp);
|
||||||
|
static void reduceQ(limb_t *result, limb_t *r);
|
||||||
|
|
||||||
|
static void mul(Point &result, const limb_t *s, Point &p, bool constTime = true);
|
||||||
|
static void mul(Point &result, const limb_t *s, bool constTime = true);
|
||||||
|
|
||||||
|
static void add(Point &p, const Point &q);
|
||||||
|
|
||||||
|
static bool equal(const Point &p, const Point &q);
|
||||||
|
|
||||||
|
static void encodePoint(uint8_t *buf, Point &point);
|
||||||
|
static bool decodePoint(Point &point, const uint8_t *buf);
|
||||||
|
|
||||||
|
static void deriveKeys(SHA512 *hash, limb_t *a, const uint8_t privateKey[32]);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -23,6 +23,7 @@
|
|||||||
#include "Poly1305.h"
|
#include "Poly1305.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "utility/EndianUtil.h"
|
#include "utility/EndianUtil.h"
|
||||||
|
#include "utility/LimbUtil.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,10 +59,8 @@
|
|||||||
* http://cr.yp.to/mac.html
|
* http://cr.yp.to/mac.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Useful sizes for limb array and word manipulation.
|
// Limb array with enough space for 130 bits.
|
||||||
#define NUM_LIMBS_128BIT (16 / sizeof(limb_t))
|
#define NUM_LIMBS_130BIT (NUM_LIMBS_128BIT + 1)
|
||||||
#define NUM_LIMBS_130BIT ((16 / sizeof(limb_t)) + 1)
|
|
||||||
#define LIMB_BITS (sizeof(limb_t) * 8)
|
|
||||||
|
|
||||||
// Endian helper macros for limbs and arrays of limbs.
|
// Endian helper macros for limbs and arrays of limbs.
|
||||||
#if BIGNUMBER_LIMB_8BIT
|
#if BIGNUMBER_LIMB_8BIT
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include "Hash.h"
|
#include "Hash.h"
|
||||||
|
|
||||||
|
class Ed25519;
|
||||||
|
|
||||||
class SHA512 : public Hash
|
class SHA512 : public Hash
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -53,6 +55,8 @@ private:
|
|||||||
} state;
|
} state;
|
||||||
|
|
||||||
void processChunk();
|
void processChunk();
|
||||||
|
|
||||||
|
friend class Ed25519;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -99,10 +99,10 @@ void printNumber(const char *name, const limb_t *x)
|
|||||||
static const char hexchars[] = "0123456789ABCDEF";
|
static const char hexchars[] = "0123456789ABCDEF";
|
||||||
Serial.print(name);
|
Serial.print(name);
|
||||||
Serial.print(" = ");
|
Serial.print(" = ");
|
||||||
for (uint8_t posn = 0; posn < NUM_LIMBS; ++posn) {
|
for (uint8_t posn = NUM_LIMBS; posn > 0; --posn) {
|
||||||
for (uint8_t bit = LIMB_BITS; bit > 0; ) {
|
for (uint8_t bit = LIMB_BITS; bit > 0; ) {
|
||||||
bit -= 4;
|
bit -= 4;
|
||||||
Serial.print(hexchars[(x[posn] >> bit) & 0x0F]);
|
Serial.print(hexchars[(x[posn - 1] >> bit) & 0x0F]);
|
||||||
}
|
}
|
||||||
Serial.print(' ');
|
Serial.print(' ');
|
||||||
}
|
}
|
||||||
@ -603,6 +603,68 @@ void testRecip()
|
|||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testSqrt(const char *x)
|
||||||
|
{
|
||||||
|
Serial.print("sqrt(");
|
||||||
|
printProgMem(x);
|
||||||
|
Serial.print("^2): ");
|
||||||
|
Serial.flush();
|
||||||
|
|
||||||
|
fromString(arg1, NUM_LIMBS, x);
|
||||||
|
Curve25519::square(arg2, arg1);
|
||||||
|
bool ok = Curve25519::sqrt(result, arg2);
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
ok = (compare(result, arg1) == 0);
|
||||||
|
if (!ok) {
|
||||||
|
// Check the negation of arg1 as well because we could
|
||||||
|
// have ended up with the inverse of the original value.
|
||||||
|
memset(temp, 0, sizeof(temp));
|
||||||
|
Curve25519::sub(temp, temp, arg1);
|
||||||
|
ok = (compare(result, temp) == 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.println("no sqrt ... ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
Serial.println("ok");
|
||||||
|
} else {
|
||||||
|
Serial.println("failed");
|
||||||
|
printNumber("actual", result);
|
||||||
|
printNumber("expected", arg1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testNoSqrt(const char *x)
|
||||||
|
{
|
||||||
|
Serial.print("no sqrt(");
|
||||||
|
printProgMem(x);
|
||||||
|
Serial.print("): ");
|
||||||
|
Serial.flush();
|
||||||
|
|
||||||
|
fromString(arg1, NUM_LIMBS, x);
|
||||||
|
bool ok = !Curve25519::sqrt(result, arg1);
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
Serial.println("ok");
|
||||||
|
} else {
|
||||||
|
Serial.println("failed");
|
||||||
|
printNumber("actual", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSqrt()
|
||||||
|
{
|
||||||
|
Serial.println("Square root:");
|
||||||
|
foreach_number (x) {
|
||||||
|
testSqrt(x);
|
||||||
|
}
|
||||||
|
testNoSqrt(num_128);
|
||||||
|
testNoSqrt(num_pi);
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
@ -613,6 +675,7 @@ void setup()
|
|||||||
testMulA24();
|
testMulA24();
|
||||||
testSwap();
|
testSwap();
|
||||||
testRecip();
|
testRecip();
|
||||||
|
testSqrt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
|
241
libraries/Crypto/examples/TestEd25519/TestEd25519.ino
Normal file
241
libraries/Crypto/examples/TestEd25519/TestEd25519.ino
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This example runs tests on the Ed25519 algorithm.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Crypto.h>
|
||||||
|
#include <Ed25519.h>
|
||||||
|
#include <RNG.h>
|
||||||
|
#include <utility/ProgMemUtil.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct TestVector
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
uint8_t privateKey[32];
|
||||||
|
uint8_t publicKey[32];
|
||||||
|
uint8_t message[2];
|
||||||
|
size_t len;
|
||||||
|
uint8_t signature[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test vectors for Ed25519 from:
|
||||||
|
// https://tools.ietf.org/id/draft-josefsson-eddsa-ed25519-02.txt
|
||||||
|
static TestVector const testVectorEd25519_1 PROGMEM = {
|
||||||
|
.name = "Ed25519 #1",
|
||||||
|
.privateKey = {0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60,
|
||||||
|
0xba, 0x84, 0x4a, 0xf4, 0x92, 0xec, 0x2c, 0xc4,
|
||||||
|
0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32, 0x69, 0x19,
|
||||||
|
0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60},
|
||||||
|
.publicKey = {0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7,
|
||||||
|
0xd5, 0x4b, 0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a,
|
||||||
|
0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25,
|
||||||
|
0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a},
|
||||||
|
.message = {0x00, 0x00},
|
||||||
|
.len = 0,
|
||||||
|
.signature = {0xe5, 0x56, 0x43, 0x00, 0xc3, 0x60, 0xac, 0x72,
|
||||||
|
0x90, 0x86, 0xe2, 0xcc, 0x80, 0x6e, 0x82, 0x8a,
|
||||||
|
0x84, 0x87, 0x7f, 0x1e, 0xb8, 0xe5, 0xd9, 0x74,
|
||||||
|
0xd8, 0x73, 0xe0, 0x65, 0x22, 0x49, 0x01, 0x55,
|
||||||
|
0x5f, 0xb8, 0x82, 0x15, 0x90, 0xa3, 0x3b, 0xac,
|
||||||
|
0xc6, 0x1e, 0x39, 0x70, 0x1c, 0xf9, 0xb4, 0x6b,
|
||||||
|
0xd2, 0x5b, 0xf5, 0xf0, 0x59, 0x5b, 0xbe, 0x24,
|
||||||
|
0x65, 0x51, 0x41, 0x43, 0x8e, 0x7a, 0x10, 0x0b}
|
||||||
|
};
|
||||||
|
static TestVector const testVectorEd25519_2 PROGMEM = {
|
||||||
|
.name = "Ed25519 #2",
|
||||||
|
.privateKey = {0x4c, 0xcd, 0x08, 0x9b, 0x28, 0xff, 0x96, 0xda,
|
||||||
|
0x9d, 0xb6, 0xc3, 0x46, 0xec, 0x11, 0x4e, 0x0f,
|
||||||
|
0x5b, 0x8a, 0x31, 0x9f, 0x35, 0xab, 0xa6, 0x24,
|
||||||
|
0xda, 0x8c, 0xf6, 0xed, 0x4f, 0xb8, 0xa6, 0xfb},
|
||||||
|
.publicKey = {0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a,
|
||||||
|
0x92, 0xb7, 0x0a, 0xa7, 0x4d, 0x1b, 0x7e, 0xbc,
|
||||||
|
0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c,
|
||||||
|
0xc0, 0xcd, 0x55, 0xf1, 0x2a, 0xf4, 0x66, 0x0c},
|
||||||
|
.message = {0x72, 0x00},
|
||||||
|
.len = 1,
|
||||||
|
.signature = {0x92, 0xa0, 0x09, 0xa9, 0xf0, 0xd4, 0xca, 0xb8,
|
||||||
|
0x72, 0x0e, 0x82, 0x0b, 0x5f, 0x64, 0x25, 0x40,
|
||||||
|
0xa2, 0xb2, 0x7b, 0x54, 0x16, 0x50, 0x3f, 0x8f,
|
||||||
|
0xb3, 0x76, 0x22, 0x23, 0xeb, 0xdb, 0x69, 0xda,
|
||||||
|
0x08, 0x5a, 0xc1, 0xe4, 0x3e, 0x15, 0x99, 0x6e,
|
||||||
|
0x45, 0x8f, 0x36, 0x13, 0xd0, 0xf1, 0x1d, 0x8c,
|
||||||
|
0x38, 0x7b, 0x2e, 0xae, 0xb4, 0x30, 0x2a, 0xee,
|
||||||
|
0xb0, 0x0d, 0x29, 0x16, 0x12, 0xbb, 0x0c, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
static TestVector testVector;
|
||||||
|
|
||||||
|
void printNumber(const char *name, const uint8_t *x, uint8_t len)
|
||||||
|
{
|
||||||
|
static const char hexchars[] = "0123456789ABCDEF";
|
||||||
|
Serial.print(name);
|
||||||
|
Serial.print(" = ");
|
||||||
|
for (uint8_t posn = 0; posn < len; ++posn) {
|
||||||
|
Serial.print(hexchars[(x[posn] >> 4) & 0x0F]);
|
||||||
|
Serial.print(hexchars[x[posn] & 0x0F]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void testFixedVectors(const struct TestVector *test)
|
||||||
|
{
|
||||||
|
// Copy the test vector out of program memory.
|
||||||
|
memcpy_P(&testVector, test, sizeof(TestVector));
|
||||||
|
test = &testVector;
|
||||||
|
|
||||||
|
// Sign using the test vector.
|
||||||
|
uint8_t signature[64];
|
||||||
|
Serial.print(test->name);
|
||||||
|
Serial.print(" sign ... ");
|
||||||
|
Serial.flush();
|
||||||
|
unsigned long start = micros();
|
||||||
|
Ed25519::sign(signature, test->privateKey, test->publicKey,
|
||||||
|
test->message, test->len);
|
||||||
|
unsigned long elapsed = micros() - start;
|
||||||
|
if (memcmp(signature, test->signature, 64) == 0) {
|
||||||
|
Serial.print("ok");
|
||||||
|
} else {
|
||||||
|
Serial.println("failed");
|
||||||
|
printNumber("actual ", signature, 64);
|
||||||
|
printNumber("expected", test->signature, 64);
|
||||||
|
}
|
||||||
|
Serial.print(" (elapsed ");
|
||||||
|
Serial.print(elapsed);
|
||||||
|
Serial.println(" us)");
|
||||||
|
|
||||||
|
// Verify using the test vector.
|
||||||
|
Serial.print(test->name);
|
||||||
|
Serial.print(" verify ... ");
|
||||||
|
Serial.flush();
|
||||||
|
start = micros();
|
||||||
|
bool verified = Ed25519::verify(signature, test->publicKey, test->message, test->len);
|
||||||
|
elapsed = micros() - start;
|
||||||
|
if (verified) {
|
||||||
|
Serial.print("ok");
|
||||||
|
} else {
|
||||||
|
Serial.println("failed");
|
||||||
|
}
|
||||||
|
Serial.print(" (elapsed ");
|
||||||
|
Serial.print(elapsed);
|
||||||
|
Serial.println(" us)");
|
||||||
|
|
||||||
|
// Check derivation of the public key from the private key.
|
||||||
|
Serial.print(test->name);
|
||||||
|
Serial.print(" derive public key ... ");
|
||||||
|
Serial.flush();
|
||||||
|
start = micros();
|
||||||
|
Ed25519::derivePublicKey(signature, test->privateKey);
|
||||||
|
elapsed = micros() - start;
|
||||||
|
if (memcmp(signature, test->publicKey, 32) == 0) {
|
||||||
|
Serial.print("ok");
|
||||||
|
} else {
|
||||||
|
Serial.println("failed");
|
||||||
|
printNumber("actual ", signature, 32);
|
||||||
|
printNumber("expected", test->publicKey, 32);
|
||||||
|
}
|
||||||
|
Serial.print(" (elapsed ");
|
||||||
|
Serial.print(elapsed);
|
||||||
|
Serial.println(" us)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void testFixedVectors()
|
||||||
|
{
|
||||||
|
//Serial.println("Fixed test vectors:");
|
||||||
|
testFixedVectors(&testVectorEd25519_1);
|
||||||
|
testFixedVectors(&testVectorEd25519_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void testDH()
|
||||||
|
{
|
||||||
|
static uint8_t alice_k[32];
|
||||||
|
static uint8_t alice_f[32];
|
||||||
|
static uint8_t bob_k[32];
|
||||||
|
static uint8_t bob_f[32];
|
||||||
|
|
||||||
|
Serial.println("Diffie-Hellman key exchange:");
|
||||||
|
Serial.print("Generate random k/f for Alice ... ");
|
||||||
|
Serial.flush();
|
||||||
|
unsigned long start = micros();
|
||||||
|
Curve25519::dh1(alice_k, alice_f);
|
||||||
|
unsigned long elapsed = micros() - start;
|
||||||
|
Serial.print("elapsed ");
|
||||||
|
Serial.print(elapsed);
|
||||||
|
Serial.println(" us");
|
||||||
|
|
||||||
|
Serial.print("Generate random k/f for Bob ... ");
|
||||||
|
Serial.flush();
|
||||||
|
start = micros();
|
||||||
|
Curve25519::dh1(bob_k, bob_f);
|
||||||
|
elapsed = micros() - start;
|
||||||
|
Serial.print("elapsed ");
|
||||||
|
Serial.print(elapsed);
|
||||||
|
Serial.println(" us");
|
||||||
|
|
||||||
|
Serial.print("Generate shared secret for Alice ... ");
|
||||||
|
Serial.flush();
|
||||||
|
start = micros();
|
||||||
|
Curve25519::dh2(bob_k, alice_f);
|
||||||
|
elapsed = micros() - start;
|
||||||
|
Serial.print("elapsed ");
|
||||||
|
Serial.print(elapsed);
|
||||||
|
Serial.println(" us");
|
||||||
|
|
||||||
|
Serial.print("Generate shared secret for Bob ... ");
|
||||||
|
Serial.flush();
|
||||||
|
start = micros();
|
||||||
|
Curve25519::dh2(alice_k, bob_f);
|
||||||
|
elapsed = micros() - start;
|
||||||
|
Serial.print("elapsed ");
|
||||||
|
Serial.print(elapsed);
|
||||||
|
Serial.println(" us");
|
||||||
|
|
||||||
|
Serial.print("Check that the shared secrets match ... ");
|
||||||
|
if (memcmp(alice_k, bob_k, 32) == 0)
|
||||||
|
Serial.println("ok");
|
||||||
|
else
|
||||||
|
Serial.println("failed");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// Start the random number generator. We don't initialise a noise
|
||||||
|
// source here because we don't need one for testing purposes.
|
||||||
|
// Real applications should of course use a proper noise source.
|
||||||
|
RNG.begin("TestEd25519 1.0", 500);
|
||||||
|
|
||||||
|
// Perform the tests.
|
||||||
|
testFixedVectors();
|
||||||
|
Serial.println();
|
||||||
|
//testDH();
|
||||||
|
//Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
}
|
59
libraries/Crypto/utility/LimbUtil.h
Normal file
59
libraries/Crypto/utility/LimbUtil.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRYPTO_LIMBUTIL_H
|
||||||
|
#define CRYPTO_LIMBUTIL_H
|
||||||
|
|
||||||
|
#include "ProgMemUtil.h"
|
||||||
|
|
||||||
|
// Number of limbs in a big number value of various sizes.
|
||||||
|
#define NUM_LIMBS_128BIT (16 / sizeof(limb_t))
|
||||||
|
#define NUM_LIMBS_256BIT (32 / sizeof(limb_t))
|
||||||
|
#define NUM_LIMBS_512BIT (64 / sizeof(limb_t))
|
||||||
|
|
||||||
|
// The number of bits in a limb.
|
||||||
|
#define LIMB_BITS (8 * sizeof(limb_t))
|
||||||
|
|
||||||
|
// Read a limb-sized quantity from program memory.
|
||||||
|
#if BIGNUMBER_LIMB_8BIT
|
||||||
|
#define pgm_read_limb(x) (pgm_read_byte((x)))
|
||||||
|
#elif BIGNUMBER_LIMB_16BIT
|
||||||
|
#define pgm_read_limb(x) (pgm_read_word((x)))
|
||||||
|
#elif BIGNUMBER_LIMB_32BIT
|
||||||
|
#define pgm_read_limb(x) (pgm_read_dword((x)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Expand a 32-bit value into a set of limbs depending upon the limb size.
|
||||||
|
// This is used when initializing constant big number values in the code.
|
||||||
|
#if BIGNUMBER_LIMB_8BIT
|
||||||
|
#define LIMB(value) ((uint8_t)(value)), \
|
||||||
|
((uint8_t)((value) >> 8)), \
|
||||||
|
((uint8_t)((value) >> 16)), \
|
||||||
|
((uint8_t)((value) >> 24))
|
||||||
|
#elif BIGNUMBER_LIMB_16BIT
|
||||||
|
#define LIMB(value) ((uint16_t)(value)), \
|
||||||
|
((uint16_t)((value) >> 16))
|
||||||
|
#elif BIGNUMBER_LIMB_32BIT
|
||||||
|
#define LIMB(value) (value)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user