示例#1
0
文件: lisk.c 项目: trezor/trezor-mcu
void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg,
                       LiskMessageSignature *resp) {
  layoutSignMessage(msg->message.bytes, msg->message.size);
  if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
    fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
    layoutHome();
    return;
  }

  layoutProgressSwipe(_("Signing"), 0);

  uint8_t signature[64];
  uint8_t hash[32];
  lisk_message_hash(msg->message.bytes, msg->message.size, hash);

  ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature);

  memcpy(resp->signature.bytes, signature, sizeof(signature));
  memcpy(resp->public_key.bytes, &node->public_key[1], 32);

  resp->has_signature = true;
  resp->signature.size = 64;
  resp->has_public_key = true;
  resp->public_key.size = 32;
}
示例#2
0
 secure_vector<uint8_t> sign(RandomNumberGenerator&) override
    {
    secure_vector<uint8_t> sig(64);
    ed25519_sign(sig.data(), m_msg.data(), m_msg.size(), m_key.get_private_key().data());
    m_msg.clear();
    return sig;
    }
示例#3
0
int
pairing_session_get_signature(pairing_session_t *session, unsigned char signature[64])
{
	unsigned char sig_msg[64];
	unsigned char key[16];
	unsigned char iv[16];
	AES_CTR_CTX aes_ctx;

	assert(session);

	if (session->status != STATUS_HANDSHAKE) {
		return -1;
	}

	/* First sign the public ECDH keys of both parties */
	memcpy(&sig_msg[0], session->ecdh_ours, 32);
	memcpy(&sig_msg[32], session->ecdh_theirs, 32);
	ed25519_sign(signature, sig_msg, sizeof(sig_msg), session->ed_ours, session->ed_private);

	/* Then encrypt the result with keys derived from the shared secret */
	derive_key_internal(session, (const unsigned char *) SALT_KEY, strlen(SALT_KEY), key, sizeof(key));
	derive_key_internal(session, (const unsigned char *) SALT_IV, strlen(SALT_IV), iv, sizeof(key));
	AES_ctr_set_key(&aes_ctx, key, iv, AES_MODE_128);
	AES_ctr_encrypt(&aes_ctx, signature, signature, 64);
	return 0;
}
示例#4
0
文件: bench.c 项目: 1234max/tor
static void
bench_ed25519_impl(void)
{
  uint64_t start, end;
  const int iters = 1<<12;
  int i;
  const uint8_t msg[] = "but leaving, could not tell what they had heard";
  ed25519_signature_t sig;
  ed25519_keypair_t kp;
  curve25519_keypair_t curve_kp;
  ed25519_public_key_t pubkey_tmp;

  ed25519_secret_key_generate(&kp.seckey, 0);
  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_public_key_generate(&kp.pubkey, &kp.seckey);
  }
  end = perftime();
  printf("Generate public key: %.2f usec\n",
         MICROCOUNT(start, end, iters));

  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_sign(&sig, msg, sizeof(msg), &kp);
  }
  end = perftime();
  printf("Sign a short message: %.2f usec\n",
         MICROCOUNT(start, end, iters));

  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_checksig(&sig, msg, sizeof(msg), &kp.pubkey);
  }
  end = perftime();
  printf("Verify signature: %.2f usec\n",
         MICROCOUNT(start, end, iters));

  curve25519_keypair_generate(&curve_kp, 0);
  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_public_key_from_curve25519_public_key(&pubkey_tmp,
                                                  &curve_kp.pubkey, 1);
  }
  end = perftime();
  printf("Convert public point from curve25519: %.2f usec\n",
         MICROCOUNT(start, end, iters));

  curve25519_keypair_generate(&curve_kp, 0);
  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_public_blind(&pubkey_tmp, &kp.pubkey, msg);
  }
  end = perftime();
  printf("Blind a public key: %.2f usec\n",
         MICROCOUNT(start, end, iters));
}
示例#5
0
void Page::resign(const std::array<uint8_t, Const::ED25519_KEY_LEN>& sk)
{
  ed25519_public_key pk;
  ed25519_publickey(sk.data(), pk);

  Json::FastWriter writer;
  std::string data = writer.write(getCommonData());
  const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data.c_str());
  ed25519_sign(bytes, data.size(), sk.data(), pk, pageSig_.data());
}
示例#6
0
int main() {
	int i, res;
	ed25519_public_key pk;
	ed25519_signature sig;
	unsigned char forge[1024] = {'x'};
	curved25519_key csk[2] = {{255}};
	uint64_t ticks, pkticks = maxticks, signticks = maxticks, openticks = maxticks, curvedticks = maxticks;

	for (i = 0; i < 1024; i++) {
		ed25519_publickey(dataset[i].sk, pk);
		edassertequal(dataset[i].pk, pk, sizeof(pk), i, "public key didn't match");
		ed25519_sign((unsigned char *)dataset[i].m, i, dataset[i].sk, pk, sig);
		edassertequal(dataset[i].sig, sig, sizeof(sig), i, "signature didn't match");
		edassert(!ed25519_sign_open((unsigned char *)dataset[i].m, i, pk, sig), i, "failed to open message");

		memcpy(forge, dataset[i].m, i);
		if (i)
			forge[i - 1] += 1;

		edassert(ed25519_sign_open(forge, (i) ? i : 1, pk, sig), i, "opened forged message");
	}

	for (i = 0; i < 1024; i++)
		curved25519_scalarmult_basepoint(csk[(i & 1) ^ 1], csk[i & 1]);
	edassertequal(curved25519_expected, csk[0], sizeof(curved25519_key), 0, "curve25519 failed to generate correct value");

	printf("success\n");

	for (i = 0; i < 2048; i++) {
		timeit(ed25519_publickey(dataset[0].sk, pk), pkticks)
		edassertequal(dataset[0].pk, pk, sizeof(pk), i, "public key didn't match");
		timeit(ed25519_sign((unsigned char *)dataset[0].m, 0, dataset[0].sk, pk, sig), signticks)
		edassertequal(dataset[0].sig, sig, sizeof(sig), i, "signature didn't match");
		timeit(res = ed25519_sign_open((unsigned char *)dataset[0].m, 0, pk, sig), openticks)
		edassert(!res, 0, "failed to open message");
		timeit(curved25519_scalarmult_basepoint(csk[1], csk[0]), curvedticks);
	}
	printf("%.0f ticks/public key generation\n", (double)pkticks);
	printf("%.0f ticks/signature\n", (double)signticks);
	printf("%.0f ticks/signature verification\n", (double)openticks);
	printf("%.0f ticks/curve25519 basepoint scalarmult\n", (double)curvedticks);
	return 0;
}
示例#7
0
文件: ed25519.c 项目: himu007/komodo
/*
 * Visitor that signs an ed25519 condition if it has a matching public key
 */
