每天进步一点点:"Canonical" 交易签名

在之前学习用私钥签名的文章中,虽然我们完成了用私钥进行签名,但是我还留下一下问题,就是生成的签名尽管可以通过验证,但是是否适用于STEEM/HIVE区块链呢?这里涉及到一个知识点就是canonical signature


(图源 :pixabay)

canonical signature

说到canonical signature,就要提到一个Signature Malleability,简单来讲就是对于同一个HASH,signature (r,s)以及signature (r, -s (mod N))都是合法的签名:

In addition for every ECDSA signature (r,s), thesignature (r, -s (mod N)) is a valid signature of the same message.

对于恶意攻击者而言,就可以利用这点来进行重播攻击,将一个交易用不同的签名提交两次(说的是啥?一头雾水ing)。

而杜绝这个问题的一个方法就是对签名的r、s进行一些约束,只有符合约束的才能算做合法的签名。

steemd中相关代码

在steemd中对应的检查代码如下:

image.png

其中两个检查代码分别如下:

image.png

如下代码会作为参数传递给签名/验证的相关函数:

has_hardfork( STEEM_HARDFORK_0_20__1944 ) ? fc::ecc::bip_0062 : fc::ecc::fc_canonical );

也就是说HF20之前用fc_canonical来检查,HF20之后用bip_0062来检查。话说,这个两个检查哪个更严格一些呢?另外bip_0062中为啥不检查

steem-python 中的相应检查

steem-python中针对用使用SECP256K1生成的签名使用如下代码检查:

1
2
3
4
5
def _is_canonical(self, sig):
return (not (sig[0] & 0x80)
and not (sig[0] == 0 and not (sig[1] & 0x80))
and not (sig[32] & 0x80)
and not (sig[32] == 0 and not (sig[33] & 0x80)))

而针对使用ecdsa生成的签名则使用如下代码来检查:

1
2
3
4
5
6
# Make sure signature is canonical!
#
lenR = sigder[3]
lenS = sigder[5 + lenR]
if lenR is 32 and lenS is 32:
其它代码

可见都不是遵循新的bip_0062标准。

不过这两组代码现在也都是工作的,我猜测是因为按着bip_0062标准,上述代码检查后的签名不符合标准的概率微乎其微,所以很难触发吧?😳

相关链接


This page is synchronized from the post: ‘每天进步一点点:”Canonical” 交易签名’

往事:3000元的违约金

大学快毕业的时候,很多同学都忙着准备考研,而我之前和朋友一起创办了个工作室,赚了一些小钱,总觉得赚钱的滋味比继续上学好得多得多。


(图源 :pixabay)

原本想着我们的工作室一定会越办越好,钱也会越赚越多,可是工作室的一个成员决定去日本留学,另外一个成员被家里安排进了国有银行,还剩两人有些支撑不下去了,工作室就无疾而终了。

最后大家分家产的时候,发现我们最多的都是硬件相关的设备和元件,而我不擅长硬件,所以家产都以很低的价格算给了我另外一个伙伴,这样手头只剩下不几个钱了。

尝过赚钱的滋味,我决定还是继续找工作赚钱比较好,虽然家里并不拮据,给我的生活费基本够花,但是花起来不够硬气,买一些所谓的大件(自行车、CD机什么的)总要征求一下家里意见,况且也不好意思浪费父母赚的辛苦钱。

于是我就参加了几次校园招聘会,其中一次竟然有部队的在校招,我很多同学都去投了这个岗位,但是无一例外地被当场拒绝,其实我并不是十分想去部队,但是看同学们被拒,挑起了我的兴趣,于是过去投了简历聊了几句。

结果部队的领导看到我的简历以及计算机四级证书还有我介绍自己工作室的一系列成果后,果然决定当场录用我,就这样稀里糊涂签了意向书。

之后对方一直打电话让我去签正式的协议,于是某个周末我到了部队的驻地,签了入伍志愿书、就业协议书等等,回来后感觉晕乎乎的,我这就成为一名光荣的人民子弟兵了?

