mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
643 lines
22 KiB
C++
643 lines
22 KiB
C++
/*
|
|
* 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/html/draft-irtf-cfrg-eddsa-05
|
|
*
|
|
* \sa Curve25519
|
|
*/
|
|
|
|
/** @cond */
|
|
|
|
// 37095705934669439343138083508754565189542113879843219016388785533085940283555
|
|
static limb_t const numD[NUM_LIMBS_256BIT] PROGMEM = {
|
|
LIMB_PAIR(0x135978A3, 0x75EB4DCA), LIMB_PAIR(0x4141D8AB, 0x00700A4D),
|
|
LIMB_PAIR(0x7779E898, 0x8CC74079), LIMB_PAIR(0x2B6FFE73, 0x52036CEE)
|
|
};
|
|
|
|
// d * 2
|
|
static limb_t const numDx2[NUM_LIMBS_256BIT] PROGMEM = {
|
|
LIMB_PAIR(0x26B2F159, 0xEBD69B94), LIMB_PAIR(0x8283B156, 0x00E0149A),
|
|
LIMB_PAIR(0xEEF3D130, 0x198E80F2), LIMB_PAIR(0x56DFFCE7, 0x2406D9DC)
|
|
};
|
|
|
|
// Extended homogenous co-ordinates for the base point.
|
|
static limb_t const numBx[NUM_LIMBS_256BIT] PROGMEM = {
|
|
LIMB_PAIR(0x8F25D51A, 0xC9562D60), LIMB_PAIR(0x9525A7B2, 0x692CC760),
|
|
LIMB_PAIR(0xFDD6DC5C, 0xC0A4E231), LIMB_PAIR(0xCD6E53FE, 0x216936D3)
|
|
};
|
|
static limb_t const numBy[NUM_LIMBS_256BIT] PROGMEM = {
|
|
LIMB_PAIR(0x66666658, 0x66666666), LIMB_PAIR(0x66666666, 0x66666666),
|
|
LIMB_PAIR(0x66666666, 0x66666666), LIMB_PAIR(0x66666666, 0x66666666)
|
|
};
|
|
static limb_t const numBz[NUM_LIMBS_256BIT] PROGMEM = {
|
|
LIMB_PAIR(0x00000001, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000),
|
|
LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000)
|
|
};
|
|
static limb_t const numBt[NUM_LIMBS_256BIT] PROGMEM = {
|
|
LIMB_PAIR(0xA5B7DDA3, 0x6DDE8AB3), LIMB_PAIR(0x775152F5, 0x20F09F80),
|
|
LIMB_PAIR(0x64ABE37D, 0x66EA4E8E), LIMB_PAIR(0xD78B7665, 0x67875F0F)
|
|
};
|
|
|
|
// 2^252 + 27742317777372353535851937790883648493
|
|
static limb_t const numQ[NUM_LIMBS_256BIT] PROGMEM = {
|
|
LIMB_PAIR(0x5CF5D3ED, 0x5812631A), LIMB_PAIR(0xA2F79CD6, 0x14DEF9DE),
|
|
LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 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;
|
|
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_PAIR(0x0A2C131B, 0xED9CE5A3), LIMB_PAIR(0x086329A7, 0x2106215D),
|
|
LIMB_PAIR(0xFFFFFFEB, 0xFFFFFFFF), LIMB_PAIR(0xFFFFFFFF, 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);
|
|
}
|