xxd-sha256-openssl-btc-private-key

xxd用法见这里这里,还有这里,示例在这里
ASCII见这里这里
openssl示例
btc地址官方文档
cryptotools项目地址

看了这篇有关btc address的文章,想在shell下检验下,主要是想看下sha256的结果在linux下如何得到的

ASCII编码: 

 ASCII第一次以规范标准的型态发表是在1967年,最后一次更新则是在1986年,至今为止共定义了128个字符,其中33个字符无法显示(这是以现今操作系统为依归,但在DOS模式下可显示出一些诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符,控制字符的用途主要是用来操控已经处理过的文字,在33个字符之外的是95个可显示的字符,包含用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。


ASCII控制字符

二进制十进制十六进制缩写可以显示的表示法名称/意义
0000 0000000NUL空字符(Null)
0000 0001101SOH标题开始
0000 0010202STX本文开始
0000 0011303ETX本文结束
0000 0100404EOT传输结束
0000 0101505ENQ请求
0000 0110606ACK确认回应
0000 0111707BEL响铃
0000 1000808BS退格
0000 1001909HT水平定位符号
0000 1010100ALF换行键
0000 1011110BVT垂直定位符号
0000 1100120CFF换页键
0000 1101130DCR归位键
0000 1110140ESO取消变换(Shift out)
0000 1111150FSI启用变换(Shift in)
0001 00001610DLE跳出数据通讯
0001 00011711DC1设备控制一(XON 启用软件速度控制)
0001 00101812DC2设备控制二
0001 00111913DC3设备控制三(XOFF 停用软件速度控制)
0001 01002014DC4设备控制四
0001 01012115NAK确认失败回应
0001 01102216SYN同步用暂停
0001 01112317ETB区块传输结束
0001 10002418CAN取消
0001 10012519EM连接介质中断
0001 1010261ASUB替换
0001 1011271BESC跳出
0001 1100281CFS文件分割符
0001 1101291DGS组群分隔符
0001 1110301ERS记录分隔符
0001 1111311FUS单元分隔符
0111 11111277FDEL删除

ASCII可显示字符

二进制十进制十六进制图形
0010 00003220(空格)(␠)
0010 00013321!
0010 00103422"
0010 00113523#
0010 01003624$
0010 01013725 %
0010 01103826&
0010 01113927'
0010 10004028(
0010 10014129)
0010 1010422A*
0010 1011432B+
0010 1100442C,
0010 1101452D-
0010 1110462E.
0010 1111472F/
0011 000048300
0011 000149311
0011 001050322
0011 001151333
0011 010052344
0011 010153355
0011 011054366
0011 011155377
0011 100056388
0011 100157399
0011 1010583A:
0011 1011593B;
0011 1100603C<
0011 1101613D=
0011 1110623E>
0011 1111633F?
 
二进制十进制十六进制图形
0100 00006440@
0100 00016541A
0100 00106642B
0100 00116743C
0100 01006844D
0100 01016945E
0100 01107046F
0100 01117147G
0100 10007248H
0100 10017349I
0100 1010744AJ
0100 1011754BK
0100 1100764CL
0100 1101774DM
0100 1110784EN
0100 1111794FO
0101 00008050P
0101 00018151Q
0101 00108252R
0101 00118353S
0101 01008454T
0101 01018555U
0101 01108656V
0101 01118757W
0101 10008858X
0101 10018959Y
0101 1010905AZ
0101 1011915B[
0101 1100925C\
0101 1101935D]
0101 1110945E^
0101 1111955F_
 
二进制十进制十六进制图形
0110 00009660`
0110 00019761a
0110 00109862b
0110 00119963c
0110 010010064d
0110 010110165e
0110 011010266f
0110 011110367g
0110 100010468h
0110 100110569i
0110 10101066Aj
0110 10111076Bk
0110 11001086Cl
0110 11011096Dm
0110 11101106En
0110 11111116Fo
0111 000011270p
0111 000111371q
0111 001011472r
0111 001111573s
0111 010011674t
0111 010111775u
0111 011011876v
0111 011111977w
0111 100012078x
0111 100112179y
0111 10101227Az
0111 10111237B{
0111 11001247C|
0111 11011257D}
0111 11101267E~


xxd:理解下来就是把文件内容或文本内容转换为ASCII码格式。
xxd命令可以为给定的标准输入或者文件做一次十六进制的输出,它也可以将十六进制输出转换为原来的二进制格式。这也有助于对任意文件的编码和解码


TLDR中输出的xxd的用法: 
xxd

  Create a hexadecimal representation (hexdump) from a binary file, or vice-versa.
  More information: https://manned.org/xxd.

  - Generate a hexdump from a binary file and display the output:
    xxd input_file

  - Generate a hexdump from a binary file and save it as a text file:
    xxd input_file output_file

  - Display a more compact output, replacing consecutive zeros (if any) with a star:
    xxd -a input_file

  - Display the output with 10 columns of one octet (byte) each:
    xxd -c 10 input_file

  - Display output only up to a length of 32 bytes:
    xxd -l 32 input_file

  - Display the output in plain mode, without any gaps between the columns:
    xxd -p input_file

  - Revert a plaintext hexdump back into binary, and save it as a binary file:
    xxd -r -p input_file output_file



文章中提到的16进制私钥:0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d
xxd的一些试验
对文本的操作: 
1、直接执行xxd
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd
00000000: 3063 3238 6663 6133 3836 6337 6132 3237  0c28fca386c7a227
00000010: 3630 3062 3266 6535 3062 3763 6165 3131  600b2fe50b7cae11
00000020: 6563 3836 6433 6266 3166 6265 3437 3162  ec86d3bf1fbe471b
00000030: 6538 3938 3237 6531 3964 3732 6161 3164  e89827e19d72aa1d

以上xxd对文本进行了16进制转储,包含:索引行数、每组的默认八位字节数为2,其分组大小为4字节、标准列长度为16位,带有空格,例如:3063:其中30是16进制标识,转换为10进制是48,对应的ASCII表中的0;63对应的10进制是99,对应的ASCII表中的c

2、-b | -bits
转到比特(二进制数字)模式,而不是十六进制模式。在这种模式下,每个字符被表示成八个0/1的数字, 而不是一般的十六进制形式。每一行都以一个用十六进制形式表示的行号,后面是 ascii (或ebcdic)形式开头。命令行选项-r, -p, -i在这个模式下不起作用

[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -b
00000000: 00110000 01100011 00110010 00111000 01100110 01100011  0c28fc
00000006: 01100001 00110011 00111000 00110110 01100011 00110111  a386c7
0000000c: 01100001 00110010 00110010 00110111 00110110 00110000  a22760
00000012: 00110000 01100010 00110010 01100110 01100101 00110101  0b2fe5
00000018: 00110000 01100010 00110111 01100011 01100001 01100101  0b7cae
0000001e: 00110001 00110001 01100101 01100011 00111000 00110110  11ec86
00000024: 01100100 00110011 01100010 01100110 00110001 01100110  d3bf1f
0000002a: 01100010 01100101 00110100 00110111 00110001 01100010  be471b
00000030: 01100101 00111000 00111001 00111000 00110010 00110111  e89827
00000036: 01100101 00110001 00111001 01100100 00110111 00110010  e19d72
0000003c: 01100001 01100001 00110001 01100100                    aa1d

以上内容中,00110000 是48的二进制表示,对应ASCII表内的0,01100011是99的二进制表示,对应ASCII表内的c。第一列代表16进制的行号,比如:00000012是代表第18行,00000018是代表24行

3、-c cols | -cols cols
每行表示<cols>个字符。 默认 16 (-i: 12, -ps: 30, -b: 6)。 最多256,以下示例内每行32个字符
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -c 32
00000000: 3063 3238 6663 6133 3836 6337 6132 3237 3630 3062 3266 6535 3062 3763 6165 3131  0c28fca386c7a227600b2fe50b7cae11
00000020: 6563 3836 6433 6266 3166 6265 3437 3162 6538 3938 3237 6531 3964 3732 6161 3164  ec86d3bf1fbe471be89827e19d72aa1d

4、-g bytes | -groupsize bytes 
每<bytes>个字符(每两个十六进制字符或者八个二进制数字)之间用一个空格隔开。用 -g 0禁止分组。在普通模式中<Bytes>默认是2在二进制模式中是1。分组并不适用于postscript 或者include style 选项
g=0时
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -g 0
00000000: 30633238666361333836633761323237  0c28fca386c7a227
00000010: 36303062326665353062376361653131  600b2fe50b7cae11
00000020: 65633836643362663166626534373162  ec86d3bf1fbe471b
00000030: 65383938323765313964373261613164  e89827e19d72aa1d

g=4时,每4个字节分一组
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -g 4
00000000: 30633238 66636133 38366337 61323237  0c28fca386c7a227
00000010: 36303062 32666535 30623763 61653131  600b2fe50b7cae11
00000020: 65633836 64336266 31666265 34373162  ec86d3bf1fbe471b
00000030: 65383938 32376531 39643732 61613164  e89827e19d72aa1d

如:30633238中,30对应10进制的48,在ASCII表内对应0,63对应10进制的99,在ASCII表内对应c,32对应10进制的50,在ASCII表内对应2,38对应10进制的56,在ASCII表内对应8

二进制中时(xxd使用了-b),默认是1: 
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -b
00000000: 00110000 01100011 00110010 00111000 01100110 01100011  0c28fc
00000006: 01100001 00110011 00111000 00110110 01100011 00110111  a386c7
0000000c: 01100001 00110010 00110010 00110111 00110110 00110000  a22760
00000012: 00110000 01100010 00110010 01100110 01100101 00110101  0b2fe5
00000018: 00110000 01100010 00110111 01100011 01100001 01100101  0b7cae
0000001e: 00110001 00110001 01100101 01100011 00111000 00110110  11ec86
00000024: 01100100 00110011 01100010 01100110 00110001 01100110  d3bf1f
0000002a: 01100010 01100101 00110100 00110111 00110001 01100010  be471b
00000030: 01100101 00111000 00111001 00111000 00110010 00110111  e89827
00000036: 01100101 00110001 00111001 01100100 00110111 00110010  e19d72
0000003c: 01100001 01100001 00110001 01100100                    aa1d

如:01100101对应10进制中的101,在ASCII表内对应的是字母e

5、 -i | -include(没试过
输出为C语言的包含文件形式。 除非xxd从标准输入读入,不然会输出一个完整的静态数组定义(与输入文件同名)


6、  -l len | -len len      
输出<len>个字符后停止。
以下输出16个字符后停止
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -l 16
00000000: 3063 3238 6663 6133 3836 6337 6132 3237  0c28fca386c7a227

0c28fca386c7a227:这个字符串共16个字符

[vagrant@vm-node1:btc]$ cat r1.txt
abdcfg
ehjki123
1414144152
556625225
225
7839
2030j0f20
限制了内容长度,将数据打印到有限的范围.
[vagrant@vm-node1:btc]$ xxd -l 0x5 r1.txt
00000000: 6162 6463 66                             abdcf


7、  -p | -ps | -postscript | -plain
以postscript的连续十六进制转储输出。这也叫做纯十六进制转储
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -p
306332386663613338366337613232373630306232666535306237636165
313165633836643362663166626534373162653839383237653139643732
61613164


8、  -r | -revert
      逆向操作:把十六进制转储转换(或者打补丁)成二进制形式。如果不输出到标准输出,xxd并不把输出文件截断,而是直接写到输出文件。用 -r -p 来从一个没有行号没有某种列格式的纯十六进制转储读入。附加的空格 和换行可以出现在任何地方。
对文本似乎没什么用,以下没有任何输出
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -r
[vagrant@vm-node1:btc]$

加上了-r -p之后:
[vagrant@vm-node1:btc]$ echo -n "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -r -p

(󇠧`
   /
    |®쇓¿¾Gª


后来创建了一个r.txt
[vagrant@vm-node1:btc]$ xxd r.txt > 123.txt
[vagrant@vm-node1:btc]$ cat r.txt
ab
dc
fg
e
hj
ki123
141
4144152
5566
25225
[vagrant@vm-node1:btc]$ cat 123.txt
00000000: 6162 0a64 630a 6667 0a65 0a68 6a0a 6b69  ab.dc.fg.e.hj.ki
00000010: 3132 330a 3134 310a 3431 3434 3135 320a  123.141.4144152.
00000020: 3535 3636 0a32 3532 3235 0a              5566.25225.

6162 0a64: 61对应10进制的97,对应ASCII表内的a,0a对应10进制的10,对应ASCII表内的“换行键”,换行符号被替换为"."了,


[vagrant@vm-node1:btc]$ xxd -p r.txt
61620a64630a66670a650a686a0a6b693132330a3134310a343134343135
320a353536360a32353232350a
[vagrant@vm-node1:btc]$ xxd -p r.txt > pr.txt #pr.txt内存储的是纯16进制的转储
[vagrant@vm-node1:btc]$ xxd -r -p pr.txt #用-r -p可以将pr.txt的内容重新变回原来的内容
ab
dc
fg
e
hj
ki123
141
4144152
5566
25225

或者直接如下操作: 
[vagrant@vm-node1:btc]$ cat r.txt
ab
dc
fg
e
hj
ki123
141
4144152
5566
25225
[vagrant@vm-node1:btc]$ xxd r.txt | xxd -r   #转储后立即可以转回来
ab
dc
fg
e
hj
ki123
141
4144152
5566
25225
 

9、  -seek offset

       用在-r之后: 会在 当前 文件的 偏移量 上 增加 <offset>。

  -s [+][-]seek

       从infile的绝对或者相对偏移量<seek>开始。+表示相对于标准输入当前的位置(如果不是标准输入就没有意义了)。- 表示从文件末尾(如果和+连用:从标准输入当前位置)向前数一些字符,从那个地方开始。如果没有 -s选项,xxd从当前位置开始。
从第5行生成转储文件?!
有个疑问:感觉是从第6个字节输出的,并不是从第5行输出的
[vagrant@vm-node1:btc]$ cat r1.txt
abdcfg
ehjki123
1414144152
556625225
225
7839
2030j0f20
[vagrant@vm-node1:btc]$ xxd r1.txt
00000000: 6162 6463 6667 0a65 686a 6b69 3132 330a  abdcfg.ehjki123.
00000010: 3134 3134 3134 3431 3532 0a35 3536 3632  1414144152.55662
00000020: 3532 3235 0a32 3235 0a37 3833 390a 3230  5225.225.7839.20
00000030: 3330 6a30 6632 300a                      30j0f20.
[vagrant@vm-node1:btc]$ xxd -s 5 r1.txt
00000005: 670a 6568 6a6b 6931 3233 0a31 3431 3431  g.ehjki123.14141
00000015: 3434 3135 320a 3535 3636 3235 3232 350a  44152.556625225.
00000025: 3232 350a 3738 3339 0a32 3033 306a 3066  225.7839.2030j0f
00000035: 3230 0a                                  20.



   -u    
大写字母。默认的是小写字母。
[vagrant@vm-node1:btc]$ xxd -u r.txt
00000000: 6162 0A64 630A 6667 0A65 0A68 6A0A 6B69  ab.dc.fg.e.hj.ki
00000010: 3132 330A 3134 310A 3431 3434 3135 320A  123.141.4144152.
00000020: 3535 3636 0A32 3532 3235 0A              5566.25225.


   -v | -version

       显示版本字符串。
[vagrant@vm-node1:btc]$ xxd -v
xxd 2021-10-22 by Juergen Weigert et al.


例:
将文件内容转换为十六进制:
xxd test.txt

使用xxd跳过第n行,想要从第6行开始生成十六进制转储(0x50表示第6行,0x00表示第1行)
xxd -s 0x50 test.txt

将输出限制为特定长度,从第一行(0x00)打印到第5行(0x40)
xxd -l 0x50 test.txt

将文件内容转换为二进制文件:
xxd -b test.txt

设置列长,默认列长度为16,即16个字符,包括空格,将列长度设置为9:现在我们将列长度设置为“9”:
xxd -c 9 test.txt

纯16进制转储,输出保存在hex文件中,并使用cat命令从hex文件中读取输出:
xxd -p test.txt > hex

cat hex

还原hex文件,将纯十六进制转储的反向输出打印为了ASCII格式:
xxd -r -p hex

分组大小字节,将输出分组为多少个八位字节,默认是2个字节,接下来设为8,即8个字节一组,分为2组:
xxd -g 8 test.txt

我们常用命令:

xxd -p  test.class >> java.txt  转为16进制

xxd -r -p java.txt >> test.class 还原文件



1.1.1 WIF、WIF-compressed 编码

下面介绍 WIF、WIF-compressed 具体的编码过程:
1、在 16 进制的私钥前面增加 version 字段,Bitcoin 主网为 0x80 ,Bitcoin 测试网为 0xef ; 对于 WIF-compressed 形式,则后面还要增加 0x01 。 这个结果称为 extended key,即:

800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d    # for WIF
800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01  # for WIF-compressed

2、对 extended key 计算 SHA-256:

1ce0723b5128b03fcfd2484368f1bbc89dc7c6eddf56589c2eccb2bacbbcafc9      # for WIF
b504a81b66924482a289ce571a614c37b122f40cefb0abba0227e143154c2153      # for WIF-compressed

3、再次计算上面结果的 SHA-256:

507a5b8dfed0fc6fe8801743720cedec06aa5c6fca72b07c49964492fb98a714      # for WIF
a62019d20340a1de1b5f254f07f2f6c96ad5165218459ab4f3c8f5a7c0e12183      # for WIF-compressed

4、第二次 SHA256 结果的前 4 个字节作为 checksum:

507a5b8d                                                              # for WIF
a62019d2                                                              # for WIF-compressed

5、把 checksum 加到 extended key 的后面:

800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d    # for WIF
800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01a62019d2  # for WIF-compressed

6、对上面结果进行 Base58Check 编码,即得到 WIF、WIF-compressed 形式:

5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ                   # WIF
KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617                  # WIF-compressed

注:Base58Check 编码表只有 58 个有效字符,具体来说,就是 10 个数字加上 26 个小写字母加上 26 个大写字母,再减去 0OIl 这 4 个容易产生混淆的字符。


1、原始私钥为: 0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d
未压缩的extend_key='800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'
压缩extend_key='800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01'

2、对步骤1的extend_key进行sha256运算
未压缩的: 
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -r -p | sha256sum
8147786c4d15106333bf278d71dadaf1079ef2d2440a4dde37d747ded5403592  -
这个结果跟文章中的不一致,文章中这步结果是:1ce0723b5128b03fcfd2484368f1bbc89dc7c6eddf56589c2eccb2bacbbcafc9

压缩的 : 
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01" | xxd -r -p | sha256sum
b504a81b66924482a289ce571a614c37b122f40cefb0abba0227e143154c2153  -

3、对步骤2结果进行sha256运算
未压缩的: 
[vagrant@vm-node1:~]$ echo -n "8147786c4d15106333bf278d71dadaf1079ef2d2440a4dde37d747ded5403592" | xxd -r -p | sha256sum  507a5b8dfed0fc6fe8801743720cedec06aa5c6fca72b07c49964492fb98a714  -
这步骤的结果跟文章中一致了!

压缩的 : 
[vagrant@vm-node1:~]$ echo -n "b504a81b66924482a289ce571a614c37b122f40cefb0abba0227e143154c2153" | xxd -r -p | sha256sum a62019d20340a1de1b5f254f07f2f6c96ad5165218459ab4f3c8f5a7c0e12183  -

4、上个步骤的结果取前4个字节,作为checksum
未压缩的: 
[vagrant@vm-node1:~]$ echo -n "507a5b8dfed0fc6fe8801743720cedec06aa5c6fca72b07c49964492fb98a714" | xxd -l 8 | xxd -r
507a5b8d

压缩的 : 
[vagrant@vm-node1:~]$ echo -n "a62019d20340a1de1b5f254f07f2f6c96ad5165218459ab4f3c8f5a7c0e12183" | xxd -l 8 | xxd -r
a62019d2

5、把extend_key和checksum拼接起来
未压缩的extend_key='800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'
压缩extend_key='800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01'

未压缩的: 
800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d

压缩的: 
800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01a62019d2

6、对步骤5结果进行base58运算
未压缩的: 
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d" | xxd -r -p | base58
5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ

压缩的: 
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01a62019d2" | xxd -r -p| base58
KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617


文章后面还有一段根据公钥计算得出地址的过程,还没来得及继续,但应该跟这个类似的


cryptotools中提供了私钥和WIF相互转换的工具: 


main = {
    'hrp': 'bc',
    'keyhash': b'\x00',
    'scripthash': b'\x05',
    'wif': b'\x80',
    'extended_prv': {
        # https://github.com/spesmilo/electrum-docs/blob/master/xpub_version_bytes.rst
        ADDRESS.P2PKH: b'\x04\x88\xad\xe4',  # xprv
        ADDRESS.P2WPKH: b'\x04\xb2\x43\x0c',  # zprv
        ADDRESS.P2WSH: b'\x02\xaa\x7a\x99',  # Zprv
        ADDRESS.P2WPKH_P2SH: b'\x04\x9d\x78\x78',  # yprv
        ADDRESS.P2WSH_P2SH: b'\x02\x95\xb4\x3f'  # Yprv
    },
    'extended_pub': {
        # https://github.com/spesmilo/electrum-docs/blob/master/xpub_version_bytes.rst
        ADDRESS.P2PKH: b'\x04\x88\xb2\x1e',  # xpub
        ADDRESS.P2WPKH: b'\x04\xb2\x47\x46',  # zpub
        ADDRESS.P2WSH: b'\x02\xaa\x7e\xd3',  # Zpub
        ADDRESS.P2WPKH_P2SH: b'\x04\x9d\x7c\xb2',  # ypub
        ADDRESS.P2WSH_P2SH: b'\x02\x95\xb4\x3f'  # Ypub
    },
    'utxo_url': 'https://blockchain.info/unspent?active={address}',
    'rawtx_url': 'https://blockchain.info/rawtx/{txid}?format=hex',
    'broadcast_url': 'https://blockchain.info/pushtx'

}



1、##将16进制原始私钥转换为WIF
    def wif(self, compressed=False) -> str:
        from btctools import base58, sha256
        from btctools.network import network
        extended = network('wif') + self.bytes() + (b'\x01' if compressed else b'')
        hashed = sha256(sha256(extended))
        checksum = hashed[:4]
        return base58.encode(extended + checksum)

#以priv_key = '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'为例
network('wif')='0x80'
未压缩:
extended='80'+'0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d' = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'

hashed=sha256(sha256(extended))
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -r -p | sha256sum | xxd -r -p | sha256sum
507a5b8dfed0fc6fe8801743720cedec06aa5c6fca72b07c49964492fb98a714  -

所以hashed='507a5b8dfed0fc6fe8801743720cedec06aa5c6fca72b07c49964492fb98a714'

checksum = hashed[:4]
[vagrant@vm-node1:~]$ echo -n "507a5b8dfed0fc6fe8801743720cedec06aa5c6fca72b07c49964492fb98a714" | xxd -p -l 8 | xxd -r -p
507a5b8d
所以checksum='507a5b8d'
extended + checksum = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d'

base58.encode(extended + checksum):
对extended + checksum做base58运算: 
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d" | xxd -r -p |base58
5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ


压缩时
extended='80'+'0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'+'01'='800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01'
hashed=sha256(sha256(extended))
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01" | xxd -r -p | sha256sum | xxd -r -p | sha256sum
a62019d20340a1de1b5f254f07f2f6c96ad5165218459ab4f3c8f5a7c0e12183  -

所以hashed='a62019d20340a1de1b5f254f07f2f6c96ad5165218459ab4f3c8f5a7c0e12183'
checksum = hashed[:4]
[vagrant@vm-node1:~]$ echo -n "a62019d20340a1de1b5f254f07f2f6c96ad5165218459ab4f3c8f5a7c0e12183" | xxd -p -l 8 | xxd -r -p
a62019d2

所以checksum='a62019d2'
extended + checksum = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01a62019d2'
base58.encode(extended + checksum):
对extended + checksum做base58运算: 
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01a62019d2" | xxd -r -p | base58
KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617

所以私钥0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d对应的压缩WIF:KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617
非压缩WIF: 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ

2、#将WIF转换为16进制原始私钥
def from_wif(cls, wif: str) -> 'PrivateKey':
        from btctools import base58, sha256
        from btctools.network import network
        bts = base58.decode(wif)
        network_byte, key, checksum = bts[0:1], bts[1:-4], bts[-4:]
        assert sha256(sha256(network_byte + key))[:4] == checksum, 'Invalid Checksum'
        assert network_byte == network('wif'), 'Invalid Network byte'
        if key.endswith(b'\x01'):
            key = key[:-1]
            compressed = True  # TODO
        else:
            compressed = False  # TODO
        return cls(key)

#以上面的为例:
#压缩WIF:  KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617
#非压缩WIF:  5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ
#计算原始私钥
bts = base58.decode(wif)
压缩时
[vagrant@vm-node1:~]$ echo -n "KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617" | base58 -d |xxd -p
800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d
72aa1d01a62019d2
bts='800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01a62019d2'

非压缩时
[vagrant@vm-node1:~]$ echo -n "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ" | base58 -d |xxd -p
800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d
72aa1d507a5b8d
bts='800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d'


network_byte, key, checksum = bts[0:1], bts[1:-4], bts[-4:]
上个步骤得到bts,此时可以求得network_byte, key, checksum
压缩时:
network_byte='80'
key='0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01'
checksum='a62019d2'

非压缩时:
network_byte='80'
key='0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'
checksum='507a5b8d'

assert sha256(sha256(network_byte + key))[:4] == checksum, 'Invalid Checksum'
#这个断言用于校验计算checksum是否一致: 
压缩时:
network_byte + key = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01'
checksum='a62019d2
sha256(sha256(network_byte + key))[:4] :
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01" | xxd -r -p | sha256sum | xxd -r -p | sha256sum |xxd -p -l 8 | xxd -r -p
a62019d2
证明checksum是一致的

非压缩时:
network_byte + key = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'
checksum='507a5b8d
sha256(sha256(network_byte + key))[:4] : 
[vagrant@vm-node1:~]$ echo -n "800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d" | xxd -r -p |sha256sum | xxd -r -p | sha256sum  |xxd -p -l 8 | xxd -r -p
507a5b8d
证明checksum是一致的

assert network_byte == network('wif'), 'Invalid Network byte'
#这个断言用于校验网络类型 是否一致,显然此时是一致的

最终得到: 
压缩时:
key='0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d01'
key=key[:-1]='0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'
非压缩时:
key='0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'

所以原始priv_key='0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d'




P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F

# Generator
G = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8

# Order
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

CURVE = ECDSA.Curve(P, 0, 7, G, N, name='secp256k1')

计算公钥: 
    def to_public(self) -> 'PublicKey':
        point = CURVE.G * self.int() #调用__mul__()
        return PublicKey(point)


ECDSA: __init__.py:
    def __mul__(self, other: int):
        assert isinstance(other, int), 'Multiplication is only defined between a point and an integer'
        return self.curve.point_mul(self, other)


class Curve
    def __init__(self, P, a, b, G, N, name):
        self.P = P
        self.a = a
        self.b = b
        self.G = Point(*G, self)
        self.N = N
        self.name = name

#pow(x, y[, z])
函数是计算 x 的 y 次方,如果 z 在存在,则再对结果进行取模,其结果等效于 pow(x,y) %z
#
    def point_add(self, p, q):
    """https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_addition"""
        P = self.P
        if p == q:
            lam = (3 * p.x * p.x) * pow(2 * p.y % P, P - 2, P)
        else:
            lam = pow(q.x - p.x, P - 2, P) * (q.y - p.y) % P

        rx = lam ** 2 - p.x - q.x
        ry = lam * (p.x - rx) - p.y
        return Point(rx % P, ry % P, curve=self)

    def point_mul(self, p, d):
        d = d % self.N
        n = p
        q = None
        exe_time = 0
        
        fmt = format(d, 'b')
        rev = reversed(fmt)
        for i in rev:
            if i == '1':
                exe_time = exe_time + 1 
                if q is None:
                    q = n
                else:
                    q = self.point_add(q, n)

            n = self.point_add(n, n)
        return q


key_to_addr_versions = {
    ADDRESS.P2PKH: lambda pub: legacy_address(pub, version_byte=network('keyhash')),
    # 'P2WPKH': partial(pubkey_to_p2wpkh, version_byte=0x06, witver=0x00),  # WAS REPLACED BY BIP 173
    ADDRESS.P2WPKH_P2SH: lambda pub: legacy_address(witness_byte(witver=0) + push(hash160(pub.encode(compressed=True))), version_byte=network('scripthash')),
    ADDRESS.P2WPKH: partial(pubkey_to_bech32, witver=0x00),
}

script_to_addr_versions = {
    ADDRESS.P2SH: lambda script: legacy_address(script, version_byte=network('scripthash')),
    # 'P2WSH': partial(script_to_p2wsh, version_byte=0x0A, witver=0x00),  # WAS REPLACED BY BIP 173
    ADDRESS.P2WSH_P2SH: lambda script: legacy_address(witness_byte(witver=0) + push(sha256(script)), version_byte=network('scripthash')),
    ADDRESS.P2WSH: partial(script_to_bech32, witver=0x00),
}