不过晕乎了不长时间后,被就一些朋友浇冷水了,说我的性格不适合部队云云,说部队生活很艰苦等等,于是乎就萌生了退意。

结果和部队领导一商量,对方是坚决反对,说我们费了这么大劲才招到你,必须得来。晕,想起了赵丽蓉老师小品里的一句台词:我说我不签,你非让我签。

最后沟通来沟通去,部队领导看我心思果然已经不再这里了,同意我撤销协议书,不过要交3000块钱的违约金,这下可难住了我,家里知道我去部队的事情高兴得不得了,坚决不允许我毁约,为了避免我毁约,不给我出这3000元。

当时手头的钱只够生活费的,去哪划拉3000元交违约金啊,这成了个大难题。结果寝室老大和我聊了这事后,果断做出决定,3000元他先替我出了,等我以后工作了有钱再还他。

其实这个寝室是我们最后一学年两个班级合并在一起的,老大和我并不是一个班的,而且后来我弄工作室的时候,大部分时间都住在校外,和老大并不算多铁。

然而在当时的情况下,老大却义无反顾地决定借钱给我,要知道我们当时基本上都是分文皆无的学生啊,当时的3000元,对我们每个人来说都是一笔巨款。

有了老大支援的3000元,我成功地和部队解除了合约,然后后来如愿以偿地应聘成功一家我当时最想加入的软件公司,如果没有那3000元,也许现在我还在部队呢。

之所以想起这段往事,是因为看一个微信群里在讨论朋友借钱的事情,有人引用了一句话:

如果你想失去一个朋友,就向他借钱;如果你想失去一个朋友,就借钱给他。


(图源 :pixabay)

还好我还没因为向别人借钱或者被别人借钱而失去朋友,真正的朋友,是不怕金钱试验的。


This page is synchronized from the post: ‘往事:3000元的违约金’

栽花

image.png

去年春天,媳妇网购了好多漂亮的花,并栽种到花盆里,有玛格丽特、有重牛、有小玲,让整个春天和夏初变得更加美丽。

因为这些花都不是宿根植物,所以从入夏开始,我就担心这些花如何过冬呢?然后决定等冬天到来时,把它们移到室内过冬。

然而还没等到冬天到来,几场大暴雨下来,我的所有的小花都牺牲了,这生命力也太不顽强了,于是我决定今年春天弄些宿根的花朵栽在花盆里。

然而还没等我寻到宿根的花朵,媳妇又网购了一些小花,当我知晓时,快递已经送到了门口,无奈只好把它们栽到花盆里喽。

image.png

image.png

image.png

image.png

image.png

墙边的百合,还是这些花好,不用我伺弄,自己就冒出来了。
image.png

郁金香也很省心,已经含苞待放了,就是花期有点短。
image.png

但愿今年栽的几株花能坚强一些,活得长久一些吧。去年是我疏忽了,今年等到夏天有大暴雨的时候,我会给它们放小棚子里。


This page is synchronized from the post: ‘栽花’

崔奶奶(2)

大概两年半以前,我写过一篇文章《崔奶奶》,崔奶奶不是虚构的人物,而是我家原来的房子所在单元一楼一号的老奶奶。

image.png
(动漫中的老奶奶,借来用用,出处未知)

在那篇文章中,崔奶奶的子女都在海外,崔奶奶一个人虽然有诸多不便,但是又是跳广场舞锻炼身体,又是在小院子里种植蔬菜,又是信仰宗教,过得也很精彩。

不过大概一年前,崔奶奶的平静生活被打破了,崔奶奶家的带小院的一楼住房竟然在中介挂牌出售,这让我惊讶万分。一次偶然看到崔奶奶,她和我聊了近一个小时,我差不多知道了事情的始末。

之前文章里说崔奶奶的子女都在海外,其实消息有些老旧了,崔奶奶的儿子已经回国,在京东物流这边的分公司供职,儿媳开公司经商。

