Skip to content
Open
Show file tree
Hide file tree
Changes from 11 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
22 changes: 22 additions & 0 deletions src/hathor.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,28 @@ 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
* Length of script_hash buffer
* @param[out] out
* Pointer to output byte buffer for address.
* @param[in] outlen
* Length of output byte buffer.
* @return 0 on success
*
*/
int address_from_script_hash(const uint8_t *script_hash,
size_t script_hash_len,
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