2021五一假期

既然弄了这个个人博客,那么就要坚持每周写点东西。可能没有几个人会看到博客,就当作是写给未来的自己的信。

五一假期回来,我想写点东西记录一下五一的旅行,随便写点,不需要华丽的文采,只是记录一下旅途中遇到的风景和有趣的人或事。


旅行计划

四月中旬的时候打算五一出去走走,放松放松心情。五一去哪玩没有确定的地方,我想去粤东,朋友不想去。我又说去粤西,朋友也不想去。我再说去广西北海,朋友说广西可以,他说要去桂林,我以前去过桂林,不想再去桂林。我又说去成都,朋友说可以。我说昆明好像也挺好,朋友也说昆明也好。

于是我们石头剪子布来决定,谁赢了谁来最终决定去哪玩,朋友赢了,五一的机票太贵,我们提前订了昆明的高铁票。

大致路线:丽江(两天两晚)——大理(一天一晚)——昆明(两天两晚)。我觉得太详细的旅游攻略会让旅行少很多未知。

04.30 出发

4.30早上六点起床,去高铁站,和朋友约好早上七点半在高铁站会合。很久没有起这么早,早起的感觉挺好的。朋友迟到了,进站口人山人海,我们差一点错过高铁。

计划赶不上变化。高铁上,朋友发现我订的去丽江的高铁票是“昆明——丽江”,而我们到达站是“昆明南”,我弄错了。两趟车的间隔时间只有四十分钟,经过一番折腾也没抢到票,只好改变行程计划,先去大理,再去丽江,最后回昆明。


苍山下,洱海边

大理古城。到大理已经是傍晚,看着车窗外,远处的苍山乌云密布。大理,下起了小雨。

去到民宿,天色已黑。

我住的房间。

金银花, 散发着淡淡的香。

晚上,我们去了段公子主题餐厅,点了几个招牌菜,喝了小瓶玫瑰酿。这家店气氛不错,服务员小姐姐身着古装,服务很周到。

晚饭后,雨停了,和朋友在大理古城逛逛。这个季节晚上微微凉,感觉很清爽,雨后空气很清新。

我住的房间是民宿环境最好的,有独立平台,可以喝茶聊天。但是不足的是隔音不好,晚上有些住客喝多了大声说话很影响休息。以后订酒店的时候要注意隔音这一点。


05.01 苍山

清晨,气温十七度左右,太阳刚刚升起,清新的空气带着淡淡的金银花香,鸟叽叽地叫着。坐在摇椅上慢慢摇晃着,闭上眼,静静聆听着喜欢的吉他指弹音乐。

朋友睡到很晚才起。吃了早餐,去苍山洗马潭索道。

坐缆车的地方,人并不多,很快就坐上了缆车。

缆车上随手一拍。照片永远拍不出身临其境的感受。

山上气温很低风很大,云雾缭绕宛如仙境。

山上一个展览馆有一些留言本,随便翻看了一下。有度蜜月的写下的浪漫约定,有热恋中的情侣写下的甜蜜情话,还有异地恋独自旅行的人写下的美好期待,也有渴望早些遇到属于自己爱情的愿望,有痴情人留下的执着,有结婚多年实现了多年前定下的有房有车的奋斗目标的夫妻……觉得他们好浪漫,祝福他们,也祝福自己。

下山后,在影视城逛了逛,下午三点多,这次不去洱海,以后再来大理去洱海吧。朋友说他以后要来洱海拍婚纱照。很多人说的要“环洱海”,我觉得没必要。不同的人旅游的方式也不一样,有些人比较喜欢跟随大众。我认为,去一个美丽的地方,用自己喜欢的方式去游玩就好。

回到古城坐车去丽江,沿途的风景很美。


到丽江古城已经晚上七点半点左右。

夕阳如画

下车的地方离我们预订的客栈很近,我们的两间房在二楼,大厅有茶桌,有水车和鲜花。

得知被某团放了鸽子,5.2玉龙雪山大索道的门票没了,只好在别的平台预订5.3的门票。和朋友讨论5.2行程,朋友说去茶马古道,我也觉得可以。

晚上,和朋友去古城转悠转悠吃点东西。

古城晚上人很多,河道边酒吧很多,每个酒吧都坐满了人,灯红酒绿。我问朋友要找家酒吧喝喝酒听听歌,朋友说这种酒吧太吵,心脏受不了。这时一对情侣走过,男的说以前进酒吧坐过没喝酒,女的说这么乖吗。

