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 115 : void btcscript_init(btcscript_ctx_t *_ctx, 43 : btcscript_cb_t _cb, 44 : uint32_t script_size) { 45 115 : ctx = _ctx; 46 115 : memset(ctx, 0, sizeof(btcscript_ctx_t)); 47 115 : ctx->state = BTCSCRIPT_ST_OPCODE; 48 115 : ctx->callback = _cb; 49 115 : ctx->bytes_remaining = script_size; 50 115 : } 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 2443 : int8_t btcscript_result() { 58 2443 : if (ctx->state < 0 || ctx->state == BTCSCRIPT_ST_DONE) 59 209 : return ctx->state; 60 2234 : 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 2347 : uint8_t btcscript_consume(uint8_t *buf, const uint8_t len) { 72 21347 : for (uint8_t i = 0; i < len; i++) { 73 19114 : ctx->bytes_remaining--; 74 19114 : switch (ctx->state) { 75 315 : case BTCSCRIPT_ST_OPCODE: 76 315 : 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 315 : 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 301 : if (ctx->opcode > BTCSCRIPT_OP_0 && 87 135 : ctx->opcode < BTCSCRIPT_OP_PUSHDATA1) { 88 37 : ctx->operand_size = ctx->opcode; 89 37 : ctx->callback(BTCSCRIPT_EV_OPCODE); 90 37 : ctx->state = BTCSCRIPT_ST_OPERAND; 91 264 : } else if (ctx->opcode == BTCSCRIPT_OP_0 || 92 98 : ctx->opcode >= BTCSCRIPT_OP_1NEGATE) { 93 184 : ctx->operand_size = 0; 94 184 : ctx->callback(BTCSCRIPT_EV_OPCODE); 95 : } else { // OP_PUSHDATA{1,2,4} 96 80 : ctx->operand_size = 0; 97 80 : ctx->size_offset = 0; 98 80 : ctx->state = BTCSCRIPT_ST_OPERAND_SIZE; 99 : } 100 301 : break; 101 179 : case BTCSCRIPT_ST_OPERAND_SIZE: 102 179 : ctx->operand_size += buf[i] << (8 * ctx->size_offset++); 103 179 : if ((ctx->opcode == BTCSCRIPT_OP_PUSHDATA1 && 104 25 : ctx->size_offset == 1) || 105 154 : (ctx->opcode == BTCSCRIPT_OP_PUSHDATA2 && 106 66 : ctx->size_offset == 2) || 107 121 : (ctx->opcode == BTCSCRIPT_OP_PUSHDATA4 && 108 88 : ctx->size_offset == 4)) { 109 80 : ctx->callback(BTCSCRIPT_EV_OPCODE); 110 80 : ctx->state = BTCSCRIPT_ST_OPERAND; 111 : } 112 179 : break; 113 18620 : case BTCSCRIPT_ST_OPERAND: 114 18620 : ctx->operand_byte = buf[i]; 115 18620 : ctx->callback(BTCSCRIPT_EV_OPERAND); 116 18620 : if (!--ctx->operand_size) { 117 117 : ctx->callback(BTCSCRIPT_EV_OPERAND_END); 118 117 : ctx->state = BTCSCRIPT_ST_OPCODE; 119 : } 120 18620 : break; 121 0 : default: 122 0 : return 0; 123 : } 124 : 125 19100 : if (!ctx->bytes_remaining) { 126 100 : if (ctx->state == BTCSCRIPT_ST_OPCODE) { 127 100 : ctx->state = BTCSCRIPT_ST_DONE; 128 : } else { 129 0 : ctx->state = BTCSCRIPT_ERR_INVALID; 130 : } 131 100 : return i + 1; 132 : } 133 : } 134 : 135 2233 : return len; 136 : }