• sCrypt 中的 ECDSA 签名验证


    我们使用 sCrypt 语言实现了 ECDSA 签名验证算法。它可以验证任意消息是否由与给定公钥对应的私钥签名,而 OP_CHECKSIG 只能在消息是当前花费交易时验证签名¹。令人惊讶的是,这是并不需要引入任何新操作码。而在 BCH 上,需要引入额外的操作码 OP_DATASIGVERIFY(又名 OP_CHECKDATASIG))完成相同的功能的。

    在这里插入图片描述

    椭圆曲线数字签名算法 (ECDSA)

    ECDSA 是比特币中用于签名生成和验证的算法。下面列出了验证算法。

    在这里插入图片描述

    实现

    如下所示,我们已经实现了该算法,使用我们之前发布的椭圆曲线库。

    首先,我们需要从以 DER 格式编码的签名中提取 rs 分量。由于它们是大端编码,我们必须转换为 小端编码,这就是数据在 Script / sCrypt 中的编码方式。

    在这里插入图片描述

    在检索到 rs 后,我们只需运行标准的 ECDSA 验证算法。

    
    import "ec.scrypt";
    import "util.scrypt";
    
    struct RSPair {
        int r;
        int s;
    }
    
    // ECDSA signatures verification for secp256k1, for arbitrary message @msg
    contract ECDSA {
        public function verify(Sig sig, PubKey pubKey, bytes msg,
            int invS, Point P, int lambda, Point U1, PointMulAux u1Aux, Point U2, PointMulAux u2Aux) {
    
            // extract (r, s) from sig
            RSPair rs = parseDERSig(sig);
            int r = rs.r;
            int s = rs.s;
            // within range
            require(r >= 1 && r < EC.n);
            require(s >= 1 && s < EC.n);
    
            // verify invS
            require((s * invS) % EC.n == 1);
            
            int e = unpack(sha256(msg));
            int u1 = (e * invS) % EC.n;
            int u2 = (r * invS) % EC.n;
    
            // U1 = u1 * G
            require(EC.isMul(EC.G, u1, U1, u1Aux));
    
            Point Q = pubKey2Point(pubKey);
            // U2 = u2 * Q
            require(EC.isMul(Q, u2, U2, u2Aux));
    
            // P == U1 + U2
            require(EC.isSum(U1, U2, lambda, P));
            // cannot be identify
            require(P != EC.ZERO);
    
            require((P.x - r) % EC.n == 0);
        }
    
        // parse signature in DER format to get (r, s) pair
        static function parseDERSig(Sig sig) : RSPair {
            int rLen = unpack(sig[3 : 4]);
            int r = fromBESigned(sig[4 : 4 + rLen]);
    
            int sLen = unpack(sig[6 + rLen : 7 + rLen]);
            int s = fromBESigned(sig[7 + rLen : 7 + rLen + sLen]);
    
            return { r , s };
        }
    
        // r & s are signed big endian
        static function fromBESigned(bytes b) : int {
            // convert big-endian to little-endian: either 32 or 33 bytes
            bytes bLE = len(b) == 32 ? reverseBytes(b, 32) : reverseBytes(b, 33);
            return unpack(bLE);
        }
    
        // convert public key to a point, assuming it's uncompressed
        static function pubKey2Point(PubKey pubKey) : Point {
            require(pubKey[: 1] == b'04');
            return { unpack(pubKey[1 : 33]), unpack(pubKey[33 : 65]) };
        }
    }
    
    
    • 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
    ECDSA 合约

    [1] 更准确地说,它针对 sighash 验证签名。

  • 相关阅读:
    Java#29(集合进阶2---双列集合)
    HTML转义字符
    linux驱动开发:IO模型
    初学vue,想自己找个中长期小型项目练练手,应该做什么?
    FPGA+ARM异核架构,基于米尔MYC-JX8MMA7核心板的全自动血细胞分析仪
    苏州德创机器视觉工程师工作怎么样?
    Lua-http库写一个爬虫程序怎么样 ?
    基于SSM的教学管理系统设计与实现
    Python 如何把 String 转换为 Json 对象
    Spring的创建与使用
  • 原文地址:https://blog.csdn.net/freedomhero/article/details/125478566