为什么你看到的1开头的bitcoin地址几乎都是34位的?

1、16进制转换成58进制。
将50位(2位版本号+40位HASH160结果+8位校验码)16进制地址换成base58编码的时候,对于base58编码后的地址,理论上应该是最高位能表达的数值数量占总体数值数量的57/58=0.9827586206896552。
例如对于10进制,0-99中2位数占比90/100=9/10,0-999中3位数占比为900/1000=9/10;
对于16进制,0-FF中2位数占比240/256=15/16,0-FFF中3位数占比3840/4096=15/16;
同理,对于58进制的base58编码,最高位能表达的数值数量占总体数值数量的57/58=0.9827586206896552。

2、程序测试。
bitcoin硬核玩家@迦楼罗王2010 ,用js编了一个程序,对1开头的bitcoin地址进行测试。通过检测循环58^i与58^(i-1)的临界点(即每位满58进位,跟其他进制一样),来计算base58编码后的地址中,34位、33位……地址数量占总体地址数量的百分比。
测试结果发现:
34=0.9999869219,
33=0.0000130780,
32=0.0000000001,
31=0.0000000000,
30=0.0000000000,
……
34位地址占比远高于理论计算结果,非34地址占比只有10万分之一。

3、深入分析。
问题出现:按说从最低位开始,按理i每增大一个,地址长度加1, 但实际上不是的,而是好几个i对应的地址长度是一样的。
根本原因:base58转换前的16进制数值,进行了前导补0,每补一个0x00,base58转换就会多生成1个,从而会占多占1位。如果不进行前导补零。那么就会符合57/58=0.9827586207。
base58编码最前面的1(在base58编码中,1就代表没有大小的0),等同于其他进制最前面的0,对数值的大小没影响,但却占了位。
base58编码的前导1,导致多个i对应一个长度,说白了就是被前导1硬凑齐的。就如同0x00ff与0x01ff,理论上来说,分别是2位和3位数,但被对数值大小不起任何作用的前导0补齐都成了4位数。

4、手工练习。
可以用我写的脑钱包程序,练习16进制转换成58进制的base58编码。网页链接

4、测试程序源代码。
(未经网友授权,就发布了

[笑cry]

。感兴趣的网友,可以测试一下)
const bs58 = require(‘bs58’);

function caculateAddressPercent() {
let ss5 = “”;
for (let i = 0; i < 50; i++) {
if (i == 0 || i == 1) {
ss5 += “0”;
} else {
ss5 += “f”;
}
}
let map = new Map();
let bbbb = BigInt(“0x” + ss5);
for (let i = 1; i <= 50; i++) {
let ele = BigInt(58) ** BigInt(i);
let ele_pre = null;
if (i == 1) {
ele_pre = BigInt(0);
} else {
ele_pre = BigInt(58) ** BigInt(i – 1);
}

if (ele > bbbb) {
console.error(“max 35 hex: ” + bbbb.toString(16));
console.error(“max 34 hex: ” + (BigInt(58) ** BigInt(i)).toString(16));
console.error(“max 35 num: ” + (bbbb – BigInt(58) ** BigInt(i)).toString(16));
let len1 = bs58.encode(Buffer.from(padString(ele.toString(16), 50), ‘hex’)).length;
map.set(len1.toString(), bbbb – ele_pre);
break;
}

console.error(“——-iii=” + i.toString() + “———ele=” + ele.toString());

let len1 = bs58.encode(Buffer.from(padString((ele – BigInt(1)).toString(16), 50), ‘hex’)).length;
let len2 = bs58.encode(Buffer.from(padString(ele.toString(16), 50), ‘hex’)).length;
console.error(“len1=” + len1.toString());
console.error(“len2=” + len2.toString());

let key = len1.toString();
let add = ele – ele_pre;
let num = map.get(key);
if (num == null) {
map.set(key, add);
} else {
num += add;
map.set(key, add);
}
console.error(“—-ele end—“);
}
console.error(map);

let total = BigInt(0);
for (let value of map.values()) {
total += value;
}
let total_deci = new Decimal(total.toString());
console.error(“total: ” + total.toString(16));
let perMap = new Map();
for (let [key, value] of map.entries()) {
let value_deci = new Decimal(value.toString());
let per = value_deci.dividedBy(total_deci).toFixed(10);
perMap.set(key, per);
}

console.error(perMap);
}

function padString(input, length) {
if (input.length >= length) {
return input.substring(0, length);
}

let output = “”;
for (let i = 0; i < length – input.length; i++) {
output += “0”;
}
output += input;
return output;
}

https://weibo.com/6101281235/MDsxEw7xG

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