Skip to content
This repository has been archived by the owner on Jun 12, 2018. It is now read-only.

Commit

Permalink
Merge pull request #76 from PashaKlybik/MUL-1212-GOLOS-signing-with-p…
Browse files Browse the repository at this point in the history
…rivate-key

Mul 1212 golos signing with private key
  • Loading branch information
Enmk committed Apr 6, 2018
2 parents 343ada1 + 6ab6969 commit 0f9702e
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 8 deletions.
55 changes: 52 additions & 3 deletions multy_core/src/golos/golos_account.cpp
Expand Up @@ -19,10 +19,19 @@
#include "wally_core.h"
#include "wally_crypto.h"

extern "C" {
#include "libwally-core/src/internal.h"
}
#include "libwally-core/src/secp256k1/include/secp256k1.h"

#include <cassert>

#include <string.h>

#define GOLOS_RECOVERY_PARAM_COMPRESSED 4
#define GOLOS_RECOVERY_PARAM_COMPACT 27
#define GOLOS_SIGNATURE_SIZE 65

namespace
{
using namespace multy_core::internal;
Expand All @@ -43,6 +52,26 @@ uint32_t get_chain_index(BlockchainType blockchain_type)
return blockchain_type.blockchain;
}

// Check that signature is in canonical format
// For details please see: bitshares/bitshares1-core#1129
bool is_canonical_signature(const std::array<unsigned char, GOLOS_SIGNATURE_SIZE>& c )
{
return !(c[1] & 0x80)
&& !(c[1] == 0 && !(c[2] & 0x80))
&& !(c[33] & 0x80)
&& !(c[33] == 0 && !(c[34] & 0x80));
}

// This extended nonce function is based on Golos implementation
static int extended_nonce_function( unsigned char *nonce32, const unsigned char *msg32,
const unsigned char *key32, const unsigned char* /*algo16*/,
void *data, unsigned int /*attempt*/)
{
unsigned int* extra = (unsigned int*) data;
(*extra)++;
return secp256k1_nonce_function_default(nonce32, msg32, key32, nullptr, nullptr, *extra);
}

} // namespace

namespace multy_core
Expand Down Expand Up @@ -124,10 +153,30 @@ class GolosPrivateKey : public PrivateKey
return make_clone(*this);
}

BinaryDataPtr sign(const BinaryData& /*data*/) const override
BinaryDataPtr sign(const BinaryData& data) const override
{
// TODO: implement signing.
return nullptr;
auto data_hash = do_hash<SHA2, 256>(data);

std::array<unsigned char, GOLOS_SIGNATURE_SIZE> result;
int recovery_id = 0;
unsigned int counter = 0;
do
{
secp256k1_ecdsa_signature signature;
if (!secp256k1_ecdsa_sign(secp_ctx(), &signature,
data_hash.data(), m_data.data(), extended_nonce_function, &counter, &recovery_id))
{
THROW_EXCEPTION("Failed to sign with private key.");
}

if (!secp256k1_ecdsa_signature_serialize_compact(secp_ctx(), result.data() + 1, &signature))
{
THROW_EXCEPTION("Failed to make compact size from signature.");
}
} while(!is_canonical_signature(result));

result.begin()[0] = GOLOS_RECOVERY_PARAM_COMPRESSED + GOLOS_RECOVERY_PARAM_COMPACT + recovery_id;
return make_clone(as_binary_data(result));
}

std::string to_string() const override
Expand Down
21 changes: 20 additions & 1 deletion multy_test/test_golos_account.cpp
Expand Up @@ -5,15 +5,20 @@
*/

#include "multy_test/serialized_keys_test_base.h"
#include "multy_core/src/golos/golos_account.h"


#include "multy_core/src/golos/golos_account.h"
#include "multy_core/src/api/key_impl.h"
#include "multy_core/golos.h"

#include "multy_test/utility.h"

#include "gtest/gtest.h"

namespace
{
using namespace multy_core::internal;
using namespace test_utility;
const BlockchainType GOLOS_MAINNET{BLOCKCHAIN_GOLOS, GOLOS_NET_TYPE_MAINNET};

const SerializedKeyTestCase GOLOS_KEYS[] =
Expand Down Expand Up @@ -112,4 +117,18 @@ INSTANTIATE_TEST_CASE_P(
::testing::Values(GOLOS_MAINNET),
::testing::ValuesIn(GOLOS_KEYS)));

GTEST_TEST(GolosTest, private_key_sign)
{
AccountPtr account;
make_account(BLOCKCHAIN_GOLOS, "5Hq2ZdSGZokcgLoNxNGL5kHKi4e3kUUCqorgFK6T6ka7KtSvYLj", reset_sp(account));
PrivateKeyPtr prv_key = account->get_private_key();
// binary serialize TX to sign golos private key
BinaryDataPtr signature = prv_key->sign(as_binary_data(from_hex("782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de1269466c1944189"
"fb3bb5a0102096d756c7479746573740b70617368616b6c7962696b010000000000000003474f4c4f5300000000")));
// signature generated form golos-core
ASSERT_EQ(as_binary_data(from_hex(
"1f2e6bb028760bacddd31dc9772e63240fd297ee2f9fcd29f3605aeb79f774fa4b7d1b4e6dc4a1cd6fd2d4e08b2ea2758680d6a5b1e49664522f391ff949b70018")),
*signature);
}

} // namespace
4 changes: 3 additions & 1 deletion third-party/libwally-core/src/secp256k1/include/secp256k1.h
Expand Up @@ -444,6 +444,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* recid: pointer to an int, which will be updated to contain the recovery id (can be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
Expand All @@ -458,7 +459,8 @@ SECP256K1_API int secp256k1_ecdsa_sign(
const unsigned char *msg32,
const unsigned char *seckey,
secp256k1_nonce_function noncefp,
const void *ndata
const void *ndata,
int* recid
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

/** Verify an ECDSA secret key.
Expand Down
4 changes: 2 additions & 2 deletions third-party/libwally-core/src/secp256k1/src/secp256k1.c
Expand Up @@ -352,7 +352,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;

int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata, int* recid) {
secp256k1_scalar r, s;
secp256k1_scalar sec, non, msg;
int ret = 0;
Expand All @@ -379,7 +379,7 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature
}
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
if (!overflow && !secp256k1_scalar_is_zero(&non)) {
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) {
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, recid)) {
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion third-party/libwally-core/src/sign.c
Expand Up @@ -191,7 +191,7 @@ int wally_ec_sig_from_bytes(const unsigned char *priv_key, size_t priv_key_len,
} else {
secp256k1_ecdsa_signature sig;

if (!secp256k1_ecdsa_sign(ctx, &sig, bytes_in, priv_key, nonce_fn, NULL)) {
if (!secp256k1_ecdsa_sign(ctx, &sig, bytes_in, priv_key, nonce_fn, NULL, NULL)) {
wally_clear(&sig, sizeof(sig));
if (secp256k1_ec_seckey_verify(ctx, priv_key))
return WALLY_ERROR; /* Nonce function failed */
Expand Down

0 comments on commit 0f9702e

Please sign in to comment.