按说儿子是管理层,儿媳自己开公司,崔奶奶继续享福就是了,或者继续过以前儿女不在身边的生活也不错。可是据说儿媳的公司需要资金周转,两口子就把主意打到了崔奶奶的房子上。

之前我说过,崔奶奶是知名大学的退休教授,所以退休金什么的都很丰厚,这个房子是以儿子的名义贷款(岁数大了不让贷款),崔奶奶自己出的首付,自己还贷,其实和儿女并没有什么关系。

我和崔奶奶说,他们公司需要资金周转,他们自己想办法去了,不能动老人的房产啊。崔奶奶无奈地叹息:“那能怎么办?和我说了,我也不能无视啊。”说着说着,崔奶奶就落下了眼泪。

这是人家的家事,我也不好多劝,不过一想到崔奶奶精心伺弄的小院以及崔奶奶小房子要卖给他人,心里还是有些不是滋味。

再后来看到中介那边更新了房屋的图片,里边搬得干干净净;再后来,又看到中介更新了房屋的图片,里边重新装修了,并且提高了售价;再后来中介和我说那个房子已经卖出去了。

然后,听到邻居们议论,崔奶奶搬走之后,儿子只给崔奶奶留了三个月的租房的钱,还有大家议论说儿子把崔奶奶的手机套餐什么的都取消了,这让我心里愈发悲哀。

一转眼,有大概一年半没有崔奶奶的音讯了,也不知道崔奶奶过得怎么样,邻居们也渐渐忘却了这些事,不再去讨论了。

昨天我去园区超市,路上看到一个白发苍苍的老奶奶拉着个行李箱往这边来,仔细一看这不是崔奶奶吗?于是我和崔奶奶又聊了一段时间。

崔奶奶和我说,她现在在附近的一个小区里租房住,条件也挺好的;至于原本的房子什么时间卖的卖多少钱,她说她根本没去关心;她前段时间去她姐姐家,在姐姐家住了大半年;她这次是去教友家里交流……

看来崔奶奶还是那个积极乐观的崔奶奶,这样我就放心了。

不禁感慨,都说养儿防老,但是教育不好的话,就是养儿啃老了;更严重一点的,就是养儿坑老了…..

相关链接


This page is synchronized from the post: ‘崔奶奶(2)’

每天进步一点点:(实战)从HIVE/STEEM签名中恢复公钥 / Recover the Public KEY from the signature

之前写过好几篇文章学习私钥、公钥、签名、验证以及从签名中恢复出公钥等等。但是这些都是理论,那么能否应用到实际中来呢?今天就来测试一下从HIVE/STEEM交易签名中恢复出公钥


(图源 :pixabay)

大家都知道,STEEM/HIVE上有很多公共账户,比如以前的busy.org、utopian.app、steemauto等等,我们将账户授权给这个账户后,这些账户就可以用我们的用户名发帖/点赞等。

假设A账户授权给B账户,然后在区块链上我们看到A账户做了一个点赞操作,那么如何判断出是A账户操作的还是B账户操作的呢?

好久以前,我曾经探索过这个问题,我的思路是取出A账户所有管理的公钥,然后去对对应的操作的签名进行验证,如果哪个公钥验证成功,则说明是这个公钥对应的账户进行的操作。

上述思路的详情以及代码可以参考:获取共同操作账户某个操作的真实操作者,附简单脚本 / Get real operator of a transaction made by the ID which operated by multi accounts, script attached

当年对私钥、公钥、签名这块学习的不够透彻,现在又过了2、3年,有没有更方便快捷的方法呢?答案就是直接从签名中恢复出公钥,这篇文章我们就来实际操作一下。

以如下这个transaction为例:

image.png

我们可以通过如下代码获取这个transaction:

block = steem.get_block(block_num)
index = block['transaction_ids'].index(tx_id)
tx = block['transactions'][index]

