diff --git a/c/auth.c b/c/auth.c index ae61b5f..5a93a4f 100644 --- a/c/auth.c +++ b/c/auth.c @@ -83,7 +83,7 @@ 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, bool compressed) { + size_t *out_pubkey_size, int recid, bool compressed) { int ret = 0; if (sig_len != SECP256K1_SIGNATURE_SIZE) { @@ -102,8 +102,7 @@ static int _recover_secp256k1_pubkey(const uint8_t *sig, size_t sig_len, } secp256k1_ecdsa_recoverable_signature signature; - if (secp256k1_ecdsa_recoverable_signature_parse_compact( - &context, &signature, sig, sig[RECID_INDEX]) == 0) { + if (secp256k1_ecdsa_recoverable_signature_parse_compact(&context, &signature, sig, (int)recid) == 0) { return ERROR_WRONG_STATE; } @@ -128,12 +127,27 @@ static int _recover_secp256k1_pubkey(const uint8_t *sig, size_t sig_len, return ret; } +// Refer to: https://en.bitcoin.it/wiki/BIP_0137 +int get_btc_recid(uint8_t d, bool *compressed) { + if (d >= 27 && d <= 30) { // P2PKH uncompressed + if (compressed) *compressed = false; + return d - 27; + } else if (d >= 31 && d <= 34) { // P2PKH compressed + if (compressed) *compressed = true; + return d - 31; + } else if (d >= 35 && d <= 38) { // Segwit P2SH + return d - 35; + } else if (d >= 39 && d <= 42) { // Segwit Bech32 + return d - 39; + } else { + return -1; + } +} + static int _recover_secp256k1_pubkey_btc(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, - bool compressed) { - (void)compressed; + size_t *out_pubkey_size) { int ret = 0; if (sig_len != SECP256K1_SIGNATURE_SIZE) { @@ -143,9 +157,11 @@ static int _recover_secp256k1_pubkey_btc(const uint8_t *sig, size_t sig_len, return ERROR_INVALID_ARG; } - // change 1 - int recid = (sig[0] - 27) & 3; - bool comp = ((sig[0] - 27) & 4) != 0; + bool rec_compressed = false; + int recid = get_btc_recid(sig[0], &rec_compressed); + if (recid == -1) { + return ERROR_INVALID_ARG; + } /* Load signature */ secp256k1_context context; @@ -169,7 +185,7 @@ static int _recover_secp256k1_pubkey_btc(const uint8_t *sig, size_t sig_len, } unsigned int flag = SECP256K1_EC_COMPRESSED; - if (comp) { + if (rec_compressed) { *out_pubkey_size = SECP256K1_PUBKEY_SIZE; flag = SECP256K1_EC_COMPRESSED; } else { @@ -193,8 +209,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, 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; @@ -217,8 +233,21 @@ int validate_signature_eth(void *prefilled_data, const uint8_t *sig, } uint8_t out_pubkey[UNCOMPRESSED_SECP256K1_PUBKEY_SIZE]; size_t out_pubkey_size = UNCOMPRESSED_SECP256K1_PUBKEY_SIZE; - ret = _recover_secp256k1_pubkey(sig, sig_len, msg, msg_len, out_pubkey, - &out_pubkey_size, false); + + // https://github.com/ethereum/go-ethereum/blob/v1.13.4/crypto/signature_nocgo.go#L72 + // The produced signature is in the [R || S || V] format where V is 0 or 1. + int recid = sig[RECID_INDEX]; + + // where the V value will be 27 or 28 for legacy reasons + // https://ethereum.github.io/yellowpaper/paper.pdf + if (recid == 27 || recid == 28) { + recid = recid - 27; + } + if (recid != 0 && recid != 1) { + return ERROR_INVALID_ARG; + } + + 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 @@ -243,7 +272,7 @@ int validate_signature_btc(void *prefilled_data, const uint8_t *sig, 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, false); + &out_pubkey_size); CHECK(err); const mbedtls_md_info_t *md_info = diff --git a/tests/auth_rust/src/tests/mod.rs b/tests/auth_rust/src/tests/mod.rs index 1660b5f..6526d37 100644 --- a/tests/auth_rust/src/tests/mod.rs +++ b/tests/auth_rust/src/tests/mod.rs @@ -268,6 +268,7 @@ fn bitcoin_pubkey_recid_verify() { verify_unit(&config), "failed conver btc", &[ + AuthErrorCodeType::InvalidArg as i32, AuthErrorCodeType::Mismatched as i32, AuthErrorCodeType::ErrorWrongState as i32, ], @@ -476,7 +477,10 @@ fn convert_btc_error() { assert_result_error( verify_unit(&config), "failed conver btc", - &[AuthErrorCodeType::Mismatched as i32], + &[ + AuthErrorCodeType::Mismatched as i32, + AuthErrorCodeType::InvalidArg as i32, + ], ); } @@ -522,7 +526,10 @@ fn convert_doge_error() { assert_result_error( verify_unit(&config), "failed conver doge", - &[AuthErrorCodeType::Mismatched as i32], + &[ + AuthErrorCodeType::Mismatched as i32, + AuthErrorCodeType::InvalidArg as i32, + ], ); }