Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS)
ifeq ($(NETWORK),mainnet)
APPNAME = "Hathor"
P2PKH_VERSION_BYTE = 0x28
P2SH_VERSION_BYTE = 0x64
else
APPNAME = "Hathor testnet"
P2PKH_VERSION_BYTE = 0x49
P2SH_VERSION_BYTE = 0x87
endif
DEFINES += P2PKH_VERSION_BYTE=$(P2PKH_VERSION_BYTE)
DEFINES += P2SH_VERSION_BYTE=$(P2SH_VERSION_BYTE)
$(info NETWORK=$(NETWORK))

APPVERSION_M = 1
Expand Down
6 changes: 6 additions & 0 deletions src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,9 @@
* Any other means that index-1 is the index of token on the token array
*/
#define TOKEN_DATA_INDEX_MASK 0x7Fu

/**
* Maximum length of a data script
* 150 max data + 2 opcodes + 1 byte of length (OP_PUSHDATA1 length ...data OP_CHECKSIG)
*/
#define MAX_DATA_SCRIPT_LEN 153
24 changes: 16 additions & 8 deletions src/handler/sign_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
#include "../token/token_parser.h"
#include "../token/types.h"

/**
* Helper to clean global context of any sign data
*/
void clean_globals() {
explicit_bzero(&G_context, sizeof(G_context));
explicit_bzero(&G_token_symbols, sizeof(G_token_symbols));
}

/**
* Verify that the given output address (pubkey hash) is ours and
* may be generated from by deriving on the given bip32 path
Expand All @@ -32,7 +40,7 @@ bool verify_change(change_output_info_t *info, tx_output_t output) {
uint8_t chain_code[32];
int error = 0;

if (info == NULL) {
if ((info == NULL) || (output.script.type != SCRIPT_P2PKH)) {
return false;
}

Expand All @@ -51,7 +59,7 @@ bool verify_change(change_output_info_t *info, tx_output_t output) {
}

// 0 means equals
return memcmp(hash, output.pubkey_hash, PUBKEY_HASH_LEN) == 0;
return memcmp(hash, output.script.hash, PUBKEY_HASH_LEN) == 0;
}

/**
Expand Down Expand Up @@ -469,7 +477,7 @@ bool receive_data(buffer_t *cdata, uint8_t chunk) {
if (chunk == 0) {
if (G_context.state == STATE_RECV_DATA) {
// sent first chunk twice? return error
explicit_bzero(&G_context, sizeof(G_context));
clean_globals();
THROW(SW_BAD_STATE);
}

Expand Down Expand Up @@ -501,7 +509,7 @@ bool receive_data(buffer_t *cdata, uint8_t chunk) {

switch (decode_elements()) {
case TX_STATE_ERR:
explicit_bzero(&G_context, sizeof(G_context));
clean_globals();
io_send_sw(SW_INVALID_TX);
ui_menu_main();
return true;
Expand Down Expand Up @@ -532,7 +540,7 @@ int handler_sign_tx(buffer_t *cdata, sing_tx_stage_e stage, uint8_t chunk) {
switch (stage) {
case SIGN_TX_STAGE_DONE:
// Caller is done with this request, cleanup and return SW_OK.
explicit_bzero(&G_context, sizeof(G_context));
clean_globals();
G_context.state = STATE_NONE;
ui_menu_main();
return io_send_sw(SW_OK);
Expand All @@ -556,22 +564,22 @@ int handler_sign_tx(buffer_t *cdata, sing_tx_stage_e stage, uint8_t chunk) {
// Caller will pass the transaction and metadata needed to approve and sign.
if (G_context.state == STATE_APPROVED) {
// cannot receive more data after user approval
explicit_bzero(&G_context, sizeof(G_context));
clean_globals();
ui_menu_main();
return io_send_sw(SW_BAD_STATE);
}
if (chunk > 0 && G_context.state != STATE_RECV_DATA) {
// Some stage before this failed but caller sent data anyway
// reject with SW_BAD_STATE
explicit_bzero(&G_context, sizeof(G_context));
clean_globals();
ui_menu_main();
return io_send_sw(SW_BAD_STATE);
}
if (!receive_data(cdata, chunk)) return -1;
break;

default:
explicit_bzero(&G_context, sizeof(G_context));
clean_globals();
ui_menu_main();
return io_send_sw(SW_BAD_STATE);
}
Expand Down
30 changes: 22 additions & 8 deletions src/hathor.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,18 @@ int compress_public_key(uint8_t *value, size_t len) {
return 0;
}

int address_from_pubkey_hash(const uint8_t *public_key_hash,
const size_t public_key_hash_len,
uint8_t *out,
size_t outlen) {
int address_from_hash(const uint8_t *hash,
const size_t hashlen,
const uint8_t version_byte,
uint8_t *out,
size_t outlen) {
uint8_t buffer[32] = {0};
if ((public_key_hash == NULL) || (out == NULL) || (public_key_hash_len < PUBKEY_HASH_LEN) ||
(outlen < 25)) {
if ((hash == NULL) || (out == NULL) || (hashlen < PUBKEY_HASH_LEN) || (outlen < 25)) {
return 1;
}
// prepend version
out[0] = P2PKH_VERSION_BYTE;
memmove(out + 1, public_key_hash, PUBKEY_HASH_LEN);
out[0] = version_byte;
memmove(out + 1, hash, PUBKEY_HASH_LEN);
// sha256d of above
if (sha256d(out, 21, buffer, 32)) {
return 1;
Expand All @@ -88,6 +88,20 @@ int address_from_pubkey_hash(const uint8_t *public_key_hash,
return 0;
}

int address_from_script_hash(const uint8_t *script_hash,
const size_t script_hash_len,
uint8_t *out,
size_t outlen) {
return address_from_hash(script_hash, script_hash_len, P2SH_VERSION_BYTE, out, outlen);
}

int address_from_pubkey_hash(const uint8_t *public_key_hash,
const size_t public_key_hash_len,
uint8_t *out,
size_t outlen) {
return address_from_hash(public_key_hash, public_key_hash_len, P2PKH_VERSION_BYTE, out, outlen);
}

int address_from_pubkey(cx_ecfp_public_key_t *public_key, uint8_t *out, size_t outlen) {
uint8_t buffer[PUBKEY_HASH_LEN] = {0};

Expand Down
19 changes: 19 additions & 0 deletions src/hathor.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ int hash160(uint8_t *in, size_t inlen, uint8_t *out, size_t outlen);
*/
int address_from_pubkey(cx_ecfp_public_key_t *public_key, uint8_t *out, size_t outlen);