static int ed25519Sign(CC *cond, CCVisitor visitor) {
    if (cond->type->typeId != CC_Ed25519Type.typeId) return 1;
    CCEd25519SigningData *signing = (CCEd25519SigningData*) visitor.context;
    if (0 != memcmp(cond->publicKey, signing->pk, 32)) return 1;
    if (!cond->signature) cond->signature = calloc(1,64);
    ed25519_sign(cond->signature, visitor.msg, visitor.msgLength,
            signing->pk, signing->skpk);
    signing->nSigned++;
    return 1;
}
示例#8
0
文件: orgs.c 项目: lavabit/magma
/**
 * @brief	Derive an organizational signet from the corresponding private key structures.
 */
prime_org_signet_t * org_signet_generate(prime_org_key_t *org) {

	prime_org_signet_t *signet = NULL;
	stringer_t *signing = NULL, *encryption = NULL, *cryptographic = MANAGEDBUF(69);

	// Ensure the org structure contains the necessary private keys.
	if (!org || !org->encryption || !org->signing || org->signing->type != ED25519_PRIV) {
		return NULL;
	}
	else if (!(signet = mm_alloc(sizeof(prime_org_signet_t)))) {
		return NULL;
	}
	// Store the public singing, and encryption keys.
	else if (!(signing = ed25519_public_get(org->signing, NULL)) ||
		!(encryption = secp256k1_public_get(org->encryption, NULL))) {
		log_pedantic("PRIME organizational signet generation failed, the public keys could not be derived from the provided private keys.");
		org_signet_free(signet);
		st_cleanup(signing);
		return NULL;
	}

	// Generate a serialized signet with the cryptographic fields.
	else if (st_write(cryptographic, prime_field_write(PRIME_ORG_SIGNET, 1, ED25519_KEY_PUB_LEN, signing, MANAGEDBUF(34)),
		prime_field_write(PRIME_ORG_SIGNET, 3, SECP256K1_KEY_PUB_LEN, encryption, MANAGEDBUF(35))) != 69) {
		log_pedantic("PRIME organizational signet generation failed, the serialized cryptographic signet could not be derived.");
		org_signet_free(signet);
		st_free(encryption);
		st_free(signing);
		return NULL;
	}

	// Generate a signature using the serialized cryptographic fields.
	else if (!(signet->signature = ed25519_sign(org->signing, cryptographic, NULL))) {
		log_pedantic("PRIME organizational signet generation failed, the cryptographic signet signature could not be derived.");
		org_signet_free(signet);
		st_free(encryption);
		st_free(signing);
		return NULL;
	}

	// Finally, convert the serialized public keys into usable structures.
	else if (!(signet->signing = ed25519_public_set(signing)) || !(signet->encryption = secp256k1_public_set(encryption))) {
		log_pedantic("PRIME organizational signet generation failed, the serialized public keys could not be parsed.");
		org_signet_free(signet);
		st_free(encryption);
		st_free(signing);
		return NULL;
	}

	// We no longer need the serialized public keys.
	st_free(encryption);
	st_free(signing);

	return signet;
}
示例#9
0
文件: item.cpp 项目: krattai/AEBL
// given the bencoded buffer ``v``, the salt (which is optional and may have
// a length of zero to be omitted), sequence number ``seq``, public key (32
// bytes ed25519 key) ``pk`` and a secret/private key ``sk`` (64 bytes ed25519
// key) a signature ``sig`` is produced. The ``sig`` pointer must point to
// at least 64 bytes of available space. This space is where the signature is
// written.
signature sign_mutable_item(
	span<char const> v
	, span<char const> salt
	, sequence_number const seq
	, public_key const& pk
	, secret_key const& sk)
{
	char str[1200];
	int const len = canonical_string(v, seq, salt, str);

	return ed25519_sign({str, size_t(len)}, pk, sk);
}
示例#10
0
/** Create a fulfillment given a secret key and the message */
Ed25519::Ed25519 (
    SecretKey const& secretKey,
    Slice message)
{
    // First derive the public key, and place it in the
    // payload:
    ed25519_publickey (
        secretKey.data(),
        payload_.data());

    ed25519_sign (
        message.data(),
        message.size(),
        secretKey.data(),
        payload_.data(),
        payload_.data() + pubkey_size_);
}
示例#11
0
	//not modify
	std::string PrivateKey::Sign(const std::string &input) const {
		unsigned char sig[10240];
		unsigned int sig_len = 0;

		if (type_ == SIGNTYPE_ED25519) {
			/*	ed25519_signature sig;*/
			ed25519_sign((unsigned char *)input.c_str(), input.size(), (const unsigned char*)raw_priv_key_.c_str(), (unsigned char*)pub_key_.GetRawPublicKey().c_str(), sig);
			sig_len = 64;
		}
		else if (type_ == SIGNTYPE_CFCASM2) {
			utils::EccSm2 key(utils::EccSm2::GetCFCAGroup());
			key.From(raw_priv_key_);
			std::string r, s;
			return key.Sign("1234567812345678", input);
		}
		else{
			LOG_ERROR("Unknown signature type(%d)", type_);
		}
		std::string output;
		output.append((const char *)sig, sig_len);
		return output;
	}
