/** * \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; }