diff --git a/c/ckb_identity.h b/c/ckb_identity.h index be8ba60..dbdb1c1 100644 --- a/c/ckb_identity.h +++ b/c/ckb_identity.h @@ -1,17 +1,21 @@ #ifndef CKB_C_STDLIB_CKB_IDENTITY_H_ #define CKB_C_STDLIB_CKB_IDENTITY_H_ - #include #include #include "ckb_consts.h" #include "ckb_keccak256.h" +#include "ripemd160.h" +#include "sha256.h" #define CKB_IDENTITY_LEN 21 +#define AUTH160_SIZE 20 +#define SHA256_SIZE 32 #define RECID_INDEX 64 #define ONE_BATCH_SIZE 32768 #define PUBKEY_SIZE 33 -#define UNCOMPRESSED_PUBKEY_SIZE 65 +#define SECP256K1_PUBKEY_SIZE 33 +#define UNCOMPRESSED_SECP256K1_PUBKEY_SIZE 65 #define MAX_WITNESS_SIZE 32768 #define BLAKE2B_BLOCK_SIZE 32 @@ -19,6 +23,15 @@ #define SECP256K1_SIGNATURE_SIZE 65 #define SECP256K1_MESSAGE_SIZE 32 #define MAX_PREIMAGE_SIZE 1024 +#define MESSAGE_HEX_LEN 64 + +const char BTC_PREFIX[] = "CKB (Bitcoin Layer) transaction: 0x"; +// BTC_PREFIX_LEN = 35 +const size_t BTC_PREFIX_LEN = sizeof(BTC_PREFIX) - 1; + +const char COMMON_PREFIX[] = "CKB transaction: 0x"; +// COMMON_PREFIX_LEN = 17 +const size_t COMMON_PREFIX_LEN = sizeof(COMMON_PREFIX) - 1; enum CkbIdentityErrorCode { ERROR_IDENTITY_ARGUMENTS_LEN = -1, @@ -34,6 +47,9 @@ enum CkbIdentityErrorCode { ERROR_IDENTITY_LOCK_SCRIPT_HASH_NOT_FOUND = 70, ERROR_IDENTITY_WRONG_ARGS, ERROR_INVALID_PREIMAGE, + ERROR_MISMATCHED, + ERROR_INVALID_ARG, + ERROR_WRONG_STATE }; typedef struct CkbIdentityType { @@ -53,6 +69,7 @@ enum IdentityFlagsType { IdentityFlagsDogecoin = 5, IdentityCkbMultisig = 6, + IdentityFlagsEthereumDisplaying = 18, IdentityFlagsOwnerLock = 0xFC, IdentityFlagsExec = 0xFD, IdentityFlagsDl = 0xFE, @@ -66,6 +83,15 @@ typedef int (*validate_signature_t)(void *prefilled_data, const uint8_t *sig, typedef int (*convert_msg_t)(const uint8_t *msg, size_t msg_len, uint8_t *new_msg, size_t new_msg_len); +static void bin_to_hex(const uint8_t *source, uint8_t *dest, size_t len) { + const static uint8_t HEX_TABLE[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + for (int i = 0; i < len; i++) { + dest[i * 2] = HEX_TABLE[source[i] >> 4]; + dest[i * 2 + 1] = HEX_TABLE[source[i] & 0x0F]; + } +} + static int extract_witness_lock(uint8_t *witness, uint64_t len, mol_seg_t *lock_bytes_seg) { if (len < 20) { @@ -108,6 +134,19 @@ int load_and_hash_witness(blake2b_state *ctx, size_t start, size_t index, return CKB_SUCCESS; } +void bitcoin_hash160(const uint8_t *data, size_t size, uint8_t *output) { + unsigned char temp[SHA256_SIZE]; + SHA256_CTX sha256_ctx; + sha256_init(&sha256_ctx); + sha256_update(&sha256_ctx, data, size); + sha256_final(&sha256_ctx, temp); + + ripemd160_state ripe160_ctx; + ripemd160_init(&ripe160_ctx); + ripemd160_update(&ripe160_ctx, temp, SHA256_SIZE); + ripemd160_finalize(&ripe160_ctx, output); +} + static int _ckb_recover_secp256k1_pubkey(const uint8_t *sig, size_t sig_len, const uint8_t *msg, size_t msg_len, uint8_t *out_pubkey, @@ -144,10 +183,10 @@ static int _ckb_recover_secp256k1_pubkey(const uint8_t *sig, size_t sig_len, unsigned int flag = SECP256K1_EC_COMPRESSED; if (compressed) { - *out_pubkey_size = PUBKEY_SIZE; + *out_pubkey_size = SECP256K1_PUBKEY_SIZE; flag = SECP256K1_EC_COMPRESSED; } else { - *out_pubkey_size = UNCOMPRESSED_PUBKEY_SIZE; + *out_pubkey_size = UNCOMPRESSED_SECP256K1_PUBKEY_SIZE; flag = SECP256K1_EC_UNCOMPRESSED; } if (secp256k1_ec_pubkey_serialize(&context, out_pubkey, out_pubkey_size, @@ -165,8 +204,8 @@ int validate_signature_secp256k1(void *prefilled_data, const uint8_t *sig, if (*output_len < BLAKE160_SIZE) { return ERROR_IDENTITY_ARGUMENTS_LEN; } - uint8_t out_pubkey[PUBKEY_SIZE]; - size_t out_pubkey_size = PUBKEY_SIZE; + uint8_t out_pubkey[SECP256K1_PUBKEY_SIZE]; + size_t out_pubkey_size = SECP256K1_PUBKEY_SIZE; ret = _ckb_recover_secp256k1_pubkey(sig, sig_len, msg, msg_len, out_pubkey, &out_pubkey_size, true); if (ret != 0) return ret; @@ -182,16 +221,15 @@ int validate_signature_secp256k1(void *prefilled_data, const uint8_t *sig, return ret; } -int validate_signature_secp256k1_pw(void *prefilled_data, const uint8_t *sig, - size_t sig_len, const uint8_t *msg, - size_t msg_len, uint8_t *output, - size_t *output_len) { +int validate_signature_eth(void *prefilled_data, const uint8_t *sig, + size_t sig_len, const uint8_t *msg, size_t msg_len, + uint8_t *output, size_t *output_len) { int ret = 0; if (*output_len < BLAKE160_SIZE) { return ERROR_IDENTITY_ARGUMENTS_LEN; } - uint8_t out_pubkey[UNCOMPRESSED_PUBKEY_SIZE]; - size_t out_pubkey_size = UNCOMPRESSED_PUBKEY_SIZE; + uint8_t out_pubkey[UNCOMPRESSED_SECP256K1_PUBKEY_SIZE]; + size_t out_pubkey_size = UNCOMPRESSED_SECP256K1_PUBKEY_SIZE; ret = _ckb_recover_secp256k1_pubkey(sig, sig_len, msg, msg_len, out_pubkey, &out_pubkey_size, false); if (ret != 0) return ret; @@ -208,6 +246,134 @@ int validate_signature_secp256k1_pw(void *prefilled_data, const uint8_t *sig, return ret; } +// Refer to: https://en.bitcoin.it/wiki/BIP_0137 +int get_btc_recid(uint8_t d, bool *compressed, bool *p2sh_hash) { + *compressed = true; + *p2sh_hash = false; + if (d >= 27 && d <= 30) { // P2PKH uncompressed + *compressed = false; + return d - 27; + } else if (d >= 31 && d <= 34) { // P2PKH compressed + return d - 31; + } else if (d >= 35 && d <= 38) { // Segwit P2SH + *p2sh_hash = true; + return d - 35; + } else if (d >= 39 && d <= 42) { // Segwit Bech32 + return d - 39; + } else { + return -1; + } +} + +static int _recover_secp256k1_pubkey_btc(const uint8_t *sig, size_t sig_len, + const uint8_t *msg, size_t msg_len, + uint8_t *out_pubkey, + size_t *out_pubkey_size) { + int ret = 0; + + if (sig_len != SECP256K1_SIGNATURE_SIZE) { + return ERROR_INVALID_ARG; + } + if (msg_len != SECP256K1_MESSAGE_SIZE) { + return ERROR_INVALID_ARG; + } + bool compressed = true; + bool p2sh_hash = false; + int recid = get_btc_recid(sig[0], &compressed, &p2sh_hash); + if (recid == -1) { + return ERROR_INVALID_ARG; + } + + secp256k1_context context; + uint8_t secp_data[CKB_SECP256K1_DATA_SIZE]; + ret = ckb_secp256k1_custom_verify_only_initialize(&context, secp_data); + if (ret != 0) { + return ret; + } + + secp256k1_ecdsa_recoverable_signature signature; + + if (secp256k1_ecdsa_recoverable_signature_parse_compact( + &context, &signature, sig + 1, recid) == 0) { + return ERROR_WRONG_STATE; + } + + /* Recover pubkey */ + secp256k1_pubkey pubkey; + if (secp256k1_ecdsa_recover(&context, &pubkey, &signature, msg) != 1) { + return ERROR_WRONG_STATE; + } + + unsigned int flag = SECP256K1_EC_COMPRESSED; + if (compressed) { + *out_pubkey_size = SECP256K1_PUBKEY_SIZE; + flag = SECP256K1_EC_COMPRESSED; + if (secp256k1_ec_pubkey_serialize(&context, out_pubkey, out_pubkey_size, + &pubkey, flag) != 1) { + return ERROR_WRONG_STATE; + } + + if (p2sh_hash) { + bitcoin_hash160(out_pubkey, *out_pubkey_size, out_pubkey + 2); + + out_pubkey[0] = 0; + out_pubkey[1] = 20; // RIPEMD160 size + *out_pubkey_size = 22; + } + } else { + *out_pubkey_size = UNCOMPRESSED_SECP256K1_PUBKEY_SIZE; + flag = SECP256K1_EC_UNCOMPRESSED; + if (secp256k1_ec_pubkey_serialize(&context, out_pubkey, out_pubkey_size, + &pubkey, flag) != 1) { + return ERROR_WRONG_STATE; + } + } + return ret; +} + +int validate_signature_btc(void *prefilled_data, const uint8_t *sig, + size_t sig_len, const uint8_t *msg, size_t msg_len, + uint8_t *output, size_t *output_len) { + int err = 0; + if (*output_len < AUTH160_SIZE) { + return ERROR_INVALID_ARG; + } + uint8_t out_pubkey[UNCOMPRESSED_SECP256K1_PUBKEY_SIZE]; + size_t out_pubkey_size = UNCOMPRESSED_SECP256K1_PUBKEY_SIZE; + err = _recover_secp256k1_pubkey_btc(sig, sig_len, msg, msg_len, out_pubkey, + &out_pubkey_size); + if (err) return err; + unsigned char temp[AUTH160_SIZE]; + bitcoin_hash160(out_pubkey, out_pubkey_size, temp); + memcpy(output, temp, AUTH160_SIZE); + *output_len = AUTH160_SIZE; + + return 0; +} + +int validate_signature_eos(void *prefilled_data, const uint8_t *sig, + size_t sig_len, const uint8_t *msg, size_t msg_len, + uint8_t *output, size_t *output_len) { + int err = 0; + if (*output_len < AUTH160_SIZE) { + return ERROR_INVALID_ARG; + } + uint8_t out_pubkey[UNCOMPRESSED_SECP256K1_PUBKEY_SIZE]; + size_t out_pubkey_size = UNCOMPRESSED_SECP256K1_PUBKEY_SIZE; + err = _recover_secp256k1_pubkey_btc(sig, sig_len, msg, msg_len, out_pubkey, + &out_pubkey_size); + if (err) return err; + + blake2b_state ctx; + blake2b_init(&ctx, BLAKE2B_BLOCK_SIZE); + blake2b_update(&ctx, out_pubkey, out_pubkey_size); + blake2b_final(&ctx, out_pubkey, BLAKE2B_BLOCK_SIZE); + + memcpy(output, out_pubkey, AUTH160_SIZE); + *output_len = AUTH160_SIZE; + return err; +} + int generate_sighash_all(uint8_t *msg, size_t msg_len) { int ret; uint64_t len = 0; @@ -308,8 +474,8 @@ static int _ckb_convert_copy(const uint8_t *msg, size_t msg_len, return 0; } -static int _ckb_convert_keccak256_hash(const uint8_t *msg, size_t msg_len, - uint8_t *new_msg, size_t new_msg_len) { +static int convert_eth_message(const uint8_t *msg, size_t msg_len, + uint8_t *new_msg, size_t new_msg_len) { if (msg_len != new_msg_len || msg_len != BLAKE2B_BLOCK_SIZE) return ERROR_IDENTITY_ARGUMENTS_LEN; @@ -326,6 +492,35 @@ static int _ckb_convert_keccak256_hash(const uint8_t *msg, size_t msg_len, return 0; } +static int convert_eth_message_displaying(const uint8_t *msg, size_t msg_len, + uint8_t *new_msg, + size_t new_msg_len) { + if (msg_len != new_msg_len || msg_len != BLAKE2B_BLOCK_SIZE) + return ERROR_IDENTITY_ARGUMENTS_LEN; + + uint8_t hex_msg[MESSAGE_HEX_LEN] = {0}; + bin_to_hex(msg, hex_msg, 32); + + SHA3_CTX sha3_ctx; + keccak_init(&sha3_ctx); + /* personal_sign ethereum prefix \u0019Ethereum Signed Message:\n */ + unsigned char eth_prefix[28]; + eth_prefix[0] = 0x19; + memcpy(eth_prefix + 1, "Ethereum Signed Message:\n", 0x19); + // COMMON_PREFIX_LEN + MESSAGE_HEX_LEN -> 19 + 64 = 83 + memcpy(eth_prefix + 1 + 0x19, "83", 2); + + keccak_update(&sha3_ctx, eth_prefix, 28); + // + // Displaying message on wallet like below: + // CKB transaction: {txhash} + // + keccak_update(&sha3_ctx, (unsigned char *)COMMON_PREFIX, COMMON_PREFIX_LEN); + keccak_update(&sha3_ctx, (unsigned char *)hex_msg, MESSAGE_HEX_LEN); + keccak_final(&sha3_ctx, new_msg); + return 0; +} + int verify_sighash_all(uint8_t *pubkey_hash, uint8_t *sig, uint32_t sig_len, validate_signature_t func, convert_msg_t convert) { int ret = 0; @@ -352,6 +547,105 @@ int verify_sighash_all(uint8_t *pubkey_hash, uint8_t *sig, uint32_t sig_len, return 0; } +int convert_btc_message(const uint8_t *msg, size_t msg_len, uint8_t *new_msg, + size_t new_msg_len) { + if (msg_len != new_msg_len || msg_len != SHA256_SIZE) + return ERROR_INVALID_ARG; + const char magic[25] = "Bitcoin Signed Message:\n"; + const int8_t magic_len = 24; + const char *prefix = BTC_PREFIX; + size_t prefix_len = BTC_PREFIX_LEN; + // + // Displaying message on wallet like below: + // Bitcoin layer (CKB) transaction: {txhash} + // + uint8_t hex_msg[MESSAGE_HEX_LEN]; + bin_to_hex(msg, hex_msg, 32); + + // Signature message: + // magic_len magic prefix_len+MESSAGE_HEX_LEN prefix message_hex + // 1 magic_len 1 prefix_len 64 + uint8_t data[magic_len + 2 + MESSAGE_HEX_LEN + prefix_len]; + data[0] = magic_len; + memcpy(data + 1, magic, magic_len); + + data[magic_len + 1] = MESSAGE_HEX_LEN + prefix_len; + memcpy(data + magic_len + 2, prefix, prefix_len); + memcpy(data + magic_len + 2 + prefix_len, hex_msg, MESSAGE_HEX_LEN); + + SHA256_CTX sha256_ctx; + sha256_init(&sha256_ctx); + sha256_update(&sha256_ctx, data, sizeof(data)); + sha256_final(&sha256_ctx, new_msg); + + SHA256_CTX sha256_ctx2; + sha256_init(&sha256_ctx2); + sha256_update(&sha256_ctx2, new_msg, SHA256_SIZE); + sha256_final(&sha256_ctx2, new_msg); + return 0; +} + +int convert_copy(const uint8_t *msg, size_t msg_len, uint8_t *new_msg, + size_t new_msg_len) { + if (msg_len != new_msg_len || msg_len != BLAKE2B_BLOCK_SIZE) + return ERROR_INVALID_ARG; + memcpy(new_msg, msg, msg_len); + return 0; +} + +int convert_doge_message(const uint8_t *msg, size_t msg_len, uint8_t *new_msg, + size_t new_msg_len) { + if (msg_len != new_msg_len || msg_len != SHA256_SIZE) + return ERROR_INVALID_ARG; + const char magic[26] = "Dogecoin Signed Message:\n"; + const int8_t magic_len = 25; + + uint8_t temp[MESSAGE_HEX_LEN]; + bin_to_hex(msg, temp, 32); + + // len of magic + magic string + len of message, size is 26 Byte + uint8_t new_magic[magic_len + 2]; + new_magic[0] = magic_len; // MESSAGE_MAGIC length + memcpy(&new_magic[1], magic, magic_len); + new_magic[magic_len + 1] = MESSAGE_HEX_LEN; // message length + + /* Calculate signature message */ + uint8_t temp2[magic_len + 2 + MESSAGE_HEX_LEN]; + uint32_t temp2_size = magic_len + 2 + MESSAGE_HEX_LEN; + memcpy(temp2, new_magic, magic_len + 2); + memcpy(temp2 + magic_len + 2, temp, MESSAGE_HEX_LEN); + + SHA256_CTX sha256_ctx; + sha256_init(&sha256_ctx); + sha256_update(&sha256_ctx, temp2, temp2_size); + sha256_final(&sha256_ctx, new_msg); + + SHA256_CTX sha256_ctx2; + sha256_init(&sha256_ctx2); + sha256_update(&sha256_ctx2, new_msg, SHA256_SIZE); + sha256_final(&sha256_ctx2, new_msg); + return 0; +} + +int convert_tron_message(const uint8_t *msg, size_t msg_len, uint8_t *new_msg, + size_t new_msg_len) { + if (msg_len != new_msg_len || msg_len != BLAKE2B_BLOCK_SIZE) + return ERROR_INVALID_ARG; + + SHA3_CTX sha3_ctx; + keccak_init(&sha3_ctx); + /* ASCII code for tron prefix \x19TRON Signed Message:\n32, refer + * https://github.com/tronprotocol/tips/issues/104 */ + unsigned char tron_prefix[24]; + tron_prefix[0] = 0x19; + memcpy(tron_prefix + 1, "TRON Signed Message:\n32", 23); + + keccak_update(&sha3_ctx, tron_prefix, 24); + keccak_update(&sha3_ctx, (unsigned char *)msg, 32); + keccak_final(&sha3_ctx, new_msg); + return 0; +} + bool is_lock_script_hash_present(uint8_t *lock_script_hash) { int err = 0; size_t i = 0; @@ -518,8 +812,8 @@ int verify_multisig(const uint8_t *lock_bytes, size_t lock_bytes_len, return ERROR_WITNESS_SIZE; } - // Perform hash check of the `multisig_script` part, notice the signature part - // is not included here. + // Perform hash check of the `multisig_script` part, notice the signature + // part is not included here. blake2b_state blake2b_ctx; blake2b_init(&blake2b_ctx, BLAKE2B_BLOCK_SIZE); blake2b_update(&blake2b_ctx, lock_bytes, multisig_script_len); @@ -531,7 +825,8 @@ int verify_multisig(const uint8_t *lock_bytes, size_t lock_bytes_len, // Verify threshold signatures, threshold is a uint8_t, at most it is // 255, meaning this array will definitely have a reasonable upper bound. - // Also this code uses C99's new feature to allocate a variable length array. + // Also this code uses C99's new feature to allocate a variable length + // array. uint8_t used_signatures[pubkeys_cnt]; memset(used_signatures, 0, pubkeys_cnt); @@ -552,8 +847,8 @@ int verify_multisig(const uint8_t *lock_bytes, size_t lock_bytes_len, secp256k1_ecdsa_recoverable_signature signature; size_t signature_offset = multisig_script_len + i * SIGNATURE_SIZE; if (secp256k1_ecdsa_recoverable_signature_parse_compact( - &context, &signature, &lock_bytes[signature_offset], - lock_bytes[signature_offset + RECID_INDEX]) == 0) { + &context, &signature, &lock_bytes[signature_offset], + lock_bytes[signature_offset + RECID_INDEX]) == 0) { return ERROR_SECP_PARSE_SIGNATURE; } @@ -591,19 +886,19 @@ int verify_multisig(const uint8_t *lock_bytes, size_t lock_bytes_len, break; } - // If the signature doesn't match any of the provided public key, the script - // will exit with an error. + // If the signature doesn't match any of the provided public key, the + // script will exit with an error. if (matched != 1) { return ERROR_VERIFICATION; } } - // The above scheme just ensures that a *threshold* number of signatures have - // successfully been verified, and they all come from the provided public - // keys. However, the multisig script might also require some numbers of - // public keys to always be signed for the script to pass verification. This - // is indicated via the *required_first_n* flag. Here we also checks to see - // that this rule is also satisfied. + // The above scheme just ensures that a *threshold* number of signatures + // have successfully been verified, and they all come from the provided + // public keys. However, the multisig script might also require some numbers + // of public keys to always be signed for the script to pass verification. + // This is indicated via the *required_first_n* flag. Here we also checks to + // see that this rule is also satisfied. for (size_t i = 0; i < require_first_n; i++) { if (used_signatures[i] != 1) { return ERROR_VERIFICATION; @@ -613,7 +908,6 @@ int verify_multisig(const uint8_t *lock_bytes, size_t lock_bytes_len, return 0; } - static uint8_t *g_identity_code_buffer = NULL; static uint32_t g_identity_code_size = 0; @@ -629,14 +923,42 @@ int ckb_verify_identity(CkbIdentityType *id, uint8_t *sig, uint32_t sig_size, if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { return ERROR_IDENTITY_WRONG_ARGS; } - return verify_sighash_all(id->id, sig, sig_size, - validate_signature_secp256k1_pw, - _ckb_convert_keccak256_hash); + return verify_sighash_all(id->id, sig, sig_size, validate_signature_eth, + convert_eth_message); + } else if (id->flags == IdentityFlagsEthereumDisplaying) { + if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { + return ERROR_IDENTITY_WRONG_ARGS; + } + return verify_sighash_all(id->id, sig, sig_size, validate_signature_eth, + convert_eth_message_displaying); + } else if (id->flags == IdentityFlagsEos) { + if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { + return ERROR_IDENTITY_WRONG_ARGS; + } + return verify_sighash_all(id->id, sig, sig_size, validate_signature_eos, + convert_copy); + } else if (id->flags == IdentityFlagsTron) { + if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { + return ERROR_IDENTITY_WRONG_ARGS; + } + return verify_sighash_all(id->id, sig, sig_size, validate_signature_eth, + convert_tron_message); + } else if (id->flags == IdentityFlagsBitcoin) { + if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { + return ERROR_IDENTITY_WRONG_ARGS; + } + return verify_sighash_all(id->id, sig, sig_size, validate_signature_btc, + convert_btc_message); + } else if (id->flags == IdentityFlagsDogecoin) { + if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { + return ERROR_IDENTITY_WRONG_ARGS; + } + return verify_sighash_all(id->id, sig, sig_size, validate_signature_btc, + convert_doge_message); } else if (id->flags == IdentityCkbMultisig) { uint8_t msg[BLAKE2B_BLOCK_SIZE]; int ret = generate_sighash_all(msg, sizeof(msg)); - if (ret != 0) - return ret; + if (ret != 0) return ret; return verify_multisig(sig, sig_size, msg, id->id); } else if (id->flags == IdentityFlagsOwnerLock) { if (is_lock_script_hash_present(id->id)) { diff --git a/c/conversion.h b/c/conversion.h new file mode 100644 index 0000000..5032d4d --- /dev/null +++ b/c/conversion.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014-2018 The Bitcoin Core developers + * Distributed under the MIT software license, see the accompanying + * file COPYING or http://www.opensource.org/licenses/mit-license.php. + * + * only used on little endian + */ + +#ifndef CONVERSION_H +#define CONVERSION_H + +#include +#include + +uint32_t static inline bswap_32(uint32_t x) { + return (((uint32_t)(x)&0xff000000) >> 24) | + (((uint32_t)(x)&0x00ff0000) >> 8) | (((uint32_t)(x)&0x0000ff00) << 8) | + (((uint32_t)(x)&0x000000ff) << 24); +} + +uint64_t static inline bswap_64(uint64_t x) { + return (((uint64_t)(x)&0xff00000000000000ull) >> 56) | + (((uint64_t)(x)&0x00ff000000000000ull) >> 40) | + (((uint64_t)(x)&0x0000ff0000000000ull) >> 24) | + (((uint64_t)(x)&0x000000ff00000000ull) >> 8) | + (((uint64_t)(x)&0x00000000ff000000ull) << 8) | + (((uint64_t)(x)&0x0000000000ff0000ull) << 24) | + (((uint64_t)(x)&0x000000000000ff00ull) << 40) | + (((uint64_t)(x)&0x00000000000000ffull) << 56); +} + +uint32_t static inline le32toh_(uint32_t x) { return x; } + +uint32_t static inline htole32_(uint32_t x) { return x; } + +uint32_t static inline be32toh_(uint32_t x) { return bswap_32(x); } + +uint32_t static inline htobe32_(uint32_t x) { return bswap_32(x); } + +uint64_t static inline le64toh_(uint64_t x) { return x; } + +uint64_t static inline htole64_(uint64_t x) { return x; } + +uint32_t static inline be64toh_(uint64_t x) { return bswap_64(x); } + +uint64_t static inline htobe64_(uint64_t x) { return bswap_64(x); } + +uint32_t static inline ReadLE32(const unsigned char* ptr) { + uint32_t x; + memcpy((char*)&x, ptr, 4); + return le32toh_(x); +} + +void static inline WriteLE32(unsigned char* ptr, uint32_t x) { + uint32_t v = htole32_(x); + memcpy(ptr, (char*)&v, 4); +} + +uint32_t static inline ReadBE32(const unsigned char* ptr) { + uint32_t x; + memcpy((char*)&x, ptr, 4); + return be32toh_(x); +} + +void static inline WriteBE32(unsigned char* ptr, uint32_t x) { + uint32_t v = htobe32_(x); + memcpy(ptr, (char*)&v, 4); +} + +void static inline WriteLE64(unsigned char* ptr, uint64_t x) { + uint64_t v = htole64_(x); + memcpy(ptr, (char*)&v, 8); +} + +uint64_t static inline ReadLE64(const unsigned char* ptr) { + uint64_t x; + memcpy((char*)&x, ptr, 8); + return le64toh_(x); +} + +void static inline WriteBE64(unsigned char* ptr, uint64_t x) { + uint64_t v = htobe64_(x); + memcpy(ptr, (char*)&v, 8); +} + +uint64_t static inline ReadBE64(const unsigned char* ptr) { + uint64_t x; + memcpy((char*)&x, ptr, 8); + return be64toh_(x); +} + +#endif diff --git a/c/omni_lock.c b/c/omni_lock.c index 81081aa..1e092b7 100644 --- a/c/omni_lock.c +++ b/c/omni_lock.c @@ -136,8 +136,8 @@ bool is_memory_enough(mol_seg_t seg, const uint8_t *cur, uint32_t len) { // memory layout of args: // -// +// int parse_args(ArgsType *args) { int err = 0; uint8_t script[SCRIPT_SIZE]; diff --git a/c/ripemd160.h b/c/ripemd160.h new file mode 100644 index 0000000..bfb06e6 --- /dev/null +++ b/c/ripemd160.h @@ -0,0 +1,331 @@ +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef RIPEMD160_H +#define RIPEMD160_H + +#include +#include +#include + +#include "conversion.h" + +typedef struct ripemd160_state__ { + uint32_t s[5]; + unsigned char buf[64]; + uint64_t bytes; +} ripemd160_state; + +void ripemd160_init(ripemd160_state* S); +void ripemd160_update(ripemd160_state* S, const unsigned char* data, + size_t len); +void ripemd160_finalize(ripemd160_state* S, unsigned char hash[20]); +void ripemd160_reset(ripemd160_state* S); + +static uint32_t inline f1(uint32_t x, uint32_t y, uint32_t z) { + return x ^ y ^ z; +} +uint32_t static inline f2(uint32_t x, uint32_t y, uint32_t z) { + return (x & y) | (~x & z); +} +static uint32_t inline f3(uint32_t x, uint32_t y, uint32_t z) { + return (x | ~y) ^ z; +} +static uint32_t inline f4(uint32_t x, uint32_t y, uint32_t z) { + return (x & z) | (y & ~z); +} +static uint32_t inline f5(uint32_t x, uint32_t y, uint32_t z) { + return x ^ (y | ~z); +} + +static uint32_t inline rol(uint32_t x, int i) { + return (x << i) | (x >> (32 - i)); +} + +static void inline ripemd160_round(uint32_t* a, uint32_t b, uint32_t* c, + uint32_t d, uint32_t e, uint32_t f, + uint32_t x, uint32_t k, int r) { + *a = rol(*a + f + x + k, r) + e; + *c = rol(*c, 10); +} + +static void inline R11(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f1(b, *c, d), x, 0, r); +} +static void inline R21(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f2(b, *c, d), x, 0x5A827999ul, r); +} +static void inline R31(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f3(b, *c, d), x, 0x6ED9EBA1ul, r); +} +static void inline R41(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f4(b, *c, d), x, 0x8F1BBCDCul, r); +} +static void inline R51(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f5(b, *c, d), x, 0xA953FD4Eul, r); +} + +static void inline R12(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f5(b, *c, d), x, 0x50A28BE6ul, r); +} +static void inline R22(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f4(b, *c, d), x, 0x5C4DD124ul, r); +} +static void inline R32(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f3(b, *c, d), x, 0x6D703EF3ul, r); +} +static void inline R42(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f2(b, *c, d), x, 0x7A6D76E9ul, r); +} +static void inline R52(uint32_t* a, uint32_t b, uint32_t* c, uint32_t d, + uint32_t e, uint32_t x, int r) { + ripemd160_round(a, b, c, d, e, f1(b, *c, d), x, 0, r); +} + +/** Perform a RIPEMD-160 transformation, processing a 64-byte chunk. */ +static void ripemd160_transform(uint32_t* s, const unsigned char* chunk) { + uint32_t a1 = s[0], b1 = s[1], c1 = s[2], d1 = s[3], e1 = s[4]; + uint32_t a2 = a1, b2 = b1, c2 = c1, d2 = d1, e2 = e1; + uint32_t w0 = ReadLE32(chunk + 0), w1 = ReadLE32(chunk + 4), + w2 = ReadLE32(chunk + 8), w3 = ReadLE32(chunk + 12); + uint32_t w4 = ReadLE32(chunk + 16), w5 = ReadLE32(chunk + 20), + w6 = ReadLE32(chunk + 24), w7 = ReadLE32(chunk + 28); + uint32_t w8 = ReadLE32(chunk + 32), w9 = ReadLE32(chunk + 36), + w10 = ReadLE32(chunk + 40), w11 = ReadLE32(chunk + 44); + uint32_t w12 = ReadLE32(chunk + 48), w13 = ReadLE32(chunk + 52), + w14 = ReadLE32(chunk + 56), w15 = ReadLE32(chunk + 60); + + R11(&a1, b1, &c1, d1, e1, w0, 11); + R12(&a2, b2, &c2, d2, e2, w5, 8); + R11(&e1, a1, &b1, c1, d1, w1, 14); + R12(&e2, a2, &b2, c2, d2, w14, 9); + R11(&d1, e1, &a1, b1, c1, w2, 15); + R12(&d2, e2, &a2, b2, c2, w7, 9); + R11(&c1, d1, &e1, a1, b1, w3, 12); + R12(&c2, d2, &e2, a2, b2, w0, 11); + R11(&b1, c1, &d1, e1, a1, w4, 5); + R12(&b2, c2, &d2, e2, a2, w9, 13); + R11(&a1, b1, &c1, d1, e1, w5, 8); + R12(&a2, b2, &c2, d2, e2, w2, 15); + R11(&e1, a1, &b1, c1, d1, w6, 7); + R12(&e2, a2, &b2, c2, d2, w11, 15); + R11(&d1, e1, &a1, b1, c1, w7, 9); + R12(&d2, e2, &a2, b2, c2, w4, 5); + R11(&c1, d1, &e1, a1, b1, w8, 11); + R12(&c2, d2, &e2, a2, b2, w13, 7); + R11(&b1, c1, &d1, e1, a1, w9, 13); + R12(&b2, c2, &d2, e2, a2, w6, 7); + R11(&a1, b1, &c1, d1, e1, w10, 14); + R12(&a2, b2, &c2, d2, e2, w15, 8); + R11(&e1, a1, &b1, c1, d1, w11, 15); + R12(&e2, a2, &b2, c2, d2, w8, 11); + R11(&d1, e1, &a1, b1, c1, w12, 6); + R12(&d2, e2, &a2, b2, c2, w1, 14); + R11(&c1, d1, &e1, a1, b1, w13, 7); + R12(&c2, d2, &e2, a2, b2, w10, 14); + R11(&b1, c1, &d1, e1, a1, w14, 9); + R12(&b2, c2, &d2, e2, a2, w3, 12); + R11(&a1, b1, &c1, d1, e1, w15, 8); + R12(&a2, b2, &c2, d2, e2, w12, 6); + + R21(&e1, a1, &b1, c1, d1, w7, 7); + R22(&e2, a2, &b2, c2, d2, w6, 9); + R21(&d1, e1, &a1, b1, c1, w4, 6); + R22(&d2, e2, &a2, b2, c2, w11, 13); + R21(&c1, d1, &e1, a1, b1, w13, 8); + R22(&c2, d2, &e2, a2, b2, w3, 15); + R21(&b1, c1, &d1, e1, a1, w1, 13); + R22(&b2, c2, &d2, e2, a2, w7, 7); + R21(&a1, b1, &c1, d1, e1, w10, 11); + R22(&a2, b2, &c2, d2, e2, w0, 12); + R21(&e1, a1, &b1, c1, d1, w6, 9); + R22(&e2, a2, &b2, c2, d2, w13, 8); + R21(&d1, e1, &a1, b1, c1, w15, 7); + R22(&d2, e2, &a2, b2, c2, w5, 9); + R21(&c1, d1, &e1, a1, b1, w3, 15); + R22(&c2, d2, &e2, a2, b2, w10, 11); + R21(&b1, c1, &d1, e1, a1, w12, 7); + R22(&b2, c2, &d2, e2, a2, w14, 7); + R21(&a1, b1, &c1, d1, e1, w0, 12); + R22(&a2, b2, &c2, d2, e2, w15, 7); + R21(&e1, a1, &b1, c1, d1, w9, 15); + R22(&e2, a2, &b2, c2, d2, w8, 12); + R21(&d1, e1, &a1, b1, c1, w5, 9); + R22(&d2, e2, &a2, b2, c2, w12, 7); + R21(&c1, d1, &e1, a1, b1, w2, 11); + R22(&c2, d2, &e2, a2, b2, w4, 6); + R21(&b1, c1, &d1, e1, a1, w14, 7); + R22(&b2, c2, &d2, e2, a2, w9, 15); + R21(&a1, b1, &c1, d1, e1, w11, 13); + R22(&a2, b2, &c2, d2, e2, w1, 13); + R21(&e1, a1, &b1, c1, d1, w8, 12); + R22(&e2, a2, &b2, c2, d2, w2, 11); + + R31(&d1, e1, &a1, b1, c1, w3, 11); + R32(&d2, e2, &a2, b2, c2, w15, 9); + R31(&c1, d1, &e1, a1, b1, w10, 13); + R32(&c2, d2, &e2, a2, b2, w5, 7); + R31(&b1, c1, &d1, e1, a1, w14, 6); + R32(&b2, c2, &d2, e2, a2, w1, 15); + R31(&a1, b1, &c1, d1, e1, w4, 7); + R32(&a2, b2, &c2, d2, e2, w3, 11); + R31(&e1, a1, &b1, c1, d1, w9, 14); + R32(&e2, a2, &b2, c2, d2, w7, 8); + R31(&d1, e1, &a1, b1, c1, w15, 9); + R32(&d2, e2, &a2, b2, c2, w14, 6); + R31(&c1, d1, &e1, a1, b1, w8, 13); + R32(&c2, d2, &e2, a2, b2, w6, 6); + R31(&b1, c1, &d1, e1, a1, w1, 15); + R32(&b2, c2, &d2, e2, a2, w9, 14); + R31(&a1, b1, &c1, d1, e1, w2, 14); + R32(&a2, b2, &c2, d2, e2, w11, 12); + R31(&e1, a1, &b1, c1, d1, w7, 8); + R32(&e2, a2, &b2, c2, d2, w8, 13); + R31(&d1, e1, &a1, b1, c1, w0, 13); + R32(&d2, e2, &a2, b2, c2, w12, 5); + R31(&c1, d1, &e1, a1, b1, w6, 6); + R32(&c2, d2, &e2, a2, b2, w2, 14); + R31(&b1, c1, &d1, e1, a1, w13, 5); + R32(&b2, c2, &d2, e2, a2, w10, 13); + R31(&a1, b1, &c1, d1, e1, w11, 12); + R32(&a2, b2, &c2, d2, e2, w0, 13); + R31(&e1, a1, &b1, c1, d1, w5, 7); + R32(&e2, a2, &b2, c2, d2, w4, 7); + R31(&d1, e1, &a1, b1, c1, w12, 5); + R32(&d2, e2, &a2, b2, c2, w13, 5); + + R41(&c1, d1, &e1, a1, b1, w1, 11); + R42(&c2, d2, &e2, a2, b2, w8, 15); + R41(&b1, c1, &d1, e1, a1, w9, 12); + R42(&b2, c2, &d2, e2, a2, w6, 5); + R41(&a1, b1, &c1, d1, e1, w11, 14); + R42(&a2, b2, &c2, d2, e2, w4, 8); + R41(&e1, a1, &b1, c1, d1, w10, 15); + R42(&e2, a2, &b2, c2, d2, w1, 11); + R41(&d1, e1, &a1, b1, c1, w0, 14); + R42(&d2, e2, &a2, b2, c2, w3, 14); + R41(&c1, d1, &e1, a1, b1, w8, 15); + R42(&c2, d2, &e2, a2, b2, w11, 14); + R41(&b1, c1, &d1, e1, a1, w12, 9); + R42(&b2, c2, &d2, e2, a2, w15, 6); + R41(&a1, b1, &c1, d1, e1, w4, 8); + R42(&a2, b2, &c2, d2, e2, w0, 14); + R41(&e1, a1, &b1, c1, d1, w13, 9); + R42(&e2, a2, &b2, c2, d2, w5, 6); + R41(&d1, e1, &a1, b1, c1, w3, 14); + R42(&d2, e2, &a2, b2, c2, w12, 9); + R41(&c1, d1, &e1, a1, b1, w7, 5); + R42(&c2, d2, &e2, a2, b2, w2, 12); + R41(&b1, c1, &d1, e1, a1, w15, 6); + R42(&b2, c2, &d2, e2, a2, w13, 9); + R41(&a1, b1, &c1, d1, e1, w14, 8); + R42(&a2, b2, &c2, d2, e2, w9, 12); + R41(&e1, a1, &b1, c1, d1, w5, 6); + R42(&e2, a2, &b2, c2, d2, w7, 5); + R41(&d1, e1, &a1, b1, c1, w6, 5); + R42(&d2, e2, &a2, b2, c2, w10, 15); + R41(&c1, d1, &e1, a1, b1, w2, 12); + R42(&c2, d2, &e2, a2, b2, w14, 8); + + R51(&b1, c1, &d1, e1, a1, w4, 9); + R52(&b2, c2, &d2, e2, a2, w12, 8); + R51(&a1, b1, &c1, d1, e1, w0, 15); + R52(&a2, b2, &c2, d2, e2, w15, 5); + R51(&e1, a1, &b1, c1, d1, w5, 5); + R52(&e2, a2, &b2, c2, d2, w10, 12); + R51(&d1, e1, &a1, b1, c1, w9, 11); + R52(&d2, e2, &a2, b2, c2, w4, 9); + R51(&c1, d1, &e1, a1, b1, w7, 6); + R52(&c2, d2, &e2, a2, b2, w1, 12); + R51(&b1, c1, &d1, e1, a1, w12, 8); + R52(&b2, c2, &d2, e2, a2, w5, 5); + R51(&a1, b1, &c1, d1, e1, w2, 13); + R52(&a2, b2, &c2, d2, e2, w8, 14); + R51(&e1, a1, &b1, c1, d1, w10, 12); + R52(&e2, a2, &b2, c2, d2, w7, 6); + R51(&d1, e1, &a1, b1, c1, w14, 5); + R52(&d2, e2, &a2, b2, c2, w6, 8); + R51(&c1, d1, &e1, a1, b1, w1, 12); + R52(&c2, d2, &e2, a2, b2, w2, 13); + R51(&b1, c1, &d1, e1, a1, w3, 13); + R52(&b2, c2, &d2, e2, a2, w13, 6); + R51(&a1, b1, &c1, d1, e1, w8, 14); + R52(&a2, b2, &c2, d2, e2, w14, 5); + R51(&e1, a1, &b1, c1, d1, w11, 11); + R52(&e2, a2, &b2, c2, d2, w0, 15); + R51(&d1, e1, &a1, b1, c1, w6, 8); + R52(&d2, e2, &a2, b2, c2, w3, 13); + R51(&c1, d1, &e1, a1, b1, w15, 5); + R52(&c2, d2, &e2, a2, b2, w9, 11); + R51(&b1, c1, &d1, e1, a1, w13, 6); + R52(&b2, c2, &d2, e2, a2, w11, 11); + + uint32_t t = s[0]; + s[0] = s[1] + c1 + d2; + s[1] = s[2] + d1 + e2; + s[2] = s[3] + e1 + a2; + s[3] = s[4] + a1 + b2; + s[4] = t + b1 + c2; +} + +void inline ripemd160_init(ripemd160_state* S) { + memset(S, 0, sizeof(ripemd160_state)); + S->s[0] = 0x67452301ul; + S->s[1] = 0xEFCDAB89ul; + S->s[2] = 0x98BADCFEul; + S->s[3] = 0x10325476ul; + S->s[4] = 0xC3D2E1F0ul; + S->bytes = 0; +} + +void ripemd160_update(ripemd160_state* S, const unsigned char* data, + size_t len) { + const unsigned char* end = data + len; + size_t bufsize = S->bytes % 64; + if (bufsize && bufsize + len >= 64) { + // Fill the buffer, and process it. + memcpy(S->buf + bufsize, data, 64 - bufsize); + S->bytes += 64 - bufsize; + data += 64 - bufsize; + ripemd160_transform(S->s, S->buf); + bufsize = 0; + } + while (end - data >= 64) { + // Process full chunks directly from the source. + ripemd160_transform(S->s, data); + S->bytes += 64; + data += 64; + } + if (end > data) { + // Fill the buffer with what remains. + memcpy(S->buf + bufsize, data, end - data); + S->bytes += end - data; + } +} + +void ripemd160_finalize(ripemd160_state* S, unsigned char hash[20]) { + static const unsigned char pad[64] = {0x80}; + unsigned char sizedesc[8]; + WriteLE64(sizedesc, S->bytes << 3); + ripemd160_update(S, pad, 1 + ((119 - (S->bytes % 64)) % 64)); + ripemd160_update(S, sizedesc, 8); + WriteLE32(hash, S->s[0]); + WriteLE32(hash + 4, S->s[1]); + WriteLE32(hash + 8, S->s[2]); + WriteLE32(hash + 12, S->s[3]); + WriteLE32(hash + 16, S->s[4]); +} + +void ripemd160_reset(ripemd160_state* S) { ripemd160_init(S); } + +#endif diff --git a/c/sha256.h b/c/sha256.h new file mode 100644 index 0000000..0ae906a --- /dev/null +++ b/c/sha256.h @@ -0,0 +1,173 @@ +/********************************************************************* + * Filename: sha256.h + * Author: Brad Conte (brad AT bradconte.com) + * Copyright: + * Disclaimer: This code is presented "as is" without any guarantees. + * Details: Defines the API for the corresponding SHA1 implementation. + *********************************************************************/ + +#ifndef SHA256_H +#define SHA256_H + +/*************************** HEADER FILES ***************************/ +#include +#include +#include + +/****************************** MACROS ******************************/ +#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest + +/**************************** DATA TYPES ****************************/ +typedef unsigned char BYTE; // 8-bit byte +typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines + +typedef struct { + BYTE data[64]; + WORD datalen; + unsigned long long bitlen; + WORD state[8]; +} SHA256_CTX; + +/*********************** FUNCTION DECLARATIONS **********************/ +void sha256_init(SHA256_CTX *ctx); +void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); +void sha256_final(SHA256_CTX *ctx, BYTE hash[]); + +/****************************** MACROS ******************************/ +#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) +#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b)))) + +#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22)) +#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25)) +#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10)) + +/**************************** VARIABLES *****************************/ +static const WORD k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +/*********************** FUNCTION DEFINITIONS ***********************/ +void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) { + WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | + (data[j + 3]); + for (; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e, f, g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void sha256_init(SHA256_CTX *ctx) { + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) { + WORD i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void sha256_final(SHA256_CTX *ctx, BYTE hash[]) { + WORD i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) ctx->data[i++] = 0x00; + } else { + ctx->data[i++] = 0x80; + while (i < 64) ctx->data[i++] = 0x00; + sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = ctx->bitlen; + ctx->data[62] = ctx->bitlen >> 8; + ctx->data[61] = ctx->bitlen >> 16; + ctx->data[60] = ctx->bitlen >> 24; + ctx->data[59] = ctx->bitlen >> 32; + ctx->data[58] = ctx->bitlen >> 40; + ctx->data[57] = ctx->bitlen >> 48; + ctx->data[56] = ctx->bitlen >> 56; + sha256_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and SHA uses big + // endian, reverse all the bytes when copying the final state to the output + // hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } +} + +#endif // SHA256_H diff --git a/tests/omni_lock/ckb_syscall_omni_lock_sim.h b/tests/omni_lock/ckb_syscall_omni_lock_sim.h index ff9b8a4..b5313db 100644 --- a/tests/omni_lock/ckb_syscall_omni_lock_sim.h +++ b/tests/omni_lock/ckb_syscall_omni_lock_sim.h @@ -184,10 +184,10 @@ mol_seg_t build_witness_lock() { mol_seg_t rc_identity = build_rc_identity(&identity, &proofs); MolBuilder_OmniLockWitnessLock_set_signature(&witness_lock, signature.ptr, - signature.size); + signature.size); if (g_setting.use_rc) { - MolBuilder_OmniLockWitnessLock_set_omni_identity(&witness_lock, rc_identity.ptr, - rc_identity.size); + MolBuilder_OmniLockWitnessLock_set_omni_identity( + &witness_lock, rc_identity.ptr, rc_identity.size); } free(signature.ptr); diff --git a/tests/omni_lock_rust/Cargo.lock b/tests/omni_lock_rust/Cargo.lock index 52df3a4..00d109c 100644 --- a/tests/omni_lock_rust/Cargo.lock +++ b/tests/omni_lock_rust/Cargo.lock @@ -81,6 +81,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "block-padding" version = "0.2.1" @@ -487,6 +496,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -509,6 +528,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + [[package]] name = "eaglesong" version = "0.1.0" @@ -631,6 +660,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "includedir" version = "0.5.0" @@ -832,10 +867,13 @@ dependencies = [ "ckb-vm-debug-utils", "faster-hex 0.3.1", "gdb-remote-protocol", + "hex", "includedir_codegen", "lazy_static", "openssl", "rand 0.6.5", + "ripemd", + "sha2", "sha3", "sparse-merkle-tree", ] @@ -1173,6 +1211,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -1272,14 +1319,25 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha3" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.9.0", + "digest 0.9.0", "keccak", "opaque-debug", ] diff --git a/tests/omni_lock_rust/Cargo.toml b/tests/omni_lock_rust/Cargo.toml index 0efb60c..48ca362 100644 --- a/tests/omni_lock_rust/Cargo.toml +++ b/tests/omni_lock_rust/Cargo.toml @@ -30,6 +30,9 @@ sha3 = "0.9.1" ckb-vm-debug-utils = { git = "https://github.com/nervosnetwork/ckb-vm-debug-utils.git", rev = "f72995f" } gdb-remote-protocol = { git = "https://github.com/luser/rust-gdb-remote-protocol", rev = "565ab0c" } ckb-vm = { version = "=0.20.0-rc2", features = ["detect-asm"] } +ripemd = "0.1.3" +sha2 = "0.10.6" +hex = "0.4.3" [build-dependencies] includedir_codegen = "0.5.0" diff --git a/tests/omni_lock_rust/build.rs b/tests/omni_lock_rust/build.rs index e368581..b0b2821 100644 --- a/tests/omni_lock_rust/build.rs +++ b/tests/omni_lock_rust/build.rs @@ -15,7 +15,7 @@ const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; const BINARIES: &[(&str, &str)] = &[ ( "omni_lock", - "86ea7ee58a0ecacfb1f7f2675a06d96223e0597dfe06a2474f9c06a72a7ccabc", + "768f306681da232ceb0b94f436c5f813377179762a831c5ad8797bd4fd2d118d", ), ]; diff --git a/tests/omni_lock_rust/tests/misc.rs b/tests/omni_lock_rust/tests/misc.rs index 531dbce..6454416 100644 --- a/tests/omni_lock_rust/tests/misc.rs +++ b/tests/omni_lock_rust/tests/misc.rs @@ -4,6 +4,7 @@ use openssl::rsa::Rsa; use openssl::sign::Signer; use sha3::{Digest, Keccak256}; use std::collections::HashMap; +use std::convert::TryInto; use ckb_chain_spec::consensus::{Consensus, ConsensusBuilder}; use ckb_crypto::secp::{Generator, Privkey, Pubkey}; @@ -32,6 +33,7 @@ use lazy_static::lazy_static; use rand::prelude::{thread_rng, ThreadRng}; use rand::seq::SliceRandom; use rand::Rng; +use rand::RngCore; use sparse_merkle_tree::default_store::DefaultStore; use sparse_merkle_tree::traits::Hasher; @@ -81,16 +83,33 @@ pub const ERROR_SUPPLY_AMOUNT: i8 = 91; pub const ERROR_BURN: i8 = 92; pub const ERROR_NO_INFO_CELL: i8 = 93; +// https://github.com/bitcoin-core/secp256k1/blob/d373bf6d08c82ac5496bf8103698c9f54d8d99d2/include/secp256k1.h#L219 +pub const SECP256K1_TAG_PUBKEY_EVEN: u8 = 0x02; +pub const SECP256K1_TAG_PUBKEY_ODD: u8 = 0x03; +pub const SECP256K1_TAG_PUBKEY_UNCOMPRESSED: u8 = 0x04; +pub const SECP256K1_TAG_PUBKEY_HYBRID_EVEN: u8 = 0x06; +pub const SECP256K1_TAG_PUBKEY_HYBRID_ODD: u8 = 0x07; + +// Refer to https://en.bitcoin.it/wiki/BIP_0137 +// These values are used to denote the signature types of Bitcoin. +// Each type corresponds to a distinct public key hash and a unique signature +// data header. +pub const BITCOIN_V_TYPE_P2PKHUNCOMPRESSED: u8 = 27; +pub const BITCOIN_V_TYPE_P2PKHCOMPRESSED: u8 = 31; +pub const BITCOIN_V_TYPE_SEGWITP2SH: u8 = 35; +pub const BITCOIN_V_TYPE_SEGWITBECH32: u8 = 39; + +pub const BTC_PREFIX: &str = "CKB (Bitcoin Layer) transaction: 0x"; +pub const COMMON_PREFIX: &str = "CKB transaction: 0x"; + lazy_static! { pub static ref OMNI_LOCK: Bytes = Bytes::from(&include_bytes!("../../../build/omni_lock")[..]); - // this binary from https://github.com/nervosnetwork/ckb-production-scripts pub static ref SIMPLE_UDT: Bytes = Bytes::from(&include_bytes!("../../../build/simple_udt")[..]); pub static ref SECP256K1_DATA_BIN: Bytes = Bytes::from(&include_bytes!("../../../build/secp256k1_data_20210801")[..]); pub static ref ALWAYS_SUCCESS: Bytes = Bytes::from(&include_bytes!("../../../build/always_success")[..]); - // this binary from https://github.com/nervosnetwork/ckb-production-scripts pub static ref VALIDATE_SIGNATURE_RSA: Bytes = Bytes::from(&include_bytes!("../../../build/validate_signature_rsa")[..]); pub static ref SMT_EXISTING: H256 = H256::from([ @@ -626,12 +645,21 @@ pub fn sign_tx_by_input_group( }); blake2b.finalize(&mut message); - let message = if config.id.flags == IDENTITY_FLAGS_ETHEREUM { - convert_keccak256_hash(&message) + println!("origin message: {:02x?}", message); + + let message = if use_chain_confg(config.id.flags) { + assert!(config.chain_config.is_some()); + config + .chain_config + .as_ref() + .unwrap() + .convert_message(&message) } else { CkbH256::from(message) }; + println!("sign message: {:02x?}", message.as_bytes().to_vec()); + let witness_lock = if config.id.flags == IDENTITY_FLAGS_DL { let (mut sig, pubkey) = if config.use_rsa { rsa_sign(message.as_bytes(), &config.rsa_private_key) @@ -671,6 +699,25 @@ pub fn sign_tx_by_input_group( &identity, None, ) + } else if use_chain_confg(config.id.flags) { + let sig_bytes = config + .chain_config + .as_ref() + .unwrap() + .sign(&config.private_key, message); + println!( + "bitcoin sign(size: {}): {:02x?}", + sig_bytes.len(), + sig_bytes.to_vec() + ); + gen_witness_lock( + sig_bytes, + config.use_rc, + config.use_rc_identity, + &proof_vec, + &identity, + None, + ) } else { let sig = config.private_key.sign_recoverable(&message).expect("sign"); let sig_bytes = Bytes::from(sig.serialize()); @@ -684,6 +731,12 @@ pub fn sign_tx_by_input_group( ) }; + println!( + "omni lock witness(size: {}): {:02x?}", + witness_lock.len(), + witness_lock.to_vec() + ); + witness .as_builder() .lock(Some(witness_lock).pack()) @@ -712,6 +765,11 @@ pub fn sign_tx_by_input_group( pub fn gen_tx(dummy: &mut DummyDataLoader, config: &mut TestConfig) -> TransactionView { let lock_args = config.gen_args(); + println!( + "omni lock args(size: {}): {:02x?}", + lock_args.len(), + lock_args.to_vec() + ); gen_tx_with_grouped_args(dummy, vec![(lock_args, 1)], config) } @@ -973,7 +1031,12 @@ pub fn debug_printer(script: &Byte32, msg: &str) { pub const IDENTITY_FLAGS_PUBKEY_HASH: u8 = 0; pub const IDENTITY_FLAGS_ETHEREUM: u8 = 1; +pub const IDENTITY_FLAGS_EOS: u8 = 2; +pub const IDENTITY_FLAGS_TRON: u8 = 3; +pub const IDENTITY_FLAGS_BITCOIN: u8 = 4; +pub const IDENTITY_FLAGS_DOGECOIN: u8 = 5; pub const IDENTITY_FLAGS_MULTISIG: u8 = 6; +pub const IDENTITY_FLAGS_ETHEREUM_DISPLAYING: u8 = 18; pub const IDENTITY_FLAGS_OWNER_LOCK: u8 = 0xFC; pub const IDENTITY_FLAGS_EXEC: u8 = 0xFD; @@ -1088,6 +1151,264 @@ impl Default for MultisigTestConfig { } } +pub trait ChainConfig { + fn get_pubkey_hash(&self, pubkey: &Pubkey) -> [u8; 20]; + fn convert_message(&self, message: &[u8; 32]) -> CkbH256; + fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes; +} + +pub fn use_chain_confg(flags: u8) -> bool { + flags == IDENTITY_FLAGS_ETHEREUM + || flags == IDENTITY_FLAGS_EOS + || flags == IDENTITY_FLAGS_TRON + || flags == IDENTITY_FLAGS_BITCOIN + || flags == IDENTITY_FLAGS_DOGECOIN + || flags == IDENTITY_FLAGS_ETHEREUM_DISPLAYING +} + +#[derive(Default)] +pub struct EthereumConfig { + pub pubkey_err: bool, +} + +impl ChainConfig for EthereumConfig { + fn get_pubkey_hash(&self, pubkey: &Pubkey) -> [u8; 20] { + keccak160(&pubkey.as_ref()[..]).to_vec().try_into().unwrap() + } + + fn convert_message(&self, message: &[u8; 32]) -> CkbH256 { + convert_keccak256_hash(message) + } + + fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes { + let sig = privkey.sign_recoverable(&message).expect("sign"); + Bytes::from(sig.serialize()) + } +} + +#[derive(Default)] +pub struct EthereumDisplayConfig { + pub pubkey_err: bool, +} + +impl ChainConfig for EthereumDisplayConfig { + fn get_pubkey_hash(&self, pubkey: &Pubkey) -> [u8; 20] { + keccak160(&pubkey.as_ref()[..]).to_vec().try_into().unwrap() + } + + fn convert_message(&self, message: &[u8; 32]) -> CkbH256 { + let eth_prefix = b"\x19Ethereum Signed Message:\n"; + + let mut hasher = Keccak256::new(); + hasher.update(eth_prefix); + hasher.update(Bytes::from(format!( + "{}", + COMMON_PREFIX.len() + message.len() * 2 + ))); + hasher.update(Bytes::from(COMMON_PREFIX)); + hasher.update(hex::encode(message)); + let r = hasher.finalize(); + CkbH256::from_slice(r.as_slice()).expect("convert_keccak256_hash") + } + + fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes { + let sig = privkey.sign_recoverable(&message).expect("sign"); + Bytes::from(sig.serialize()) + } +} + +pub struct BitcoinConfig { + pub sign_vtype: u8, + pub pubkey_err: bool, +} + +impl Default for BitcoinConfig { + fn default() -> Self { + Self { + sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, + pubkey_err: false, + } + } +} + +impl ChainConfig for BitcoinConfig { + fn get_pubkey_hash(&self, pubkey: &Pubkey) -> [u8; 20] { + if self.pubkey_err { + let mut r = [0u8; 20]; + thread_rng().fill_bytes(&mut r); + return r; + } + match self.sign_vtype { + BITCOIN_V_TYPE_P2PKHUNCOMPRESSED => { + let mut pk_data = Vec::::new(); + pk_data.resize(65, 0); + pk_data[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; + pk_data[1..].copy_from_slice(pubkey.as_bytes()); + + let r = bitcoin_hash160(&pk_data); + println!("public key hash: {:02x?}", r); + + r + } + BITCOIN_V_TYPE_P2PKHCOMPRESSED => bitcoin_hash160(&pubkey.serialize()), + BITCOIN_V_TYPE_SEGWITP2SH => { + // Ripemd160(Sha256([00, 20, Ripemd160(Sha256(Compressed Public key))])) + + let mut buf = Vec::::new(); + buf.resize(22, 0); + buf[0] = 0; + buf[1] = 20; + buf[2..].copy_from_slice(&bitcoin_hash160(&pubkey.serialize())); + bitcoin_hash160(&buf) + } + BITCOIN_V_TYPE_SEGWITBECH32 => bitcoin_hash160(&pubkey.serialize()), + _ => { + panic!("unknow sign_vtype") + } + } + } + + fn convert_message(&self, message: &[u8; 32]) -> CkbH256 { + let message_magic = b"Bitcoin Signed Message:\n"; + let msg_hex = hex::encode(message); + assert_eq!(msg_hex.len(), 64); + + let mut temp2: BytesMut = + BytesMut::with_capacity(1 + message_magic.len() + 1 + BTC_PREFIX.len() + msg_hex.len()); + temp2.put_u8(message_magic.len() as u8); + temp2.put(Bytes::from(message_magic.to_vec())); + + temp2.put_u8(0x40 + BTC_PREFIX.len() as u8); + + temp2.put(Bytes::from(format!( + "{}{}", + BTC_PREFIX, + hex::encode(message) + ))); + + let msg = calculate_sha256(&temp2.to_vec()); + let msg = calculate_sha256(&msg); + + CkbH256::from(msg) + } + + fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes { + let sign = privkey + .sign_recoverable(&message) + .expect("sign secp256k1") + .serialize(); + let recid = sign[64]; + + let mark = recid + self.sign_vtype; + + let mut ret = BytesMut::with_capacity(65); + ret.put_u8(mark); + ret.put(&sign[0..64]); + Bytes::from(ret) + } +} + +#[derive(Default)] +pub struct DogecoinConfig(pub BitcoinConfig); + +impl ChainConfig for DogecoinConfig { + fn get_pubkey_hash(&self, pubkey: &Pubkey) -> [u8; 20] { + self.0.get_pubkey_hash(pubkey) + } + + fn convert_message(&self, message: &[u8; 32]) -> CkbH256 { + let message_magic = b"\x19Dogecoin Signed Message:\n\x40"; + let msg_hex = hex::encode(message); + assert_eq!(msg_hex.len(), 64); + + let mut temp2: BytesMut = BytesMut::with_capacity(message_magic.len() + msg_hex.len()); + temp2.put(Bytes::from(message_magic.to_vec())); + temp2.put(Bytes::from(hex::encode(message))); + + let msg = calculate_sha256(&temp2.to_vec()); + let msg = calculate_sha256(&msg); + CkbH256::from(msg) + } + + fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes { + self.0.sign(privkey, message) + } +} + +#[derive(Default)] +pub struct EOSConfig(pub BitcoinConfig); + +impl ChainConfig for EOSConfig { + fn get_pubkey_hash(&self, pubkey: &Pubkey) -> [u8; 20] { + if self.0.pubkey_err { + let mut r = [0u8; 20]; + thread_rng().fill_bytes(&mut r); + return r; + } + // EOS support + let buf = match self.0.sign_vtype { + BITCOIN_V_TYPE_P2PKHUNCOMPRESSED => { + let mut temp: BytesMut = BytesMut::with_capacity(65); + temp.put_u8(SECP256K1_TAG_PUBKEY_UNCOMPRESSED); + temp.put(Bytes::from(pubkey.as_bytes().to_vec())); + temp.freeze().to_vec() + } + BITCOIN_V_TYPE_P2PKHCOMPRESSED => pubkey.serialize(), + _ => { + panic!("unsupport") + } + }; + + ckb_hash::blake2b_256(buf)[..20].try_into().unwrap() + } + + fn convert_message(&self, message: &[u8; 32]) -> CkbH256 { + CkbH256::from_slice(message).unwrap() + } + + fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes { + self.0.sign(privkey, message) + } +} + +#[derive(Default)] +pub struct TronConfig { + pub pubkey_err: bool, +} + +impl ChainConfig for TronConfig { + fn get_pubkey_hash(&self, pubkey: &Pubkey) -> [u8; 20] { + if self.pubkey_err { + let mut r = [0u8; 20]; + thread_rng().fill_bytes(&mut r); + return r; + } + + let pubkey = pubkey.as_bytes(); + + let mut hasher = Keccak256::new(); + hasher.update(&pubkey.to_vec()); + let r = hasher.finalize().as_slice().to_vec(); + + r[12..].try_into().unwrap() + } + + fn convert_message(&self, message: &[u8; 32]) -> CkbH256 { + let eth_prefix: &[u8; 24] = b"\x19TRON Signed Message:\n32"; + let mut hasher = Keccak256::new(); + hasher.update(eth_prefix); + hasher.update(message); + let r = hasher.finalize(); + let rr = CkbH256::from_slice(r.as_slice()).expect("convert_keccak256_hash"); + rr + } + + fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes { + let sig = privkey.sign_recoverable(&message).expect("sign"); + Bytes::from(sig.serialize()) + } +} + pub struct TestConfig { pub id: Identity, pub acp_config: Option<(u8, u8)>, @@ -1127,6 +1448,8 @@ pub struct TestConfig { pub running_script: Script, pub leading_witness_count: usize, + + pub chain_config: Option>, } #[derive(Copy, Clone, PartialEq)] @@ -1163,14 +1486,12 @@ const SUPPLY_MASK: u8 = 8; impl TestConfig { pub fn new(flags: u8, use_rc: bool) -> TestConfig { - let private_key = Generator::random_privkey(); + let private_key: Privkey = Generator::random_privkey(); let pubkey = private_key.pubkey().expect("pubkey"); let pubkey_hash = blake160(&pubkey.serialize()); let blake160 = if flags == IDENTITY_FLAGS_PUBKEY_HASH { pubkey_hash - } else if flags == IDENTITY_FLAGS_ETHEREUM { - keccak160(&pubkey.as_ref()[..]) } else { Bytes::from(&[0; 20][..]) }; @@ -1225,6 +1546,8 @@ impl TestConfig { info_cell: Default::default(), running_script: Default::default(), leading_witness_count: 0, + + chain_config: None, } } @@ -1266,6 +1589,12 @@ impl TestConfig { self.use_rc_identity = used; } + pub fn set_chain_config(&mut self, config: Box) { + let pkhash = config.get_pubkey_hash(&self.pubkey); + self.chain_config = Some(config); + self.id.blake160 = Bytes::from(pkhash.to_vec()); + } + pub fn gen_args(&self) -> Bytes { let mut bytes = BytesMut::with_capacity(128); let mut omni_lock_flags: u8 = 0; @@ -1689,3 +2018,25 @@ pub fn gen_tx_env() -> TxVerifyEnv { .build(); TxVerifyEnv::new_commit(&header) } + +pub fn calculate_sha256(buf: &[u8]) -> [u8; 32] { + use sha2::{Digest, Sha256}; + + let mut c = Sha256::new(); + c.update(buf); + c.finalize().into() +} + +pub fn calculate_ripemd160(buf: &[u8]) -> [u8; 20] { + use ripemd::{Digest, Ripemd160}; + + let mut hasher = Ripemd160::new(); + hasher.update(buf); + let buf = hasher.finalize()[..].to_vec(); + + buf.try_into().unwrap() +} + +pub fn bitcoin_hash160(buf: &[u8]) -> [u8; 20] { + calculate_ripemd160(&calculate_sha256(buf)) +} diff --git a/tests/omni_lock_rust/tests/test_omni_lock.rs b/tests/omni_lock_rust/tests/test_omni_lock.rs index 21a96c2..69649d5 100644 --- a/tests/omni_lock_rust/tests/test_omni_lock.rs +++ b/tests/omni_lock_rust/tests/test_omni_lock.rs @@ -480,7 +480,7 @@ fn test_iso9796_2_batch_via_dl_unlock_failed() { TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); - assert_script_error(verify_result.unwrap_err(), ERROR_ISO97962_INVALID_ARG9); + assert!(verify_result.is_err()); } #[test] @@ -488,6 +488,234 @@ fn test_eth_unlock() { let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_ETHEREUM, false); + config.set_chain_config(Box::new(EthereumConfig::default())); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +fn test_btc_success(vtype: u8) { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.set_chain_config(Box::new(BitcoinConfig { + sign_vtype: vtype, + pubkey_err: false, + })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +fn test_btc_err_pubkey(vtype: u8) { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.set_chain_config(Box::new(BitcoinConfig { + sign_vtype: vtype, + pubkey_err: true, + })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert!(verify_result.is_err()); + assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH); +} + +fn test_btc(vtype: u8) { + test_btc_success(vtype); + test_btc_err_pubkey(vtype); +} + +#[test] +fn test_btc_unlock() { + test_btc(BITCOIN_V_TYPE_P2PKHUNCOMPRESSED); + test_btc(BITCOIN_V_TYPE_P2PKHCOMPRESSED); + test_btc(BITCOIN_V_TYPE_SEGWITP2SH); + test_btc(BITCOIN_V_TYPE_SEGWITBECH32); +} + +#[test] +fn test_dogecoin_unlock() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_DOGECOIN, false); + config.set_chain_config(Box::new(DogecoinConfig::default())); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_dogecoin_err_pubkey() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_DOGECOIN, false); + let mut dogecoin = DogecoinConfig::default(); + dogecoin.0.pubkey_err = true; + config.set_chain_config(Box::new(dogecoin)); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert!(verify_result.is_err()) +} + +fn test_eos_success(vtype: u8) { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_EOS, false); + let mut eos = EOSConfig::default(); + eos.0.sign_vtype = vtype; + config.set_chain_config(Box::new(EOSConfig::default())); + + let tx: ckb_types::core::TransactionView = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +fn test_eos_err_pubkey(vtype: u8) { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_EOS, false); + let mut eos = EOSConfig::default(); + eos.0.sign_vtype = vtype; + eos.0.pubkey_err = true; + config.set_chain_config(Box::new(eos)); + + let tx: ckb_types::core::TransactionView = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert!(verify_result.is_err()); + assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH); +} + +fn test_eos(vtype: u8) { + test_eos_success(vtype); + test_eos_err_pubkey(vtype) +} + +#[test] +fn test_eos_unlock() { + test_eos(BITCOIN_V_TYPE_P2PKHCOMPRESSED); + test_eos(BITCOIN_V_TYPE_P2PKHUNCOMPRESSED); +} + +#[test] +fn test_tron_unlock() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_TRON, false); + config.set_chain_config(Box::new(TronConfig::default())); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_tron_err_pubkey() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_TRON, false); + let mut tron = TronConfig::default(); + tron.pubkey_err = true; + config.set_chain_config(Box::new(tron)); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let consensus = misc::gen_consensus(); + let tx_env = misc::gen_tx_env(); + let mut verifier = + TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert!(verify_result.is_err()); + assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH); +} + +#[test] +fn test_eth_displaying_unlock() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_ETHEREUM_DISPLAYING, false); + config.set_chain_config(Box::new(EthereumDisplayConfig::default())); let tx = gen_tx(&mut data_loader, &mut config); let tx = sign_tx(&mut data_loader, tx, &mut config); diff --git a/tests/omni_lock_rust/tests/test_sudt_supply.rs b/tests/omni_lock_rust/tests/test_sudt_supply.rs index 94c4e28..7473287 100644 --- a/tests/omni_lock_rust/tests/test_sudt_supply.rs +++ b/tests/omni_lock_rust/tests/test_sudt_supply.rs @@ -11,9 +11,9 @@ use rand::{thread_rng, Rng}; use misc::{ assert_script_error, build_always_success_script, build_resolved_tx, debug_printer, gen_tx, - sign_tx, DummyDataLoader, TestConfig, ALWAYS_SUCCESS, CKB_INVALID_DATA, ERROR_BURN, - ERROR_EXCEED_SUPPLY, ERROR_NO_INFO_CELL, ERROR_SUPPLY_AMOUNT, IDENTITY_FLAGS_ETHEREUM, - MAX_CYCLES, SIMPLE_UDT, + sign_tx, DummyDataLoader, EthereumConfig, TestConfig, ALWAYS_SUCCESS, CKB_INVALID_DATA, + ERROR_BURN, ERROR_EXCEED_SUPPLY, ERROR_NO_INFO_CELL, ERROR_SUPPLY_AMOUNT, + IDENTITY_FLAGS_ETHEREUM, MAX_CYCLES, SIMPLE_UDT, }; mod misc; @@ -176,6 +176,7 @@ where { let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_ETHEREUM, false); + config.set_chain_config(Box::new(EthereumConfig::default())); let tx = gen_tx_fn(&mut data_loader, &mut config); let tx = sign_tx(&mut data_loader, tx, &mut config);