走到一个观景台,我叫朋友一起上去看看。楼上可以看到整个丽江古城的夜景。原来是喝酒地方,我们选了一个最好的位置,点了一瓶酒。喝着酒,聊聊天,听歌手弹唱民谣,看楼下人来人往,欣赏古城夜景。

回到客栈已经很晚,看见一只好可爱的猫。


05.02 拉市海

茶马古道骑马。

骑完马,马夫带我们进茶馆喝茶,免费的。一个当地的阿姨跟我们介绍纳西族人的风俗。纳西族人以胖黑为美,男人叫“胖几哥”女人叫“胖几妹”。男的十八之前要学会抽烟喝酒,越胖越黑大肚子的胖几哥最好娶媳妇。女的越黑越胖代表越能干越好嫁人。纳西族是”女人的天下,男人的天堂“,纳西族人女人负责“挣钱养家”,男人负责玩。这些与历史原因有关。在古代,当地的男人要跑马帮,走茶马古道,常年在外漂泊,几年才回一次家,有时跌落悬崖或者路上遇到土匪强盗就永远回不来了。

当地的马帮茶很有特色,入口有点苦,喝完之后,阿姨给我们倒了一杯白开水,甜的。

吃完中饭,我们和一起坐车来的两个姑娘去湿地公园玩。她们下午回昆明,回去回学校做作业, 她们在昆明读研,研一。

回到客栈天色还早,和朋友客栈的沙发上稍微休息。小猫躺正在沙发上酣睡,我坐在旁边,只是抬头看了我一眼,然后继续睡。好可爱!

傍晚,我在古城北的观景平台停下脚步,看着天空云卷云舒,光与影映衬下的古城风景美如画。戴上耳机,听着库部真明的指弹曲,静静的欣赏眼下美丽的晚霞和晚霞下的丽江古城。

我们总是忙忙碌碌地在追逐,很多人都有自己清晰的人生规划和职业规划,甚至,同龄人已经想好了二十几年后五六十岁退休的生活,我挺佩服那些人的,他们很清楚知道自己想要什么,把不确定的人生过的那么确定。

越是浮躁的时候,越需要静下来好好思考,不要随波逐流。

天色暗了,古城里渐渐亮起了灯光。

晚上和朋友吃火锅。朋友喜欢吃辣,就点了特辣锅底。

朋友说他女朋友生他气了,怪他没叫她一起出来玩。他女朋友在老家,不在深圳。


05.03 玉龙雪山

早上六点半起床,取了票,吃了早餐,打了辆车去玉龙雪山。

我带上了前两天在大理苍山买的两瓶氧气。下了索道,离最高处的平台还有一段距离,需要爬上去。

最高处的平台,很多人在摆拍游客照,我没过多停留就往下走。发现下面的风景比上面好,人不多,可以停下来慢慢欣赏雪山风景。

玉龙雪山下来之后,去了蓝月谷。很多人拍婚纱照。

蓝月谷之后,再去看《印象丽江》。

我选了一个第一排的最中间的座位,看不到后面的雪山背景,但是离演员们非常近。近距离感受,很震撼。

看完演出,朋友说他想回古城再玩一晚,看看烟花表演,不和我一起去昆明了。我们就此分别。

到昆明南站已经晚上十一点了。到酒店放下行李后,出去吃点夜宵,路边的小吃烧烤摊很多,人很多很热闹。


05.04 昆明

乐队演出,看了下半场

经过斗南地铁站的时候,很多人手捧鲜花。斗南有一个全国最大花卉交易市场。

花,是一种生活态度。

官渡古镇

特色小吃——凉豆粉

特色大饼

官渡古镇特别有生活的气息。


05.05 返程

早上六点多,洗漱完,吃了早餐,走路去高铁站只要几分钟。

车上听听音乐看看书,最近在看《秋园》。

回到住的地方已经下午四点多。

在买的纪念品——东巴纸上写下一句话:

人生就像一场旅行,在乎的不是目的地,而是沿途的风景和看风景的心情。

(完)

学习

这里记录课程学习(非技术类)历程.

2021的学习计划:

  • 积极心理学课程(哈佛)
  • 英语
  • 经济学概论课程

比特币地址生成

btc_gen_addr.jpg

PubKeyToAddr.png

实现

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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259

#!coding:utf8

#author:yqq
#date:2019/3/4 0004 14:35
#description: 比特币地址生成算法

import hashlib
import ecdsa
import os


