Skip to content

Commit

Permalink
add Secp256R1Raw support (#33)
Browse files Browse the repository at this point in the history
* add secp256r1 raw message verification (signature without hash)

* update libecc
  • Loading branch information
contrun authored Dec 26, 2023
1 parent e8316d0 commit 677c46f
Show file tree
Hide file tree
Showing 10 changed files with 419 additions and 177 deletions.
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

0 comments on commit 677c46f

Please sign in to comment.