p2sh(pay to script hash)

マルチシグ、複数署名の解法
複数の秘密鍵から単一の集約署名であるシェノア署名が一般的になると思われる

### ベアマルチシグ
オプコードのOP_CHECKMULTISIG (0xae)を理解する必要がある。
OP_CHECKMULTISIGは、スタックから多数の要素をポップし、必要な数の署名がトランザクションインプットに対して有効か否かを返す
トランザクションアウトプットは長いScriptPubKeyのまま

ベアマルチシグのScriptPubKey
51 OP_1
41 Length of pubkey
04fc..3d pubkey1
21 Length of pubkey2
0202..00 pubkey2
52 OP_2
ae OP_CHECKMULTISIG

ベアマルチシグのScriptSig
00 OP_0
48 Length of signature1
3045…01 signature1

pubkeyやsignatureの数が多くなればなるほどバイト数が多くなる
pubkey, signatureのm, nは1~20の数値を指定できる

### SCRIPTの例
OP_0, signature1, signature2, …, signature m, OP_m, pubkey1, … pubkey n, OP_n, OP_CHECKMULTISIG
OP_CHECKMULTISIGは、m + n + 3個の要素をポップし、n個の公開鍵のリストのうち、m個の署名が有効である場合は1をスタックにプッシュ、有効でない場合は0
OP_CHECKMULTISIGは m + n + 2この要素をプップするはずが、m + n + 3でポップしているため、OP_0が追加されている。

def op_checkmultisig(stack, z):
    if len(stack) < 1:
        return False
    n = decode_num(stack.pop())
    if len(stack) < n + 1:
        return False
    sec_pubkeys = []
    for _ in range(n):
        sec_pubkeys.append(stack.pop())
    m = decode_num(stack.pop())
    if len(stack) < m + 1:
        return False
    der_signatures = []
    for _ in range(m):
        der_signatures.append(stack.pop()[:-1])
    stack.pop()
    try:
        points = [S256Point.parse(sec) for sec in sec_pubkeys]
        sigs = [Signature.parse(der) for der in der_signatures]
        for sig in sigs:
            if len(points) == 0:
                LOGGER.info("signatures no good or not in right order")
                return False
            success = False
            while points:
                point = points.pop(0)
                if point.verify(z, sig):
                    success = True
                    break
                if not success:
                    return False
        stack.append(encode_num(1))
    except (ValueError, SyntaxError):
        return False
    return True

### ベアマルチシグの問題
m of nの署名を要求して単一障害を回避するが、問題がある
– ScriptPubKeyが長くなる
– outputsが通常のp2pkhアウトプットの5~20倍になる
これらの問題を軽減するためにPay to script hash(p2sh)が誕生している
L Scriptコマンドのハッシュを取得し、後でハッシュ化する前のScriptコマンドを明らかにする

### 特別なルールを実行するPay-to-script-hash
RedeemScript, OH_HASH160, hash, OP_EQUAL
スタックが1で終わる場合、RedeemScriptがパースされ、Scriptコマンドセットに追加 BIP160で導入された
2-of-2マルチシグのScriptPubKeyがあるとする これをp2shに変換する作業をスクリプトのハッシュを取得してスクリプトを引き換えたいときに利用しやすいように保持する
52 OP_2
21 Length of pubkey1
02…db70 pubkey1
21 Length of pubkey2
03…bb71 pubkey2
52 OP_2
ae OP_CHECKMULTISIG

Pay to script hash(p2sh)のScriptPubKey
a9 OP_HASH160
14 Length of Hash
74d6…56 hash
87 OP_EQUAL

これまでのScriptPubKeyに相当するもののhash160 アンロック時に明らかにしなければならないRedeemScriptのハッシュに資金をロックする
RedeemScriptは公開だけでなくアンロックにも必要で、ブロックチェーン上にはないため、p2shアドレスの作成者が保管しておかなければならない

2-of-2マルチシグのScriptSig
00 OP_0
48 Length of signature1
3045…3701 signature1
48 Length of signature2
3045…2201 signature
47 Length of RedeemScript
5221…ae RedeemScript

### 連結のScript
ScriptPubKey: OP_HASH160, hash, OP_EQUAL
ScriptSig: OP_0, signature1, signature2, RedeemScript
Script: OP_0, signature1, signature2, RedeemScript, OP_HASH160, hash, OP_EQUAL

特別なルールを実行するp2shのパターン: RedeemScript, OP_HASH160, hash, OP_EQUAL
RedeemScriptはScriptコマンドにセット
h160した結果がScriptPubKeyにあるh160の値と等しくなるRedeemScriptを明らかにすると、RedeemScriptはScriptPubKeyの代わりとして機能する
資金をロックするスクリプトをハッシュして、スクリプト自体の代わりにブロックチェーンに入れる

OP_0, signature1, signature2, RedeemScript, OP_HASH160, hash, OP_EQUAL
OP_HASH160でRedeemScriptをhashにするので、
OP_0, signature1, signature2, hash, OP_EQUALとなる。
hashが等しい場合は結果は有効とみなされる

52 OP_2
21 Length of pubkey1
02…db70 pubkey1
21 Length of pubkey2
03…bb71 pubkey2
52 OP_2
ae OP_CHECKMULTISIG