#2019-05-15 添加私钥限制范围
g_b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

#g_nMaxPrivKey = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140 - 0x423423843 #私钥最大值 (差值是自定义的)
#g_nMinPrivKey = 0x0000000000000000000000000000000000000000000000000000000000000001 + 0x324389329 #私钥最小值 (增值是自定义的)

#2019-11-12 根据官方定义修改 有限域
# http://www.secg.org/sec2-v2.pdf#page=9&zoom=100,0,249
# 关于 有限域的定义 请参考
# 0xEFFFFFC2F = 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1
g_nFactor = 0xEFFFFFC2F + 0x23492397 #增值自定义
g_nMaxPrivKey = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140 - g_nFactor #私钥最大值 (差值是自定义的)
g_nMinPrivKey = 0x0000000000000000000000000000000000000000000000000000000000000001 + g_nFactor #私钥最小值 (增值是自定义的)



def Base58encode(n):
'''
base58编码
:param n: 需要编码的数
:return: 编码后的
'''
result = ''
while n > 0:
result = g_b58[n % 58] + result
n /= 58
return result


def Base256decode(s):
'''
base256编码
:param s:
:return:
'''
result = 0
for c in s:
result = result * 256 + ord(c)
return result


def CountLeadingChars(s, ch):
'''
计算一个字符串开头的字符的次数
比如: CountLeadingChars('000001234', '0') 结果是5
:param s:字符串
:param ch:字符
:return:次数
'''
count = 0
for c in s:
if c == ch:
count += 1
else:
break
return count


def Base58CheckEncode(version, payload):
'''

:param version: 版本前缀 , 用于区分主网 和 测试网络
:param payload:
:return:
'''
s = chr(version) + payload
checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4] #两次sha256, 区前4字节作为校验和
result = s + checksum
leadingZeros = CountLeadingChars(result, '\0')
return '1' * leadingZeros + Base58encode(Base256decode(result))


def PrivKeyToPubKey(privKey):
'''
私钥-->公钥
:param privKey: 共65个字节: 0x04 + x的坐标 + y的坐标
:return:
'''
sk = ecdsa.SigningKey.from_string(privKey.decode('hex'), curve=ecdsa.SECP256k1)
# vk = sk.verifying_key
return ('\04' + sk.verifying_key.to_string()).encode('hex')

def PrivKeyToPubKeyCompress(privKey):
'''
私钥-->公钥 压缩格式公钥
:param privKey: ( 如果是奇数,前缀是 03; 如果是偶数, 前缀是 02) + x轴坐标
:return:
'''
sk = ecdsa.SigningKey.from_string(privKey.decode('hex'), curve=ecdsa.SECP256k1)
# vk = sk.verifying_key
try:
# print(sk.verifying_key.to_string().encode('hex'))
point_x = sk.verifying_key.to_string().encode('hex')[ : 32*2] #获取点的 x 轴坐标
point_y = sk.verifying_key.to_string().encode('hex')[32*2 : ] #获取点的 y 轴坐标
# print("point_x:", point_x)

if (long(point_y, 16) & 1) == 1: # 如果是奇数,前缀是 03; 如果是偶数, 前缀是 02
prefix = '03'
else:
prefix = '02'
return prefix + point_x
except:
raise("array overindex")
pass



#https://en.bitcoin.it/wiki/List_of_address_prefixes
def PubKeyToAddr(privKey, isTestnet = False):
'''
公钥-->地址
:param privKey:私钥
:param isTestnet:是否是测试网络
:return:地址
'''
ripemd160 = hashlib.new('ripemd160')
ripemd160.update(hashlib.sha256(privKey.decode('hex')).digest())
if isTestnet:
return Base58CheckEncode(0x6F, ripemd160.digest()) #0x6F p2pkh testnet
# return base58CheckEncode(0x05, ripemd160.digest()) #05 p2sh mainnet
return Base58CheckEncode(0x00, ripemd160.digest()) #00 p2pkh mainnet




def PrivKeyToWIF(privKey, isTestnet = False):
'''
将私钥转为 WIF格式 , 用于比特币钱包导入
:param privKey: 私钥(16进制字符串)
:return: WIF格式的私钥
'''
if isTestnet:
# return Base58CheckEncode(0xEF, privKey.decode('hex') + '\01') #0xEF 测试网络 fix bug: 2019-04-03 yqq 01是多余的, 只有是压缩的格式的时候,才需要加
return Base58CheckEncode(0xEF, privKey.decode('hex') ) #0xEF 测试网络
# return Base58CheckEncode(0x80, privKey.decode('hex') + '\01') #0x80 主网
return Base58CheckEncode(0x80, privKey.decode('hex') ) #0x80 主网

