diff --git a/c/cobuild.c b/c/cobuild.c index 8152271..79ef047 100644 --- a/c/cobuild.c +++ b/c/cobuild.c @@ -32,6 +32,7 @@ This is an implementation in C of cobuild. See reference implementation in Rust: #define BLAKE2B_BLOCK_SIZE 32 #define MAX_CELL_SIZE 8192 +#define MAX_TYPESCRIPT_COUNT 512 #define CHECK2(cond, code) \ do { \ @@ -66,6 +67,7 @@ enum CobuildErrorCode { ERROR_SEAL, ERROR_FLOW, ERROR_OTX_START_DUP, + ERROR_WRONG_OTX, }; enum WitnessLayoutId { @@ -97,7 +99,8 @@ const char *PERSONAL_SIGHASH_ALL = "ckb-tcob-sighash"; const char *PERSONAL_SIGHASH_ALL_ONLY = "ckb-tcob-sgohash"; const char *PERSONAL_OTX = "ckb-tcob-otxhash"; -#define MAX_TYPESCRIPT_COUNT 512 +// forward declaration +int ckb_calculate_inputs_len(); /* The seal cursor uses this data source. So the lifetime of data source should @@ -138,8 +141,8 @@ void print_cursor(const char *name, mol2_cursor_t cursor) { } // After being enabled, there will be a lot of logs. -#define BLAKE2B_UPDATE blake2b_update_debug -// #define BLAKE2B_UPDATE blake2b_update +// #define BLAKE2B_UPDATE blake2b_update_debug +#define BLAKE2B_UPDATE blake2b_update int blake2b_update_debug(blake2b_state *S, const void *pin, size_t inlen) { blake2b_update(S, pin, inlen); print_raw_data("blake2b_update: ", (uint8_t *)pin, inlen); @@ -504,8 +507,8 @@ static int hash_cell(blake2b_state *ctx, size_t index, size_t source, BLAKE2B_UPDATE(ctx, &cell_data_len, 4); (*count) += 4; err = ckb_hash_cursor(ctx, cell_data_cursor); - (*count) += cell_data_cursor.size; CHECK(err); + (*count) += cell_data_cursor.size; exit: return err; @@ -733,10 +736,11 @@ int ckb_generate_otx_smh(mol2_cursor_t message_cursor, uint8_t *smh, err = ckb_hash_cursor(&ctx, message_cursor); CHECK(err); + count += message_cursor.size; + + BLAKE2B_UPDATE(&ctx, &size->input_cells, 4); + count += 4; - uint32_t inputs_len = size->input_cells; - BLAKE2B_UPDATE(&ctx, &inputs_len, sizeof(inputs_len)); - count += sizeof(inputs_len); // hash input cell and data for (size_t index = start->start_input_cell; index < (start->start_input_cell + size->input_cells); index++) { @@ -752,9 +756,8 @@ int ckb_generate_otx_smh(mol2_cursor_t message_cursor, uint8_t *smh, CHECK(err); } // hash output cell and data - uint32_t outputs_len = size->output_cells; - BLAKE2B_UPDATE(&ctx, &outputs_len, sizeof(outputs_len)); - count += sizeof(outputs_len); + BLAKE2B_UPDATE(&ctx, &size->output_cells, 4); + count += 4; for (size_t index = start->start_output_cell; index < (start->start_output_cell + size->output_cells); index++) { err = hash_cell(&ctx, index, CKB_SOURCE_OUTPUT, &count); @@ -762,9 +765,8 @@ int ckb_generate_otx_smh(mol2_cursor_t message_cursor, uint8_t *smh, } // hash cell deps - uint32_t celldeps_len = size->cell_deps; - BLAKE2B_UPDATE(&ctx, &celldeps_len, sizeof(celldeps_len)); - count += sizeof(celldeps_len); + BLAKE2B_UPDATE(&ctx, &size->cell_deps, 4); + count += 4; for (size_t index = start->start_cell_deps; index < (start->start_cell_deps + size->cell_deps); index++) { @@ -778,9 +780,8 @@ int ckb_generate_otx_smh(mol2_cursor_t message_cursor, uint8_t *smh, } // hash header deps - uint32_t headerdeps_len = size->header_deps; - BLAKE2B_UPDATE(&ctx, &headerdeps_len, sizeof(headerdeps_len)); - count += sizeof(headerdeps_len); + BLAKE2B_UPDATE(&ctx, &size->header_deps, 4); + count += 4; for (size_t index = start->start_header_deps; index < (start->start_header_deps + size->header_deps); index++) { uint8_t header_dep[32]; @@ -796,6 +797,25 @@ int ckb_generate_otx_smh(mol2_cursor_t message_cursor, uint8_t *smh, return err; } +static bool is_otx_witness(size_t index, bool *out_of_bounds) { + int err = 0; + uint32_t id = 0; + uint64_t id_len = sizeof(id); + *out_of_bounds = false; + err = ckb_load_witness(&id, &id_len, 0, index, CKB_SOURCE_INPUT); + if (err == CKB_INDEX_OUT_OF_BOUND) { + *out_of_bounds = true; + return false; + } + if (err) { + return false; + } + if (id_len < sizeof(id)) { + return false; + } + return id == WitnessLayoutOtx; +} + int ckb_cobuild_entry(ScriptEntryType callback) { int err = 0; uint8_t smh[BLAKE2B_BLOCK_SIZE]; @@ -813,6 +833,7 @@ int ckb_cobuild_entry(ScriptEntryType callback) { bool has_otx = false; OtxStart otx_start = {0}; // step 2 + // step 4 err = ckb_fetch_otx_start(&has_otx, &i, &otx_start); CHECK(err); if (!has_otx) { @@ -828,17 +849,20 @@ int ckb_cobuild_entry(ScriptEntryType callback) { ce = cs; hs = otx_start.start_header_deps; he = hs; - for (size_t index = i + 1;; index++) { + size_t index = i + 1; + for (;; index++) { mol2_cursor_t cursor; err = ckb_new_witness_cursor(&cursor, g_cobuild_seal_data_source, MAX_CACHE_SIZE, index, CKB_SOURCE_INPUT); if (err == CKB_INDEX_OUT_OF_BOUND) { + // step 6, not WitnessLayoutOtx break; } CHECK(err); uint32_t id = 0; err = try_union_unpack_id(&cursor, &id); if (err) { + // step 6, not WitnessLayoutOtx // maybe WitnessArgs or empty break; } @@ -896,6 +920,7 @@ int ckb_cobuild_entry(ScriptEntryType callback) { if (memcmp(hash, current_script_hash, sizeof(hash)) == 0) { // step 6.f seal = loop_seal.t->seal(&loop_seal); + CHECK2(!seal_found, ERROR_SEAL); seal_found = true; } } @@ -917,6 +942,46 @@ int ckb_cobuild_entry(ScriptEntryType callback) { break; } } // end of step 6 loop + + // step 7 + size_t j = index; + // [0, i) + for (size_t index = 0; index < i; i++) { + bool out_of_bounds = false; + CHECK2(!is_otx_witness(index, &out_of_bounds), ERROR_WRONG_OTX); + } + // [j, +infinite] + for (size_t index = j;; index++) { + bool out_of_bounds = false; + CHECK2(!is_otx_witness(index, &out_of_bounds), ERROR_WRONG_OTX); + if (out_of_bounds) { + break; + } + } + // step 8 + size_t inputs_len = ckb_calculate_inputs_len(); + bool found = false; + for (size_t index = 0; index < inputs_len; index++) { + // scan all input cell in [0, is) and [ie, +infinity) + if (index < is || index >= ie) { + uint8_t hash[BLAKE2B_BLOCK_SIZE]; + uint64_t len = BLAKE2B_BLOCK_SIZE; + err = ckb_load_cell_by_field(hash, &len, 0, j, CKB_SOURCE_INPUT, + CKB_CELL_FIELD_LOCK_HASH); + if (err == CKB_INDEX_OUT_OF_BOUND) { + break; + } + CHECK(err); + if (memcmp(hash, current_script_hash, sizeof(hash)) == 0) { + found = true; + break; + } + } + } + if (found) { + err = ckb_cobuild_normal_entry(callback); + CHECK(err); + } exit: return err; -} \ No newline at end of file +} diff --git a/c/omni_lock.c b/c/omni_lock.c index f2cf918..3e00a9a 100644 --- a/c/omni_lock.c +++ b/c/omni_lock.c @@ -98,7 +98,7 @@ typedef struct WitnessLockType { SmtProofEntryVecType proofs; } WitnessLockType; -uint8_t code_buff[MAX_CODE_SIZE] __attribute__((aligned(RISCV_PGSIZE))); +uint8_t g_code_buff[MAX_CODE_SIZE] __attribute__((aligned(RISCV_PGSIZE))); // make compiler happy int make_cursor_from_witness(WitnessArgsType *witness, bool *_input) { @@ -315,14 +315,11 @@ int smt_verify_identity(CkbIdentityType *id, SmtProofEntryVecType *proofs, } static int parse_witness_lock(WitnessLockType *witness_lock, - mol2_cursor_t *seal, bool witness_existing) { + mol2_cursor_t *seal) { int err = 0; witness_lock->has_signature = false; witness_lock->has_identity = false; witness_lock->has_proofs = false; - if (!witness_existing) { - return 0; - } // convert Bytes to OmniLockWitnessLock OmniLockWitnessLockType mol_witness_lock = make_OmniLockWitnessLock(seal); IdentityOptType identity_opt = @@ -393,8 +390,11 @@ int omnilock_entry(const uint8_t *smh, mol2_cursor_t seal, bool cobuild_enabled, // this identity can be either from witness lock (witness_lock.id) or script // args (args.id) CkbIdentityType identity = {0}; - err = parse_witness_lock(&witness_lock, &seal, witness_existing); - CHECK(err); + // In some scenarios(e.g. owner lock), corresponding witness doesn't exist + if (witness_existing) { + err = parse_witness_lock(&witness_lock, &seal); + CHECK(err); + } err = parse_args(&args); CHECK(err); @@ -445,7 +445,7 @@ int omnilock_entry(const uint8_t *smh, mol2_cursor_t seal, bool cobuild_enabled, return check_payment_unlock(min_ckb_amount, min_udt_amount); } } - ckb_identity_init_code_buffer(code_buff, MAX_CODE_SIZE); + ckb_identity_init_code_buffer(g_code_buff, MAX_CODE_SIZE); err = ckb_verify_identity(&identity, witness_lock.signature, witness_lock.signature_size, witness_lock.preimage, witness_lock.preimage_size, smh); diff --git a/tests/omni_lock_rust/tests/test_omni_lock.rs b/tests/omni_lock_rust/tests/test_omni_lock.rs index eb135ea..324b357 100644 --- a/tests/omni_lock_rust/tests/test_omni_lock.rs +++ b/tests/omni_lock_rust/tests/test_omni_lock.rs @@ -624,7 +624,7 @@ fn test_binary_unchanged() { let actual_hash = faster_hex::hex_string(&hash); assert_eq!( - "187a5bfaad0aef3c9e7d71f840f7848b4dd88fc695377e09ce0b0aa5f5533738", + "de18c338ecb57ee4a5d2fe0d0983ab5a3d0ee4f8bd920e793ce0296c9fc3ac60", &actual_hash ); }