Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Secp256R1Raw support #33

Merged
merged 14 commits into from
Dec 26, 2023
141 changes: 86 additions & 55 deletions c/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ int md_string(const mbedtls_md_info_t *md_info, const uint8_t *buf, size_t n,
static int _recover_secp256k1_pubkey(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, bool compressed) {
size_t *out_pubkey_size, int recid,
bool compressed) {
int ret = 0;

if (sig_len != SECP256K1_SIGNATURE_SIZE) {
Expand Down Expand Up @@ -208,18 +209,23 @@ static int _recover_secp256k1_pubkey_btc(const uint8_t *sig, size_t sig_len,
if (v_type == BTCVType_P2PKHUncompressed) {
*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) {
if (secp256k1_ec_pubkey_serialize(&context, out_pubkey, out_pubkey_size,
&pubkey, flag) != 1) {
return ERROR_WRONG_STATE;
}
} else if (v_type == BTCVType_P2PKHCompressed || v_type == BTCVType_SegwitBech32 || v_type == BTCVType_SegwitP2SH) {
} else if (v_type == BTCVType_P2PKHCompressed ||
v_type == BTCVType_SegwitBech32 ||
v_type == BTCVType_SegwitP2SH) {
*out_pubkey_size = SECP256K1_PUBKEY_SIZE;
flag = SECP256K1_EC_COMPRESSED;
if (secp256k1_ec_pubkey_serialize(&context, out_pubkey, out_pubkey_size, &pubkey, flag) != 1) {
if (secp256k1_ec_pubkey_serialize(&context, out_pubkey, out_pubkey_size,
&pubkey, flag) != 1) {
return ERROR_WRONG_STATE;
}

if (v_type == BTCVType_SegwitP2SH) {
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
unsigned char temp[SHA256_SIZE];
int err = md_string(md_info, out_pubkey, *out_pubkey_size, temp);
if (err) return err;
Expand Down Expand Up @@ -250,7 +256,8 @@ int validate_signature_ckb(void *prefilled_data, const uint8_t *sig,
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(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 @@ -292,7 +299,8 @@ int validate_signature_eth(void *prefilled_data, const uint8_t *sig,
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(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 @@ -307,15 +315,17 @@ int validate_signature_eth(void *prefilled_data, const uint8_t *sig,
return ret;
}

int validate_signature_eos(void *prefilled_data, const uint8_t *sig, size_t sig_len, const uint8_t *msg, size_t msg_len,
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);
err = _recover_secp256k1_pubkey_btc(sig, sig_len, msg, msg_len, out_pubkey,
&out_pubkey_size);
CHECK(err);

blake2b_state ctx;
Expand Down Expand Up @@ -476,20 +486,23 @@ size_t write_varint(uint8_t *dest, size_t n) {
}

// Read uint16_t from varint buffer
// See https://github.com/solana-labs/solana/blob/3b0b0ba07d345ef86e270187a1a7d99bd0da7f4c/sdk/program/src/short_vec.rs#L120-L148
// See
// https://github.com/solana-labs/solana/blob/3b0b0ba07d345ef86e270187a1a7d99bd0da7f4c/sdk/program/src/short_vec.rs#L120-L148
int read_varint_u16(uint8_t **src, size_t src_size, uint16_t *result) {
size_t maximum_full_bytes = sizeof(uint16_t) * 8 / 7;

uint8_t *ptr = *src;
uint16_t acc = 0;
for (size_t i = 0; i <= maximum_full_bytes; i++) {
if (i >= src_size) {
return -1;
}
uint8_t current_value = *ptr;
size_t bits = (i < maximum_full_bytes) ? 7 : sizeof(uint16_t)*8 - maximum_full_bytes*7;
size_t bits = (i < maximum_full_bytes)
? 7
: sizeof(uint16_t) * 8 - maximum_full_bytes * 7;
uint8_t maximum_value = (1 << bits) - 1;
acc += ((uint16_t)(current_value & maximum_value) << (i*7));
acc += ((uint16_t)(current_value & maximum_value) << (i * 7));
ptr = ptr + 1;
if (current_value < 0x80 && i < maximum_full_bytes) {
*src = ptr;
Expand Down Expand Up @@ -619,24 +632,37 @@ int validate_signature_monero(void *prefilled_data, const uint8_t *sig,
return err;
}

int validate_solana_signed_message(const uint8_t *signed_msg, size_t signed_msg_len, const uint8_t *pub_key,
const uint8_t *blockhash) {
int validate_solana_signed_message(const uint8_t *signed_msg,
size_t signed_msg_len,
const uint8_t *pub_key,
const uint8_t *blockhash) {
int err = 0;
// Official solana transaction structure documentation.
// [Transactions | Solana Docs](https://docs.solana.com/developing/programming-model/transactions)
// [Transactions | Solana
// Docs](https://docs.solana.com/developing/programming-model/transactions)
// See also
// https://github.com/solana-labs/solana/blob/3b0b0ba07d345ef86e270187a1a7d99bd0da7f4c/sdk/program/src/message/legacy.rs#L90-L129
CHECK2(signed_msg_len > SOLANA_MESSAGE_HEADER_SIZE + SOLANA_BLOCKHASH_SIZE, ERROR_INVALID_ARG);
CHECK2(signed_msg_len > SOLANA_MESSAGE_HEADER_SIZE + SOLANA_BLOCKHASH_SIZE,
ERROR_INVALID_ARG);
uint8_t num_signers = *signed_msg;
uint16_t num_keys = 0;
uint8_t *pub_key_ptr = (uint8_t *)(signed_msg + SOLANA_MESSAGE_HEADER_SIZE);
CHECK2(read_varint_u16(&pub_key_ptr, signed_msg_len - SOLANA_MESSAGE_HEADER_SIZE, &num_keys) == 0, ERROR_INVALID_ARG);
size_t pub_key_size = (pub_key_ptr - (uint8_t *)(signed_msg + SOLANA_MESSAGE_HEADER_SIZE)) + SOLANA_PUBKEY_SIZE * num_keys;
CHECK2(signed_msg_len > SOLANA_MESSAGE_HEADER_SIZE + pub_key_size + SOLANA_BLOCKHASH_SIZE, ERROR_INVALID_ARG);
const uint8_t *blockhash_ptr = signed_msg + SOLANA_MESSAGE_HEADER_SIZE + pub_key_size;
CHECK2(memcmp(blockhash_ptr, blockhash, SOLANA_BLOCKHASH_SIZE) == 0, ERROR_INVALID_ARG);
for (uint8_t i=0; i<num_signers; i++) {
uint8_t *tmp_pub_key = pub_key_ptr + i*SOLANA_PUBKEY_SIZE;
CHECK2(read_varint_u16(&pub_key_ptr,
signed_msg_len - SOLANA_MESSAGE_HEADER_SIZE,
&num_keys) == 0,
ERROR_INVALID_ARG);
size_t pub_key_size =
(pub_key_ptr - (uint8_t *)(signed_msg + SOLANA_MESSAGE_HEADER_SIZE)) +
SOLANA_PUBKEY_SIZE * num_keys;
CHECK2(signed_msg_len > SOLANA_MESSAGE_HEADER_SIZE + pub_key_size +
SOLANA_BLOCKHASH_SIZE,
ERROR_INVALID_ARG);
const uint8_t *blockhash_ptr =
signed_msg + SOLANA_MESSAGE_HEADER_SIZE + pub_key_size;
CHECK2(memcmp(blockhash_ptr, blockhash, SOLANA_BLOCKHASH_SIZE) == 0,
ERROR_INVALID_ARG);
for (uint8_t i = 0; i < num_signers; i++) {
uint8_t *tmp_pub_key = pub_key_ptr + i * SOLANA_PUBKEY_SIZE;
if (memcmp(tmp_pub_key, pub_key, SOLANA_PUBKEY_SIZE) == 0) {
return 0;
}
Expand All @@ -657,14 +683,17 @@ int validate_signature_solana(void *prefilled_data, const uint8_t *sig,
sig_len = (size_t)sig[0] | ((size_t)sig[1] << 8);
CHECK2(sig_len <= SOLANA_UNWRAPPED_SIGNATURE_SIZE, ERROR_INVALID_ARG);
const uint8_t *signature_ptr = sig + 2;
const uint8_t *pub_key_ptr = signature_ptr + SOLANA_SIGNATURE_SIZE;
const uint8_t *signed_msg_ptr = signature_ptr + SOLANA_SIGNATURE_SIZE + SOLANA_PUBKEY_SIZE;
size_t signed_msg_len = sig_len - SOLANA_SIGNATURE_SIZE - SOLANA_PUBKEY_SIZE;

CHECK(validate_solana_signed_message(signed_msg_ptr, signed_msg_len, pub_key_ptr, msg));
const uint8_t *pub_key_ptr = signature_ptr + SOLANA_SIGNATURE_SIZE;
const uint8_t *signed_msg_ptr =
signature_ptr + SOLANA_SIGNATURE_SIZE + SOLANA_PUBKEY_SIZE;
size_t signed_msg_len =
sig_len - SOLANA_SIGNATURE_SIZE - SOLANA_PUBKEY_SIZE;

CHECK(validate_solana_signed_message(signed_msg_ptr, signed_msg_len,
pub_key_ptr, msg));

int suc = ed25519_verify(signature_ptr, signed_msg_ptr, signed_msg_len, pub_key_ptr);
int suc = ed25519_verify(signature_ptr, signed_msg_ptr, signed_msg_len,
pub_key_ptr);
CHECK2(suc == 1, ERROR_WRONG_STATE);

blake2b_state ctx;
Expand All @@ -679,64 +708,69 @@ int validate_signature_solana(void *prefilled_data, const uint8_t *sig,
return err;
}


// Ton uses ed25519 to sign messages. The message to be signed is
// message = utf8_encode("ton-proof-item-v2/") ++
// Address ++
// AppDomain ++
// Timestamp ++
// Payload
// signature = Ed25519Sign(privkey, sha256(0xffff ++ utf8_encode("ton-connect") ++ sha256(message)))
// where
// Prefix = 18 bytes "ton-proof-item-v2/" without trailing null
// Address = Big endian work chain (uint32) + address (32 bytes)
// AppDomain = Little endian domain length (uint32) + domain (string without trailling null)
// Timestamp = Epoch seconds Little endian uint64
// Payload = Arbitrary bytes, we use block hash here
// See ton official document on ton-proof https://docs.ton.org/develop/dapps/ton-connect/sign
int get_toncoin_message(const uint8_t *signed_msg, size_t signed_msg_len, const uint8_t *blockhash, uint8_t output[32]) {
// signature = Ed25519Sign(privkey, sha256(0xffff ++ utf8_encode("ton-connect")
// ++ sha256(message))) where Prefix = 18 bytes "ton-proof-item-v2/" without
// trailing null Address = Big endian work chain (uint32) + address (32 bytes)
// AppDomain = Little endian domain length (uint32) + domain (string without
// trailling null) Timestamp = Epoch seconds Little endian uint64 Payload =
// Arbitrary bytes, we use block hash here See ton official document on
// ton-proof https://docs.ton.org/develop/dapps/ton-connect/sign
int get_toncoin_message(const uint8_t *signed_msg, size_t signed_msg_len,
const uint8_t *blockhash, uint8_t output[32]) {
int err = 0;
uint8_t preimage1[TONCOIN_MAX_PREIMAGE_SIZE];
uint8_t preimage2[TONCOIN_PREIMAGE2_SIZE];

int preimage1_size = signed_msg_len + TONCOIN_MESSAGE_PREFIX_SIZE + TONCOIN_BLOCKHASH_SIZE;
int preimage1_size =
signed_msg_len + TONCOIN_MESSAGE_PREFIX_SIZE + TONCOIN_BLOCKHASH_SIZE;
CHECK2(preimage1_size <= TONCOIN_MAX_PREIMAGE_SIZE, ERROR_INVALID_ARG);

const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);

memcpy(preimage1, "ton-proof-item-v2/", TONCOIN_MESSAGE_PREFIX_SIZE);
memcpy(preimage1+TONCOIN_MESSAGE_PREFIX_SIZE, signed_msg, signed_msg_len);
memcpy(preimage1+TONCOIN_MESSAGE_PREFIX_SIZE+signed_msg_len, blockhash, TONCOIN_BLOCKHASH_SIZE);
memcpy(preimage1 + TONCOIN_MESSAGE_PREFIX_SIZE, signed_msg, signed_msg_len);
memcpy(preimage1 + TONCOIN_MESSAGE_PREFIX_SIZE + signed_msg_len, blockhash,
TONCOIN_BLOCKHASH_SIZE);
preimage2[0] = 0xff;
preimage2[1] = 0xff;
memcpy(preimage2+2, "ton-connect", TONCOIN_MESSAGE_PREFIX2_SIZE);
memcpy(preimage2 + 2, "ton-connect", TONCOIN_MESSAGE_PREFIX2_SIZE);

CHECK(md_string(md_info, preimage1, preimage1_size, preimage2+2+TONCOIN_MESSAGE_PREFIX2_SIZE));
CHECK(md_string(md_info, preimage1, preimage1_size,
preimage2 + 2 + TONCOIN_MESSAGE_PREFIX2_SIZE));
CHECK(md_string(md_info, preimage2, TONCOIN_PREIMAGE2_SIZE, output));
exit:
return err;
}

int validate_signature_toncoin(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) {
size_t sig_len, const uint8_t *msg,
size_t msg_len, uint8_t *output,
size_t *output_len) {
int err = 0;

CHECK2(sig_len == TONCOIN_WRAPPED_SIGNATURE_SIZE, ERROR_INVALID_ARG);
CHECK2(msg_len == TONCOIN_BLOCKHASH_SIZE, ERROR_INVALID_ARG);
sig_len = (size_t)sig[0] | ((size_t)sig[1] << 8);
CHECK2(sig_len <= TONCOIN_UNWRAPPED_SIGNATURE_SIZE, ERROR_INVALID_ARG);
const uint8_t *signature_ptr = sig + 2;
const uint8_t *pub_key_ptr = signature_ptr + TONCOIN_SIGNATURE_SIZE;
const uint8_t *signed_msg_ptr = signature_ptr + TONCOIN_SIGNATURE_SIZE + TONCOIN_PUBKEY_SIZE;
size_t signed_msg_len = sig_len - TONCOIN_SIGNATURE_SIZE - TONCOIN_PUBKEY_SIZE;
const uint8_t *pub_key_ptr = signature_ptr + TONCOIN_SIGNATURE_SIZE;
const uint8_t *signed_msg_ptr =
signature_ptr + TONCOIN_SIGNATURE_SIZE + TONCOIN_PUBKEY_SIZE;
size_t signed_msg_len =
sig_len - TONCOIN_SIGNATURE_SIZE - TONCOIN_PUBKEY_SIZE;

uint8_t message[32];
CHECK(get_toncoin_message(signed_msg_ptr, signed_msg_len, msg, message));

int suc = ed25519_verify(signature_ptr, message, sizeof(message), pub_key_ptr);
int suc =
ed25519_verify(signature_ptr, message, sizeof(message), pub_key_ptr);
CHECK2(suc == 1, ERROR_WRONG_STATE);

blake2b_state ctx;
Expand All @@ -753,7 +787,6 @@ int validate_signature_toncoin(void *prefilled_data, const uint8_t *sig,
return err;
}


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)
Expand Down Expand Up @@ -1189,5 +1222,3 @@ int main(int argc, char *argv[]) {

return ckb_auth_validate_with_func(argc, argv, *ckb_auth_validate);
}


49 changes: 42 additions & 7 deletions c/auth_libecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,40 @@
#undef CKB_SUCCESS
// clang-format on


int validate_signature_secp256r1(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) {
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;
}
CHECK2(msg_len == BLAKE2B_BLOCK_SIZE, ERROR_INVALID_ARG);
CHECK2(sig_len == SECP256R1_DATA_SIZE, ERROR_INVALID_ARG);
const uint8_t *pub_key_ptr = sig;
const uint8_t *signature_ptr = pub_key_ptr + SECP256R1_PUBKEY_SIZE;

CHECK(secp256r1_verify_signature(signature_ptr, SECP256R1_SIGNATURE_SIZE,
pub_key_ptr, SECP256R1_PUBKEY_SIZE, msg,
msg_len));

blake2b_state ctx;
uint8_t pubkey_hash[BLAKE2B_BLOCK_SIZE] = {0};
blake2b_init(&ctx, BLAKE2B_BLOCK_SIZE);
blake2b_update(&ctx, pub_key_ptr, SECP256R1_PUBKEY_SIZE);
blake2b_final(&ctx, pubkey_hash, sizeof(pubkey_hash));

memcpy(output, pubkey_hash, AUTH160_SIZE);
*output_len = AUTH160_SIZE;
exit:
return err;
}

int validate_signature_secp256r1_raw(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) {
Expand All @@ -29,9 +58,11 @@ int validate_signature_secp256r1(void *prefilled_data, const uint8_t *sig,
CHECK2(msg_len == BLAKE2B_BLOCK_SIZE, ERROR_INVALID_ARG);
CHECK2(sig_len == SECP256R1_DATA_SIZE, ERROR_INVALID_ARG);
const uint8_t *pub_key_ptr = sig;
const uint8_t *signature_ptr = pub_key_ptr + SECP256R1_PUBKEY_SIZE;
const uint8_t *signature_ptr = pub_key_ptr + SECP256R1_PUBKEY_SIZE;

CHECK(secp256r1_verify_signature(signature_ptr, SECP256R1_SIGNATURE_SIZE, pub_key_ptr, SECP256R1_PUBKEY_SIZE, msg, msg_len ));
CHECK(secp256r1_raw_verify_signature(signature_ptr,
SECP256R1_SIGNATURE_SIZE, pub_key_ptr,
SECP256R1_PUBKEY_SIZE, msg, msg_len));

blake2b_state ctx;
uint8_t pubkey_hash[BLAKE2B_BLOCK_SIZE] = {0};
Expand Down Expand Up @@ -75,7 +106,6 @@ static int verify(uint8_t *pubkey_hash, const uint8_t *sig, uint32_t sig_len,
return err;
}


// dynamic linking entry
__attribute__((visibility("default"))) int ckb_auth_validate(
uint8_t auth_algorithm_id, const uint8_t *signature,
Expand All @@ -91,6 +121,11 @@ __attribute__((visibility("default"))) int ckb_auth_validate(
err = verify(pubkey_hash, signature, signature_size, message,
message_size, validate_signature_secp256r1, convert_copy);
CHECK(err);
} else if (auth_algorithm_id == AuthAlgorithmIdSecp256R1Raw) {
err = verify(pubkey_hash, signature, signature_size, message,
message_size, validate_signature_secp256r1_raw,
convert_copy);
CHECK(err);
} else {
CHECK2(false, ERROR_NOT_IMPLEMENTED);
}
Expand Down
Loading