示例#12
0
// given the bencoded buffer ``v``, the salt (which is optional and may have
// a length of zero to be omitted), sequence number ``seq``, public key (32
// bytes ed25519 key) ``pk`` and a secret/private key ``sk`` (64 bytes ed25519
// key) a signature ``sig`` is produced. The ``sig`` pointer must point to
// at least 64 bytes of available space. This space is where the signature is
// written.
void sign_mutable_item(
    std::pair<char const*, int> v,
    std::pair<char const*, int> salt,
    boost::uint64_t seq,
    char const* pk,
    char const* sk,
    char* sig)
{
#ifdef TORRENT_USE_VALGRIND
    VALGRIND_CHECK_MEM_IS_DEFINED(v.first, v.second);
    VALGRIND_CHECK_MEM_IS_DEFINED(sk, item_sk_len);
    VALGRIND_CHECK_MEM_IS_DEFINED(pk, item_pk_len);
#endif

    char str[canonical_length];
    int len = canonical_string(v, seq, salt, str);

    ed25519_sign((unsigned char*)sig,
                 (unsigned char const*)str,
                 len,
                 (unsigned char const*)pk,
                 (unsigned char const*)sk
                );
}
示例#13
0
Ed25519::Ed25519 (
    SecretKey const& secretKey,
    PublicKey const& publicKey,
    Slice message)
{
    if (publicKeyType (publicKey) != KeyType::ed25519)
        LogicError ("An Ed25519 public key is required.");

    // When PublicKey wraps an Ed25519 key it prefixes
    // the key itself with a 0xED byte. We carefully
    // skip that byte.
    std::memcpy (
        payload_.data(),
        publicKey.data() + 1,
        publicKey.size() - 1);

    // Now sign:
    ed25519_sign (
        message.data(),
        message.size(),
        secretKey.data(),
        payload_.data(),
        payload_.data() + pubkey_size_);
}
示例#14
0
void c_crypto_ed25519::sign (const string &msg, unsigned char *signature) const {
	ed25519_sign(signature, reinterpret_cast<const unsigned char *>(msg.c_str()), msg.length(), public_key, private_key);
}
示例#15
0
int main(int argc, char *argv[]) {
    unsigned char public_key[32], private_key[64], seed[32], scalar[32];
    unsigned char other_public_key[32], other_private_key[64];
    unsigned char shared_secret[32], other_shared_secret[32];
    unsigned char signature[64];

    clock_t start;
    clock_t end;
    int i;

    /* create a random seed, and a keypair out of that seed */
    ed25519_create_seed(seed);
    ed25519_create_keypair(public_key, private_key, seed);

    /* create signature on the message with the keypair */
    ed25519_sign(signature, message, strlen(message), public_key, private_key);

    /* verify the signature */
    if (ed25519_verify(signature, message, strlen(message), public_key)) {
        printf("valid signature\n");
    } else {
        printf("invalid signature\n");
    }

    /* create scalar and add it to the keypair */
    ed25519_create_seed(scalar);
    ed25519_add_scalar(public_key, private_key, scalar);

    /* create signature with the new keypair */
    ed25519_sign(signature, message, strlen(message), public_key, private_key);

    /* verify the signature with the new keypair */
    if (ed25519_verify(signature, message, strlen(message), public_key)) {
        printf("valid signature\n");
    } else {
        printf("invalid signature\n");
    }

    /* make a slight adjustment and verify again */
    signature[44] ^= 0x10;
    if (ed25519_verify(signature, message, strlen(message), public_key)) {
        printf("did not detect signature change\n");
    } else {
        printf("correctly detected signature change\n");
    }

    /* generate two keypairs for testing key exchange */
    ed25519_create_seed(seed);
    ed25519_create_keypair(public_key, private_key, seed);
    ed25519_create_seed(seed);
    ed25519_create_keypair(other_public_key, other_private_key, seed);

    /* create two shared secrets - from both perspectives - and check if they're equal */
    ed25519_key_exchange(shared_secret, other_public_key, private_key);
    ed25519_key_exchange(other_shared_secret, public_key, other_private_key);

    for (i = 0; i < 32; ++i) {
        if (shared_secret[i] != other_shared_secret[i]) {
            printf("key exchange was incorrect\n");
            break;
        }
    }

    if (i == 32) {
        printf("key exchange was correct\n");
    }

    /* test performance */
    printf("testing seed generation performance: ");
    start = clock();
    for (i = 0; i < 10000; ++i) {
        ed25519_create_seed(seed);
    }
    end = clock();

    printf("%fus per seed\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);


    printf("testing key generation performance: ");
    start = clock();
    for (i = 0; i < 10000; ++i) {
        ed25519_create_keypair(public_key, private_key, seed);
    }
    end = clock();

    printf("%fus per keypair\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);

    printf("testing sign performance: ");
    start = clock();
    for (i = 0; i < 10000; ++i) {
        ed25519_sign(signature, message, strlen(message), public_key, private_key);
    }
    end = clock();

    printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);

    printf("testing verify performance: ");
    start = clock();
    for (i = 0; i < 10000; ++i) {
        ed25519_verify(signature, message, strlen(message), public_key);
    }
    end = clock();

    printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
    

    printf("testing keypair scalar addition performance: ");
    start = clock();
    for (i = 0; i < 10000; ++i) {
        ed25519_add_scalar(public_key, private_key, scalar);
    }
    end = clock();

    printf("%fus per keypair\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);

    printf("testing public key scalar addition performance: ");
    start = clock();
    for (i = 0; i < 10000; ++i) {
        ed25519_add_scalar(public_key, NULL, scalar);
    }
    end = clock();

    printf("%fus per key\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);

    printf("testing key exchange performance: ");
    start = clock();
    for (i = 0; i < 10000; ++i) {
        ed25519_key_exchange(shared_secret, other_public_key, private_key);
    }
    end = clock();

    printf("%fus per shared secret\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);

    return 0;
}
示例#16
0
/** Helper for tor_cert_create(): signs any 32 bytes, not just an ed25519
 * key.
 */
static tor_cert_t *
tor_cert_sign_impl(const ed25519_keypair_t *signing_key,
                      uint8_t cert_type,
                      uint8_t signed_key_type,
                      const uint8_t signed_key_info[32],
                      time_t now, time_t lifetime,
                      uint32_t flags)
{
  tor_cert_t *torcert = NULL;

  ed25519_cert_t *cert = ed25519_cert_new();
  cert->cert_type = cert_type;
  cert->exp_field = (uint32_t) CEIL_DIV(now + lifetime, 3600);
  cert->cert_key_type = signed_key_type;
  memcpy(cert->certified_key, signed_key_info, 32);

  if (flags & CERT_FLAG_INCLUDE_SIGNING_KEY) {
    ed25519_cert_extension_t *ext = ed25519_cert_extension_new();
    ext->ext_type = CERTEXT_SIGNED_WITH_KEY;
    memcpy(ext->un_signing_key, signing_key->pubkey.pubkey, 32);
    ed25519_cert_add_ext(cert, ext);
    ++cert->n_extensions;
  }

  const ssize_t alloc_len = ed25519_cert_encoded_len(cert);
  tor_assert(alloc_len > 0);
  uint8_t *encoded = tor_malloc(alloc_len);
  const ssize_t real_len = ed25519_cert_encode(encoded, alloc_len, cert);
  if (real_len < 0)
    goto err;
  tor_assert(real_len == alloc_len);
  tor_assert(real_len > ED25519_SIG_LEN);
  uint8_t *sig = encoded + (real_len - ED25519_SIG_LEN);
  tor_assert(tor_mem_is_zero((char*)sig, ED25519_SIG_LEN));

  ed25519_signature_t signature;
  if (ed25519_sign(&signature, encoded,
                   real_len-ED25519_SIG_LEN, signing_key)<0) {
    log_warn(LD_BUG, "Can't sign certificate");
    goto err;
  }
  memcpy(sig, signature.sig, ED25519_SIG_LEN);

  torcert = tor_cert_parse(encoded, real_len);
  if (! torcert) {
    log_warn(LD_BUG, "Generated a certificate we cannot parse");
    goto err;
  }

  if (tor_cert_checksig(torcert, &signing_key->pubkey, now) < 0) {
    log_warn(LD_BUG, "Generated a certificate whose signature we can't check");
    goto err;
  }

  tor_free(encoded);

  goto done;

 err:
  tor_cert_free(torcert);
  torcert = NULL;
 done:
  ed25519_cert_free(cert);
  tor_free(encoded);
  return torcert;
}
示例#17
0
static void
test_crypto_ed25519_fuzz_donna(void *arg)
{
  const unsigned iters = 1024;
  uint8_t msg[1024];
  unsigned i;
  (void)arg;

  tt_uint_op(iters, OP_EQ, sizeof(msg));
  crypto_rand((char*) msg, sizeof(msg));

  /* Fuzz Ed25519-donna vs ref10, alternating the implementation used to
   * generate keys/sign per iteration.
   */
  for (i = 0; i < iters; ++i) {
    const int use_donna = i & 1;
    uint8_t blinding[32];
    curve25519_keypair_t ckp;
    ed25519_keypair_t kp, kp_blind, kp_curve25519;
    ed25519_public_key_t pk, pk_blind, pk_curve25519;
    ed25519_signature_t sig, sig_blind;
    int bit = 0;

    crypto_rand((char*) blinding, sizeof(blinding));

    /* Impl. A:
     *  1. Generate a keypair.
     *  2. Blinded the keypair.
     *  3. Sign a message (unblinded).
     *  4. Sign a message (blinded).
     *  5. Generate a curve25519 keypair, and convert it to Ed25519.
     */
    ed25519_set_impl_params(use_donna);
    tt_int_op(0, OP_EQ, ed25519_keypair_generate(&kp, i&1));
    tt_int_op(0, OP_EQ, ed25519_keypair_blind(&kp_blind, &kp, blinding));
    tt_int_op(0, OP_EQ, ed25519_sign(&sig, msg, i, &kp));
    tt_int_op(0, OP_EQ, ed25519_sign(&sig_blind, msg, i, &kp_blind));

    tt_int_op(0, OP_EQ, curve25519_keypair_generate(&ckp, i&1));
    tt_int_op(0, OP_EQ, ed25519_keypair_from_curve25519_keypair(
            &kp_curve25519, &bit, &ckp));

    /* Impl. B:
     *  1. Validate the public key by rederiving it.
     *  2. Validate the blinded public key by rederiving it.
     *  3. Validate the unblinded signature (and test a invalid signature).
     *  4. Validate the blinded signature.
     *  5. Validate the public key (from Curve25519) by rederiving it.
     */
    ed25519_set_impl_params(!use_donna);
    tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pk, &kp.seckey));
    tt_mem_op(pk.pubkey, OP_EQ, kp.pubkey.pubkey, 32);

    tt_int_op(0, OP_EQ, ed25519_public_blind(&pk_blind, &kp.pubkey, blinding));
    tt_mem_op(pk_blind.pubkey, OP_EQ, kp_blind.pubkey.pubkey, 32);

    tt_int_op(0, OP_EQ, ed25519_checksig(&sig, msg, i, &pk));
    sig.sig[0] ^= 15;
    tt_int_op(-1, OP_EQ, ed25519_checksig(&sig, msg, sizeof(msg), &pk));

    tt_int_op(0, OP_EQ, ed25519_checksig(&sig_blind, msg, i, &pk_blind));

    tt_int_op(0, OP_EQ, ed25519_public_key_from_curve25519_public_key(
            &pk_curve25519, &ckp.pubkey, bit));
    tt_mem_op(pk_curve25519.pubkey, OP_EQ, kp_curve25519.pubkey.pubkey, 32);
  }

 done:
  ;
}
示例#18
0
文件: lisk.c 项目: trezor/trezor-mcu
void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) {
  lisk_update_raw_tx(node, msg);

  if (msg->has_transaction) {
    SHA256_CTX ctx;
    sha256_Init(&ctx);

    switch (msg->transaction.type) {
      case LiskTransactionType_Transfer:
        layoutRequireConfirmTx(msg->transaction.recipient_id,
                               msg->transaction.amount);
        break;
      case LiskTransactionType_RegisterDelegate:
        layoutRequireConfirmDelegateRegistration(&msg->transaction.asset);
        break;
      case LiskTransactionType_CastVotes:
        layoutRequireConfirmCastVotes(&msg->transaction.asset);
        break;
      case LiskTransactionType_RegisterSecondPassphrase:
        layoutLiskPublicKey(msg->transaction.asset.signature.public_key.bytes);
        break;
      case LiskTransactionType_RegisterMultisignatureAccount:
        layoutRequireConfirmMultisig(&msg->transaction.asset);
        break;
      default:
        fsm_sendFailure(FailureType_Failure_DataError,
                        _("Invalid transaction type"));
        layoutHome();
        break;
    }
    if (!protectButton((msg->transaction.type ==
                                LiskTransactionType_RegisterSecondPassphrase
                            ? ButtonRequestType_ButtonRequest_PublicKey
                            : ButtonRequestType_ButtonRequest_SignTx),
                       false)) {
      fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled");
      layoutHome();
      return;
    }

    layoutRequireConfirmFee(msg->transaction.fee, msg->transaction.amount);
    if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
      fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled");
      layoutHome();
      return;
    }
    layoutProgressSwipe(_("Signing transaction"), 0);

    sha256_Update(&ctx, (const uint8_t *)&msg->transaction.type, 1);

    lisk_hashupdate_uint32(&ctx, msg->transaction.timestamp);

    sha256_Update(&ctx, msg->transaction.sender_public_key.bytes, 32);

    if (msg->transaction.has_requester_public_key) {
      sha256_Update(&ctx, msg->transaction.requester_public_key.bytes,
                    msg->transaction.requester_public_key.size);
    }

    uint64_t recipient_id = 0;
    if (msg->transaction.has_recipient_id &&
        msg->transaction.recipient_id[0] != 0) {
      // parse integer from lisk address ("123L" -> 123)
      for (size_t i = 0; i < strlen(msg->transaction.recipient_id) - 1; i++) {
        if (msg->transaction.recipient_id[i] < '0' ||
            msg->transaction.recipient_id[i] > '9') {
          fsm_sendFailure(FailureType_Failure_DataError,
                          _("Invalid recipient_id"));
          layoutHome();
          return;
        }
        recipient_id *= 10;
        recipient_id += (msg->transaction.recipient_id[i] - '0');
      }
    }
    lisk_hashupdate_uint64_be(&ctx, recipient_id);
    lisk_hashupdate_uint64_le(&ctx, msg->transaction.amount);

    lisk_hashupdate_asset(&ctx, msg->transaction.type, &msg->transaction.asset);

    // if signature exist calculate second signature
    if (msg->transaction.has_signature) {
      sha256_Update(&ctx, msg->transaction.signature.bytes,
                    msg->transaction.signature.size);
    }

    uint8_t hash[32];
    sha256_Final(&ctx, hash);
    ed25519_sign(hash, 32, node->private_key, &node->public_key[1],
                 resp->signature.bytes);

    resp->has_signature = true;
    resp->signature.size = 64;
  }
}