def PrivKeyToWIFCompress(privKey, isTestnet = False):
'''
压缩格式
将私钥转为 WIF格式 , 用于比特币钱包导入
:param privKey: 私钥(16进制字符串)
:return: WIF格式的私钥
'''
if isTestnet:
return Base58CheckEncode(0xEF, privKey.decode('hex') + '\01') #0xEF 测试网络
return Base58CheckEncode(0x80, privKey.decode('hex') + '\01') #0x80 主网


def GenPrivKey():
'''
生成私钥, 使用 os.urandom (底层使用了操作系统的随机函数接口, 取决于CPU的性能,各种的硬件的数据指标)
:return:私钥(16进制编码)
'''

#2019-05-15 添加私钥范围限制
while True:
privKey = os.urandom(32).encode('hex') #生成 256位 私钥
if g_nMinPrivKey < int(privKey, 16) < g_nMaxPrivKey:
return privKey


def GenAddr(isTestnet=False):
'''
此函数用于C++调用,
:param isTestnet: 是否是测试网络
:return: (私钥, 公钥, 地址)
'''
privKey = GenPrivKey()
# print("privkey : " + privKey)
privKeyWIF = PrivKeyToWIF(privKey, isTestnet)
# print("privkey WIF:" + PrivKeyToWIF(privKey, isTestnet))
pubKey = PrivKeyToPubKey(privKey)
# print("pubkey : " + pubKey)
addr = PubKeyToAddr(pubKey, isTestnet)
# print("addr : " + addr)
return str(privKeyWIF), str(pubKey), str(addr)




def GenAddrCompress(isTestnet=False):
'''
此函数用于C++调用,
:param isTestnet: 是否是测试网络
:param isCompress: 是否压缩
:return: (私钥, 公钥, 地址)
'''
privKey = GenPrivKey()
# print("privkey : " + privKey)
privKeyWIF = PrivKeyToWIFCompress(privKey, isTestnet)
# print("privkey WIF:" + PrivKeyToWIF(privKey, isTestnet))
pubKey = PrivKeyToPubKeyCompress(privKey)
# print("pubkey : " + pubKey)
addr = PubKeyToAddr(pubKey, isTestnet)
# print("addr : " + addr)
return str(privKeyWIF), str(pubKey), str(addr)



def GenMultiAddr(nAddrCount = 1, isTestnet=True):
'''
生成多个地址
:param nAddrCount:
:param isTestnet:
:return:
'''
# return [("1111", "2222", "3333"), ("4444", "55555", "66666")]
# return [1, 2, 3, 4]
# return ["1111", "2222", "3333", "4444"]

lstRet = []
for i in range(nAddrCount):
lstRet.append(GenAddrCompress(isTestnet))
return lstRet

#
def good():

isTestnet = True


# private_key = GenPrivKey()
private_key = '95b51ad564bd26811aeafc06ebe64643d2a50f82aa4901e714ba4be635ed9a57'
print("privkey : " + private_key)
print("privkey WIF:" + PrivKeyToWIF(private_key, isTestnet))
pubKey = PrivKeyToPubKey(private_key)
print("pubkey : " + pubKey)
addr = PubKeyToAddr( pubKey , isTestnet)
print("addr : " + addr)
print("-----------------------------")
print("privkey WIF compress:" + PrivKeyToWIFCompress(private_key, isTestnet))
pubKey = PrivKeyToPubKeyCompress(private_key)
print("pubkey compress : " + pubKey)
addr = PubKeyToAddr( pubKey , isTestnet)
print("addr compress: " + addr)
#
#
# def main():
# good()
# for i in range(1):
# print(GenAddr(True))

# if __name__ == '__main__':
#
# main()

关于地址压缩

参考链接: https://bitcoin.stackexchange.com/questions/3059/what-is-a-compressed-bitcoin-key


2021评语:

以上的python实现, 可以作为理解比特币地址生成的例子

如果实际项目开发中需要进行地址生成, 可以借助一些现成的库进行地址管理, 推荐使用BIP44规范进行私钥管理

什么是BIP44: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki

比特币的一些库:

Python:

C++:

Golang:

Rust:

  • Copyrights © 2021-2024 youngqqcn

请我喝杯咖啡吧~