Line data Source code
1 : /** 2 : * The MIT License (MIT) 3 : * 4 : * Copyright (c) 2021 RSK Labs Ltd 5 : * 6 : * Permission is hereby granted, free of charge, to any person obtaining a copy 7 : * of this software and associated documentation files (the "Software"), to 8 : * deal in the Software without restriction, including without limitation the 9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 : * sell copies of the Software, and to permit persons to whom the Software is 11 : * furnished to do so, subject to the following conditions: 12 : * 13 : * The above copyright notice and this permission notice shall be included in 14 : * all copies or substantial portions of the Software. 15 : * 16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 : * IN THE SOFTWARE. 23 : */ 24 : 25 : #include <stdint.h> 26 : #include <string.h> 27 : 28 : #include "btcscript.h" 29 : 30 : #include "svarint.h" 31 : 32 : // Context pointer 33 : static btcscript_ctx_t *ctx; 34 : 35 : /* 36 : * Initialize the parser. 37 : * 38 : * @arg[in] ctx the context to be used for this session 39 : * @arg[in] cb the callback to be used for this session 40 : * @arg[in] script_size the total script size in bytes 41 : */ 42 159 : void btcscript_init(btcscript_ctx_t *_ctx, 43 : btcscript_cb_t _cb, 44 : uint32_t script_size) { 45 159 : ctx = _ctx; 46 159 : memset(ctx, 0, sizeof(btcscript_ctx_t)); 47 159 : ctx->state = BTCSCRIPT_ST_OPCODE; 48 159 : ctx->callback = _cb; 49 159 : ctx->bytes_remaining = script_size; 50 159 : } 51 : 52 : /* 53 : * Tell whether parsing is finished, and 54 : * whether it triggered an error (and which one) 55 : * This should be checked after every call to btcscript_consume 56 : */ 57 11289 : int8_t btcscript_result() { 58 11289 : if (ctx->state < 0 || ctx->state == BTCSCRIPT_ST_DONE) 59 293 : return ctx->state; 60 10996 : return BTCSCRIPT_ERR_NONE; 61 : } 62 : 63 : /* 64 : * Consume a chunk of bytes. 65 : * 66 : * @arg[in] buf: buffer holding bytes to be consumed 67 : * @arg[in] len: number of bytes to consume in buffer 68 : * 69 : * @return the number of bytes actually read and processed 70 : */ 71 11151 : uint8_t btcscript_consume(uint8_t *buf, const uint8_t len) { 72 38913 : for (uint8_t i = 0; i < len; i++) { 73 27918 : ctx->bytes_remaining--; 74 27918 : switch (ctx->state) { 75 539 : case BTCSCRIPT_ST_OPCODE: 76 539 : ctx->opcode = buf[i]; 77 : // Push only - taken from 78 : // https://github.com/bitcoin/bitcoin/blob/v0.20.2/src/script/script.cpp#L242 79 539 : if (ctx->opcode > BTCSCRIPT_OP_16) { 80 14 : ctx->state = BTCSCRIPT_ERR_INVALID; 81 14 : return i + 1; 82 : } 83 : 84 : // Taken from 85 : // https://github.com/bitcoin/bitcoin/blob/v0.20.2/src/script/script.cpp#L278 86 525 : if (ctx->opcode > BTCSCRIPT_OP_0 && 87 195 : ctx->opcode < BTCSCRIPT_OP_PUSHDATA1) { 88 53 : ctx->operand_size = ctx->opcode; 89 53 : ctx->callback(BTCSCRIPT_EV_OPCODE); 90 53 : ctx->state = BTCSCRIPT_ST_OPERAND; 91 472 : } else if (ctx->opcode == BTCSCRIPT_OP_0 || 92 142 : ctx->opcode >= BTCSCRIPT_OP_1NEGATE) { 93 350 : ctx->operand_size = 0; 94 350 : ctx->callback(BTCSCRIPT_EV_OPCODE); 95 : } else { // OP_PUSHDATA{1,2,4} 96 122 : ctx->operand_size = 0; 97 122 : ctx->size_offset = 0; 98 122 : ctx->state = BTCSCRIPT_ST_OPERAND_SIZE; 99 : } 100 525 : break; 101 233 : case BTCSCRIPT_ST_OPERAND_SIZE: 102 233 : ctx->operand_size += buf[i] << (8 * ctx->size_offset++); 103 233 : if ((ctx->opcode == BTCSCRIPT_OP_PUSHDATA1 && 104 59 : ctx->size_offset == 1) || 105 174 : (ctx->opcode == BTCSCRIPT_OP_PUSHDATA2 && 106 78 : ctx->size_offset == 2) || 107 135 : (ctx->opcode == BTCSCRIPT_OP_PUSHDATA4 && 108 96 : ctx->size_offset == 4)) { 109 122 : ctx->callback(BTCSCRIPT_EV_OPCODE); 110 122 : ctx->state = BTCSCRIPT_ST_OPERAND; 111 : } 112 233 : break; 113 27146 : case BTCSCRIPT_ST_OPERAND: 114 27146 : ctx->operand_byte = buf[i]; 115 27146 : ctx->callback(BTCSCRIPT_EV_OPERAND); 116 27146 : if (!--ctx->operand_size) { 117 171 : ctx->callback(BTCSCRIPT_EV_OPERAND_END); 118 171 : ctx->state = BTCSCRIPT_ST_OPCODE; 119 : } 120 27146 : break; 121 0 : default: 122 0 : return 0; 123 : } 124 : 125 27904 : if (!ctx->bytes_remaining) { 126 142 : if (ctx->state == BTCSCRIPT_ST_OPCODE) { 127 140 : ctx->state = BTCSCRIPT_ST_DONE; 128 : } else { 129 2 : ctx->state = BTCSCRIPT_ERR_INVALID; 130 : } 131 142 : return i + 1; 132 : } 133 : } 134 : 135 10995 : return len; 136 : }