代入block_num 42357710和tx_id 2e3091807ff1d25630d27815f8605f270f913f8d后,我们会得到类似如下的transaction(为了便于查看,签名部分我没截全):

image.png

这个内容(去掉签名后)可以理解成要被签名的原始内容,而签名是针对原始内容序列化后的摘要进行的,获取摘要部分是很复杂的部分,以后再探究,我们可以先用steem-python的代码来获取摘要:

tx_obj = transactions.SignedTransaction(**tx)
tx_obj.deriveDigest("HIVE")
digest = tx_obj.digest

好了,摘要我们有了,签名信息就更简单了,我们直接用如下语句就可以取到:

signature = tx["signatures"][0]

现在从签名中恢复公钥的要素基本全了:摘要 & 签名。不过在这之前我们要知道STEEM/HIVE的签名和普通的签名有一丁点不同:那就是第一个字节包含了recover_pubkey_parameter这个东西,我们可以把它理解成实际公钥在恢复出来的公钥组的位置。

sig = unhexlify(signature)
recover_pubkey_parameter = sig[0] - 4 -27

接下来就是将signature剩余部分分解成为r、s,可以用如下代码(r、s长度均为32字节):

r = int.from_bytes(sig[1:33], "big")
s = int.from_bytes(sig[33:65], "big")

接下来就可以计算出公钥啦:

Sig = ecdsa.ecdsa.Signature(r, s)
digest_number = ecdsa.util.string_to_number(digest)
pubks = Sig.recover_public_keys(digest_number,ecdsa.SECP256k1.generator)
pk = ecdsa.VerifyingKey.from_public_point(pubks[recover_pubkey_parameter].point, curve=ecdsa.SECP256k1)
print(hexlify(pk.to_string(encoding="compressed")))

算出来的公钥是一长串数字,再调用gphBase58CheckEncode()并加上STM前缀,就可以变成我们的公钥啦。公共上述代码,计算出来的公钥为:

image.png

再看一下我的POSTING Key:

image.png

是不是完全一样啊,所以我这波实战操作还是成功的,并且这也是一个有实际意义的操作,至少我自己觉得比2、3年前的代码要进步的多得多啦。

相关链接


This page is synchronized from the post: ‘每天进步一点点:(实战)从HIVE/STEEM签名中恢复公钥 / Recover the Public KEY from the signature’

3000万的消费券,要去抽奖吗?

昨天朋友圈和微信群都在传ZF即将给市民发放3000万的消费券来刺激消费,听到这个消息我也被刺激得不得了,3000万啊,哪怕分到万分之一也好。


(图源 :pixabay)

不过在仔细想想,好像不是这么回事,按着资料,沈阳常住人口831.6万人,城镇人口673.6万人,就算是500万人去分,那么平均一人才6元。

不过看了一下通知,不是平均分,而是需要预约、摇号、发放三个步骤,并不是符合条件的市民就能领取。

所谓的预约我看了一下,必须要本人实名的微信号关注一个公众号,然后在公众号内输入本人的姓名、身份证号完成预约。也就是没有实名微信号并且不绑定公众号的不能预约。

再看了一下:

第一期发放消费券1000万元,其中餐饮消费券500万元,综合消费券500万元,共20万份;

也就是第一期最多20万人中奖,3000万都发下来的话,也不过是60W人中奖,中奖的概率是十分之一。

而且这些消费券,据公开消息,是一些100-50的券,这样价值又打了折扣。据我一个羊毛党朋友说,这样的券可以卖给商家,能卖到40元一张,那样的话倒也不错。

不过又是预约、又是抽签、又是100-50,想着中奖面也不算很大,就不去弄了,给需要的人吧。


(图源 :pixabay)

政府弄这个刺激消费,倒是不错,如果能再多发一些,面值大一些,中奖率高一些,就更好啦。😍


This page is synchronized from the post: ‘3000万的消费券,要去抽奖吗?’

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×