• BSV 上的私钥谜题


    我们引入了一种称为私钥谜题的新型 BSV 智能合约,它只能通过提供给定公钥的对应私钥来解锁。

    在以前的合约中,只需要以数字签名的形式证明拥有私钥。私钥保密,不会暴露。私钥谜题合约则相反,私钥是被公开的。

    对 ECDSA 的 Nonce 重用攻击

    为了生成签名,ECDSA 需要一个私钥 d、一个随机数 k(称为 nonce)和消息的散列 hr 是点 k * Gx 坐标,其中 G 是生成器。

    在这里插入图片描述

    (r, s) 就是签名。

    当使用相同的私钥和相同随机数 k 的对不同消息进行签名时,就会出现问题。我们将有两个签名 (r, s1) 和 (r, s2)。 r 相同,因为 k 相同。
    在这里插入图片描述

    在这里插入图片描述

    我们可以通过以下方式恢复随机数:

    在这里插入图片描述

    我们还可以通过以下方式恢复私钥:

    在这里插入图片描述

    索尼 PlayStation 3 因为暴露了此漏洞被黑客入侵。因此,为不同的签名选择不同的 k 至关重要。

    私钥谜题

    我们将利用漏洞来间接曝光私钥。我们有意要求对使用相同私钥和随机数签名的两条不同消息的两个有效签名,如下所示。

    contract PrivateKeyPuzzle {
        PubKey pubKey;
    
        // extract r from DER-encoded signature
        static function extractRFromSig(Sig sig) : bytes {
            int rlen = unpack(sig[3 : 4]);
            return sig[4 : 4 + rlen];
        }
    
        public function unlock(Sig sig1, Sig sig2) {
            require(checkSig(sig1, this.pubKey));
            // ensure signed messages are different option (1): insert CODESEPERATOR in between two checkSigs
            ***
            require(checkSig(sig2, this.pubKey));
    
            // sign with same r, thus same ephemeral key k
            require(extractRFromSig(sig1) == extractRFromSig(sig2));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    PrivateKeyPuzzle 合约

    我们在第 11 行和第 14 行验证两个签名使用了相同的公钥和私钥。 第 5 行的函数 extraRFromSig() 允许我们从签名中提取 r,DER 编码如下。

    在这里插入图片描述

    17 行确保 r 相同,因此在两个签名中相同的 k 使用。

    签名的消息称为 sighash 原像。请注意,我们在第 13 行插入了一个 OP_CODESEPARATOR 以确保两个签名的消息是不同的,因为它们具有不同的 scriptCode(sighash 原像的第 5 部分)。

    还有其他方法可以确保签名消息不同。例如,我们可以在签名时使用不同的 sighash 标志(sighash 原像的第 10 部分)。

    
    // extract SIGHASH flag from DER-encoded signature
    static function extractSighashFlagFromSig(Sig sig) : SigHashType {
        int len = len(sig);
        return SigHashType(sig[len - 2 : ]);
    }
    
    public function unlock(Sig sig1, Sig sig2) {
        require(checkSig(sig1, this.pubKey));
        require(checkSig(sig2, this.pubKey));
    
        // ensure signed messages are different option (2): use different sighash flags
        require(extractSighashFlagFromSig(sig1) == (SigHash.NONE | SigHash.FORKID));
        require(extractSighashFlagFromSig(sig2) != (SigHash.NONE | SigHash.FORKID));
    
        // sign with same r, thus same ephemeral key k
        require(extractRFromSig(sig1) == extractRFromSig(sig2));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    PrivateKeyPuzzle 合约

    sig1 使用 NONE ,将交易输出的从签名的消息中排除,而 sig2 包含了交易输出,因此不同。

    替代实现

    还有其他方法可以强制公开私钥:

    私钥谜题比它们更紧凑和高效。

    致谢

    本文改编自论文比特币私钥锁定交易的想法。

  • 相关阅读:
    C语言中static关键字用法
    ASO优化之关于Google Play中的搜索引擎优化
    平面设计实验六 色彩调整与风景美化
    谈谈用户态 TCP 协议实现
    VS2019 编译Postgrsql 的windows平台代码和调试
    网上PHP+Redis分布式锁的实现都有问题
    Android 使用Kotlin封装RecyclerView
    Swift创建单例
    AI问诊逐渐取代医生是不是伪命题?实测国内外医疗专用大模型
    【相关概念】经济金融中的Momentum
  • 原文地址:https://blog.csdn.net/freedomhero/article/details/126306991