--- /dev/null
+> newmalleablekey
+{
+"PrivatePair" : "DfAmbLTs7VDvUor5YF1gU5K5CGsHWezFh9htgiJBbmd3Z48H2Cu3NpYjSDQ1qaKvMGctkCgyqLCiEJFNCEBNxhhwLpquXDAa",
+"PublicPair" : "5GRSi9q1XUVBYxifTr5D5bQUKFvyfWc8GFH8eLUqsE9fMYRtn2WhnNjNFpbaZBrypP3E9jMUYGwya7UM3Vfs8UqkqWTxiut4rKU"
+}
+
+> adjustmalleablepubkey 5GRSi9q1XUVBYxifTr5D5bQUKFvyfWc8GFH8eLUqsE9fMYRtn2WhnNjNFpbaZBrypP3E9jMUYGwya7UM3Vfs8UqkqWTxiut4rKU
+{
+"R" : "022f010598ec5687f719edce97f6ba7e32fc34c7d7b45ba49de115bb670210f59f",
+"PubkeyVariant" : "03105ec5214ce118828cfb08a349b04f336ed4eae50995dbe5268112748008fdf7",
+"KeyVariantID" : "4UcaTGRRNWiH2xs6tTFHwtVzjS1BZrMLrB"
+}
+
+> adjustmalleablekey DfAmbLTs7VDvUor5YF1gU5K5CGsHWezFh9htgiJBbmd3Z48H2Cu3NpYjSDQ1qaKvMGctkCgyqLCiEJFNCEBNxhhwLpquXDAa 03105ec5214ce118828cfb08a349b04f336ed4eae50995dbe5268112748008fdf7 022f010598ec5687f719edce97f6ba7e32fc34c7d7b45ba49de115bb670210f59f
+{
+"PrivateKey" : "MDhzYBXJHrkaoDVSnJjaxzHVYURyAgVzqEhft2oeMhyfww1pDW6K"
+}
+
+> importprivkey MDhzYBXJHrkaoDVSnJjaxzHVYURyAgVzqEhft2oeMhyfww1pDW6K "test"
+
+> validateaddress 4UcaTGRRNWiH2xs6tTFHwtVzjS1BZrMLrB
+{
+"isvalid" : true,
+"address" : "4UcaTGRRNWiH2xs6tTFHwtVzjS1BZrMLrB",
+"ismine" : true,
+"watchonly" : false,
+"isscript" : false,
+"pubkey" : "03105ec5214ce118828cfb08a349b04f336ed4eae50995dbe5268112748008fdf7",
+"iscompressed" : true,
+"account" : "test"
+}
+
+> dumpprivkey 4UcaTGRRNWiH2xs6tTFHwtVzjS1BZrMLrB
+MDhzYBXJHrkaoDVSnJjaxzHVYURyAgVzqEhft2oeMhyfww1pDW6K
src/qt/multisiginputentry.h \
src/qt/multisigdialog.h \
src/qt/secondauthdialog.h \
- src/qt/qrcodedialog.h
+ src/qt/qrcodedialog.h \
+ src/ies.h
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/intro.cpp \
src/qt/multisigdialog.cpp \
src/qt/secondauthdialog.cpp \
src/qt/qrcodedialog.cpp \
- src/base58.cpp
+ src/base58.cpp \
+ src/cryptogram.cpp \
+ src/ecies.cpp
RESOURCES += \
src/qt/bitcoin.qrc
{ "repairwallet", &repairwallet, false, true},
{ "resendtx", &resendtx, false, true},
{ "makekeypair", &makekeypair, false, true},
+ { "newmalleablekey", &newmalleablekey, false, false},
+ { "adjustmalleablekey", &adjustmalleablekey, false, false},
+ { "adjustmalleablepubkey", &adjustmalleablepubkey, false, false},
+ { "listmalleablepubkeys", &listmalleablepubkeys, false, false},
{ "sendalert", &sendalert, false, false},
};
extern json_spirit::Value resendtx(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value makekeypair(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value mergecoins(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value newmalleablekey(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value adjustmalleablekey(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value adjustmalleablepubkey(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value listmalleablepubkeys(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp);
--- /dev/null
+/**
+ * @file /cryptron/secure.c
+ *
+ * @brief Functions for handling the secure data type.
+ *
+ * $Author: Ladar Levison $
+ * $Website: http://lavabit.com $
+ *
+ */
+
+#include "ies.h"
+#define HEADSIZE (sizeof(cryptogram_head_t))
+
+size_t cryptogram_key_length(const cryptogram_t *cryptogram) {
+ cryptogram_head_t *head = (cryptogram_head_t *)cryptogram;
+ return head->length.key;
+}
+
+size_t cryptogram_mac_length(const cryptogram_t *cryptogram) {
+ cryptogram_head_t *head = (cryptogram_head_t *)cryptogram;
+ return head->length.mac;
+}
+
+size_t cryptogram_body_length(const cryptogram_t *cryptogram) {
+ cryptogram_head_t *head = (cryptogram_head_t *)cryptogram;
+ return head->length.body;
+}
+
+size_t cryptogram_data_sum_length(const cryptogram_t *cryptogram) {
+ cryptogram_head_t *head = (cryptogram_head_t *)cryptogram;
+ return (head->length.key + head->length.mac + head->length.body);
+}
+
+size_t cryptogram_total_length(const cryptogram_t *cryptogram) {
+ cryptogram_head_t *head = (cryptogram_head_t *)cryptogram;
+ return HEADSIZE + (head->length.key + head->length.mac + head->length.body);
+}
+
+unsigned char * cryptogram_key_data(const cryptogram_t *cryptogram) {
+ return (unsigned char *)cryptogram + HEADSIZE;
+}
+
+unsigned char * cryptogram_mac_data(const cryptogram_t *cryptogram) {
+ cryptogram_head_t *head = (cryptogram_head_t *)cryptogram;
+ return (unsigned char *)cryptogram + (HEADSIZE + head->length.key + head->length.body);
+}
+
+unsigned char * cryptogram_body_data(const cryptogram_t *cryptogram) {
+ cryptogram_head_t *head = (cryptogram_head_t *)cryptogram;
+ return (unsigned char *)cryptogram + (HEADSIZE + head->length.key);
+}
+
+cryptogram_t * cryptogram_alloc(size_t key, size_t mac, size_t body) {
+ cryptogram_t *cryptogram = (cryptogram_t *) malloc(HEADSIZE + key + mac + body);
+ cryptogram_head_t *head = (cryptogram_head_t *)cryptogram;
+ head->length.key = key;
+ head->length.mac = mac;
+ head->length.body = body;
+ return cryptogram;
+}
+
+void cryptogram_free(cryptogram_t *cryptogram) {
+ free(cryptogram);
+ return;
+}
--- /dev/null
+/**
+ * @file /cryptron/ecies.c
+ *
+ * @brief ECIES encryption/decryption functions.
+ *
+ * $Author: Ladar Levison $
+ * $Website: http://lavabit.com $
+ *
+ */
+
+#include "ies.h"
+#include <iostream>
+#include <vector>
+#include <openssl/ecdh.h>
+
+#define SET_ERROR(string) \
+ sprintf(error, "%s %s:%d", (string), __FILE__, __LINE__)
+#define SET_OSSL_ERROR(string) \
+ sprintf(error, "%s {error = %s} %s:%d", (string), ERR_error_string(ERR_get_error(), NULL), __FILE__, __LINE__)
+
+/* Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
+ * Taken from openssl/crypto/ecdh/ech_kdf.c in github:openssl/openssl
+ * ffa08b3242e0f10f1fef3c93ef3f0b51de8c27a9 */
+
+/* Key derivation function from X9.62/SECG */
+/* Way more than we will ever need */
+#define ECDH_KDF_MAX (1 << 30)
+int ECDH_KDF_X9_62(unsigned char *out, size_t outlen,
+ const unsigned char *Z, size_t Zlen,
+ const unsigned char *sinfo, size_t sinfolen,
+ const EVP_MD *md)
+{
+ EVP_MD_CTX mctx;
+ int rv = 0;
+ unsigned int i;
+ size_t mdlen;
+ unsigned char ctr[4];
+ if (sinfolen > ECDH_KDF_MAX || outlen > ECDH_KDF_MAX || Zlen > ECDH_KDF_MAX)
+ return 0;
+ mdlen = EVP_MD_size(md);
+ EVP_MD_CTX_init(&mctx);
+ for (i = 1;;i++)
+ {
+ unsigned char mtmp[EVP_MAX_MD_SIZE];
+ EVP_DigestInit_ex(&mctx, md, NULL);
+ ctr[3] = i & 0xFF;
+ ctr[2] = (i >> 8) & 0xFF;
+ ctr[1] = (i >> 16) & 0xFF;
+ ctr[0] = (i >> 24) & 0xFF;
+ if (!EVP_DigestUpdate(&mctx, Z, Zlen))
+ goto err;
+ if (!EVP_DigestUpdate(&mctx, ctr, sizeof(ctr)))
+ goto err;
+ if (!EVP_DigestUpdate(&mctx, sinfo, sinfolen))
+ goto err;
+ if (outlen >= mdlen)
+ {
+ if (!EVP_DigestFinal(&mctx, out, NULL))
+ goto err;
+ outlen -= mdlen;
+ if (outlen == 0)
+ break;
+ out += mdlen;
+ }
+ else
+ {
+ if (!EVP_DigestFinal(&mctx, mtmp, NULL))
+ goto err;
+ memcpy(out, mtmp, outlen);
+ OPENSSL_cleanse(mtmp, mdlen);
+ break;
+ }
+ }
+ rv = 1;
+ err:
+ EVP_MD_CTX_cleanup(&mctx);
+ return rv;
+}
+
+static size_t envelope_key_len(const ies_ctx_t *ctx)
+{
+ return EVP_CIPHER_key_length(ctx->cipher) + EVP_MD_size(ctx->md);
+}
+
+static EC_KEY * ecies_key_create(const EC_KEY *user, char *error) {
+
+ const EC_GROUP *group;
+ EC_KEY *key = NULL;
+
+ if (!(key = EC_KEY_new())) {
+ SET_OSSL_ERROR("EC_KEY_new failed");
+ return NULL;
+ }
+
+ if (!(group = EC_KEY_get0_group(user))) {
+ SET_ERROR("The user key does not have group");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ if (EC_KEY_set_group(key, group) != 1) {
+ SET_OSSL_ERROR("EC_KEY_set_group failed");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ if (EC_KEY_generate_key(key) != 1) {
+ SET_OSSL_ERROR("EC_KEY_generate_key failed");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ return key;
+}
+
+static unsigned char *prepare_envelope_key(const ies_ctx_t *ctx, cryptogram_t *cryptogram, char *error)
+{
+
+ const size_t key_buf_len = envelope_key_len(ctx);
+ const size_t ecdh_key_len = (EC_GROUP_get_degree(EC_KEY_get0_group(ctx->user_key)) + 7) / 8;
+ unsigned char *envelope_key = NULL, *ktmp = NULL;
+ EC_KEY *ephemeral = NULL;
+ size_t written_length;
+
+ /* High-level ECDH via EVP does not allow use of arbitrary KDF function.
+ * We should use low-level API for KDF2
+ * c.f. openssl/crypto/ec/ec_pmeth.c */
+ if ((envelope_key = (unsigned char *) OPENSSL_malloc(key_buf_len)) == NULL) {
+ SET_ERROR("Failed to allocate memory for envelope_key");
+ goto err;
+ }
+
+ if (!(ephemeral = ecies_key_create(ctx->user_key, error))) {
+ goto err;
+ }
+
+ /* key agreement and KDF
+ * reference: openssl/crypto/ec/ec_pmeth.c */
+ ktmp = (unsigned char *) OPENSSL_malloc(ecdh_key_len);
+ if (ktmp == NULL) {
+ SET_ERROR("No memory for ECDH temporary key");
+ goto err;
+ }
+
+ if (ECDH_compute_key(ktmp, ecdh_key_len, EC_KEY_get0_public_key(ctx->user_key), ephemeral, NULL)
+ != (int)ecdh_key_len) {
+ SET_OSSL_ERROR("An error occurred while ECDH_compute_key");
+ goto err;
+ }
+
+ /* equals to ISO 18033-2 KDF2 */
+ if (!ECDH_KDF_X9_62(envelope_key, key_buf_len, ktmp, ecdh_key_len, 0, 0, ctx->kdf_md)) {
+ SET_OSSL_ERROR("Failed to stretch with KDF2");
+ goto err;
+ }
+
+ /* Store the public key portion of the ephemeral key. */
+ written_length = EC_POINT_point2oct(
+ EC_KEY_get0_group(ephemeral),
+ EC_KEY_get0_public_key(ephemeral),
+ POINT_CONVERSION_COMPRESSED,
+ cryptogram_key_data(cryptogram),
+ ctx->stored_key_length,
+ NULL);
+ if (written_length == 0) {
+ SET_OSSL_ERROR("Error while recording the public portion of the envelope key");
+ goto err;
+ }
+ if (written_length != ctx->stored_key_length) {
+ SET_ERROR("Written envelope key length does not match with expected");
+ goto err;
+ }
+
+ EC_KEY_free(ephemeral);
+ OPENSSL_cleanse(ktmp, ecdh_key_len);
+ OPENSSL_free(ktmp);
+
+ return envelope_key;
+
+ err:
+ if (ephemeral)
+ EC_KEY_free(ephemeral);
+ if (envelope_key) {
+ OPENSSL_cleanse(envelope_key, key_buf_len);
+ OPENSSL_free(envelope_key);
+ }
+ if (ktmp) {
+ OPENSSL_cleanse(ktmp, ecdh_key_len);
+ OPENSSL_free(ktmp);
+ }
+ return NULL;
+}
+
+static int store_cipher_body(
+ const ies_ctx_t *ctx,
+ const unsigned char *envelope_key,
+ const unsigned char *data,
+ size_t length,
+ cryptogram_t *cryptogram,
+ char *error)
+{
+ int out_len, len_sum = 0;
+ size_t expected_len = cryptogram_body_length(cryptogram);
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ EVP_CIPHER_CTX cipher;
+ unsigned char *body;
+
+ /* For now we use an empty initialization vector. */
+ memset(iv, 0, EVP_MAX_IV_LENGTH);
+
+ EVP_CIPHER_CTX_init(&cipher);
+ body = cryptogram_body_data(cryptogram);
+
+ if (EVP_EncryptInit_ex(&cipher, ctx->cipher, NULL, envelope_key, iv) != 1
+ || EVP_EncryptUpdate(&cipher, body, &out_len, data, length) != 1) {
+ SET_OSSL_ERROR("Error while trying to secure the data using the symmetric cipher");
+ EVP_CIPHER_CTX_cleanup(&cipher);
+ return 0;
+ }
+
+ if (expected_len < (size_t)out_len) {
+ SET_ERROR("The symmetric cipher overflowed");
+ EVP_CIPHER_CTX_cleanup(&cipher);
+ return 0;
+ }
+
+ body += out_len;
+ len_sum += out_len;
+ if (EVP_EncryptFinal_ex(&cipher, body, &out_len) != 1) {
+ SET_OSSL_ERROR("Error while finalizing the data using the symmetric cipher");
+ EVP_CIPHER_CTX_cleanup(&cipher);
+ cryptogram_free(cryptogram);
+ return 0;
+ }
+
+ EVP_CIPHER_CTX_cleanup(&cipher);
+
+ if (expected_len < (size_t)len_sum) {
+ SET_ERROR("The symmetric cipher overflowed");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int store_mac_tag(const ies_ctx_t *ctx, const unsigned char *envelope_key, cryptogram_t *cryptogram, char *error) {
+ const size_t key_offset = EVP_CIPHER_key_length(ctx->cipher);
+ const size_t key_length = EVP_MD_size(ctx->md);
+ const size_t mac_length = cryptogram_mac_length(cryptogram);
+ unsigned int out_len;
+ HMAC_CTX hmac;
+
+ HMAC_CTX_init(&hmac);
+
+ /* Generate hash tag using encrypted data */
+ if (HMAC_Init_ex(&hmac, envelope_key + key_offset, key_length, ctx->md, NULL) != 1
+ || HMAC_Update(&hmac, cryptogram_body_data(cryptogram), cryptogram_body_length(cryptogram)) != 1
+ || HMAC_Final(&hmac, cryptogram_mac_data(cryptogram), &out_len) != 1) {
+ SET_OSSL_ERROR("Unable to generate tag");
+ HMAC_CTX_cleanup(&hmac);
+ return 0;
+ }
+
+ HMAC_CTX_cleanup(&hmac);
+
+ if (out_len != mac_length) {
+ SET_ERROR("MAC length expectation does not meet");
+ return 0;
+ }
+
+ return 1;
+}
+
+cryptogram_t * ecies_encrypt(const ies_ctx_t *ctx, const unsigned char *data, size_t length, char *error) {
+
+ const size_t block_length = EVP_CIPHER_block_size(ctx->cipher);
+ const size_t mac_length = EVP_MD_size(ctx->md);
+ cryptogram_t *cryptogram = NULL;
+ unsigned char *envelope_key = NULL;
+
+ if (!ctx || !data || !length) {
+ SET_ERROR("Invalid arguments");
+ return NULL;
+ }
+
+ if (block_length == 0 || block_length > EVP_MAX_BLOCK_LENGTH) {
+ SET_ERROR("Derived block size is incorrect");
+ return NULL;
+ }
+
+ cryptogram = cryptogram_alloc(ctx->stored_key_length,
+ mac_length,
+ length + (length % block_length ? (block_length - (length % block_length)) : 0));
+ if (!cryptogram) {
+ SET_ERROR("Unable to allocate a cryptogram_t buffer to hold the encrypted result.");
+ goto err;
+ }
+
+ if ((envelope_key = prepare_envelope_key(ctx, cryptogram, error)) == NULL) {
+ goto err;
+ }
+
+ if (!store_cipher_body(ctx, envelope_key, data, length, cryptogram, error)) {
+ goto err;
+ }
+
+ if (!store_mac_tag(ctx, envelope_key, cryptogram, error)) {
+ goto err;
+ }
+
+ OPENSSL_cleanse(envelope_key, envelope_key_len(ctx));
+ OPENSSL_free(envelope_key);
+
+ return cryptogram;
+
+ err:
+ if (cryptogram)
+ cryptogram_free(cryptogram);
+ if (envelope_key) {
+ OPENSSL_cleanse(envelope_key, envelope_key_len(ctx));
+ OPENSSL_free(envelope_key);
+ }
+ return NULL;
+}
+
+static EC_KEY *ecies_key_create_public_octets(EC_KEY *user, unsigned char *octets, size_t length, char *error) {
+
+ EC_KEY *key = NULL;
+ EC_POINT *point = NULL;
+ const EC_GROUP *group = NULL;
+
+ if (!(key = EC_KEY_new())) {
+ SET_OSSL_ERROR("Cannot create instance for ephemeral key");
+ return NULL;
+ }
+
+ if (!(group = EC_KEY_get0_group(user))) {
+ SET_ERROR("Cannot get group from user key");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ if (EC_KEY_set_group(key, group) != 1) {
+ SET_OSSL_ERROR("EC_KEY_set_group failed");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ if (!(point = EC_POINT_new(group))) {
+ SET_OSSL_ERROR("EC_POINT_new failed");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ if (EC_POINT_oct2point(group, point, octets, length, NULL) != 1) {
+ SET_OSSL_ERROR("EC_POINT_oct2point failed");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ if (EC_KEY_set_public_key(key, point) != 1) {
+ SET_OSSL_ERROR("EC_KEY_set_public_key failed");
+ EC_POINT_free(point);
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ EC_POINT_free(point);
+
+ if (EC_KEY_check_key(key) != 1) {
+ SET_OSSL_ERROR("EC_KEY_check_key failed");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ return key;
+}
+
+unsigned char *restore_envelope_key(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, char *error)
+{
+
+ const size_t key_buf_len = envelope_key_len(ctx);
+ const size_t ecdh_key_len = (EC_GROUP_get_degree(EC_KEY_get0_group(ctx->user_key)) + 7) / 8;
+ EC_KEY *ephemeral = NULL, *user_copy = NULL;
+ unsigned char *envelope_key = NULL, *ktmp = NULL;
+
+ if ((envelope_key = (unsigned char *) OPENSSL_malloc(key_buf_len)) == NULL) {
+ SET_ERROR("Failed to allocate memory for envelope_key");
+ goto err;
+ }
+
+ if (!(user_copy = EC_KEY_new())) {
+ SET_OSSL_ERROR("Failed to create instance for user key copy");
+ goto err;
+ }
+
+ if (!(EC_KEY_copy(user_copy, ctx->user_key))) {
+ SET_OSSL_ERROR("Failed to copy user key");
+ goto err;
+ }
+
+ if (!(ephemeral = ecies_key_create_public_octets(user_copy, cryptogram_key_data(cryptogram), cryptogram_key_length(cryptogram), error))) {
+ goto err;
+ }
+
+ /* key agreement and KDF
+ * reference: openssl/crypto/ec/ec_pmeth.c */
+ ktmp = (unsigned char *) OPENSSL_malloc(ecdh_key_len);
+ if (ktmp == NULL) {
+ SET_ERROR("No memory for ECDH temporary key");
+ goto err;
+ }
+
+ if (ECDH_compute_key(ktmp, ecdh_key_len, EC_KEY_get0_public_key(ephemeral), user_copy, NULL)
+ != (int)ecdh_key_len) {
+ SET_OSSL_ERROR("An error occurred while ECDH_compute_key");
+ goto err;
+ }
+
+ /* equals to ISO 18033-2 KDF2 */
+ if (!ECDH_KDF_X9_62(envelope_key, key_buf_len, ktmp, ecdh_key_len, 0, 0, ctx->kdf_md)) {
+ SET_OSSL_ERROR("Failed to stretch with KDF2");
+ goto err;
+ }
+
+ EC_KEY_free(user_copy);
+ EC_KEY_free(ephemeral);
+ OPENSSL_cleanse(ktmp, ecdh_key_len);
+ OPENSSL_free(ktmp);
+
+ return envelope_key;
+
+ err:
+ if (ephemeral)
+ EC_KEY_free(ephemeral);
+ if (user_copy)
+ EC_KEY_free(user_copy);
+ if (envelope_key) {
+ OPENSSL_cleanse(envelope_key, key_buf_len);
+ OPENSSL_free(envelope_key);
+ }
+ if (ktmp) {
+ OPENSSL_cleanse(ktmp, ecdh_key_len);
+ OPENSSL_free(ktmp);
+ }
+ return NULL;
+}
+
+static int verify_mac(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, const unsigned char * envelope_key, char *error)
+{
+ const size_t key_offset = EVP_CIPHER_key_length(ctx->cipher);
+ const size_t key_length = EVP_MD_size(ctx->md);
+ const size_t mac_length = cryptogram_mac_length(cryptogram);
+ unsigned int out_len;
+ HMAC_CTX hmac;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+ HMAC_CTX_init(&hmac);
+
+ /* Generate hash tag using encrypted data */
+ if (HMAC_Init_ex(&hmac, envelope_key + key_offset, key_length, ctx->md, NULL) != 1
+ || HMAC_Update(&hmac, cryptogram_body_data(cryptogram), cryptogram_body_length(cryptogram)) != 1
+ || HMAC_Final(&hmac, md, &out_len) != 1) {
+ SET_OSSL_ERROR("Unable to generate tag");
+ HMAC_CTX_cleanup(&hmac);
+ return 0;
+ }
+
+ HMAC_CTX_cleanup(&hmac);
+
+ if (out_len != mac_length) {
+ SET_ERROR("MAC length expectation does not meet");
+ return 0;
+ }
+
+ if (memcmp(md, cryptogram_mac_data(cryptogram), mac_length) != 0) {
+ SET_ERROR("MAC tag verification failed");
+ return 0;
+ }
+
+ return 1;
+}
+
+unsigned char *decrypt_body(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, const unsigned char *envelope_key, size_t *length, char *error)
+{
+ int out_len;
+ size_t output_sum;
+ const size_t body_length = cryptogram_body_length(cryptogram);
+ unsigned char iv[EVP_MAX_IV_LENGTH], *block, *output;
+ EVP_CIPHER_CTX cipher;
+
+ if (!(output = (unsigned char*)malloc(body_length + 1))) {
+ SET_ERROR("Failed to allocate memory for clear text");
+ return NULL;
+ }
+
+ /* For now we use an empty initialization vector */
+ memset(iv, 0, EVP_MAX_IV_LENGTH);
+ memset(output, 0, body_length + 1);
+
+ EVP_CIPHER_CTX_init(&cipher);
+
+ block = output;
+ if (EVP_DecryptInit_ex(&cipher, ctx->cipher, NULL, envelope_key, iv) != 1
+ || EVP_DecryptUpdate(&cipher, block, &out_len, cryptogram_body_data(cryptogram), body_length) != 1) {
+ SET_OSSL_ERROR("Unable to decrypt");
+ EVP_CIPHER_CTX_cleanup(&cipher);
+ free(output);
+ return NULL;
+ }
+ output_sum = out_len;
+
+ block += output_sum;
+ if (EVP_DecryptFinal_ex(&cipher, block, &out_len) != 1) {
+ printf("Unable to decrypt the data using the chosen symmetric cipher. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
+ EVP_CIPHER_CTX_cleanup(&cipher);
+ free(output);
+ return NULL;
+ }
+ output_sum += out_len;
+
+ EVP_CIPHER_CTX_cleanup(&cipher);
+
+ *length = output_sum;
+
+ return output;
+}
+
+unsigned char * ecies_decrypt(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, size_t *length, char *error)
+{
+ unsigned char *envelope_key = NULL, *output = NULL;
+
+ if (!ctx || !cryptogram || !length || !error) {
+ SET_ERROR("Invalid argument");
+ goto err;
+ }
+
+ envelope_key = restore_envelope_key(ctx, cryptogram, error);
+ if (envelope_key == NULL) {
+ goto err;
+ }
+
+ if (!verify_mac(ctx, cryptogram, envelope_key, error)) {
+ goto err;
+ }
+
+ if ((output = decrypt_body(ctx, cryptogram, envelope_key, length, error)) == NULL) {
+ goto err;
+ }
+
+ err:
+ OPENSSL_cleanse(envelope_key, envelope_key_len(ctx));
+ OPENSSL_free(envelope_key);
+
+ return output;
+}
+
+ies_ctx_t *create_context(EC_KEY *user_key)
+{
+ ies_ctx_t* ctx = (ies_ctx_t*) malloc(sizeof(ies_ctx_t));
+ ctx->cipher = EVP_aes_128_cbc();
+ ctx->md = EVP_sha1();
+ ctx->kdf_md = EVP_sha1();
+ ctx->stored_key_length = 33;
+ ctx->user_key = user_key;
+
+ return ctx;
+}
--- /dev/null
+/**
+ * reference: ecies.h
+ */
+
+#ifndef _IES_H_
+#define _IES_H_
+
+#include <openssl/ssl.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+typedef struct {
+ const EVP_CIPHER *cipher;
+ const EVP_MD *md; /* for mac tag */
+ const EVP_MD *kdf_md; /* for KDF */
+ size_t stored_key_length;
+ const EC_KEY *user_key;
+} ies_ctx_t;
+
+typedef struct {
+ struct {
+ size_t key;
+ size_t mac;
+ size_t body;
+ } length;
+} cryptogram_head_t;
+
+typedef unsigned char * cryptogram_t;
+
+void cryptogram_free(cryptogram_t *cryptogram);
+unsigned char * cryptogram_key_data(const cryptogram_t *cryptogram);
+unsigned char * cryptogram_mac_data(const cryptogram_t *cryptogram);
+unsigned char * cryptogram_body_data(const cryptogram_t *cryptogram);
+size_t cryptogram_key_length(const cryptogram_t *cryptogram);
+size_t cryptogram_mac_length(const cryptogram_t *cryptogram);
+size_t cryptogram_body_length(const cryptogram_t *cryptogram);
+size_t cryptogram_data_sum_length(const cryptogram_t *cryptogram);
+size_t cryptogram_total_length(const cryptogram_t *cryptogram);
+cryptogram_t * cryptogram_alloc(size_t key, size_t mac, size_t body);
+cryptogram_t * ecies_encrypt(const ies_ctx_t *ctx, const unsigned char *data, size_t length, char *error);
+unsigned char * ecies_decrypt(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, size_t *length, char *error);
+ies_ctx_t *create_context(EC_KEY *user_key);
+
+#endif /* _IES_H_ */
CTxDestination address;
std::string addrStr;
- uint64_t coinAge = max( (txOut.nValue * nDayWeight) / (COIN * nOneDay), 0LL);
+ uint64_t coinAge = max( (txOut.nValue * nDayWeight) / (COIN * nOneDay), (int64_t)0);
if (ExtractDestination(txOut.scriptPubKey, address))
{
//uint64_t coinAge = max(nValue * dayWeight / COIN, (int64_t)0);
//return target * coinAge / pow(static_cast<double>(2), 256);
int64_t Weight = (min((GetAdjustedTime() - nTime) + timeOffset, (int64_t)(nStakeMinAge+nStakeMaxAge)) - nStakeMinAge);
- uint64_t coinAge = max(nValue * Weight / (COIN * nOneDay), 0LL);
+ uint64_t coinAge = max(nValue * Weight / (COIN * nOneDay), (int64_t)0);
return coinAge / (pow(static_cast<double>(2),32) * difficulty);
}
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
+#include <openssl/ssl.h>
+#include <openssl/ecdh.h>
#include "key.h"
+#include "base58.h"
+#include "ies.h"
// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
key2.SetSecret(secret, fCompr);
return GetPubKey() == key2.GetPubKey();
}
+
+CPoint::CPoint()
+{
+ std::string err;
+ group = NULL;
+ point = NULL;
+ ctx = NULL;
+
+ group = EC_GROUP_new_by_curve_name(NID_secp256k1);
+ if (!group) {
+ err = "EC_KEY_new_by_curve_name failed.";
+ goto finish;
+ }
+
+ point = EC_POINT_new(group);
+ if (!point) {
+ err = "EC_POINT_new failed.";
+ goto finish;
+ }
+
+ ctx = BN_CTX_new();
+ if (!ctx) {
+ err = "BN_CTX_new failed.";
+ goto finish;
+ }
+
+ return;
+
+finish:
+ if (group) EC_GROUP_free(group);
+ if (point) EC_POINT_free(point);
+ throw std::runtime_error(std::string("CPoint::CPoint() : - ") + err);
+}
+
+bool CPoint::operator!=(const CPoint &a)
+{
+ if (EC_POINT_cmp(group, point, a.point, ctx) != 0)
+ return true;
+ return false;
+}
+CPoint::~CPoint()
+{
+ if (point) EC_POINT_free(point);
+ if (group) EC_GROUP_free(group);
+ if (ctx) BN_CTX_free(ctx);
+}
+
+// Initialize from octets stream
+bool CPoint::setBytes(const std::vector<unsigned char> &vchBytes)
+{
+ if (!EC_POINT_oct2point(group, point, &vchBytes[0], vchBytes.size(), ctx)) {
+ return false;
+ }
+ return true;
+}
+
+// Initialize from octets stream
+bool CPoint::setPubKey(const CPubKey &vchPubKey)
+{
+ return setBytes(vchPubKey.Raw());
+}
+
+// Serialize to octets stream
+bool CPoint::getBytes(std::vector<unsigned char> &vchBytes)
+{
+ unsigned int nSize = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, NULL, 0, ctx);
+ vchBytes.resize(nSize);
+ if (!(nSize == EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, &vchBytes[0], nSize, ctx))) {
+ return false;
+ }
+ return true;
+}
+
+// ECC multiplication by specified multiplier
+bool CPoint::ECMUL(const CBigNum &bnMultiplier)
+{
+ if (!EC_POINT_mul(group, point, NULL, point, &bnMultiplier, NULL)) {
+ printf("CPoint::ECMUL() : EC_POINT_mul failed");
+ return false;
+ }
+
+ return true;
+}
+
+// Calculate G*m + q
+bool CPoint::ECMULGEN(const CBigNum &bnMultiplier, const CPoint &qPoint)
+{
+ if (!EC_POINT_mul(group, point, &bnMultiplier, qPoint.point, BN_value_one(), NULL)) {
+ printf("CPoint::ECMULGEN() : EC_POINT_mul failed.");
+ return false;
+ }
+
+ return true;
+}
+
+// CMalleablePubKey
+
+void CMalleablePubKey::GetVariant(CPubKey &R, CPubKey &vchPubKeyVariant)
+{
+ EC_KEY *eckey = NULL;
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ if (eckey == NULL) {
+ throw key_error("CMalleablePubKey::GetVariant() : EC_KEY_new_by_curve_name failed");
+ }
+
+ // Use standard key generation function to get r and R values.
+ //
+ // r will be presented by private key;
+ // R is ECDSA public key which calculated as G*r
+ if (!EC_KEY_generate_key(eckey)) {
+ throw key_error("CMalleablePubKey::GetVariant() : EC_KEY_generate_key failed");
+ }
+
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
+
+ int nSize = i2o_ECPublicKey(eckey, NULL);
+ if (!nSize) {
+ throw key_error("CMalleablePubKey::GetVariant() : i2o_ECPublicKey failed");
+ }
+
+ std::vector<unsigned char> vchPubKey(nSize, 0);
+ unsigned char* pbegin_R = &vchPubKey[0];
+
+ if (i2o_ECPublicKey(eckey, &pbegin_R) != nSize) {
+ throw key_error("CMalleablePubKey::GetVariant() : i2o_ECPublicKey returned unexpected size");
+ }
+
+ // R = G*r
+ R = CPubKey(vchPubKey);
+
+ // OpenSSL BIGNUM representation of r value
+ CBigNum bnr;
+ bnr = *(CBigNum*) EC_KEY_get0_private_key(eckey);
+ EC_KEY_free(eckey);
+
+ CPoint point;
+ if (!point.setPubKey(pubKeyL)) {
+ throw key_error("CMalleablePubKey::GetVariant() : Unable to decode L value");
+ }
+
+ // Calculate L*r
+ point.ECMUL(bnr);
+
+ std::vector<unsigned char> vchLr;
+ if (!point.getBytes(vchLr)) {
+ throw key_error("CMalleablePubKey::GetVariant() : Unable to convert Lr value");
+ }
+
+ // Calculate Hash(L*r) and then get a BIGNUM representation of hash value.
+ CBigNum bnHash;
+ bnHash.setuint160(Hash160(vchLr));
+
+ CPoint pointH;
+ pointH.setPubKey(pubKeyH);
+
+ CPoint P;
+ // Calculate P = Hash(L*r)*G + H
+ P.ECMULGEN(bnHash, pointH);
+
+ if (P.IsInfinity()) {
+ throw key_error("CMalleablePubKey::GetVariant() : P is infinity");
+ }
+
+ std::vector<unsigned char> vchResult;
+ P.getBytes(vchResult);
+
+ vchPubKeyVariant = CPubKey(vchResult);
+}
+
+std::string CMalleablePubKey::ToString() const
+{
+ CDataStream ssKey(SER_NETWORK, PROTOCOL_VERSION);
+ ssKey << *this;
+ std::vector<unsigned char> vch(ssKey.begin(), ssKey.end());
+
+ return EncodeBase58Check(vch);
+}
+
+bool CMalleablePubKey::SetString(const std::string& strMalleablePubKey)
+{
+ std::vector<unsigned char> vchTemp;
+ if (!DecodeBase58Check(strMalleablePubKey, vchTemp)) {
+ throw key_error("CMalleablePubKey::SetString() : Provided key data seems corrupted.");
+ }
+
+ CDataStream ssKey(vchTemp, SER_NETWORK, PROTOCOL_VERSION);
+ ssKey >> *this;
+
+ return IsValid();
+}
+
+bool CMalleablePubKey::operator==(const CMalleablePubKey &b)
+{
+ return (nVersion == b.nVersion &&
+ pubKeyL == b.pubKeyL &&
+ pubKeyH == b.pubKeyH);
+}
+
+
+// CMalleableKey
+
+void CMalleableKey::Reset()
+{
+ vchSecretL.clear();
+ vchSecretH.clear();
+
+ nVersion = 0;
+}
+
+void CMalleableKey::MakeNewKeys()
+{
+ CKey L, H;
+ bool fCompressed = true;
+
+ L.MakeNewKey(true);
+ H.MakeNewKey(true);
+
+ vchSecretL = L.GetSecret(fCompressed);
+ vchSecretH = H.GetSecret(fCompressed);
+
+ nVersion = CURRENT_VERSION;
+}
+
+CMalleableKey::CMalleableKey()
+{
+ Reset();
+}
+
+CMalleableKey::CMalleableKey(const CMalleableKey &b)
+{
+ SetSecrets(b.vchSecretL, b.vchSecretH);
+}
+
+CMalleableKey::CMalleableKey(const CSecret &L, const CSecret &H)
+{
+ SetSecrets(L, H);
+}
+
+CMalleableKey& CMalleableKey::operator=(const CMalleableKey &b)
+{
+ SetSecrets(b.vchSecretL, b.vchSecretH);
+
+ return (*this);
+}
+
+CMalleableKey::~CMalleableKey()
+{
+}
+
+bool CMalleableKey::IsNull() const
+{
+ return nVersion != CURRENT_VERSION;
+}
+
+bool CMalleableKey::SetSecrets(const CSecret &pvchSecretL, const CSecret &pvchSecretH)
+{
+ Reset();
+ CKey L, H;
+
+ if (pvchSecretL.size() != 32 || !pvchSecretH.size() != 32 || !L.SetSecret(pvchSecretL, true) || !H.SetSecret(pvchSecretH, true))
+ {
+ nVersion = 0;
+ return false;
+ }
+
+ vchSecretL = pvchSecretL;
+ vchSecretH = pvchSecretH;
+ nVersion = CURRENT_VERSION;
+
+ return true;
+}
+
+void CMalleableKey::GetSecrets(CSecret &pvchSecretL, CSecret &pvchSecretH) const
+{
+ pvchSecretL = vchSecretL;
+ pvchSecretH = vchSecretH;
+}
+
+CMalleablePubKey CMalleableKey::GetMalleablePubKey() const
+{
+ CKey L, H;
+ L.SetSecret(vchSecretL, true);
+ H.SetSecret(vchSecretH, true);
+
+ std::vector<unsigned char> vchPubKeyL = L.GetPubKey().Raw();
+ std::vector<unsigned char> vchPubKeyH = H.GetPubKey().Raw();
+
+ return CMalleablePubKey(vchPubKeyL, vchPubKeyH);
+}
+
+// Check ownership
+bool CMalleableKey::CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant) const
+{
+ if (IsNull()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Attempting to run on NULL key object.");
+ }
+
+ if (!R.IsValid()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : R is invalid");
+ }
+
+ if (!vchPubKeyVariant.IsValid()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : public key variant is invalid");
+ }
+
+ CPoint point_R;
+ if (!point_R.setPubKey(R)) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Unable to decode R value");
+ }
+
+ CKey H;
+ H.SetSecret(vchSecretH, true);
+ std::vector<unsigned char> vchPubKeyH = H.GetPubKey().Raw();
+
+ CPoint point_H;
+ if (!point_H.setPubKey(vchPubKeyH)) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Unable to decode H value");
+ }
+
+ CPoint point_P;
+ if (!point_P.setPubKey(vchPubKeyVariant)) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Unable to decode P value");
+ }
+
+ // Infinity points are senseless
+ if (point_P.IsInfinity()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : P is infinity");
+ }
+
+ CBigNum bnl;
+ bnl.setBytes(std::vector<unsigned char>(vchSecretL.begin(), vchSecretL.end()));
+
+ point_R.ECMUL(bnl);
+
+ std::vector<unsigned char> vchRl;
+ if (!point_R.getBytes(vchRl)) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Unable to convert Rl value");
+ }
+
+ // Calculate Hash(R*l)
+ CBigNum bnHash;
+ bnHash.setuint160(Hash160(vchRl));
+
+ CPoint point_Ps;
+ // Calculate Ps = Hash(L*r)*G + H
+ point_Ps.ECMULGEN(bnHash, point_H);
+
+ // Infinity points are senseless
+ if (point_Ps.IsInfinity()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Ps is infinity");
+ }
+
+ // Check ownership
+ if (point_Ps != point_P) {
+ return false;
+ }
+
+ return true;
+}
+
+// Check ownership and restore private key
+bool CMalleableKey::CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant, CKey &privKeyVariant) const
+{
+ if (IsNull()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Attempting to run on NULL key object.");
+ }
+
+ if (!R.IsValid()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : R is invalid");
+ }
+
+ if (!vchPubKeyVariant.IsValid()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : public key variant is invalid");
+ }
+
+ CPoint point_R;
+ if (!point_R.setPubKey(R)) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Unable to decode R value");
+ }
+
+ CKey H;
+ H.SetSecret(vchSecretH, true);
+ std::vector<unsigned char> vchPubKeyH = H.GetPubKey().Raw();
+
+ CPoint point_H;
+ if (!point_H.setPubKey(vchPubKeyH)) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Unable to decode H value");
+ }
+
+ CPoint point_P;
+ if (!point_P.setPubKey(vchPubKeyVariant)) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Unable to decode P value");
+ }
+
+ // Infinity points are senseless
+ if (point_P.IsInfinity()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : P is infinity");
+ }
+
+ CBigNum bnl;
+ bnl.setBytes(std::vector<unsigned char>(vchSecretL.begin(), vchSecretL.end()));
+
+ point_R.ECMUL(bnl);
+
+ std::vector<unsigned char> vchRl;
+ if (!point_R.getBytes(vchRl)) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Unable to convert Rl value");
+ }
+
+ // Calculate Hash(R*l)
+ CBigNum bnHash;
+ bnHash.setuint160(Hash160(vchRl));
+
+ CPoint point_Ps;
+ // Calculate Ps = Hash(L*r)*G + H
+ point_Ps.ECMULGEN(bnHash, point_H);
+
+ // Infinity points are senseless
+ if (point_Ps.IsInfinity()) {
+ throw key_error("CMalleableKey::CheckKeyVariant() : Ps is infinity");
+ }
+
+ // Check ownership
+ if (point_Ps != point_P) {
+ return false;
+ }
+
+ // OpenSSL BIGNUM representation of the second private key from (l, h) pair
+ CBigNum bnh;
+ bnh.setBytes(std::vector<unsigned char>(vchSecretH.begin(), vchSecretH.end()));
+
+ // Calculate p = Hash(R*l) + h
+ CBigNum bnp = bnHash + bnh;
+
+ std::vector<unsigned char> vchp = bnp.getBytes();
+ privKeyVariant.SetSecret(CSecret(vchp.begin(), vchp.end()), true);
+
+ return true;
+}
+
+std::string CMalleableKey::ToString() const
+{
+ CDataStream ssKey(SER_NETWORK, PROTOCOL_VERSION);
+ ssKey << *this;
+ std::vector<unsigned char> vch(ssKey.begin(), ssKey.end());
+
+ return EncodeBase58Check(vch);
+}
+
+bool CMalleableKey::SetString(const std::string& strMutableKey)
+{
+ std::vector<unsigned char> vchTemp;
+ if (!DecodeBase58Check(strMutableKey, vchTemp)) {
+ throw key_error("CMalleableKey::SetString() : Provided key data seems corrupted.");
+ }
+
+ CDataStream ssKey(vchTemp, SER_NETWORK, PROTOCOL_VERSION);
+ ssKey >> *this;
+
+ return IsNull();
+}
+
+// CMalleableKeyView
+
+CMalleableKeyView::CMalleableKeyView(const CMalleableKey &b)
+{
+ if (b.vchSecretL.size() != 32)
+ throw key_error("CMalleableKeyView::CMalleableKeyView() : L size must be 32 bytes");
+
+ if (b.vchSecretH.size() != 32)
+ throw key_error("CMalleableKeyView::CMalleableKeyView() : L size must be 32 bytes");
+
+ vchSecretL = b.vchSecretL;
+
+ CKey H;
+ H.SetSecret(b.vchSecretH, true);
+
+ vchPubKeyH = H.GetPubKey().Raw();
+ nVersion = b.nVersion;
+}
+
+CMalleableKeyView::CMalleableKeyView(const CMalleableKeyView &b)
+{
+ vchSecretL = b.vchSecretL;
+ vchPubKeyH = b.vchPubKeyH;
+ nVersion = CURRENT_VERSION;
+}
+
+CMalleableKeyView::CMalleableKeyView(const CSecret &L, const CPubKey &pvchPubKeyH)
+{
+ vchSecretL = L;
+ vchPubKeyH = pvchPubKeyH.Raw();
+ nVersion = CURRENT_VERSION;
+}
+
+CMalleableKeyView& CMalleableKeyView::operator=(const CMalleableKey &b)
+{
+ vchSecretL = b.vchSecretL;
+
+ CKey H;
+ H.SetSecret(b.vchSecretH, true);
+ vchPubKeyH = H.GetPubKey().Raw();
+ nVersion = b.nVersion;
+
+ return (*this);
+}
+
+CMalleableKeyView::~CMalleableKeyView()
+{
+}
+
+CMalleablePubKey CMalleableKeyView::GetMalleablePubKey() const
+{
+ CKey keyL;
+ keyL.SetSecret(vchSecretL, true);
+ return CMalleablePubKey(keyL.GetPubKey(), vchPubKeyH);
+}
+
+// Check ownership
+bool CMalleableKeyView::CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant) const
+{
+ if (!R.IsValid()) {
+ throw key_error("CMalleableKeyView::CheckKeyVariant() : R is invalid");
+ }
+
+ if (!vchPubKeyVariant.IsValid()) {
+ throw key_error("CMalleableKeyView::CheckKeyVariant() : public key variant is invalid");
+ }
+
+ CPoint point_R;
+ if (!point_R.setPubKey(R)) {
+ throw key_error("CMalleableKeyView::CheckKeyVariant() : Unable to decode R value");
+ }
+
+ CPoint point_H;
+ if (!point_H.setPubKey(vchPubKeyH)) {
+ throw key_error("CMalleableKeyView::CheckKeyVariant() : Unable to decode H value");
+ }
+
+ CPoint point_P;
+ if (!point_P.setPubKey(vchPubKeyVariant)) {
+ throw key_error("CMalleableKeyView::CheckKeyVariant() : Unable to decode P value");
+ }
+
+ // Infinity points are senseless
+ if (point_P.IsInfinity()) {
+ throw key_error("CMalleableKeyView::CheckKeyVariant() : P is infinity");
+ }
+
+ CBigNum bnl;
+ bnl.setBytes(std::vector<unsigned char>(vchSecretL.begin(), vchSecretL.end()));
+
+ point_R.ECMUL(bnl);
+
+ std::vector<unsigned char> vchRl;
+ if (!point_R.getBytes(vchRl)) {
+ throw key_error("CMalleableKeyView::CheckKeyVariant() : Unable to convert Rl value");
+ }
+
+ // Calculate Hash(R*l)
+ CBigNum bnHash;
+ bnHash.setuint160(Hash160(vchRl));
+
+ CPoint point_Ps;
+ // Calculate Ps = Hash(L*r)*G + H
+ point_Ps.ECMULGEN(bnHash, point_H);
+
+ // Infinity points are senseless
+ if (point_Ps.IsInfinity()) {
+ throw key_error("CMalleableKeyView::CheckKeyVariant() : Ps is infinity");
+ }
+
+ // Check ownership
+ if (point_Ps != point_P) {
+ return false;
+ }
+
+ return true;
+}
+
+std::string CMalleableKeyView::ToString() const
+{
+ CDataStream ssKey(SER_NETWORK, PROTOCOL_VERSION);
+ ssKey << *this;
+ std::vector<unsigned char> vch(ssKey.begin(), ssKey.end());
+
+ return EncodeBase58Check(vch);
+}
+
+bool CMalleableKeyView::SetString(const std::string& strMutableKey)
+{
+ std::vector<unsigned char> vchTemp;
+ if (!DecodeBase58Check(strMutableKey, vchTemp)) {
+ throw key_error("CMalleableKeyView::SetString() : Provided key data seems corrupted.");
+ }
+
+ CDataStream ssKey(vchTemp, SER_NETWORK, PROTOCOL_VERSION);
+ ssKey >> *this;
+
+ return IsNull();
+}
+
+bool CMalleableKeyView::IsNull() const
+{
+ return nVersion != CURRENT_VERSION;
+}
+
+//// Asymmetric encryption
+
+void CPubKey::EncryptData(const std::vector<unsigned char>& data, std::vector<unsigned char>& encrypted)
+{
+ CKey key;
+ key.SetPubKey(*this);
+
+ key.EncryptData(data, encrypted);
+}
+
+void CKey::EncryptData(const std::vector<unsigned char>& data, std::vector<unsigned char>& encrypted)
+{
+ ies_ctx_t *ctx;
+ char error[1024] = "Unknown error";
+ cryptogram_t *cryptogram;
+
+ ctx = create_context(pkey);
+ if (!EC_KEY_get0_public_key(ctx->user_key))
+ throw key_error("Given EC key is not public key");
+
+ cryptogram = ecies_encrypt(ctx, (unsigned char*)&data[0], data.size(), error);
+ if (cryptogram == NULL) {
+ free(ctx);
+ ctx = NULL;
+ throw key_error(std::string("Error in encryption: %s") + error);
+ }
+
+ encrypted.resize(cryptogram_data_sum_length(cryptogram));
+ unsigned char *key_data = cryptogram_key_data(cryptogram);
+ memcpy(&encrypted[0], key_data, encrypted.size());
+ cryptogram_free(cryptogram);
+ free(ctx);
+}
+
+void CKey::DecryptData(const std::vector<unsigned char>& encrypted, std::vector<unsigned char>& data)
+{
+ ies_ctx_t *ctx;
+ char error[1024] = "Unknown error";
+ cryptogram_t *cryptogram;
+ size_t length;
+ unsigned char *decrypted;
+
+ ctx = create_context(pkey);
+ if (!EC_KEY_get0_private_key(ctx->user_key))
+ throw key_error("Given EC key is not private key");
+
+ size_t key_length = ctx->stored_key_length;
+ size_t mac_length = EVP_MD_size(ctx->md);
+ cryptogram = cryptogram_alloc(key_length, mac_length, encrypted.size() - key_length - mac_length);
+
+ memcpy(cryptogram_key_data(cryptogram), &encrypted[0], encrypted.size());
+
+ decrypted = ecies_decrypt(ctx, cryptogram, &length, error);
+ cryptogram_free(cryptogram);
+ free(ctx);
+
+ if (decrypted == NULL) {
+ throw key_error(std::string("Error in decryption: %s") + error);
+ }
+
+ data.resize(length);
+ memcpy(&data[0], decrypted, length);
+ free(decrypted);
+}
#include "uint256.h"
#include "hash.h"
#include "bignum.h"
+#include "ies.h"
#include <openssl/ec.h> // for EC_KEY definition
std::vector<unsigned char> Raw() const {
return vchPubKey;
}
+
+ // Encrypt data
+ void EncryptData(const std::vector<unsigned char>& data, std::vector<unsigned char>& encrypted);
};
// Reserialize to DER
static bool ReserealizeSignature(std::vector<unsigned char>& vchSig);
+
+ // Encrypt data
+ void EncryptData(const std::vector<unsigned char>& data, std::vector<unsigned char>& encrypted);
+
+ // Decrypt data
+ void DecryptData(const std::vector<unsigned char>& encrypted, std::vector<unsigned char>& data);
+};
+
+class CPoint
+{
+private:
+ EC_POINT *point;
+ EC_GROUP* group;
+ BN_CTX* ctx;
+
+public:
+ CPoint();
+ bool operator!=(const CPoint &a);
+ ~CPoint();
+
+ // Initialize from octets stream
+ bool setBytes(const std::vector<unsigned char> &vchBytes);
+
+ // Initialize from pubkey
+ bool setPubKey(const CPubKey &vchPubKey);
+
+ // Serialize to octets stream
+ bool getBytes(std::vector<unsigned char> &vchBytes);
+
+ // ECC multiplication by specified multiplier
+ bool ECMUL(const CBigNum &bnMultiplier);
+
+ // Calculate G*m + q
+ bool ECMULGEN(const CBigNum &bnMultiplier, const CPoint &qPoint);
+
+ bool IsInfinity() { return EC_POINT_is_at_infinity(group, point); }
+};
+
+class CMalleablePubKey
+{
+private:
+ unsigned char nVersion;
+ CPubKey pubKeyL;
+ CPubKey pubKeyH;
+ friend class CMalleableKey;
+
+ static const unsigned char CURRENT_VERSION = 1;
+
+public:
+ CMalleablePubKey() { nVersion = CMalleablePubKey::CURRENT_VERSION; }
+ CMalleablePubKey(const std::string& strMalleablePubKey) { SetString(strMalleablePubKey); }
+ CMalleablePubKey(const CPubKey &pubKeyInL, const CPubKey &pubKeyInH) : pubKeyL(pubKeyInL), pubKeyH(pubKeyInH) { nVersion = CMalleablePubKey::CURRENT_VERSION; }
+ CMalleablePubKey(const std::vector<unsigned char> &pubKeyInL, const std::vector<unsigned char> &pubKeyInH) : pubKeyL(pubKeyInL), pubKeyH(pubKeyInH) { nVersion = CMalleablePubKey::CURRENT_VERSION; }
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(pubKeyL);
+ READWRITE(pubKeyH);
+ )
+
+ bool IsValid() const {
+ return pubKeyL.IsValid() && pubKeyH.IsValid();
+ }
+
+ bool operator==(const CMalleablePubKey &b);
+ bool operator!=(const CMalleablePubKey &b) { return !(*this == b); }
+
+ std::string ToString() const;
+ bool SetString(const std::string& strMalleablePubKey);
+ uint256 GetID() const;
+
+ CPubKey& GetL() { return pubKeyL; }
+ CPubKey& GetH() { return pubKeyH; }
+ void GetVariant(CPubKey &R, CPubKey &vchPubKeyVariant);
+};
+
+class CMalleableKey
+{
+private:
+ unsigned char nVersion;
+ CSecret vchSecretL;
+ CSecret vchSecretH;
+
+ friend class CMalleableKeyView;
+
+ static const unsigned char CURRENT_VERSION = 1;
+
+public:
+ CMalleableKey();
+ CMalleableKey(const CMalleableKey &b);
+ CMalleableKey(const CSecret &L, const CSecret &H);
+ CMalleableKey& operator=(const CMalleableKey &b);
+ ~CMalleableKey();
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(vchSecretL);
+ READWRITE(vchSecretH);
+ )
+
+ std::string ToString() const;
+ bool SetString(const std::string& strMalleablePubKey);
+
+ void Reset();
+ void MakeNewKeys();
+ bool IsNull() const;
+ bool SetSecrets(const CSecret &pvchSecretL, const CSecret &pvchSecretH);
+ void GetSecrets(CSecret &pvchSecretL, CSecret &pvchSecretH) const;
+
+ CMalleablePubKey GetMalleablePubKey() const;
+ bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant) const;
+ bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant, CKey &privKeyVariant) const;
+};
+
+class CMalleableKeyView
+{
+private:
+ unsigned char nVersion;
+ CSecret vchSecretL;
+ CPubKey vchPubKeyH;
+
+ static const unsigned char CURRENT_VERSION = 1;
+
+public:
+ CMalleableKeyView() { nVersion = 0; };
+ CMalleableKeyView(const CMalleableKey &b);
+ CMalleableKeyView(const CSecret &L, const CPubKey &pvchPubKeyH);
+
+ CMalleableKeyView(const CMalleableKeyView &b);
+ CMalleableKeyView& operator=(const CMalleableKey &b);
+ ~CMalleableKeyView();
+
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(vchSecretL);
+ READWRITE(vchPubKeyH);
+ )
+
+ bool IsNull() const;
+ std::string ToString() const;
+ bool SetString(const std::string& strMalleablePubKey);
+
+ CMalleablePubKey GetMalleablePubKey() const;
+ bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant) const;
+
+ bool operator <(const CMalleableKeyView& kv) const { return vchPubKeyH.GetID() < kv.vchPubKeyH.GetID(); }
};
#endif
return (!setWatchOnly.empty());
}
+CCryptoKeyStore::CCryptoKeyStore() : fUseCrypto(false)
+{
+ std::string strMalleableKey = GetArg("-masterkey", "");
+ CMalleableKey malleableKey;
+ if (strMalleableKey != "")
+ malleableKey.SetString(strMalleableKey);
+ else
+ malleableKey.MakeNewKeys();
+
+ const CMalleableKeyView& keyView(malleableKey);
+ mapMalleableKeys[keyView] = malleableKey;
+}
+
bool CCryptoKeyStore::SetCrypted()
{
{
break;
return false;
}
+
vMasterKey = vMasterKeyIn;
}
NotifyStatusChanged(this);
vchSecret = key.GetSecret(fCompressed);
return true;
}
+
+ virtual bool CheckOwnership(const CPubKey &pubKeyVariant, const CPubKey &R) const =0;
+ virtual bool CreatePrivKey(const CPubKey &pubKeyVariant, const CPubKey &R, CKey &privKey) const =0;
+ virtual void ListMalleablePubKeys(std::list<CMalleablePubKey> &malleablePubKeyList) const =0;
};
typedef std::map<CKeyID, std::pair<CSecret, bool> > KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
typedef std::set<CScript> WatchOnlySet;
+typedef std::map<CMalleableKeyView, CMalleableKey> MalleableKeyMap;
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore
{
protected:
KeyMap mapKeys;
+ MalleableKeyMap mapMalleableKeys;
+
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;
virtual bool RemoveWatchOnly(const CScript &dest);
virtual bool HaveWatchOnly(const CScript &dest) const;
virtual bool HaveWatchOnly() const;
+
+ bool CheckOwnership(const CPubKey &pubKeyVariant, const CPubKey &R) const
+ {
+ {
+ LOCK(cs_KeyStore);
+ for (MalleableKeyMap::const_iterator mi = mapMalleableKeys.begin(); mi != mapMalleableKeys.end(); mi++)
+ {
+ if (mi->first.CheckKeyVariant(R, pubKeyVariant))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool CreatePrivKey(const CPubKey &pubKeyVariant, const CPubKey &R, CKey &privKey) const
+ {
+ {
+ LOCK(cs_KeyStore);
+ for (MalleableKeyMap::const_iterator mi = mapMalleableKeys.begin(); mi != mapMalleableKeys.end(); mi++)
+ {
+ if (mi->second.CheckKeyVariant(R, pubKeyVariant, privKey))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void ListMalleablePubKeys(std::list<CMalleablePubKey> &malleablePubKeyList) const
+ {
+ malleablePubKeyList.clear();
+
+ {
+ LOCK(cs_KeyStore);
+ for (MalleableKeyMap::const_iterator mi = mapMalleableKeys.begin(); mi != mapMalleableKeys.end(); mi++)
+ malleablePubKeyList.push_back(mi->first.GetMalleablePubKey());
+ }
+ }
};
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
public:
- CCryptoKeyStore() : fUseCrypto(false)
- {
- }
+ CCryptoKeyStore();
bool IsCrypted() const
{
obj/walletdb.o \
obj/noui.o \
obj/kernel.o \
- obj/kernel_worker.o
+ obj/kernel_worker.o \
+ obj/ecies.o \
+ obj/cryptogram.o
all: novacoind
obj/walletdb.o \
obj/noui.o \
obj/kernel.o \
- obj/kernel_worker.o
+ obj/kernel_worker.o \
+ obj/ecies.o \
+ obj/cryptogram.o
all: novacoind.exe
obj/walletdb.o \
obj/noui.o \
obj/kernel.o \
- obj/kernel_worker.o
+ obj/kernel_worker.o \
+ obj/ecies.o \
+ obj/cryptogram.o
all: novacoind.exe
obj/walletdb.o \
obj/noui.o \
obj/kernel.o \
- obj/kernel_worker.o
+ obj/kernel_worker.o \
+ obj/ecies.o \
+ obj/cryptogram.o
ifneq (${USE_IPV6}, -)
DEFS += -DUSE_IPV6=$(USE_IPV6)
obj/walletdb.o \
obj/noui.o \
obj/kernel.o \
- obj/kernel_worker.o
+ obj/kernel_worker.o \
+ obj/ecies.o \
+ obj/cryptogram.o
all: novacoind
extern bool fTestNet;
static inline unsigned short GetDefaultPort(const bool testnet = fTestNet)
{
- return testnet ? 17777 : 7777;
+ return static_cast<unsigned short>(testnet ? 17777 : 7777);
}
#include "main.h"
#include "net.h"
#include "wallet.h"
+#include "script.h"
+#include "util.h"
using namespace std;
using namespace boost;
return;
}
- out.push_back(Pair("reqSigs", nRequired));
- out.push_back(Pair("type", GetTxnOutputType(type)));
+ if (type != TX_NULL_DATA)
+ {
+ out.push_back(Pair("reqSigs", nRequired));
+ out.push_back(Pair("type", GetTxnOutputType(type)));
- Array a;
- BOOST_FOREACH(const CTxDestination& addr, addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
- out.push_back(Pair("addresses", a));
+ Array a;
+ BOOST_FOREACH(const CTxDestination& addr, addresses)
+ a.push_back(CBitcoinAddress(addr).ToString());
+ out.push_back(Pair("addresses", a));
+ }
+ else
+ {
+ out.push_back(Pair("type", GetTxnOutputType(type)));
+ }
}
void TxToJSON(const CTransaction& tx, const uint256& hashBlock, Object& entry)
Value createrawtransaction(const Array& params, bool fHelp)
{
- if (fHelp || params.size() != 2)
+ if (fHelp || params.size() > 3 || params.size() < 2)
throw runtime_error(
- "createrawtransaction '[{\"txid\":txid,\"vout\":n},...]' '{address:amount,...}'\n"
+ "createrawtransaction <'[{\"txid\":txid,\"vout\":n},...]'> <'{address:amount,...}'> [hex data]\n"
"Create a transaction spending given inputs\n"
"(array of objects containing transaction id and output number),\n"
- "sending to given address(es).\n"
+ "sending to given address(es),\n"
+ "optional data to add into data-carrying output.\n"
"Returns hex-encoded raw transaction.\n"
"Note that the transaction's inputs are not signed, and\n"
"it is not stored in the wallet or transmitted to the network.");
rawTx.vout.push_back(out);
}
+ if (params.size() == 3)
+ {
+ // Data carrying output
+ CScript scriptPubKey;
+ scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
+ CTxOut out(0, scriptPubKey);
+ rawTx.vout.push_back(out);
+ }
+
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << rawTx;
return HexStr(ss.begin(), ss.end());
return Value::null;
}
-// ppcoin: make a public-private key pair
+// Make a public-private key pair
Value makekeypair(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 1)
+ if (fHelp || params.size() > 0)
throw runtime_error(
- "makekeypair [prefix]\n"
- "Make a public/private key pair.\n"
- "[prefix] is optional preferred prefix for the public key.\n");
+ "makekeypair\n"
+ "Make a public/private key pair.\n");
string strPrefix = "";
if (params.size() > 0)
strPrefix = params[0].get_str();
-
+
CKey key;
- key.MakeNewKey(false);
+ key.MakeNewKey(true);
CPrivKey vchPrivKey = key.GetPrivKey();
Object result;
result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
+
+ bool fCompressed;
+ CSecret vchSecret = key.GetSecret(fCompressed);
+ result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));
return result;
}
+
+Value newmalleablekey(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 0)
+ throw runtime_error(
+ "newmalleablekey\n"
+ "Make a malleable public/private key pair.\n");
+
+ CMalleableKey malleableKey;
+ malleableKey.MakeNewKeys();
+ CMalleablePubKey malleablePubKey = malleableKey.GetMalleablePubKey();
+
+ CDataStream ssPublicBytes(SER_NETWORK, PROTOCOL_VERSION);
+ ssPublicBytes << malleablePubKey;
+
+ Object result;
+ result.push_back(Pair("PrivatePair", malleableKey.ToString()));
+ result.push_back(Pair("PublicPair", malleablePubKey.ToString()));
+ result.push_back(Pair("PublicBytes", HexStr(ssPublicBytes.begin(), ssPublicBytes.end())));
+
+ return result;
+}
+
+Value adjustmalleablekey(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 3)
+ throw runtime_error(
+ "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
+ "Calculate new private key using provided malleable key, public key and R data.\n");
+
+ CMalleableKey malleableKey;
+ malleableKey.SetString(params[0].get_str());
+
+ CKey privKeyVariant;
+ CPubKey vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
+
+ CPubKey R(ParseHex(params[2].get_str()));
+
+ if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
+ throw runtime_error("Unable to calculate the private key");
+ }
+
+ Object result;
+ bool fCompressed;
+ CSecret vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
+
+ result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
+
+ return result;
+}
+
+Value adjustmalleablepubkey(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 2 || params.size() == 0)
+ throw runtime_error(
+ "adjustmalleablepubkey <Malleable public key data>\n"
+ "Calculate new public key using provided malleable public key data.\n");
+
+ string pubKeyPair = params[0].get_str();
+ CMalleablePubKey malleablePubKey;
+
+ if (pubKeyPair.size() == 138) {
+ CDataStream ssPublicBytes(ParseHex(pubKeyPair), SER_NETWORK, PROTOCOL_VERSION);
+ ssPublicBytes >> malleablePubKey;
+ } else
+ malleablePubKey.SetString(pubKeyPair);
+
+ CPubKey R, vchPubKeyVariant;
+ malleablePubKey.GetVariant(R, vchPubKeyVariant);
+
+ Object result;
+ result.push_back(Pair("R", HexStr(R.Raw())));
+ result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.Raw())));
+ result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
+
+
+ return result;
+}
+
+Value listmalleablepubkeys(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "listmalleablepubkeys\n"
+ "Get list of malleable public keys.\n");
+
+ std::list<CMalleablePubKey> keyList;
+ pwalletMain->ListMalleablePubKeys(keyList);
+
+ Array result;
+ BOOST_FOREACH(const CMalleablePubKey &key, keyList)
+ {
+ result.push_back(key.ToString());
+ }
+
+ return result;
+}
{
case TX_NONSTANDARD: return "nonstandard";
case TX_PUBKEY: return "pubkey";
+ case TX_PUBKEY_DROP: return "pubkeydrop";
case TX_PUBKEYHASH: return "pubkeyhash";
case TX_SCRIPTHASH: return "scripthash";
case TX_MULTISIG: return "multisig";
// Standard tx, sender provides pubkey, receiver adds signature
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
+ if (GetTime() > SMALLDATA_SWITCH_TIME)
+ {
+ // Malleable pubkey tx hack, sender provides generated pubkey combined with R parameter. The R parameter is dropped before checking a signature.
+ mTemplates.insert(make_pair(TX_PUBKEY_DROP, CScript() << OP_PUBKEY << OP_PUBKEY << OP_DROP << OP_CHECKSIG));
+ }
+
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
}
else if (opcode2 == OP_SMALLDATA)
{
- // small pushdata, <= 80 bytes
- if (vch1.size() > 80)
+ // small pushdata, <= 1024 bytes
+ if (vch1.size() > (GetTime() > SMALLDATA_SWITCH_TIME ? 1024 : 80))
break;
}
else if (opcode1 != opcode2 || vch1 != vch2)
}
-bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+bool Sign1(const CKeyID& address, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet)
{
CKey key;
if (!keystore.GetKey(address, key))
return true;
}
-bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+bool SignR(const CPubKey& pubKey, const CPubKey& R, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet)
+{
+ CKey key;
+ if (!keystore.CreatePrivKey(pubKey, R, key))
+ return false;
+
+ vector<unsigned char> vchSig;
+ if (!key.Sign(hash, vchSig))
+ return false;
+ vchSig.push_back((unsigned char)nHashType);
+ scriptSigRet << vchSig;
+
+ return true;
+}
+
+bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
// Returns false if scriptPubKey could not be completely satisfied.
//
-bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
+bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, const uint256& hash, int nHashType,
CScript& scriptSigRet, txnouttype& whichTypeRet)
{
scriptSigRet.clear();
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
+ case TX_PUBKEY_DROP:
+ {
+ CPubKey key = CPubKey(vSolutions[0]);
+ CPubKey R = CPubKey(vSolutions[1]);
+ return SignR(key, R, keystore, hash, nHashType, scriptSigRet);
+ }
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
case TX_NULL_DATA:
return 1;
case TX_PUBKEY:
+ case TX_PUBKEY_DROP:
return 1;
case TX_PUBKEYHASH:
return 2;
if (keystore.HaveKey(keyID))
return MINE_SPENDABLE;
break;
+ case TX_PUBKEY_DROP:
+ {
+ CPubKey key = CPubKey(vSolutions[0]);
+ if (keystore.HaveKey(key.GetID()))
+ return MINE_SPENDABLE;
+ else
+ {
+ CPubKey R = CPubKey(vSolutions[1]);
+ if (keystore.CheckOwnership(key, R))
+ return MINE_SPENDABLE;
+ }
+ }
+ break;
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
if (keystore.HaveKey(keyID))
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
- if (whichType == TX_PUBKEY)
+ if (whichType == TX_PUBKEY || whichType == TX_PUBKEY_DROP)
{
addressRet = CPubKey(vSolutions[0]).GetID();
return true;
return result;
}
-static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2)
{
return result;
}
-static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const txnouttype txType, const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2)
{
return PushAll(sigs1);
return PushAll(sigs2);
case TX_PUBKEY:
+ case TX_PUBKEY_DROP:
case TX_PUBKEYHASH:
// Signatures are bigger than placeholders or empty scripts:
if (sigs1.empty() || sigs1[0].empty())
return CScript();
}
-CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const CScript& scriptSig1, const CScript& scriptSig2)
{
txnouttype txType;
TX_NONSTANDARD,
// 'standard' transaction types:
TX_PUBKEY,
+ TX_PUBKEY_DROP,
TX_PUBKEYHASH,
TX_SCRIPTHASH,
TX_MULTISIG,
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
// combine them intelligently and return the result.
-CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
+CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
#endif
static const unsigned int TARGETS_SWITCH_TIME = 1374278400; // Saturday, 20-Jul-2013 00:00:00 UTC
static const unsigned int COINBASE_SIGOPS_SWITCH_TIME = 1447977600; // Friday, 20-Nov-15 00:00:00 UTC
+static const unsigned int SMALLDATA_SWITCH_TIME = 1458432000; // Sunday, 20-Mar-16 00:00:00 UTC
#endif