damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

bech32_util.c (3431B)


      1 #include "config.h"
      2 #include "bech32.h"
      3 #include "bech32_util.h"
      4 #include "hash_u5.h"
      5 #include "talstr.h"
      6 #include "tal.h"
      7 #include "short_types.h"
      8 #include <stdbool.h>
      9 
     10 static u8 get_bit(const u8 *src, size_t bitoff)
     11 {
     12         return ((src[bitoff / 8] >> (7 - (bitoff % 8))) & 1);
     13 }
     14 
     15 void bech32_push_bits(u5 **data, const void *src, size_t nbits)
     16 {
     17         size_t i, b;
     18         size_t data_len = tal_count(*data);
     19 
     20         for (i = 0; i < nbits; i += b) {
     21                 tal_resize(data, data_len+1);
     22                 (*data)[data_len] = 0;
     23                 for (b = 0; b < 5; b++) {
     24                         (*data)[data_len] <<= 1;
     25                         /* If we need bits we don't have, zero */
     26                         if (i+b < nbits)
     27                                 (*data)[data_len] |= get_bit(src, i+b);
     28                 }
     29                 data_len++;
     30         }
     31 }
     32 
     33 static u8 get_u5_bit(const u5 *src, size_t bitoff)
     34 {
     35         return ((src[bitoff / 5] >> (4 - (bitoff % 5))) & 1);
     36 }
     37 
     38 void bech32_pull_bits(u8 **data, const u5 *src, size_t nbits)
     39 {
     40         size_t i;
     41         size_t data_len = tal_count(*data);
     42 
     43     /* We discard trailing bits. */
     44         for (i = 0; i + 8 <= nbits; i += 8) {
     45                 tal_resize(data, data_len+1);
     46                 (*data)[data_len] = 0;
     47                 for (size_t b = 0; b < 8; b++) {
     48                         (*data)[data_len] <<= 1;
     49             (*data)[data_len] |= get_u5_bit(src, i+b);
     50                 }
     51                 data_len++;
     52         }
     53 }
     54 
     55 /* Returns a char, tracks case. */
     56 static int fixup_char(int c, bool *upper, bool *lower)
     57 {
     58     if (c >= 'A' && c <= 'Z') {
     59         *upper = true;
     60         return c + ('a' - 'A');
     61     } else if (c >= 'a' && c <= 'z') {
     62         *lower = true;
     63     }
     64     return c;
     65 }
     66 
     67 bool from_bech32_charset(const tal_t *ctx,
     68              const char *bech32,
     69              size_t bech32_len,
     70              char **hrp, u8 **data)
     71 {
     72     u5 *u5data;
     73     const char *sep;
     74     bool upper = false, lower = false;
     75     size_t datalen;
     76 
     77     sep = memchr(bech32, '1', bech32_len);
     78     if (!sep)
     79         return false;
     80 
     81     *hrp = tal_strndup(ctx, bech32, sep - bech32);
     82     for (size_t i = 0; i < strlen(*hrp); i++)
     83         (*hrp)[i] = fixup_char((*hrp)[i], &upper, &lower);
     84 
     85     datalen = bech32_len - (sep + 1 - bech32);
     86     u5data = tal_arr(NULL, u5, datalen);
     87     for (size_t i = 0; i < datalen; i++) {
     88         int c = sep[1+i];
     89         if (c < 0 || c > 128)
     90             goto fail;
     91         c = fixup_char(c, &upper, &lower);
     92         if (bech32_charset_rev[c] == -1)
     93             goto fail;
     94         u5data[i] = bech32_charset_rev[c];
     95     }
     96 
     97     /* Check case consistency */
     98     if (upper && lower)
     99         goto fail;
    100 
    101     *data = tal_arr(ctx, u8, 0);
    102     bech32_pull_bits(data, u5data, tal_bytelen(u5data) * 5);
    103     tal_free(u5data);
    104     return true;
    105 
    106 fail:
    107     *hrp = tal_free(*hrp);
    108     tal_free(u5data);
    109     return false;
    110 }
    111 
    112 char *to_bech32_charset(const tal_t *ctx,
    113             const char *hrp, const u8 *data)
    114 {
    115     u5 *u5data = tal_arr(NULL, u5, 0);
    116     char *ret;
    117 
    118     bech32_push_bits(&u5data, data, tal_bytelen(data) * 8);
    119     ret = tal_dup_arr(ctx, char, hrp, strlen(hrp),
    120               1 + tal_bytelen(u5data) + 1);
    121     ret[strlen(hrp)] = '1';
    122     for (size_t i = 0; i < tal_bytelen(u5data); i++)
    123         ret[strlen(hrp) + 1 + i] = bech32_charset[u5data[i]];
    124     ret[strlen(hrp) + 1 + tal_bytelen(u5data)] = '\0';
    125     tal_free(u5data);
    126     return ret;
    127 }