mirror of
https://github.com/danog/ton.git
synced 2024-12-02 09:28:02 +01:00
281 lines
8.2 KiB
C++
281 lines
8.2 KiB
C++
/*
|
|
This file is part of TON Blockchain Library.
|
|
|
|
TON Blockchain Library is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
TON Blockchain Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Copyright 2017-2019 Telegram Systems LLP
|
|
*/
|
|
#include "Ed25519.h"
|
|
|
|
#include "td/utils/Random.h"
|
|
|
|
namespace crypto {
|
|
namespace Ed25519 {
|
|
|
|
bool all_bytes_same(const unsigned char *str, std::size_t size) {
|
|
unsigned char c = str[0];
|
|
for (std::size_t i = 0; i < size; i++) {
|
|
if (str[i] != c) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PublicKey::clear(void) {
|
|
if (inited != pk_empty) {
|
|
std::memset(pubkey, 0, pubkey_bytes);
|
|
PubKey.zeroize();
|
|
PubKey_xz.zeroize();
|
|
}
|
|
inited = pk_empty;
|
|
}
|
|
|
|
PublicKey::PublicKey(const unsigned char pub_key[pubkey_bytes])
|
|
: inited(pk_empty), PubKey(ellcurve::Fp25519()), PubKey_xz(ellcurve::Fp25519()) {
|
|
import_public_key(pub_key);
|
|
}
|
|
|
|
PublicKey::PublicKey(const ellcurve::TwEdwardsCurve::SegrePoint &Pub_Key)
|
|
: inited(pk_empty), PubKey(ellcurve::Fp25519()), PubKey_xz(ellcurve::Fp25519()) {
|
|
import_public_key(Pub_Key);
|
|
}
|
|
|
|
bool PublicKey::import_public_key(const unsigned char pub_key[pubkey_bytes]) {
|
|
clear();
|
|
if (all_bytes_same(pub_key, pubkey_bytes)) {
|
|
return false;
|
|
}
|
|
bool ok = false;
|
|
PubKey = ellcurve::Ed25519().import_point(pub_key, ok);
|
|
if (!ok) {
|
|
clear();
|
|
return false;
|
|
}
|
|
std::memcpy(pubkey, pub_key, pubkey_bytes);
|
|
PubKey_xz.X = PubKey.Z + PubKey.Y;
|
|
PubKey_xz.Z = PubKey.Z - PubKey.Y;
|
|
inited = pk_init;
|
|
return true;
|
|
}
|
|
|
|
bool PublicKey::import_public_key(const ellcurve::TwEdwardsCurve::SegrePoint &Pub_Key) {
|
|
clear();
|
|
if (!Pub_Key.is_valid()) {
|
|
return false;
|
|
}
|
|
PubKey = Pub_Key;
|
|
PubKey_xz.X = PubKey.Z + PubKey.Y;
|
|
PubKey_xz.Z = PubKey.Z - PubKey.Y;
|
|
inited = pk_init;
|
|
|
|
if (!PubKey.export_point(pubkey)) {
|
|
clear();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool PublicKey::export_public_key(unsigned char pubkey_buffer[pubkey_bytes]) const {
|
|
if (inited != pk_init) {
|
|
std::memset(pubkey_buffer, 0, pubkey_bytes);
|
|
return false;
|
|
} else {
|
|
std::memcpy(pubkey_buffer, pubkey, pubkey_bytes);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool PublicKey::check_message_signature(const unsigned char signature[sign_bytes], const unsigned char *message,
|
|
std::size_t msg_size) {
|
|
if (inited != pk_init) {
|
|
return false;
|
|
}
|
|
unsigned char hash[64];
|
|
{
|
|
digest::SHA512 hasher(signature, 32);
|
|
hasher.feed(pubkey, 32);
|
|
hasher.feed(message, msg_size);
|
|
hasher.extract(hash);
|
|
}
|
|
auto &E = ellcurve::Ed25519();
|
|
const arith::Bignum &L = E.get_ell();
|
|
arith::Bignum H, S;
|
|
S.import_lsb(signature + 32, 32);
|
|
H.import_lsb(hash, 64);
|
|
H %= L;
|
|
H = L - H;
|
|
auto sG = E.power_gen(S);
|
|
auto hA = E.power_point(PubKey, H);
|
|
auto pR1 = E.add_points(sG, hA);
|
|
unsigned char pR1_bytes[32];
|
|
if (!pR1.export_point(pR1_bytes)) {
|
|
return false;
|
|
}
|
|
return !std::memcmp(pR1_bytes, signature, 32);
|
|
}
|
|
|
|
// ---------------------
|
|
class PrivateKey;
|
|
|
|
bool PrivateKey::random_private_key(bool strong) {
|
|
inited = false;
|
|
if (!prng::rand_gen().rand_bytes(privkey, privkey_bytes, strong)) {
|
|
clear();
|
|
return false;
|
|
}
|
|
return process_private_key();
|
|
}
|
|
|
|
void PrivateKey::clear(void) {
|
|
std::memset(privkey, 0, privkey_bytes);
|
|
std::memset(priv_salt, 0, sizeof(priv_salt));
|
|
priv_exp.clear();
|
|
PubKey.clear();
|
|
inited = false;
|
|
}
|
|
|
|
bool PrivateKey::import_private_key(const unsigned char pk[privkey_bytes]) {
|
|
clear();
|
|
if (all_bytes_same(pk, privkey_bytes)) {
|
|
return false;
|
|
}
|
|
std::memcpy(privkey, pk, privkey_bytes);
|
|
return process_private_key();
|
|
}
|
|
|
|
bool PrivateKey::export_private_key(unsigned char pk[privkey_bytes]) const { // careful!
|
|
if (!inited) {
|
|
std::memset(pk, 0, privkey_bytes);
|
|
return false;
|
|
} else {
|
|
std::memcpy(pk, privkey, privkey_bytes);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool PrivateKey::process_private_key() {
|
|
unsigned char buff[64];
|
|
digest::hash_str<digest::SHA512>(buff, privkey, privkey_bytes);
|
|
std::memcpy(priv_salt, buff + 32, 32);
|
|
buff[0] = (unsigned char)(buff[0] & -8);
|
|
buff[31] = (unsigned char)((buff[31] | 0x40) & ~0x80);
|
|
priv_exp.import_lsb(buff, 32);
|
|
PubKey = ellcurve::Ed25519().power_gen(priv_exp, true); // uniform
|
|
inited = PubKey.ok();
|
|
if (!inited) {
|
|
clear();
|
|
}
|
|
return inited;
|
|
}
|
|
|
|
bool PrivateKey::compute_shared_secret(unsigned char secret[shared_secret_bytes], const PublicKey &Pub) {
|
|
if (!inited || !Pub.ok()) {
|
|
std::memset(secret, 0, shared_secret_bytes);
|
|
*(long *)secret = static_cast<long>(td::Random::fast_uint64());
|
|
return false;
|
|
}
|
|
// uniform power!
|
|
auto P = ellcurve::Curve25519().power_xz(Pub.get_point_xz(), priv_exp);
|
|
if (P.is_infty()) {
|
|
std::memset(secret, 0, shared_secret_bytes);
|
|
*(long *)secret = static_cast<long>(td::Random::fast_uint64());
|
|
return false;
|
|
}
|
|
P.export_point_u(secret);
|
|
return true;
|
|
}
|
|
|
|
bool PrivateKey::compute_temp_shared_secret(unsigned char secret[shared_secret_bytes],
|
|
const unsigned char temp_pub_key[pubkey_bytes]) {
|
|
PublicKey tempPubkey(temp_pub_key);
|
|
if (!tempPubkey.ok()) {
|
|
return false;
|
|
}
|
|
return compute_shared_secret(secret, tempPubkey);
|
|
}
|
|
|
|
bool PrivateKey::sign_message(unsigned char signature[sign_bytes], const unsigned char *message, std::size_t msg_size) {
|
|
if (!inited) {
|
|
std::memset(signature, 0, sign_bytes);
|
|
return false;
|
|
}
|
|
unsigned char r_bytes[64];
|
|
digest::hash_two_str<digest::SHA512>(r_bytes, priv_salt, 32, message, msg_size);
|
|
const arith::Bignum &L = ellcurve::Ed25519().get_ell();
|
|
arith::Bignum eR;
|
|
eR.import_lsb(r_bytes, 64);
|
|
eR %= L;
|
|
std::memset(r_bytes, 0, sizeof(r_bytes));
|
|
|
|
// uniform power
|
|
auto pR = ellcurve::Ed25519().power_gen(eR, true);
|
|
|
|
auto ok = pR.export_point(signature, true);
|
|
(void)ok;
|
|
assert(ok);
|
|
{
|
|
digest::SHA512 hasher(signature, 32);
|
|
hasher.feed(PubKey.get_pubkey_ptr(), 32);
|
|
hasher.feed(message, msg_size);
|
|
hasher.extract(r_bytes);
|
|
}
|
|
arith::Bignum S;
|
|
S.import_lsb(r_bytes, 64);
|
|
S %= L;
|
|
S *= priv_exp;
|
|
S += eR;
|
|
S %= L;
|
|
eR.clear();
|
|
S.export_lsb(signature + 32, 32);
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------
|
|
class TempKeyGenerator;
|
|
|
|
unsigned char *TempKeyGenerator::get_temp_private_key(unsigned char *to, const unsigned char *message, std::size_t size,
|
|
const unsigned char *rand,
|
|
std::size_t rand_size) { // rand may be 0
|
|
digest::SHA256 hasher(message, size);
|
|
hasher.feed(random_salt, salt_size);
|
|
if (rand && rand_size) {
|
|
hasher.feed(rand, rand_size);
|
|
}
|
|
if (!to) {
|
|
to = buffer;
|
|
}
|
|
hasher.extract(to);
|
|
//++ *((long *)random_salt);
|
|
return to;
|
|
}
|
|
|
|
void TempKeyGenerator::create_temp_private_key(PrivateKey &pk, const unsigned char *message, std::size_t size,
|
|
const unsigned char *rand, std::size_t rand_size) {
|
|
pk.import_private_key(get_temp_private_key(buffer, message, size, rand, rand_size));
|
|
std::memset(buffer, 0, privkey_bytes);
|
|
}
|
|
|
|
bool TempKeyGenerator::create_temp_shared_secret(unsigned char temp_pub_key[pubkey_bytes],
|
|
unsigned char shared_secret[shared_secret_bytes],
|
|
const PublicKey &recipientPubKey, const unsigned char *message,
|
|
std::size_t size, const unsigned char *rand, std::size_t rand_size) {
|
|
PrivateKey tmpPk;
|
|
create_temp_private_key(tmpPk, message, size, rand, rand_size);
|
|
return tmpPk.export_public_key(temp_pub_key) && tmpPk.compute_shared_secret(shared_secret, recipientPubKey);
|
|
}
|
|
|
|
} // namespace Ed25519
|
|
} // namespace crypto
|