Skip to content

Commit

Permalink
Solana (phantom wallet) support (#48)
Browse files Browse the repository at this point in the history
* Solana (phantom wallet) draft support
* Check consumed cycles
* Optimize get_witness_layout
* Add macro DISABLE_MESSAGE_CALCULATION_FLOW
  • Loading branch information
XuJiandong authored Apr 8, 2024
1 parent fd6674d commit 2a04f15
Show file tree
Hide file tree
Showing 13 changed files with 550 additions and 79 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@
[submodule "deps/secp256k1"]
path = deps/secp256k1
url = https://github.com/nervosnetwork/secp256k1.git
[submodule "deps/ed25519"]
path = deps/ed25519
url = https://github.com/nervosnetwork/ed25519.git
17 changes: 14 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ CLANG_FORMAT_DOCKER := xujiandong/ckb-riscv-llvm-toolchain@sha256:6409ab0d3e335c
all: build/omni_lock build/always_success

all-via-docker:
docker run --rm -v `pwd`:/code ${BUILDER_DOCKER} bash -c "cd /code && make"
docker run -u $(shell id -u):$(shell id -g) --rm -v `pwd`:/code ${BUILDER_DOCKER} bash -c "cd /code && make"

build/always_success: c/always_success.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
Expand All @@ -45,6 +45,15 @@ $(SECP256K1_SRC):
CC=$(CC) LD=$(LD) ./configure --enable-ecmult-static-precomputation --with-ecmult-window=6 --enable-module-recovery --host=$(TARGET) && \
make src/ecmult_static_pre_context.h src/ecmult_static_context.h

build/ed25519/%.o: deps/ed25519/src/%.c
mkdir -p build/ed25519
$(CC) -c -DCKB_DECLARATION_ONLY -I deps/ed25519/src $(CFLAGS) -o $@ $^

build/libed25519.a: build/ed25519/sign.o build/ed25519/verify.o build/ed25519/sha512.o build/ed25519/sc.o build/ed25519/keypair.o \
build/ed25519/key_exchange.o build/ed25519/ge.o build/ed25519/fe.o build/ed25519/add_scalar.o
$(AR) cr $@ $^


ALL_C_SOURCE := $(wildcard c/omni_lock.c c/omni_lock_acp.h c/omni_lock_time_lock.h \
tests/omni_lock/omni_lock_sim.c tests/omni_lock/ckb_syscall_omni_lock_sim.h tests/omni_lock/omni_lock_supply.h\
c/cobuild.h c/molecule2_verify.h mol2_utils.h)
Expand Down Expand Up @@ -72,8 +81,8 @@ omni_lock_mol:

build/omni_lock: c/omni_lock.c c/omni_lock_supply.h c/omni_lock_acp.h build/secp256k1_data_info.h $(SECP256K1_SRC) \
c/ckb_identity.h c/mol2_utils.h c/cobuild_basic_mol2.h c/molecule2_verify.h \
c/cobuild.h c/mol2_utils.h c/molecule2_verify.h
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
c/cobuild.h c/mol2_utils.h c/molecule2_verify.h build/libed25519.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< build/libed25519.a
cp $@ $@.debug
$(OBJCOPY) --strip-debug --strip-all $@

Expand All @@ -88,8 +97,10 @@ cobuild_mol:
clean: clean2
rm -rf build/secp256k1_data_info.h build/dump_secp256k1_data
rm -f build/secp256k1_data
rm -rf build/ed25519 build/libed25519.a
cd deps/secp256k1 && [ -f "Makefile" ] && make clean

# not clean libraries, e.g. secp256k1
clean2:
rm -rf build/*.debug
rm -f build/omni_lock
Expand Down
47 changes: 43 additions & 4 deletions c/ckb_identity.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@
#define SECP256K1_MESSAGE_SIZE 32
#define MAX_PREIMAGE_SIZE 1024
#define MESSAGE_HEX_LEN 64
#define ED25519_SIGNATURE_SIZE 64
#define ED25519_PUBKEY_SIZE 32

const char BTC_PREFIX[] = "CKB (Bitcoin Layer) transaction: 0x";
// BTC_PREFIX_LEN = 35
const size_t BTC_PREFIX_LEN = sizeof(BTC_PREFIX) - 1;
#define 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;
// COMMON_PREFIX_LEN = 19
#define COMMON_PREFIX_LEN (sizeof(COMMON_PREFIX) - 1)

enum CkbIdentityErrorCode {
ERROR_IDENTITY_ARGUMENTS_LEN = -1,
Expand Down Expand Up @@ -63,7 +65,6 @@ typedef struct CkbIdentityType {

enum IdentityFlagsType {
IdentityFlagsCkb = 0,
// values 1~5 are used by pw-lock
IdentityFlagsEthereum = 1,
IdentityFlagsEos = 2,
IdentityFlagsTron = 3,
Expand All @@ -72,6 +73,7 @@ enum IdentityFlagsType {
IdentityCkbMultisig = 6,

IdentityFlagsEthereumDisplaying = 18,
IdentityFlagsSolana = 19,
IdentityFlagsOwnerLock = 0xFC,
IdentityFlagsExec = 0xFD,
IdentityFlagsDl = 0xFE,
Expand Down Expand Up @@ -374,6 +376,37 @@ int validate_signature_eos(void *prefilled_data, const uint8_t *sig,
return err;
}

int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key);
int validate_signature_solana(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) {
if (*output_len < AUTH160_SIZE || msg_len != SHA256_SIZE) {
return ERROR_INVALID_ARG;
}

// CKB transaction: 0x<signing message hash, hex format>
uint8_t displaying_msg[COMMON_PREFIX_LEN + MESSAGE_HEX_LEN] = {0};
memcpy(displaying_msg, COMMON_PREFIX, COMMON_PREFIX_LEN);
bin_to_hex(msg, displaying_msg + COMMON_PREFIX_LEN, msg_len);

// Unlike secp256k1, Ed25519 cannot recover the public key from the signature alone.
// The public key is located immediately after the signature.
const uint8_t* pubkey = sig + ED25519_SIGNATURE_SIZE;
int success = ed25519_verify(sig, displaying_msg, sizeof(displaying_msg), pubkey);
if (!success) {
return ERROR_MISMATCHED;
}

uint8_t hash[SHA256_SIZE] = {0};
blake2b_state ctx;
blake2b_init(&ctx, BLAKE2B_BLOCK_SIZE);
blake2b_update(&ctx, pubkey, ED25519_PUBKEY_SIZE);
blake2b_final(&ctx, hash, BLAKE2B_BLOCK_SIZE);
memcpy(output, hash, AUTH160_SIZE);
*output_len = AUTH160_SIZE;
return 0;
}

int generate_sighash_all(uint8_t *msg, size_t msg_len) {
int ret;
uint64_t len = 0;
Expand Down Expand Up @@ -941,6 +974,12 @@ int ckb_verify_identity(CkbIdentityType *id, uint8_t *sig, uint32_t sig_size,
}
return verify_sighash_all(id->id, sig, sig_size, validate_signature_btc,
convert_doge_message, signing_message_hash);
} else if (id->flags == IdentityFlagsSolana) {
if (sig == NULL || sig_size != (ED25519_SIGNATURE_SIZE + ED25519_PUBKEY_SIZE)) {
return ERROR_IDENTITY_WRONG_ARGS;
}
return verify_sighash_all(id->id, sig, sig_size, validate_signature_solana,
convert_copy, signing_message_hash);
} else if (id->flags == IdentityCkbMultisig) {
return verify_multisig(sig, sig_size, signing_message_hash, id->id);
} else if (id->flags == IdentityFlagsOwnerLock) {
Expand Down
36 changes: 23 additions & 13 deletions c/cobuild.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,16 @@ int new_otx_blake2b(blake2b_state *S) {
}

static inline int get_witness_layout(BytesVecType witnesses, uint32_t index,
WitnessLayoutType *witness_layout) {
WitnessLayoutType *witness_layout,
bool verify_recursively) {
bool existing = false;
mol2_cursor_t witness = witnesses.t->get(&witnesses, index, &existing);
if (!existing) {
return COBUILD_ERROR_MOL2_UNEXPECTED;
}

WitnessLayoutType witness_layout2 = make_WitnessLayout(&witness);
if (verify_WitnessLayout(&witness_layout2)) {
if (verify_WitnessLayout(&witness_layout2, verify_recursively)) {
return COBUILD_ERROR_GENERAL;
}
if (witness_layout != NULL) {
Expand Down Expand Up @@ -248,7 +249,7 @@ int ckb_fetch_sighash_message(BytesVecType witnesses, MessageType *message) {
uint32_t witness_len = witnesses.t->len(&witnesses);
for (uint32_t index = 0; index < witness_len; index++) {
WitnessLayoutType witness_layout = {0};
if (get_witness_layout(witnesses, index, &witness_layout) == 0) {
if (get_witness_layout(witnesses, index, &witness_layout, false) == 0) {
uint32_t id = witness_layout.t->item_id(&witness_layout);
if (id == WitnessLayoutSighashAll) {
// tested by:
Expand Down Expand Up @@ -280,7 +281,7 @@ static inline int ckb_fetch_otx_start(BytesVecType witnesses, bool *has_otx,
uint32_t witness_len = witnesses.t->len(&witnesses);
for (uint32_t index = 0; index < witness_len; index++) {
WitnessLayoutType witness_layout = {0};
err = get_witness_layout(witnesses, index, &witness_layout);
err = get_witness_layout(witnesses, index, &witness_layout, false);
if (err == 0) {
uint32_t id = witness_layout.t->item_id(&witness_layout);
if (id == WitnessLayoutOtxStart) {
Expand Down Expand Up @@ -398,7 +399,7 @@ int ckb_generate_smh(const Env *env, mol2_cursor_t message_cursor,
CKB_COBUILD_CHECK(err);
}
blake2b_final(&ctx, smh, BLAKE2B_BLOCK_SIZE);
printf("ckb_generate_smh total hashed %d bytes", count);
printf("ckb_generate_smh total hashed %zu bytes", count);

exit:
return err;
Expand Down Expand Up @@ -490,6 +491,14 @@ static int check_type_script_existing(MessageType msg) {
static int parse_seal(const mol2_cursor_t original_seal, mol2_cursor_t *seal,
uint8_t *message_calculation_flow) {
int err = 0;
// message calculation flow is not part of cobuild protocol.
// Some of lock scripts may need this.
#ifdef DISABLE_MESSAGE_CALCULATION_FLOW
*seal = original_seal;
*message_calculation_flow = 0;
return 0;
#endif

uint32_t prefix_length = 1;
uint8_t prefix[1] = {0};

Expand Down Expand Up @@ -532,7 +541,7 @@ int ckb_cobuild_normal_entry(const Env *env, ScriptEntryType callback) {
CKB_SOURCE_GROUP_INPUT);
CKB_COBUILD_CHECK(err);
WitnessLayoutType witness_layout = make_WitnessLayout(&witness);
CKB_COBUILD_CHECK2(!verify_WitnessLayout(&witness_layout),
CKB_COBUILD_CHECK2(!verify_WitnessLayout(&witness_layout, false),
COBUILD_ERROR_SIGHASHALL_NOSEAL);

uint32_t id = witness_layout.t->item_id(&witness_layout);
Expand Down Expand Up @@ -691,7 +700,7 @@ int ckb_generate_otx_smh(const Env *env, mol2_cursor_t message_cursor,
err = ckb_hash_cursor(&ctx, header_dep_cursor);
count += header_dep_cursor.size;
}
printf("ckb_generate_otx_smh totally hashed %d bytes", count);
printf("ckb_generate_otx_smh totally hashed %zu bytes", count);
blake2b_final(&ctx, smh, BLAKE2B_BLOCK_SIZE);
exit:
return err;
Expand All @@ -712,9 +721,10 @@ int ckb_cobuild_entry(const Env *env, ScriptEntryType callback,
// Legacy Flow Handling
*cobuild_enabled = false;
for (uint32_t i = 0; i < witness_len; i++) {
if (get_witness_layout(witnesses, i, NULL) == 0) {
if (get_witness_layout(witnesses, i, NULL, true) == 0) {
*cobuild_enabled = true;
break;
// Do not break here. All witnesses are recursively verified at this
// point. Subsequent witnesses will not be recursively verified.
}
}
if (!*cobuild_enabled) {
Expand Down Expand Up @@ -749,7 +759,7 @@ int ckb_cobuild_entry(const Env *env, ScriptEntryType callback,
printf("Otx starts at index %d(inclusive)", index);
for (; index < witness_len; index++) {
WitnessLayoutType witness_layout = {0};
err = get_witness_layout(witnesses, index, &witness_layout);
err = get_witness_layout(witnesses, index, &witness_layout, false);
if (err != 0) {
// step 6, not WitnessLayoutOtx
break;
Expand Down Expand Up @@ -861,7 +871,7 @@ int ckb_cobuild_entry(const Env *env, ScriptEntryType callback,
// [0, i) [j, +infinity)
if (index < i || index >= j) {
WitnessLayoutType witness_layout = {0};
err = get_witness_layout(witnesses, index, &witness_layout);
err = get_witness_layout(witnesses, index, &witness_layout, false);
if (err == 0) {
// test_cobuild_otx_noexistent_otx_id
uint32_t id = witness_layout.t->item_id(&witness_layout);
Expand All @@ -883,7 +893,7 @@ int ckb_cobuild_entry(const Env *env, ScriptEntryType callback,
CKB_COBUILD_CHECK_LOOP(err);
if (memcmp(hash, env->current_script_hash, sizeof(hash)) == 0) {
printf(
"Same lock script found beyond otx, at index %d. "
"Same lock script found beyond otx, at index %zu. "
"ckb_cobuild_normal_entry called.",
index);
found = true;
Expand All @@ -898,7 +908,7 @@ int ckb_cobuild_entry(const Env *env, ScriptEntryType callback,
CKB_COBUILD_CHECK(err);
}
CKB_COBUILD_CHECK2(execution_count > 0, COBUILD_ERROR_NO_CALLBACK);
printf("execution_count = %d", execution_count);
printf("execution_count = %zu", execution_count);
exit:
return err;
}
Expand Down
42 changes: 29 additions & 13 deletions c/molecule2_verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ typedef enum WitnessLayoutId {
} WitnessLayoutId;

int verify_WitnessArgs(WitnessArgsType *witness);
int verify_WitnessLayout(WitnessLayoutType *witness);
int verify_WitnessLayout(WitnessLayoutType *witness, bool recursive);

#ifndef MOLECULEC_C2_DECLARATION_ONLY

Expand Down Expand Up @@ -177,28 +177,44 @@ int get_union_id(mol2_cursor_t *cur, uint32_t *union_id) {
return MOL2_OK;
}

int verify_WitnessLayout(WitnessLayoutType *witness) {
int verify_WitnessLayout(WitnessLayoutType *witness, bool recursive) {
int err = MOL2_OK;
uint32_t union_id = 0;
CHECK(get_union_id(&witness->cur, &union_id));

err = get_union_id(&witness->cur, &union_id);
CHECK(err);
switch (union_id) {
case WitnessLayoutSighashAll: {
SighashAllType sighash_all = witness->t->as_SighashAll(witness);
return verify_SighashAll(&sighash_all);
if (recursive) {
SighashAllType sighash_all = witness->t->as_SighashAll(witness);
err = verify_SighashAll(&sighash_all);
CHECK(err);
}
break;
}
case WitnessLayoutSighashAllOnly: {
SighashAllOnlyType sighash_all_only =
witness->t->as_SighashAllOnly(witness);
return verify_SighashAllOnly(&sighash_all_only);
if (recursive) {
SighashAllOnlyType sighash_all_only =
witness->t->as_SighashAllOnly(witness);
err = verify_SighashAllOnly(&sighash_all_only);
CHECK(err);
}
break;
}
case WitnessLayoutOtx: {
OtxType otx = witness->t->as_Otx(witness);
return verify_Otx(&otx);
if (recursive) {
OtxType otx = witness->t->as_Otx(witness);
err = verify_Otx(&otx);
CHECK(err);
}
break;
}
case WitnessLayoutOtxStart: {
OtxStartType otx_start = witness->t->as_OtxStart(witness);
return verify_OtxStart(&otx_start);
if (recursive) {
OtxStartType otx_start = witness->t->as_OtxStart(witness);
err = verify_OtxStart(&otx_start);
CHECK(err);
}
break;
}
default: {
return MOL2_ERR_UNKNOWN_ITEM;
Expand Down
1 change: 0 additions & 1 deletion c/omni_lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ bool is_memory_enough(mol_seg_t seg, const uint8_t *cur, uint32_t len) {
int parse_args(ScriptType script, ArgsType *args) {
int err = 0;

// TODO: do we need to validate Script structure here?
mol2_cursor_t script_args = script.t->args(&script);

// parse flags
Expand Down
1 change: 1 addition & 0 deletions deps/ed25519
Submodule ed25519 added at 34582a
5 changes: 5 additions & 0 deletions tests/omni_lock/omni_lock_sim.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ int hex2bin(uint8_t* buf, const char* src) {
return length;
}

int ed25519_verify(const unsigned char* signature, const unsigned char* message,
size_t message_len, const unsigned char* public_key) {
return 0;
}

UTEST(pubkey_hash, pass) {
init_input(&g_setting);
g_setting.flags = IdentityFlagsCkb;
Expand Down
Loading

0 comments on commit 2a04f15

Please sign in to comment.