C言語でBase58のエンコードとデコードを教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
Base58
Base58は,ビットコインで利用するために開発されたテキストベースのエンコード方式です.
Base58はリップル等の他の仮想通貨にも利用されています.
Base58はBase64のサブセットで,アルファベットの大文字と小文字,数字が利用されていますが,画面に表示した時に間違いやすいという理由で以下の4文字が省かれています.
- 0(ゼロ)とO(大文字のオー)
- l(小文字のエル)とI(大文字のアイ)
また,英数字以外の特殊文字である「+」と「/」も省かれています.
なので,Base64の64文字からこれらの6文字が省かれて58文字になるので,Base58という名前になります.
Base58は,文字セットの並び順の正しい規定が存在せず個別の実装に依存しています.
例えば,仮想通貨ビットコインとリップルにおけるBase58のアルファベットは以下になります.
- ビットコイン:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
- リップル:rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz
ビットコインやリップルを知りたいあなたはこちらからどうぞ.
C言語でBase64のエンコードとデコードを知りたいあなたはこちらからどうぞ.
Base58の解説動画はこちらです.
Base58のエンコードとデコード
Base58のエンコードとデコードするコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <stdint.h> #include <string.h> static const char b58_digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; static const int8_t b58_digits_map[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, }; #define UINT32_BITS (sizeof(uint32_t) * 8) #define B58_32BIT_MASK 0x00000000ffffffffUL #define BUFSIZE 256 void do_dec(uint8_t dec[], uint8_t input[], size_t input_size) { uint8_t bin[input_size]; size_t binsz = input_size; const uint8_t *b58u = input; unsigned char *binu = bin; size_t outisz = (binsz + sizeof(uint32_t) - 1) / sizeof(uint32_t); uint32_t c; uint32_t outi[outisz]; uint64_t t; size_t i, j; uint8_t bytesleft = binsz % sizeof(uint32_t); uint32_t zeromask = bytesleft ? (B58_32BIT_MASK << (bytesleft * 8)) : 0; unsigned zerocount = 0; size_t zeros; if (!input_size) { input_size = strlen((char *) input); } memset(outi, 0, sizeof(outi)); for (i = 0; i < input_size && b58u[i] == '1'; i++) { zerocount++; } for (; i < input_size; i++) { if (b58u[i] & 0x80) { fprintf(stderr, "Error: High-bit set on invalid digit\n"); exit(1); } if (b58_digits_map[b58u[i]] == -1) { fprintf(stderr, "Error: Invalid base58 digit\n"); exit(2); } c = (uint32_t) b58_digits_map[b58u[i]]; for (j = outisz; j-- > 0;) { t = ((uint64_t) outi[j]) * 58 + c; c = t >> UINT32_BITS; outi[j] = t & B58_32BIT_MASK; } if (c) { fprintf(stderr, "Error: Too big output number (carry to the next int32)\n"); exit(3); } if (outi[0] & zeromask) { fprintf(stderr, "Error: Too big output number (last int32 filled too far)\n"); exit(4); } } j = 0; if (bytesleft) { for (i = bytesleft; i > 0; i--) { *(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff; } j++; } for (; j < outisz; j++) { for (i = sizeof(*outi); i > 0; i--) { *(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff; } } binu = bin; for (i = 0; i < binsz; i++) { if (binu[i]) { break; } binsz--; } binsz += zerocount; if (binsz > input_size) { zeros = binsz - input_size; memset(dec, 0, zeros); memcpy(&dec[zeros], bin, input_size); } else { memcpy(dec, &bin[input_size - binsz], binsz); } } void do_enc(uint8_t enc[], uint8_t input[], size_t input_size) { int carry; size_t i, j, zcount, size, length; for (zcount = 0; zcount < input_size && !input[zcount]; zcount++) ; size = (input_size * 138) / 100 + 1; uint8_t buf[size]; memset(buf, 0, sizeof(buf)); while (input_size > 0) { carry = input[0]; for (i = 0; (carry != 0 || i < length) && i < size; i++) { carry += 256 * buf[size - i - 1]; buf[size - i - 1] = carry % 58; carry /= 58; } length = i; for (i = 1; i < input_size; i++) { input[i - 1] = input[i]; } input[i - 1] = '\0'; input_size--; } for (j = 0; j < size && !buf[j]; j++) ; if (zcount) { memset(enc, '1', zcount); } for (i = zcount; j < size; i++, j++) { enc[i] = b58_digits_ordered[buf[j]]; } enc[i] = '\0'; } int main(void) { size_t size; uint8_t buf[BUFSIZE], enc[BUFSIZE], dec[BUFSIZE]; printf("Please input a string: "); scanf("%s", buf); size = strlen((char *) buf); do_enc(enc, buf, size); printf("enc = %s\n", enc); size = strlen((char *) enc); do_dec(dec, enc, size); printf("dec = %s\n", dec); return 0; } |
実行結果は以下になります.
「Cat」や私のビットコインのアドレス「1AM3Lgq5ChDNXpMchoket9Smc8SVBpSkqh」を入力すると正常にエンコードとデコードできることがわかります.
こちらのツールで結果を確認しましょう.
1 2 3 4 5 6 7 8 9 |
$ gcc base58.c $ a.out Please input a string: Cat enc = PdgX dec = Cat $ a.out Please input a string: 1AM3Lgq5ChDNXpMchoket9Smc8SVBpSkqh enc = 27akD4zkR1XSYrkaMEe3T5FdTN2cUT2tWWMMi28pGxfAWDu dec = 1AM3Lgq5ChDNXpMchoket9Smc8SVBpSkqh |
まとめ
C言語でBase58のエンコードとデコードを紹介しました.
Base58は,ビットコインとリップルで採用されていることがわかりました.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!