在无需分叉的情况下模拟任何 SIGHASH 标志

我们开发了一种新颖的方法来模拟任何 SIGHASH 标志,只需在智能合约中编写逻辑即可。它不需要更改协议,因此比每次构思新用例时通过分叉添加硬编码标志更实用和灵活。

SIGHASH 标志

SIGHASH 标志决定交易的哪一部分由签名者签名。具体来说,它控制签名涵盖以下 10 项中的哪些项。

在这里插入图片描述

SigHash 原像格式

共有三个基本标志:SIGHASH_ALLSIGHASH_NONESIGHASH_SINGLE。还有一个修饰符标志 SIGHASH_ANYONECANPAY,产生六种组合。

在这里插入图片描述

不同 sighash 组合

已经有人提议添加更多标志,以自定义签署交易的各个部分,这在现有标志下是不可能的。下面列出了一个例子:

/** Signature hash types/flags */
enum
{
    
    
    // Input Specific
    SIGHASH_WITHOUT_PREV_SCRIPTPUBKEY     = 0x01,
    SIGHASH_WITHOUT_PREV_VALUE            = 0x02,
    SIGHASH_WITHOUT_INPUT_TXID            = 0x04,
    SIGHASH_WITHOUT_INPUT_INDEX           = 0x08,
    SIGHASH_WITHOUT_INPUT_SEQUENCE        = 0x10,

    // Output Specific
    SIGHASH_WITHOUT_OUTPUT_SCRIPTPUBKEY   = 0x20,
    SIGHASH_WITHOUT_OUTPUT_VALUE          = 0x40,

    // Whether to serialize the other (other than self) inputs/outputs
    SIGHASH_WITHOUT_INPUTS                = 0x010000,
    SIGHASH_WITHOUT_OUTPUTS               = 0x020000,

    // Whether to serialize this input/output at all (these take priority over SIGHASH_WITHOUT_INPUTS and SIGHASH_WITHOUT_OUTPUTS)
    SIGHASH_WITHOUT_INPUT_SELF            = 0x040000,
    SIGHASH_WITHOUT_OUTPUT_SELF           = 0x080000,

    // Transaction specific fields
    SIGHASH_WITHOUT_TX_VERSION            = 0x100000,
    SIGHASH_WITHOUT_TX_LOCKTIME           = 0x200000,

    // Sign value not derived from transaction
    // (Whenever nHashType is negative, the script signature is for the value on the stack, e.g. stacktop(-3))
    SIGHASH_SIGN_STACK_ELEMENT            = 0x10000000,
};
提议的标识

然而,它们中的每一个都必须在节点软件中进行硬编码,因此需要一个潜在的有争议的分支。

模拟任何 SIGHASH 标志

我们提供了一个框架来模拟任意 SIGHASH 标志。新的 SIGHASH 标志可以简单地以智能合约的形式添加,因此根本不需要升级 BSV。总的来说,它分为三个步骤:

  1. 使用 OP_PUSH_TX 获取当前的 sighash
  2. 根据新的标志语义修改/屏蔽 sighash
  3. 使用 ECDSA 签名算法根据新的 sighash 检查签名。

例如,我们实现了 SIGHASH_ANYPREVOUT

SIGHASH_ANYPREVOUT

BIP-118 中的 SIGHASH_ANYPREVOUT(以前称为 SIGHASH_NOINPUT)从签名中排除了 UTXO 的标识符。
用它签名的交易不链接到特定的 UTXO,因此可以花费任何 UTXO,只要满足有正确的签名或其它满足其它花费条件。

这可以用于,例如,当用户想要授权第三方应用程序花费她的硬币时。她可以使用 SIGHASH_ANYPREVOUT 进行预签名,并且应用程序可以在她不在时一次又一次地重复使用签名。

以下合约检查输入签名(即 Sig sig)是否未涵盖正在花费的 UTXO,等同于使用 SIGHASH_ANYPREVOUT 进行签名。

import "ec.scrypt";

// a template to implement any new SIGHASH flags
contract UniversalSigHash {
    
    
    PubKey pubKey;

    // sig is with SIGHASH flag SIGHASH_NOINPUT
    public function checkSigHashNoInput(Sig sig, SigHashPreimage sighash) {
    
    
        // get sighash preimage using SIGHASH_ALL
        require(Tx.checkPreimage(sighash));

        /* reconstruct the new sighash being signed */
        bytes sighash1 = sighash[: 4];
        // set item 2, 3, and 4 to 0
        bytes blankedSighash2to3 = b'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
        bytes sighash5to10 = sighash[104 : ];
        bytes sighashNew = sighash1 + blankedSighash2to3 + sighash5to10;

        // check signature against the new sighash using elliptic curve library
        require(EC.verifySig(sighashNew, sig, this.pubKey));
    }
}
UniversalSighash 合约
  1. 第 1 步:第 10 行确保 sighash 用于使用 OP_PUSH_TX 的当前交易。
  2. 第 2 步:第 13-17 行将 sighash 的第 234 项设置为全 0,即清空输入 UTXO。
  3. 第 3 步:第 20 行使用椭圆曲线库确保签名完全覆盖新的 sighash。相当于BTC上的 OP_CHECKSIGFROMSTACK 或 BCH上的 OP_DATASIGVERIFY/OP_CHECKDATASIG

可扩展性

可以扩展相同的方法来模拟任何标志。例如,空白项目 2 和 3 等于 SIGHASH_ANYONECANPAY,空白项目 6 本质上是 SIGHASH_WITHOUT_PREV_VALUE。BSV 智能合约的表现力支持任意标记。

猜你喜欢

转载自blog.csdn.net/freedomhero/article/details/128282576