V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
acess
V2EX  ›  Bitcoin

说说为什么一个比特币私钥可以对应多个地址

  •  
  •   acess · 2021-04-22 03:13:27 +08:00 · 1189 次点击
    这是一个创建于 1312 天前的主题,其中的信息可能已经有所发展或是发生改变。
    楼主来半桶水瞎掰扯一下这个蛋疼的问题……


    (1)光是公钥就分两种:压缩和非压缩。现在一般用压缩的。

    于是,光是 1 开头的 P2PKH 地址,就有两个,因为压缩公钥和非压缩公钥哈希出来也不一样。


    (2)锁定脚本,或者叫输出脚本,这方面的写法几乎无穷无尽……虽然典型 /常见的也就那么几种。

    这个说来话长。

    不过到这里已经可以看到:

    2 种公钥×N 种输出脚本=……
    额,有点画美不看……

    而且,未来激活了 taproot,公钥可以和脚本哈希合体,里面还可以藏入……额……嵌套多层的脚本哈希……
    额……

    (又不知道哪里触发 V 站的和谐了,哎,跟贴吧一样难用,楼下继续)
    第 1 条附言  ·  2021-04-22 04:51:28 +08:00
    前情提要: /t/772048
    30 条回复    2021-04-23 01:00:21 +08:00
    acess
        1
    acess  
    OP
       2021-04-22 03:14:44 +08:00
    (因为万恶的和谐,必须把文字拆开,看看哪里触发了和谐,抱歉)
    acess
        2
    acess  
    OP
       2021-04-22 03:14:59 +08:00
    不过,幸运的是,对于现在最通用的 BIP39/44/49/84 钱包来说(不幸的是,最“官方”的 Bitcoin Core 目前还不是这个体系,尤其是有些开发者很抵制 BIP39 助记词,哎),不同的地址类型需要走不同的 HD 推导路径,不会出现一个公 /私钥被用到多种不同地址身上的情况。

    只要你自己不自找麻烦,不把单个私钥或公钥手动导出后瞎折腾(换句话说,如果你瞎折腾了,那就可能出现问题,主要就是,你自己折腾出来的新地址,只能在你自己折腾的非标准钱包里看到交易记录和余额;而在标准的钱包里扫描不到,就好像丢了币一样),那还是:

    [一个私钥]<=>[一个公钥]<=>[一个地址]
    acess
        3
    acess  
    OP
       2021-04-22 03:15:33 +08:00
    还是 1-1 对应,还是那么简单清爽——虽然……
    acess
        4
    acess  
    OP
       2021-04-22 03:15:45 +08:00
    ……虽然,你给钱包导入 1 个 HD 助记词(或者叫 HD 种子)后,还是会:
    acess
        5
    acess  
    OP
       2021-04-22 03:15:55 +08:00
    (1)生成好多个地址;
    (2)每次无论是收款还是付款,都会换(生成)一个新的地址(但是别怕,只要 HD 种子备份好了,这些地址都可以恢复出来);
    (3)而且这些地址还分 3 种:
    acess
        6
    acess  
    OP
       2021-04-22 03:16:14 +08:00
    第一种:1 开头的 P2PKH 地址,最老、最经典、最通用;矿工费没有折扣所以最贵。
    (公钥当然是压缩公钥。P2PKH 可以用非压缩公钥,但是现在一般都不用了。另外下面提到的隔离见证还是禁用压缩公钥的)
    acess
        7
    acess  
    OP
       2021-04-22 03:16:21 +08:00
    第二种:3 开头的 P2SH-P2WPKH 地址,又叫 P2SH 封装隔离见证地址,或者叫“兼容”隔离见证地址。
    兼容性和第一种差不多;
    矿工费因为享受了折扣,所以(在转出时)比第一种便宜不少,但是因为 P2SH 封装本身也要占字节数,所以矿工费仍然比第三种贵;
    acess
        8
    acess  
    OP
       2021-04-22 03:16:28 +08:00
    第三种:bc1 开头的 P2WPKH 地址,又叫 Bech32 地址,或者叫“原生”隔离见证地址。
    前两种地址都是中本聪设计的 Base58check 编码,大小写混合; Bech32 编码是新设计的,不含混合大小写,要么全大写要么全小写。
    因为 Bech32 编码是新设计的,所以存在兼容性问题:老钱包不识别新地址,于是老钱包(在操作上)就不能转账给这种新地址——把钱包升级到支持 Bech32 的新版,或者把私钥 /助记词导出,再导入给支持 Bech32 的其他钱包,就可以了。
    新钱包从新地址转给老钱包是没问题的(顶多就是零确认看不到,进链确认了就能看到进账了)。
    acess
        9
    acess  
    OP
       2021-04-22 03:18:50 +08:00
    下面展开说说输出脚本这个梗……
    acess
        10
    acess  
    OP
       2021-04-22 03:19:09 +08:00
    1 开头的 P2PKH 地址,实际上对应了一个“锁定脚本”,它规定了,在满足什么条件下,可以把币“解锁”、转(花)出去。

    如果条件不满足(比如,你没给出有效的数字签名;或者是锁定时间还没到期,等等),那这笔交易就是非法的,不能打包进链,哪个矿工敢打包,大家就都不承认他挖的区块。

    这个锁定脚本的写法,很显然是很自由的……但是如果你写的不是标准的脚本,那按理说就没有对应的地址可以表示这个脚本了。
    acess
        11
    acess  
    OP
       2021-04-22 03:19:20 +08:00
    于是,很久很久以前(没记错的话是 2012 年),比特币引入了一个新功能,P2SH 。
    acess
        12
    acess  
    OP
       2021-04-22 03:19:46 +08:00
    无论你的锁定脚本写得多么乱七八糟,都可以哈希一下,然后,这个脚本的哈希值就可以用一个 3 开头的地址来表示。

    3 开头的地址——看看,有地址了!无论多么乱七八糟的锁定脚本,都可以用一个标准的、3 开头的地址来表示。
    acess
        13
    acess  
    OP
       2021-04-22 03:19:57 +08:00
    这个脚本哈希值就可以代表你原先写的那个脚本,这种情况下,哈希之前的锁定脚本就改叫“赎回脚本”( redeem script )了。

    未来要把币“解锁”转出去的时候,不仅要提供“解锁”的条件(一般就是数字签名),还要把“赎回脚本”的原文一同给出。
    大家把你给出的赎回脚本进行哈希,和当初的脚本哈希比对,结果一致,然后就按照赎回脚本规定的步骤,去验证币能不能“解锁”花出去。
    acess
        14
    acess  
    OP
       2021-04-22 03:20:19 +08:00
    (其实 P2SH 是把原先存在的一种很鸡肋的输出脚本语义改变了……这种很鸡肋的输出脚本,在比特币引入 P2SH 功能之前,只走到“把你给出的赎回脚本进行哈希,和当初的脚本哈希比对,结果一致”这一步,就算验证通过了。这种情况,乍一看,好像是“输入密码即可提款”,很简单,但没有实用性。为什么没有实用性?因为任何人都可以把交易输出里的收款地址篡改成自己的,篡改完了交易仍然有效。P2PKH 就不是这样,交易输出是受数字签名保护的,篡改了输出,交易就无效了。总之,P2SH 用一种很 hack 的方式,把之前几乎无用的一种输出脚本重新定义,改进了现在广泛使用的新功能)
    acess
        15
    acess  
    OP
       2021-04-22 03:21:52 +08:00
    (楼上“P2PKH 就不是这样”这里没打错,我就是拿 P2PKH 举个例子,和 P2SH 的前身做一个对比)
    acess
        16
    acess  
    OP
       2021-04-22 03:23:12 +08:00
    (哎,14 楼还是有一处打字错误,纠正一下:“改进 [后就变成] 了现在广泛使用的新功能”,抱歉)
    acess
        17
    acess  
    OP
       2021-04-22 03:27:18 +08:00
    然后回到主贴提到的:
    “未来激活了 taproot,公钥可以和脚本哈希合体,里面还可以藏入……额……嵌套多层的脚本哈希……”

    乍一看很可怕。但是,只要明白了 P2SH 是咋回事——无非就是,先登记合同的哈希值,未来要按照合同内容执行时,再提供完整的合同全文——那就会明白,taproot (这里不单指 taproot 本身,还包括了 MAST )并不是吓人的复杂怪物。

    (不过老实说楼主也没亲自测试过 taproot,可能很多地方还有误解,轻喷)
    acess
        18
    acess  
    OP
       2021-04-22 03:35:05 +08:00
    首先,P2SH 不是用来封装锁定脚本的么,实际上都被大家用来封装什么了呢?
    大多数时候,都是多重签名(其次就是隔离见证)。
    一个地址,被多把私钥共同控制。
    M of N 多重签名,就是一共有 N 把私钥参与,其中至少 M 把私钥签名后,就可以把币花(转)出去。
    acess
        19
    acess  
    OP
       2021-04-22 03:41:52 +08:00
    实际上 P2SH (以及隔离见证改进版的 P2SH,也就是 P2WSH 。P2WSH 也是 bc1 开头,但是比 P2WPKH 更长)用到多重签名上还存在一个陷阱:

    如果你把币存到了 2of3 多重签名地址上,但是只备份了其中两把私钥,
    那么不好意思,
    (如果你把设置好的钱包文件删了)你的币丢了,永久丢失,谁也找不回来。

    欸,不是 2of3 么,2 把私钥不是够了么,怎么会找不回来呢?

    因为,要从 P2SH 地址里把币花出去,你不仅需要用 2 把私钥签名,还要知道被哈希的那个赎回脚本的完整原文是什么。如果你不知道第三把私钥对应的公钥,那也就等于你不知道赎回脚本。
    当初建立多重签名钱包的时候,肯定是三个公钥都参与进来,才得到赎回脚本,然后赎回脚本哈希后就可以得到 3 开头的 P2SH 地址。

    很显然,从脚本哈希是不能反推出脚本原文的,包括公钥。
    如果你既没有赎回脚本本身,又没有第三把私钥对应的公钥(用这个公钥很显然可以重建赎回脚本),那就回天乏术了。
    acess
        20
    acess  
    OP
       2021-04-22 03:42:24 +08:00
    taproot 本身,就是说,一个公钥(这里需要配合将来要支持的 Schnorr 数字签名,而不是现在用的 ECDSA 数字签名),你看来看去,怎么看,它都只是一个公钥;但实际上,它不止是个公钥,这个公钥里还隐含了一个哈希值。
    acess
        21
    acess  
    OP
       2021-04-22 04:00:41 +08:00
    19 楼提到的陷阱,是不是在 taproot 里能避免,这个老实说我还不是非常确定,毕竟楼主我是半桶水;但是 taproot 能干啥,我应该还是知道的。


    首先复读一下,P2SH 是啥样的?

    先登记合同的哈希值(脚本哈希),未来要按照合同内容执行时(把币花出去),再提供完整的合同全文(赎回脚本)。


    然后,taproot 又是什么情况?

    前文不是提到,公钥里可以藏一个哈希么,很显然,这个哈希可以是脚本哈希啊,于是就可以把 P2SH 的功能包括进来了。

    然后,即便是把哈希藏到公钥里,只要交易打包进链,那“合同全文内容”还是固定了,改不了了。

    但是,没关系。重点来了——
    taproot 的这个公钥,不仅可以藏哈希;归功于 Schnorr 数字签名的神奇数学性质,这个公钥本身,还可以是多个公钥“合体”变成的。

    然后,只要合体前的多把私钥全部都签名了,那么就可以无视(作废)掉当初藏进去的那个脚本哈希。

    欸,作废了?那还藏这个脚本哈希进去有啥用?
    有用啊。
    如果多把私钥的主人们并没有全部达成一致意见,出现了争议,那就可以把当初订立的合同(赎回脚本)重新拿出来,对外出示,还是可以按照当初订立的合同来执行。

    (这里也存在不少遗憾,比如这个神奇的 Schnorr 签名只能在所有人一个不落下全部都达成一致的情况下才好用;光靠 schnorr 签名本身,并不能实现“少数服从多数”的多重签名;(理论上)顶多只能实现反过来的“多数服从少数”。想要“少数服从多数”,还是得靠脚本)
    acess
        22
    acess  
    OP
       2021-04-22 04:09:31 +08:00
    到了这里,其实“嵌套多层的脚本哈希”是啥,也许即便我不说,可能你大概也明白了。

    因为有神奇的 schnorr 签名加持,在[所有人一个不落下全部都达成一致意见的情况下],就可以无视当初藏进公钥的那个脚本哈希,不用出示完整的赎回脚本。

    如果碰到了需要出示完整赎回脚本的情况呢?

    脚本里,其实还可以包含一个公钥,这个公钥乍一看,怎么看都只是个公钥,实际上,它里面藏了一个脚本哈希……

    这个脚本哈希呢,在需要出示脚本原文的时候,里面其实还可以包括一个公钥,这个公钥乍一看,怎么看都只是个公钥,实际上,它里面藏了一个脚本哈希……

    ……

    嗯,就是这样,套娃了。
    据我所知,(与 Schnorr 签名结合使用的) MAST 就是这么一回事。

    而且,很容易想到:
    就像代码里的 if then else,两个分支里只有一个会执行,不同条件执行不同的分支;
    MAST 也是类似的,而且,你只需要出示被执行的那部分代码,没执行的那部分,你不用出示,然后大家就都只能看到哈希,看不到原文。
    acess
        23
    acess  
    OP
       2021-04-22 04:21:16 +08:00
    最后,很多时候 taproot 被宣传成“比特币的隐私功能”

    如果我没理解错,这其实和很多人预想的不太一样。
    acess
        24
    acess  
    OP
       2021-04-22 04:21:32 +08:00
    taproot 的隐私性,据我所知只体现在两个方面:

    (1)公钥里是不是藏了脚本哈希,外界看不出来,公钥和公钥看上去长得都很像,分不清彼此。所以,存在“可互换性”方面的好处。

    (2)MAST 里只需要披露被执行的那部分脚本原文,不被执行的就可以不披露,外界只能看到哈希值,看不到原文。
    acess
        25
    acess  
    OP
       2021-04-22 04:22:01 +08:00
    额,怎么说呢,和绝大多数人脑补的匿名性、不可追踪性什么的,好像不怎么能挂得上边(虽然第(1)点涉及“可互换性”,勉强挂得上边吧)……不知道是不是我了解不到位。而且 taproot 未来还是要通过软分叉实现,换句话说,taproot 本身,相对之前已经存在的 P2PKH 、P2SH 、P2WPKH……这些,就已经是又一个截然不同的、新的地址类型——不同的地址类型其实是对“隐私”/“可互换性”不利的,这恰恰就是 taproot 想要缓解的问题。
    acess
        26
    acess  
    OP
       2021-04-22 04:22:16 +08:00
    换句话说,只有未来所有人都用上 taproot 了,taproot 的第(1)点好处才能完全体现;然而哪怕是现在,还有相当比例的人很守旧,连隔离见证都不愿意用(或者说,不知道怎么才能启用)。
    acess
        27
    acess  
    OP
       2021-04-22 04:23:17 +08:00
    本来 schnorr 签名理论上还可以实现 CISA ( cross-input signature aggregation,跨输出签名聚·合),看上去对 coinjoin 很有用
    acess
        28
    acess  
    OP
       2021-04-22 04:23:24 +08:00
    (可以大幅节省字节数,N 个人一起混币,交易里只占一份数字签名的字节数,而不是 N 份),但 CISA 貌似也还是没有实现……
    yqrm
        29
    yqrm  
       2021-04-22 15:48:58 +08:00
    10 年老 BTCer 来挽尊😂
    zealic
        30
    zealic  
       2021-04-23 01:00:21 +08:00
    楼主对 BIP39/44/49/84 理解的很深入。

    Taproot 这里描述的很好,可以进一步理解其工作方式。

    从另一个角度上考虑,Schnorr 的所有人签名并且不暴露赎回脚本这个功能也是非常有用的,更多的可能性不会在于钱包方面,而且和其他链如以太、波卡进行跨链交互,甚至多链交互。
    这种跨链合约通过代码保证,所有人的全签名又可以保证不同的跨链智能合约进行合约嵌套组合(比如 AAVE 的闪电贷),可以实现非常复杂有趣的玩法,当然可能产生天量 GAS 费,因此这个设想还是需要 ETH 2.0 的支持。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2736 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 10:07 · PVG 18:07 · LAX 02:07 · JFK 05:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.