LCOV - code coverage report
Current view: top level - powhsm/src - svarint.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 54 56 96.4 %
Date: 2025-07-10 13:49:13 Functions: 5 5 100.0 %

          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 "svarint.h"
      29             : 
      30             : // Context pointer
      31             : static svarint_ctx_t* ctx;
      32             : 
      33             : /*
      34             :  * Initialize the parser.
      35             :  *
      36             :  * @arg[in] ctx the context to be used for this session
      37             :  */
      38       28215 : void svarint_init(svarint_ctx_t* _ctx) {
      39       28215 :     ctx = _ctx;
      40       28215 :     memset(ctx, 0, sizeof(svarint_ctx_t));
      41       28215 :     ctx->state = SVARINT_ST_HEADER;
      42       28215 : }
      43             : 
      44             : /*
      45             :  * Tells whether the parser has not yet consumed any bytes
      46             :  */
      47       28365 : int8_t svarint_notstarted() {
      48       28365 :     return ctx->state == SVARINT_ST_HEADER;
      49             : }
      50             : 
      51             : /*
      52             :  * Tell whether parsing is finished, and
      53             :  * whether it triggered an error (and which one)
      54             :  * This should be checked after every call to svarint_consume
      55             :  */
      56       28693 : int8_t svarint_result() {
      57       28693 :     if (ctx->state < 0 || ctx->state == SVARINT_ST_DONE)
      58       28333 :         return ctx->state;
      59         360 :     return SVARINT_ERR_NONE;
      60             : }
      61             : 
      62             : /*
      63             :  * Consume a chunk of bytes.
      64             :  *
      65             :  * @arg[in] buf: buffer holding bytes to be consumed
      66             :  * @arg[in] len: number of bytes to consume in buffer
      67             :  *
      68             :  * @return the number of bytes actually read and processed
      69             :  */
      70       28472 : uint8_t svarint_consume(const uint8_t* buf, const uint8_t len) {
      71       29642 :     for (uint8_t i = 0; i < len; i++) {
      72       29434 :         switch (ctx->state) {
      73       28214 :         case SVARINT_ST_HEADER:
      74       28214 :             if (buf[i] < 0xFD) {
      75       27856 :                 ctx->value = buf[i];
      76       27856 :                 ctx->state = SVARINT_ST_DONE;
      77       27856 :                 return 1; // Read one byte, done
      78             :             } else {
      79         358 :                 ctx->size = 2 << (buf[i] - 0xFD);
      80         358 :                 ctx->offset = 0;
      81         358 :                 ctx->value = 0;
      82         358 :                 ctx->state = SVARINT_ST_BODY;
      83             :             }
      84         358 :             break;
      85        1170 :         case SVARINT_ST_BODY:
      86             :             // We don't support values greater than 32 bits in practice
      87             :             // (we do support up to 32 bit values
      88             :             // represented as 64 bit values though)
      89        1170 :             if (ctx->offset > 3 && buf[i] > 0) {
      90          52 :                 ctx->state = SVARINT_ERR_UNSUPPORTED;
      91          52 :                 return i + 1;
      92             :             }
      93             :             // Read little endian varint value
      94        1118 :             ctx->value += buf[i] << (8 * ctx->offset++);
      95        1118 :             if (--ctx->size == 0) {
      96         306 :                 ctx->state = SVARINT_ST_DONE;
      97         306 :                 return i + 1;
      98             :             }
      99         812 :             break;
     100          50 :         default:
     101             :             // Trying to read in any other state triggers an invalid error
     102          50 :             ctx->state = SVARINT_ERR_INVALID;
     103          50 :             return 0;
     104             :         }
     105             :     }
     106             : 
     107         208 :     return len;
     108             : }
     109             : 
     110             : /*
     111             :  * Encode a varint into a buffer.
     112             :  * Values longer than a byte are encoded in little endian
     113             :  * as per the bitcoin varint spec.
     114             :  *
     115             :  * @arg[in] value: value to encode
     116             :  * @arg[in] buf: destination buffer
     117             :  * @arg[in] len: destination buffer size
     118             :  *
     119             :  * @return the number of bytes actually written
     120             :  */
     121          49 : uint8_t svarint_encode(uint32_t value, uint8_t* buf, const uint8_t len) {
     122          49 :     if (value < 0xFD) {
     123          37 :         if (len < 1)
     124           0 :             return 0;
     125          37 :         buf[0] = (uint8_t)value;
     126          37 :         return 1;
     127          12 :     } else if (value <= 0xFFFF) {
     128           9 :         if (len < 3)
     129           0 :             return 0;
     130           9 :         buf[0] = 0xFD;
     131           9 :         buf[1] = value & 0xFF;
     132           9 :         buf[2] = (value & 0xFF00) >> 8;
     133           9 :         return 3;
     134             :     } else if (value <= 0xFFFFFFFF) {
     135           3 :         buf[0] = 0xFE;
     136           3 :         buf[1] = value & 0xFF;
     137           3 :         buf[2] = (value & 0xFF00) >> 8;
     138           3 :         buf[3] = (value & 0xFF0000) >> 16;
     139           3 :         buf[4] = (value & 0xFF000000) >> 24;
     140           3 :         return 5;
     141             :     } else {
     142             :         // We do not support values greater than 2^32-1
     143             :         return 0;
     144             :     }
     145             : }

Generated by: LCOV version 1.16