diff --git a/common/codex32.c b/common/codex32.c index 781223d7a..afaee90e1 100644 --- a/common/codex32.c +++ b/common/codex32.c @@ -16,6 +16,145 @@ #include #include +struct checksum_engine { + u8 generator[15]; + u8 residue[15]; + u8 target[15]; + size_t len; +}; + +static const struct checksum_engine initial_engine_csum[] = { + /* Short Codex32 Engine */ + { + { + 25, 27, 17, 8, 0, 25, + 25, 25, 31, 27, 24, 16, + 16, + }, + { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, + }, + { + 16, 25, 24, 3, 25, 11, + 16, 23, 29, 3, 25, 17, + 10, + }, + 13, + }, + /* Long Codex32 Engine */ + { + { + 15, 10, 25, 26, 9, 25, + 21, 6, 23, 21, 6, 5, + 22, 4, 23 + }, + { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1 + }, + { + 16, 25, 24, 3, 25, 11, + 16, 23, 29, 3, 25, 17, + 10, 25, 6 + }, + 15, + } +}; + +static const uint8_t logi[32] = +{ + 0, 0, 1, 14, 2, 28, 15, 22, + 3, 5, 29, 26, 16, 7, 23, 11, + 4, 25, 6, 10, 30, 13, 27, 21, + 17, 18, 8, 19, 24, 9, 12, 20, +}; + +static const uint8_t log_inv[31] = +{ + 1, 2, 4, 8, 16, 9, 18, 13, + 26, 29, 19, 15, 30, 21, 3, 6, + 12, 24, 25, 27, 31, 23, 7, 14, + 28, 17, 11, 22, 5, 10, 20, +}; + +static void addition_gf32(uint8_t *x, uint8_t y) +{ + *x = *x ^ y; + return; +} + +static void multiply_gf32(uint8_t *x, uint8_t y) +{ + if (*x == 0 || y == 0) { + *x = 0; + } else { + *x = log_inv[(logi[*x] + logi[y]) % 31]; + } + return; +} + +/* Helper to input a single field element in the checksum engine. */ +static void input_fe(const u8 *generator, u8 *residue, uint8_t e, int len) +{ + size_t res_len = len; + u8 xn = residue[0]; + + for(size_t i = 1; i < res_len; i++) { + residue[i - 1] = residue[i]; + } + + residue[res_len - 1] = e; + + for(size_t i = 0; i < res_len; i++) { + u8 x = generator[i]; + multiply_gf32(&x, xn); + addition_gf32(&residue[i], x); + } +} + +/* Helper to input the HRP of codex32 string into the checksum engine */ +static void input_hrp(const u8 *generator, u8 *residue, const char *hrp, int len) +{ + size_t i = 0; + for (i = 0; i < strlen(hrp); i++) { + input_fe(generator, residue, tolower(hrp[i]) >> 5, len); + } + input_fe(generator, residue, tolower(hrp[i]) >> 0, len); + for (i = 0; i < strlen(hrp); i++) { + input_fe(generator, residue, tolower(hrp[i]) & 0x1f, len); + } + return; +} + +/* Helper to input data strong of codex32 into the checksum engine. */ +static void input_data_str(u8 *generator, u8 *residue, const char *datastr, int len) +{ + size_t i = 0; + + for (i = 0; i < strlen(datastr); i++) { + input_fe(generator, residue, bech32_charset_rev[(int)datastr[i]], len); + } + + return; +} + +/* Helper to verify codex32 checksum */ +static bool checksum_verify (const char *hrp, const char *codex_datastr, bool codexl) +{ + struct checksum_engine engine = initial_engine_csum[codexl]; + + input_hrp((&engine)->generator, (&engine)->residue ,hrp, engine.len); + input_data_str((&engine)->generator, (&engine)->residue, codex_datastr, engine.len); + + if (memcmp((&engine)->target, (&engine)->residue, + engine.len) != 0) { + return false; + } + return true; +} /* Helper to sanity check the codex32 string parts */ static char *sanity_check (const tal_t *ctx, @@ -185,6 +324,10 @@ struct codex32 *codex32_decode(const tal_t *ctx, checksum_len = 13; } + if(!checksum_verify(hrp, codex_datastr, parts->codexl)) { + *fail = tal_fmt(ctx, "Invalid checksum!"); + return tal_free(parts); + } parts->hrp = hrp; parts->threshold = *pull_front_bytes(parts, &codex_datastr, 1) - '0'; diff --git a/common/codex32.h b/common/codex32.h index 4936b1f2b..237a2010d 100644 --- a/common/codex32.h +++ b/common/codex32.h @@ -18,6 +18,7 @@ struct codex32 { const char *share_idx; const char *payload; const char *checksum; + /* True if it is a codex32 long string, otherwise false. */ bool codexl; codex32_encoding type; };