OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY Specification
OP_CHECKDATASIG
OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY check whether a signature is valid with respect to a message and a public key.
OP_CHECKDATASIG permits data to be imported into a script, and have its validity checked against some signing authority such as an "Oracle".
OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY are designed to be implemented similarly to OP_CHECKSIG [1]. Conceptually, one could imagine OP_CHECKSIG functionality being replaced by OP_CHECKDATASIG, along with a separate Op Code to create a hash from the transaction based on the SigHash algorithm.
OP_CHECKDATASIG Specification
Semantics
OP_CHECKDATASIG fails immediately if the stack is not well formed. To be well formed, the stack must contain at least three elements [<sig>
, <msg>
, <pubKey>
] in this order where <pubKey>
is the top element and
<pubKey>
must be a validly encoded public key<msg>
can be any string<sig>
must follow the strict DER encoding as described in [2] and the S-value of<sig>
must be at most the curve order divided by 2 as described in [3]
If the stack is well formed, then OP_CHECKDATASIG pops the top three elements [<sig>
, <msg>
, <pubKey>
] from the stack and pushes true onto the stack if <sig>
is valid with respect to the raw single-SHA256 hash of <msg>
and <pubKey>
using the secp256k1 elliptic curve. Otherwise, it pops three elements and pushes false onto the stack in the case that <sig>
is the empty string and fails in all other cases.
Nullfail is enforced the same as for OP_CHECKSIG [3]. If the signature does not match the supplied public key and message hash, and the signature is not an empty byte array, the entire script fails.
Opcode Number
OP_CHECKDATASIG uses the previously unused opcode number 186 (0xba in hex encoding)
SigOps
Signature operations accounting for OP_CHECKDATASIG shall be calculated the same as OP_CHECKSIG. This means that each OP_CHECKDATASIG shall be counted as one (1) SigOp.
Activation
Use of OP_CHECKDATASIG, unless occuring in an unexecuted OP_IF branch, will make the transaction invalid if it is included in a block where the median timestamp of the prior 11 blocks is less than 1542300000.
Unit Tests
<sig> <msg> <pubKey> OP_CHECKDATASIG
fails if 15 November 2018 protocol upgrade is not yet activated.<sig> <msg> OP_CHECKDATASIG
fails if there are fewer than 3 items on stack.<sig> <msg> <pubKey> OP_CHECKDATASIG
fails if<pubKey>
is not a validly encoded public key.<sig> <msg> <pubKey> OP_CHECKDATASIG
fails if<sig>
is not a validly encoded signature with strict DER encoding.<sig> <msg> <pubKey> OP_CHECKDATASIG
fails if signature<sig>
is not empty and does not pass the Low S check.<sig> <msg> <pubKey> OP_CHECKDATASIG
fails if signature<sig>
is not empty and does not pass signature validation of<msg>
and<pubKey>
.<sig> <msg> <pubKey> OP_CHECKDATASIG
pops three elements and pushes false onto the stack if<sig>
is an empty byte array.<sig> <msg> <pubKey> OP_CHECKDATASIG
pops three elements and pushes true onto the stack if<sig>
is a valid signature of<msg>
with respect to<pubKey>
.
OP_CHECKDATASIGVERIFY Specification
Semantics
OP_CHECKDATASIGVERIFY is equivalent to OP_CHECKDATASIG followed by OP_VERIFY. It leaves nothing on the stack, and will cause the script to fail immediately if the signature check does not pass.
Opcode Number
OP_CHECKDATASIGVERIFY uses the previously unused opcode number 187 (0xbb in hex encoding)
SigOps
Signature operations accounting for OP_CHECKDATASIGVERIFY shall be calculated the same as OP_CHECKSIGVERIFY. This means that each OP_CHECKDATASIGVERIFY shall be counted as one (1) SigOp.
Activation
Use of OP_CHECKDATASIGVERIFY, unless occuring in an unexecuted OP_IF branch, will make the transaction invalid if it is included in a block where the median timestamp of the prior 11 blocks is less than 1542300000.
Unit Tests
<sig> <msg> <pubKey> OP_CHECKDATASIGVERIFY
fails if 15 November 2018 protocol upgrade is not yet activated.<sig> <msg> OP_CHECKDATASIGVERIFY
fails if there are fewer than 3 item on stack.<sig> <msg> <pubKey> OP_CHECKDATASIGVERIFY
fails if<pubKey>
is not a validly encoded public key.<sig> <msg> <pubKey> OP_CHECKDATASIGVERIFY
fails if<sig>
is not a validly encoded signature with strict DER encoding.<sig> <msg> <pubKey> OP_CHECKDATASIGVERIFY
fails if signature<sig>
is not empty and does not pass the Low S check.<sig> <msg> <pubKey> OP_CHECKDATASIGVERIFY
fails if<sig>
is not a valid signature of<msg>
with respect to<pubKey>
.<sig> <msg> <pubKey> OP_CHECKDATASIGVERIFY
pops the top three stack elements if<sig>
is a valid signature of<msg>
with respect to<pubKey>
.
Sample Implementation [4, 5]
case OP_CHECKDATASIG:
case OP_CHECKDATASIGVERIFY: {
// Make sure this remains an error before activation.
if ((flags & SCRIPT_ENABLE_CHECKDATASIG) == 0) {
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
// (sig message pubkey -- bool)
if (stack.size() < 3) {
return set_error(
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
}
valtype &vchSig = stacktop(-3);
valtype &vchMessage = stacktop(-2);
valtype &vchPubKey = stacktop(-1);
if (!CheckDataSignatureEncoding(vchSig, flags,
serror) ||
!CheckPubKeyEncoding(vchPubKey, flags, serror)) {
// serror is set
return false;
}
bool fSuccess = false;
if (vchSig.size()) {
valtype vchHash(32);
CSHA256()
.Write(vchMessage.data(), vchMessage.size())
.Finalize(vchHash.data());
uint256 message(vchHash);
CPubKey pubkey(vchPubKey);
fSuccess = pubkey.Verify(message, vchSig);
}
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) &&
vchSig.size()) {
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
}
popstack(stack);
popstack(stack);
popstack(stack);
stack.push_back(fSuccess ? vchTrue : vchFalse);
if (opcode == OP_CHECKDATASIGVERIFY) {
if (fSuccess) {
popstack(stack);
} else {
return set_error(serror,
SCRIPT_ERR_CHECKDATASIGVERIFY);
}
}
} break;
Sample Usage
The following example shows a spend and redeem script for a basic use of CHECKDATASIG. This example validates the signature of some data, provides a placeholder where you would then process that data, and finally allows one of 2 signatures to spend based on the outcome of the data processing.
spend script:
push txsignature
push txpubkey
push msg
push sig
redeem script:
(txsig, txpubkey msg, sig)
OP_OVER (txsig, txpubkey, msg, sig, msg)
push data pubkey (txsig, txpubkey, msg, sig, msg, pubkey)
OP_CHECKDATASIGVERIFY (txsig, txpubkey, msg)
Now that msg is on the stack top, the script can write predicates on it, resulting in the message being consumed and a true/false condition left on the stack: (txpubkey, txsig, boolean)
OP_IF (txsig, txpubkey)
OP_DUP (txsig, txpubkey, txpubkey)
OP_HASH160 (txsig, txpubkey, address)
push <p2pkh spend address> (txsig, txpubkey, address, p2pkh spend address)
OP_EQUALVERIFY (txsig, txpubkey)
OP_CHECKSIG
OP_ELSE
(same as if clause but a different <p2pkh spend address>)
OP_ENDIF
History
This specification is based on Andrew Stone’s OP_DATASIGVERIFY proposal [6, 7]. It is modified from Stone's original proposal based on a synthesis of all the peer-review and feedback received [8].
References
[1] OP_CHECKSIG
[3] Low-S and Nullfail Specification
[4] Bitcoin ABC implementation
[5] Bitcoin ABC implementation update
[6] Andrew Stone’s OP_DATASIGVERIFY