#include #include "sha3.h" #define SHA3_BLOCK_SIZE 32 #define CUSTOM_ABORT 1 #define CUSTOM_PRINT_ERR 1 #include "syscall.h" void custom_abort() { syscall_errno(93, 10, 0, 0, 0, 0, 0); } int custom_print_err(const char* arg, ...) { (void)arg; return 0; } #include /* * We are including secp256k1 implementation directly so gcc can strip * unused functions. For some unknown reasons, if we link in libsecp256k1.a * directly, the final binary will include all functions rather than those used. */ #include int char_to_int(char ch) { if (ch >= '0' && ch <= '9') { return ch - '0'; } if (ch >= 'a' && ch <= 'f') { return ch - 'a' + 10; } return -1; } int hex_to_bin(char* buf, size_t buf_len, const char* hex) { int i = 0; for (; i < buf_len && hex[i * 2] != '\0' && hex[i * 2 + 1] != '\0'; i++) { int a = char_to_int(hex[i * 2]); int b = char_to_int(hex[i * 2 + 1]); if (a < 0 || b < 0) { return -1; } buf[i] = ((a & 0xF) << 4) | (b & 0xF); } if (i == buf_len && hex[i * 2] != '\0') { return -1; } return i; } #define CHECK_LEN(x) \ if ((x) <= 0) { \ return x; \ } /* * Arguments are listed in the following order: * 0. Program name, ignored here, only preserved for compatibility reason * 1. Current script hash in hex format, which is 128 bytes. While this program * cannot verify the hash directly, this ensures the script is include in * signature calculation * 2. Other additional parameters that might be included. Notice only ASCII * characters are included, so binary should be passed as binary format. * 3. Pubkey in hex format, a maximum of 130 bytes will be processed * 4. Signature in hex format, a maximum of 512 bytes will be processed * * This program will run double sha256 on all arguments excluding pubkey and * signature(also for simplicity, we are running sha256 on ASCII chars directly, * not deserialized raw bytes), then it will use sha256 result calculated as the * message to verify the signature. It returns 0 if the signature works, and * a non-zero value otherwise. * * Note all hex values passed in as arguments must have lower case letters for * deterministic behavior. */ int main(int argc, char* argv[]) { char buf[256]; int len; if (argc < 4) { return -1; } secp256k1_context context; int ret = secp256k1_context_initialize(&context, SECP256K1_CONTEXT_VERIFY); if (ret == 0) { return 4; } len = hex_to_bin(buf, 65, argv[argc - 2]); CHECK_LEN(len); secp256k1_pubkey pubkey; ret = secp256k1_ec_pubkey_parse(&context, &pubkey, buf, len); if (ret == 0) { return 1; } len = hex_to_bin(buf, 256, argv[argc - 1]); CHECK_LEN(len); secp256k1_ecdsa_signature signature; secp256k1_ecdsa_signature_parse_der(&context, &signature, buf, len); if (ret == 0) { return 3; } sha3_ctx_t sha3_ctx; unsigned char hash[SHA3_BLOCK_SIZE]; sha3_init(&sha3_ctx, SHA3_BLOCK_SIZE); for (int i = 1; i < argc - 2; i++) { sha3_update(&sha3_ctx, argv[i], strlen(argv[i])); } sha3_final(hash, &sha3_ctx); sha3_init(&sha3_ctx, SHA3_BLOCK_SIZE); sha3_update(&sha3_ctx, hash, SHA3_BLOCK_SIZE); sha3_final(hash, &sha3_ctx); ret = secp256k1_ecdsa_verify(&context, &signature, hash, &pubkey); if (ret == 1) { ret = 0; } else { ret = 2; } return ret; }