Skip to content

Commit

Permalink
Support prefilled data in dynamic library (#41)
Browse files Browse the repository at this point in the history
* Add ckb_auth_load_prefilled_data

* Rename some interfaces

* Always fetch the prefilled data length in Rust

add examples of C & Rust
  • Loading branch information
XuJiandong authored Jan 17, 2024
1 parent 3937fed commit 6c84034
Show file tree
Hide file tree
Showing 13 changed files with 304 additions and 96 deletions.
101 changes: 81 additions & 20 deletions c/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ int md_string(const mbedtls_md_info_t *md_info, const uint8_t *buf, size_t n,
return err;
}

static int _recover_secp256k1_pubkey(const uint8_t *sig, size_t sig_len,
static int _recover_secp256k1_pubkey(uint8_t *prefilled_data,
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 recid,
Expand All @@ -98,8 +99,7 @@ static int _recover_secp256k1_pubkey(const uint8_t *sig, size_t sig_len,

/* Load signature */
secp256k1_context context;
uint8_t secp_data[CKB_SECP256K1_DATA_SIZE];
ret = ckb_secp256k1_custom_verify_only_initialize(&context, secp_data);
ret = ckb_secp256k1_custom_verify_only_initialize(&context, prefilled_data);
if (ret != 0) {
return ret;
}
Expand Down Expand Up @@ -164,7 +164,8 @@ int bitcoin_hash160(const uint8_t *data, size_t size, uint8_t *output) {
return 0;
}

static int _recover_secp256k1_pubkey_btc(const uint8_t *sig, size_t sig_len,
static int _recover_secp256k1_pubkey_btc(uint8_t *prefilled_data,
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) {
Expand All @@ -182,10 +183,9 @@ static int _recover_secp256k1_pubkey_btc(const uint8_t *sig, size_t sig_len,
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);

ret = ckb_secp256k1_custom_verify_only_initialize(&context, prefilled_data);
if (ret != 0) {
return ret;
}
Expand Down Expand Up @@ -243,8 +243,9 @@ int validate_signature_ckb(uint8_t *prefilled_data, uint8_t algorithm_id,
uint8_t out_pubkey[SECP256K1_PUBKEY_SIZE];
size_t out_pubkey_size = SECP256K1_PUBKEY_SIZE;

ret = _recover_secp256k1_pubkey(sig, sig_len, msg, msg_len, out_pubkey,
&out_pubkey_size, sig[RECID_INDEX], true);
ret = _recover_secp256k1_pubkey(prefilled_data, sig, sig_len, msg, msg_len,
out_pubkey, &out_pubkey_size,
sig[RECID_INDEX], true);
if (ret != 0) return ret;

blake2b_state ctx;
Expand Down Expand Up @@ -286,8 +287,8 @@ int validate_signature_eth(uint8_t *prefilled_data, uint8_t algorithm_id,
return ERROR_INVALID_ARG;
}

ret = _recover_secp256k1_pubkey(sig, sig_len, msg, msg_len, out_pubkey,
&out_pubkey_size, recid, false);
ret = _recover_secp256k1_pubkey(prefilled_data, sig, sig_len, msg, msg_len,
out_pubkey, &out_pubkey_size, recid, false);
if (ret != 0) return ret;

// here are the 2 differences than validate_signature_secp256k1
Expand All @@ -311,8 +312,8 @@ int validate_signature_eos(uint8_t *prefilled_data, uint8_t algorithm_id,
}
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);
err = _recover_secp256k1_pubkey_btc(prefilled_data, sig, sig_len, msg,
msg_len, out_pubkey, &out_pubkey_size);
CHECK(err);

blake2b_state ctx;
Expand All @@ -335,8 +336,8 @@ int validate_signature_btc(uint8_t *prefilled_data, uint8_t algorithm_id,
}
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);
err = _recover_secp256k1_pubkey_btc(prefilled_data, sig, sig_len, msg,
msg_len, out_pubkey, &out_pubkey_size);
CHECK(err);

unsigned char temp[AUTH160_SIZE];
Expand All @@ -363,8 +364,7 @@ int validate_signature_schnorr(uint8_t *prefilled_data, uint8_t algorithm_id,
return ERROR_INVALID_ARG;
}
secp256k1_context ctx;
uint8_t secp_data[CKB_SECP256K1_DATA_SIZE];
err = ckb_secp256k1_custom_verify_only_initialize(&ctx, secp_data);
err = ckb_secp256k1_custom_verify_only_initialize(&ctx, prefilled_data);
if (err != 0) return err;

secp256k1_xonly_pubkey pk;
Expand Down Expand Up @@ -440,7 +440,7 @@ int validate_signature_ripple(uint8_t *prefilled_data, uint8_t algorithm_id,
CHECK2(memcmp(sign_data.ckb_msg, msg, RIPPLE_ACCOUNT_ID_SIZE) == 0,
ERROR_INVALID_ARG);

CHECK(verify_ripple(&sign_data));
CHECK(verify_ripple(prefilled_data, &sign_data));
get_ripple_pubkey_hash(sign_data.public_key, out_pubkey_hash);
exit:
return err;
Expand Down Expand Up @@ -1034,8 +1034,7 @@ int verify_multisig(uint8_t *prefilled_data, const uint8_t *lock_bytes,
// contract, you don't have to wait for the foundation to ship a new
// cryptographic algorithm. You can just build and ship your own.
secp256k1_context context;
uint8_t secp_data[CKB_SECP256K1_DATA_SIZE];
ret = ckb_secp256k1_custom_verify_only_initialize(&context, secp_data);
ret = ckb_secp256k1_custom_verify_only_initialize(&context, prefilled_data);
if (ret != 0) return ret;

// We will perform *threshold* number of signature verifications here.
Expand Down Expand Up @@ -1107,7 +1106,69 @@ int verify_multisig(uint8_t *prefilled_data, const uint8_t *lock_bytes,
return 0;
}

static bool require_secp256k1_data(uint8_t algorithm_id) {
switch (algorithm_id) {
case AuthAlgorithmIdCkb:
case AuthAlgorithmIdEthereum:
case AuthAlgorithmIdEos:
case AuthAlgorithmIdTron:
case AuthAlgorithmIdBitcoin:
case AuthAlgorithmIdDogecoin:
case AuthAlgorithmIdCkbMultisig:
case AuthAlgorithmIdSchnorr:
case AuthAlgorithmIdLitecoin:
case AuthAlgorithmIdRipple:
return true;
default:
return false;
}
return false;
}

// dynamic linking entry
__attribute__((visibility("default"))) int ckb_auth_load_prefilled_data(
uint8_t algorithm_id, uint8_t *prefilled_data, size_t *len) {
if (require_secp256k1_data(algorithm_id)) {
if (prefilled_data == NULL) {
if (*len == 0) {
*len = CKB_AUTH_RECOMMEND_PREFILLED_LEN;
return 0;
} else {
return ERROR_PREFILLED;
}
} else {
if (*len >= CKB_AUTH_RECOMMEND_PREFILLED_LEN) {
size_t index = SIZE_MAX;
int err =
ckb_look_for_dep_with_hash(ckb_secp256k1_data_hash, &index);
if (err) {
return err;
}
uint64_t len = CKB_AUTH_RECOMMEND_PREFILLED_LEN;
err = ckb_load_cell_data(prefilled_data, &len, 0, index,
CKB_SOURCE_CELL_DEP);
if (err || len != CKB_AUTH_RECOMMEND_PREFILLED_LEN) {
return ERROR_PREFILLED;
}
return 0;
} else {
return ERROR_PREFILLED;
}
}
} else {
if (prefilled_data == NULL) {
if (*len == 0) {
return 0;
} else {
return ERROR_PREFILLED;
}
} else {
*len = 0;
return 0;
}
}
}

__attribute__((visibility("default"))) int ckb_auth_validate(
uint8_t *prefilled_data, uint8_t algorithm_id, const uint8_t *sig,
size_t sig_len, const uint8_t *msg, size_t msg_len, uint8_t *pubkey_hash,
Expand Down
1 change: 1 addition & 0 deletions c/auth.syms
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
ckb_auth_validate;
ckb_auth_load_prefilled_data;
};
8 changes: 7 additions & 1 deletion c/auth_libecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ static int verify_secp256r1(CkbAuthValidatorType *validator,
return err;
}

// secp256r1 don't need prefilled data.
__attribute__((visibility("default"))) int ckb_auth_load_prefilled_data(
uint8_t algorithm_id, uint8_t *prefilled_data, size_t *len) {
*len = 0;
return 0;
}

// dynamic linking entry
__attribute__((visibility("default"))) int ckb_auth_validate(
uint8_t *prefilled_data, uint8_t algorithm_id, const uint8_t *sig,
Expand All @@ -116,7 +123,6 @@ __attribute__((visibility("default"))) int ckb_auth_validate(
CHECK2(msg != NULL, ERROR_INVALID_ARG);
CHECK2(msg_len > 0, ERROR_INVALID_ARG);
CHECK2(pubkey_hash_len == AUTH160_SIZE, ERROR_INVALID_ARG);

if (algorithm_id == AuthAlgorithmIdSecp256R1) {
err = verify_secp256r1(&validator, validate_signature_secp256r1,
convert_copy);
Expand Down
66 changes: 58 additions & 8 deletions c/ckb_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
#define CKB_AUTH_LEN 21
#define AUTH160_SIZE 20
#define BLAKE2B_BLOCK_SIZE 32
// This recommended values is from secp256k1 data but might be changed in the
// future. The buffer with this size must be success to call
// ckb_auth_load_prefilled_data, for any algorithm id. For dependency issue,
// don't include secp256k1_data_info_20210801.h in this file.
#define CKB_AUTH_RECOMMEND_PREFILLED_LEN 1048576

enum AuthErrorCodeType {
ERROR_NOT_IMPLEMENTED = 100,
Expand All @@ -47,6 +52,8 @@ enum AuthErrorCodeType {
ERROR_SPAWN_INVALID_PUBKEY,
// schnorr
ERROR_SCHNORR,
// prefilled error
ERROR_PREFILLED,
};

typedef struct CkbAuthType {
Expand Down Expand Up @@ -96,6 +103,9 @@ typedef int (*ckb_auth_validate_t)(uint8_t *prefilled_data,
size_t sig_len, const uint8_t *msg,
size_t msg_len, uint8_t *pubkey_hash,
size_t pubkey_hash_len);
typedef int (*ckb_auth_load_prefilled_data_t)(uint8_t algorithm_id,
uint8_t *prefilled_data,
size_t *len);

typedef struct CkbAuthValidatorType {
uint8_t *prefilled_data;
Expand All @@ -108,6 +118,9 @@ typedef struct CkbAuthValidatorType {
size_t pubkey_hash_len;
} CkbAuthValidatorType;

int ckb_auth_load_prefilled_data(uint8_t algorithm_id, uint8_t *prefilled_data,
size_t *len);

#ifndef CKB_AUTH_DISABLE_DYNAMIC_LIB

#ifndef CKB_AUTH_DL_BUFF_SIZE
Expand All @@ -130,18 +143,22 @@ typedef struct {

void *handle;
ckb_auth_validate_t func;
ckb_auth_load_prefilled_data_t func2;
} CkbDLCache;

static CkbDLCache g_dl_cache[CKB_AUTH_DL_MAX_COUNT];
static size_t g_dl_cache_count = 0;

int get_dl_func_by_code_hash(const uint8_t *code_hash, uint8_t hash_type,
ckb_auth_validate_t *out_func) {
ckb_auth_validate_t *out_func,
ckb_auth_load_prefilled_data_t *out_func2) {
// Find from cache
for (size_t i = 0; i < g_dl_cache_count; i++) {
CkbDLCache *cache = &g_dl_cache[i];
if (memcmp(cache->code_hash, code_hash, BLAKE2B_BLOCK_SIZE) == 0 &&
hash_type == cache->hash_type) {
*out_func = cache->func;
*out_func2 = cache->func2;
return 0;
}
}
Expand Down Expand Up @@ -173,8 +190,14 @@ int get_dl_func_by_code_hash(const uint8_t *code_hash, uint8_t hash_type,
if (cache->func == 0) {
return CKB_INVALID_DATA;
}
cache->func2 = (ckb_auth_load_prefilled_data_t)ckb_dlsym(
cache->handle, "ckb_auth_load_prefilled_data");
if (cache->func2 == 0) {
return CKB_INVALID_DATA;
}

*out_func = cache->func;
*out_func2 = cache->func2;
memcpy(cache->code_hash, code_hash, BLAKE2B_BLOCK_SIZE);
cache->hash_type = hash_type;

Expand All @@ -184,7 +207,28 @@ int get_dl_func_by_code_hash(const uint8_t *code_hash, uint8_t hash_type,

#endif // CKB_AUTH_DISABLE_DYNAMIC_LIB

int ckb_auth(uint8_t *prefilled_data, CkbEntryType *entry, CkbAuthType *id,
int ckb_auth_prepare(CkbEntryType *entry, uint8_t algorithm_id,
uint8_t *prefilled_data, size_t *len) {
if (entry->entry_category == EntryCategoryDynamicLibrary) {
#ifdef CKB_AUTH_DISABLE_DYNAMIC_LIB
// none dynamic library doesn't require prepare
return 0;
#else // CKB_AUTH_DISABLE_DYNAMIC_LIB
ckb_auth_validate_t func = NULL;
ckb_auth_load_prefilled_data_t func2 = NULL;
int err = get_dl_func_by_code_hash(entry->code_hash, entry->hash_type,
&func, &func2);
if (err) {
return err;
}
return func2(algorithm_id, prefilled_data, len);
#endif // CKB_AUTH_DISABLE_DYNAMIC_LIB
} else {
return 0;
}
}

int ckb_auth(CkbEntryType *entry, uint8_t *prefilled_data, CkbAuthType *id,
const uint8_t *signature, uint32_t signature_size,
const uint8_t *message32) {
int err = 0;
Expand All @@ -194,8 +238,9 @@ int ckb_auth(uint8_t *prefilled_data, CkbEntryType *entry, CkbAuthType *id,
return ERROR_INVALID_ARG;
#else // CKB_AUTH_DISABLE_DYNAMIC_LIB
ckb_auth_validate_t func = NULL;
err =
get_dl_func_by_code_hash(entry->code_hash, entry->hash_type, &func);
ckb_auth_load_prefilled_data_t func2 = NULL;
err = get_dl_func_by_code_hash(entry->code_hash, entry->hash_type,
&func, &func2);
if (err) {
return err;
}
Expand Down Expand Up @@ -310,10 +355,15 @@ static int ckb_auth_validate_with_func(int argc, char *argv[],
pubkey_hash_len == AUTH160_SIZE,
ERROR_SPAWN_INVALID_PUBKEY);

// TODO: load prefilled data when in entry of exec/spawn
err = validate_func(NULL, algorithm_id, signature, (size_t)signature_len,
message, (size_t)message_len, pubkey_hash,
(size_t)pubkey_hash_len);
// In exec/spawn, it's safe to allocate big stack memory since the script
// owns whole 4M memory.
uint8_t secp_data[CKB_AUTH_RECOMMEND_PREFILLED_LEN];
size_t len = sizeof(secp_data);
err = ckb_auth_load_prefilled_data(algorithm_id, secp_data, &len);
CHECK(err);
err = validate_func(secp_data, algorithm_id, signature,
(size_t)signature_len, message, (size_t)message_len,
pubkey_hash, (size_t)pubkey_hash_len);
CHECK(err);

exit:
Expand Down
5 changes: 2 additions & 3 deletions c/ripple.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,17 +215,16 @@ int get_ripple_verify_data(const uint8_t *sign, size_t sign_len,
#undef SIGN_BUFF_OFFSET
}

int verify_ripple(RippleSignatureData *data) {
int verify_ripple(uint8_t *prefilled_data, RippleSignatureData *data) {
int err = 0;

uint8_t msg_hash[256];
const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
CHECK(mbedtls_md(md_info, data->sign_msg, data->sign_msg_len, msg_hash));

uint8_t secp256k1_ctx_buf[CKB_SECP256K1_DATA_SIZE];
secp256k1_context ctx;
ckb_secp256k1_custom_verify_only_initialize(&ctx, secp256k1_ctx_buf);
ckb_secp256k1_custom_verify_only_initialize(&ctx, prefilled_data);

secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
Expand Down
Loading

0 comments on commit 6c84034

Please sign in to comment.