/**
* Convert script hash160 to address.
*
* address = version byte + script_hash + first 4 bytes of sha256d(hash)
*
* @param[in] script_hash
* Script hash160
* An array of at least 20 bytes (uint8_t).
* @param[in] script_hash_len
* Lenght of script_hash buffer
* @param[out] out
* Pointer to output byte buffer for address.
* @param[in] outlen
* Lenght of output byte buffer.
* @return 0 on success
*
*/
int address_from_script_hash(const uint8_t *hash, size_t hashlen, uint8_t *out, size_t outlen);

/**
* Convert public key hash160 to address.
*
Expand Down
19 changes: 14 additions & 5 deletions src/transaction/deserialize.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <stdbool.h> // bool
#include <string.h> // memset, explicit_bzero, memmove
#include <string.h> // memmove

#include "deserialize.h"

Expand All @@ -9,6 +9,7 @@
#include "constants.h"
#include "../common/buffer.h"
#include "types.h"
#include "script.h"

/**
* XXX: considering only P2PKH, without timelock
Expand Down Expand Up @@ -76,10 +77,18 @@ size_t parse_output(uint8_t *in, size_t inlen, tx_output_t *output) {
if (!(buffer_read_u8(&buf, &output->token_data) && buffer_read_u16(&buf, &script_len, BE))) {
THROW(TX_STATE_READY);
}
// validate script and extract pubkey hash
validate_p2pkh_script(&buf, script_len);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find where you moved this validation to. Don't you need it anymore?

// validate already asserted the length for this extraction
memmove(output->pubkey_hash, buf.ptr + buf.offset + 3, PUBKEY_HASH_LEN);

// parse script
uint16_t err = parse_output_script(&buf, script_len, &output->script);
if (err == ERR_MORE_DATA_REQUIRED) {
// More data is required to parse the script
THROW(TX_STATE_READY);
}
if (err) {
PRINTF("Error parsing output script: %d\n", err);
THROW(err);
}

if (!buffer_seek_cur(&buf, script_len)) {
THROW(SW_TX_PARSING_FAIL);
}
Expand Down
6 changes: 6 additions & 0 deletions src/transaction/opcodes.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#ifndef OPCODES_H
#define OPCODES_H

#define OP_PUSHDATA1 0x4C

#define OP_GREATERTHAN_TIMESTAMP 0x6F

#define OP_DUP 0x76

#define OP_EQUALVERIFY 0x88

#define OP_EQUAL 0x87

#define OP_HASH160 0xA9

#define OP_CHECKSIG 0xAC
Expand Down
Loading