Return-Path: <jlrubin@mit.edu>
Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])
 by lists.linuxfoundation.org (Postfix) with ESMTP id AB13AC000E
 for <bitcoin-dev@lists.linuxfoundation.org>;
 Sat,  3 Jul 2021 18:31:02 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
 by smtp1.osuosl.org (Postfix) with ESMTP id A005F83DAC
 for <bitcoin-dev@lists.linuxfoundation.org>;
 Sat,  3 Jul 2021 18:31:02 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
X-Spam-Flag: NO
X-Spam-Score: -4.199
X-Spam-Level: 
X-Spam-Status: No, score=-4.199 tagged_above=-999 required=5
 tests=[BAYES_00=-1.9, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_MED=-2.3,
 SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Received: from smtp1.osuosl.org ([127.0.0.1])
 by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
 with ESMTP id lPoH9xxOPkJO
 for <bitcoin-dev@lists.linuxfoundation.org>;
 Sat,  3 Jul 2021 18:31:00 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from outgoing.mit.edu (outgoing-auth-1.mit.edu [18.9.28.11])
 by smtp1.osuosl.org (Postfix) with ESMTPS id 5ACCB83DA2
 for <bitcoin-dev@lists.linuxfoundation.org>;
 Sat,  3 Jul 2021 18:31:00 +0000 (UTC)
Received: from mail-il1-f171.google.com (mail-il1-f171.google.com
 [209.85.166.171]) (authenticated bits=0)
 (User authenticated as jlrubin@ATHENA.MIT.EDU)
 by outgoing.mit.edu (8.14.7/8.12.4) with ESMTP id 163IUwPA020133
 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=NOT)
 for <bitcoin-dev@lists.linuxfoundation.org>; Sat, 3 Jul 2021 14:30:58 -0400
Received: by mail-il1-f171.google.com with SMTP id z1so13218450ils.0
 for <bitcoin-dev@lists.linuxfoundation.org>;
 Sat, 03 Jul 2021 11:30:58 -0700 (PDT)
X-Gm-Message-State: AOAM5321FUQreYnM7zAxzkJ/vP/ZmC04KDyYCfOj3KkW8W2fmwA0EHUM
 WsqW1l7o8QrhKXsUq1UBG8APsoPNE1hU6Zd2ZqM=
X-Google-Smtp-Source: ABdhPJyEuztlkc/a5KebV5ukNFkephX3asdRGenawAyNZfvCWkTslE1Ve3TNEbUehFz0lg/FyhWdzG1rzJ4jZLTZa/A=
X-Received: by 2002:a92:6f0a:: with SMTP id k10mr4211114ilc.105.1625337057853; 
 Sat, 03 Jul 2021 11:30:57 -0700 (PDT)
MIME-Version: 1.0
References: <CAD5xwhjmu-Eee47Ho5eA6E6+aAdnchLU0OVZo=RTHaXnN17x8A@mail.gmail.com>
 <CAMZUoK=-jrH+fr=tUTHmLojm2-Ff99KYm9H97yhd=7bcOVG=fg@mail.gmail.com>
In-Reply-To: <CAMZUoK=-jrH+fr=tUTHmLojm2-Ff99KYm9H97yhd=7bcOVG=fg@mail.gmail.com>
From: Jeremy <jlrubin@mit.edu>
Date: Sat, 3 Jul 2021 11:30:45 -0700
X-Gmail-Original-Message-ID: <CAD5xwhg0N1byx-G2tk=jjmZSHSBirpaX6OHTnh_x9iDEVF8PrQ@mail.gmail.com>
Message-ID: <CAD5xwhg0N1byx-G2tk=jjmZSHSBirpaX6OHTnh_x9iDEVF8PrQ@mail.gmail.com>
To: "Russell O'Connor" <roconnor@blockstream.com>
Content-Type: multipart/alternative; boundary="000000000000f945a705c63c4597"
Cc: Bitcoin Protocol Discussion <bitcoin-dev@lists.linuxfoundation.org>
Subject: Re: [bitcoin-dev] CHECKSIGFROMSTACK/{Verify} BIP for Bitcoin
X-BeenThere: bitcoin-dev@lists.linuxfoundation.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: Bitcoin Protocol Discussion <bitcoin-dev.lists.linuxfoundation.org>
List-Unsubscribe: <https://lists.linuxfoundation.org/mailman/options/bitcoin-dev>, 
 <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=unsubscribe>
List-Archive: <http://lists.linuxfoundation.org/pipermail/bitcoin-dev/>
List-Post: <mailto:bitcoin-dev@lists.linuxfoundation.org>
List-Help: <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=help>
List-Subscribe: <https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev>, 
 <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=subscribe>
X-List-Received-Date: Sat, 03 Jul 2021 18:31:02 -0000

--000000000000f945a705c63c4597
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Awesome to hear that!

Actually I don't think I did know (or I forgot/didn't catch it) that there
was an updated spec for elements, I searched around for what I could find
and came up empty handed. Do you have any links for that? That sounds
perfect to me.


On Sat, Jul 3, 2021, 10:50 AM Russell O'Connor <roconnor@blockstream.com>
wrote:

> Hi Jermy,
>
> As you are aware, we, and by we I mean mostly Sanket, are developing an
> updated OP_CHECKSIGFROMSTACK implementation for tapscript on elements.  T=
he
> plan here would be to effectively support the an interface to the
> variable-length extension of BIP-0340 schnorr signatures.
>
> BIP-0340 would dispense with DER encoding (good riddance).
> BIP-0340 signatures are batch verifiable along with other BIP-0340
> transaction signatures and taproot tweak verification.
> Support for variable length messages in BIP-0340 has been discussed in <
> https://github.com/sipa/bips/issues/207> and an implementation has
> recently been merged in <
> https://github.com/bitcoin-core/secp256k1/pull/844>.  The BIP has not yet
> been updated but the difference is that the message m does not have to be
> 32-bytes (it is recommended that the message be a 32-bit tagged hash or a
> message with a 64-bit application specific prefix). The CHECKSIGFROMSTACK
> operation (in tapscript) would use a stack item for this m value to
> BIP-0340 signature verification and would not necessarily have to be 32
> bytes.
>
> I think this design we are aiming for would be perfectly suited for
> Bitcoin as well.
>
> On Sat, Jul 3, 2021 at 12:32 PM Jeremy via bitcoin-dev <
> bitcoin-dev@lists.linuxfoundation.org> wrote:
>
>> Reproduced below is the BIP text from Bitcoin Cash's (MIT-Licensed)
>> specification for "CheckDataSig", more or less the same thing as
>> CHECKSIGFROMSTACK
>> https://github.com/bitcoincashorg/bitcoincash.org/blob/master/spec/op_ch=
eckdatasig.md.
>> In contrast to Element's implementation, it does not have Element's bugs
>> around verify semantics and uses the nullfail rule, and there is a
>> specification document so it seemed like the easiest starting point for
>> discussion v.s. drafting something from scratch.
>>
>> Does anyone have any issue with adapting this exact text and
>> implementation to a BIP for Bitcoin using 2 OP_SUCCESSX opcodes?
>>
>> Note that with *just* CheckSigFromStack, while you can do some very
>> valuable use cases, but without OP_CAT it does not enable sophisticated
>> covenants (and as per
>> https://www.wpsoftware.net/andrew/blog/cat-and-schnorr-tricks-i.html
>> just CAT alone enables such uses).
>>
>> Design questions worth considering as modifications:
>>
>> 1. Should CSFS require some sort of tagged hash? Very likely answer is n=
o
>> =E2=80=93 tags interfere with certain use cases
>> 2. Should CSFS split the signature=E2=80=99s R & S value stack items for=
 some
>> applications that otherwise may require OP_CAT? E.g. using a pinned R va=
lue
>> allows you to extract a private key if ever double signed, using 2 R val=
ues
>> allows pay-to-reveal-key contracts. Most likely answer is no, if that is
>> desired then OP_CAT can be introduced
>> 3. Should CSFS support a cheap way to reference the taproot internal or
>> external key? Perhaps, can be handled with undefined upgradeable keytype=
s.
>> One might want to use the internal key, if the signed data should be val=
id
>> independent of the tapscript tree. One might want to use the external ke=
y,
>> if the data should only be valid for a single tapscript key + tree.
>> 4. Should invalid public keys types be a NOP to support future extended
>> pubkey types?
>>
>>
>>
>> Best,
>>
>>
>> Jeremy
>>
>>
>> ---
>> layout: specification
>> title: OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY Specification
>> category: spec
>> date: 2018-08-20
>> activation: 1542300000
>> version: 0.6
>> ---
>>
>> OP_CHECKDATASIG
>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>>
>> OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY check whether a signature is v=
alid 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 C=
ode 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>`, `<ms=
g>`, `<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 desc=
ribed in [3]
>>
>> If the stack is well formed, then OP_CHECKDATASIG pops the top three ele=
ments [`<sig>`, `<msg>`, `<pubKey>`] from the stack and pushes true onto th=
e stack if `<sig>` is valid with respect to the raw single-SHA256 hash of `=
<msg>` and `<pubKey>` using the secp256k1 elliptic curve. Otherwise, it pop=
s three elements and pushes false onto the stack in the case that `<sig>` i=
s the empty string and fails in all other cases.
>>
>> Nullfail is enforced the same as for OP_CHECKSIG [3]. If the signature d=
oes not match the supplied public key and message hash, and the signature i=
s not an empty byte array, the entire script fails.
>>
>> ### Opcode Number
>>
>> OP_CHECKDATASIG uses the previously unused opcode number 186 (0xba in he=
x encoding)
>>
>> ### SigOps
>>
>> Signature operations accounting for OP_CHECKDATASIG shall be calculated =
the same as OP_CHECKSIG. This means that each OP_CHECKDATASIG shall be coun=
ted as one (1) SigOp.
>>
>> ### Activation
>>
>> Use of OP_CHECKDATASIG, unless occuring in an unexecuted OP_IF branch, w=
ill make the transaction invalid if it is included in a block where the med=
ian timestamp of the prior 11 blocks is less than 1542300000.
>>
>> ### Unit Tests
>>
>>  - `<sig> <msg> <pubKey> OP_CHECKDATASIG` fails if 15 November 2018 prot=
ocol upgrade is not yet activated.
>>  - `<sig> <msg> OP_CHECKDATASIG` fails if there are fewer than 3 items o=
n stack.
>>  - `<sig> <msg> <pubKey> OP_CHECKDATASIG` fails if `<pubKey>` is not a v=
alidly encoded public key.
>>  - `<sig> <msg> <pubKey> OP_CHECKDATASIG` fails if `<sig>` is not a vali=
dly 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 respec=
t to `<pubKey>`.
>>
>> OP_CHECKDATASIGVERIFY Specification
>> -----------------------------------
>>
>> ### Semantics
>>
>> OP_CHECKDATASIGVERIFY is equivalent to OP_CHECKDATASIG followed by OP_VE=
RIFY. It leaves nothing on the stack, and will cause the script to fail imm=
ediately 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 calcu=
lated the same as OP_CHECKSIGVERIFY. This means that each OP_CHECKDATASIGVE=
RIFY shall be counted as one (1) SigOp.
>>
>> ### Activation
>>
>> Use of OP_CHECKDATASIGVERIFY, unless occuring in an unexecuted OP_IF bra=
nch, will make the transaction invalid if it is included in a block where t=
he median timestamp of the prior 11 blocks is less than 1542300000.
>>
>> ### Unit Tests
>>
>>  - `<sig> <msg> <pubKey> OP_CHECKDATASIGVERIFY` fails if 15 November 201=
8 protocol upgrade is not yet activated.
>>  - `<sig> <msg> OP_CHECKDATASIGVERIFY` fails if there are fewer than 3 i=
tem on stack.
>>  - `<sig> <msg> <pubKey> OP_CHECKDATASIGVERIFY`fails if `<pubKey>` is no=
t 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 `<pubK=
ey>`.
>>
>> Sample Implementation [4, 5]
>> ----------------------------
>>
>> ```c++
>>                     case OP_CHECKDATASIG:
>>                     case OP_CHECKDATASIGVERIFY: {
>>                         // Make sure this remains an error before activa=
tion.
>>                         if ((flags & SCRIPT_ENABLE_CHECKDATASIG) =3D=3D =
0) {
>>                             return set_error(serror, SCRIPT_ERR_BAD_OPCO=
DE);
>>                         }
>>
>>                         // (sig message pubkey -- bool)
>>                         if (stack.size() < 3) {
>>                             return set_error(
>>                                 serror, SCRIPT_ERR_INVALID_STACK_OPERATI=
ON);
>>                         }
>>
>>                         valtype &vchSig =3D stacktop(-3);
>>                         valtype &vchMessage =3D stacktop(-2);
>>                         valtype &vchPubKey =3D stacktop(-1);
>>
>>                         if (!CheckDataSignatureEncoding(vchSig, flags,
>>                                                         serror) ||
>>                             !CheckPubKeyEncoding(vchPubKey, flags, serro=
r)) {
>>                             // serror is set
>>                             return false;
>>                         }
>>
>>                         bool fSuccess =3D false;
>>                         if (vchSig.size()) {
>>                             valtype vchHash(32);
>>                             CSHA256()
>>                                 .Write(vchMessage.data(), vchMessage.siz=
e())
>>                                 .Finalize(vchHash.data());
>>                             uint256 message(vchHash);
>>                             CPubKey pubkey(vchPubKey);
>>                             fSuccess =3D pubkey.Verify(message, vchSig);
>>                         }
>>
>>                         if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL=
) &&
>>                             vchSig.size()) {
>>                             return set_error(serror, SCRIPT_ERR_SIG_NULL=
FAIL);
>>                         }
>>
>>                         popstack(stack);
>>                         popstack(stack);
>>                         popstack(stack);
>>                         stack.push_back(fSuccess ? vchTrue : vchFalse);
>>                         if (opcode =3D=3D OP_CHECKDATASIGVERIFY) {
>>                             if (fSuccess) {
>>                                 popstack(stack);
>>                             } else {
>>                                 return set_error(serror,
>>                                                  SCRIPT_ERR_CHECKDATASIG=
VERIFY);
>>                             }
>>                         }
>>                     } 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 o=
ne 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 a=
ddress)
>>   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=E2=80=99s OP_DATASIGVERIFY p=
roposal [6, 7]. It is modified from Stone's original proposal based on a sy=
nthesis of all the peer-review and feedback received [8].
>>
>> References
>> ----------
>>
>> [1] [OP_CHECKSIG](https://en.bitcoin.it/wiki/OP_CHECKSIG)
>>
>> [2] [Strict DER Encoding](https://github.com/bitcoin/bips/blob/master/bi=
p-0066.mediawiki)
>>
>> [3] [Low-S and Nullfail Specification](https://github.com/bitcoin/bips/b=
lob/master/bip-0146.mediawiki)
>>
>> [4] [Bitcoin ABC implementation](https://reviews.bitcoinabc.org/D1621)
>>
>> [5] [Bitcoin ABC implementation update](https://reviews.bitcoinabc.org/D=
1646)
>>
>> [6] [Andrew Stone=E2=80=99s OP_DATASIGVERIFY](https://github.com/Bitcoin=
Unlimited/BitcoinUnlimited/blob/bucash1.3.0.0/doc/opdatasigverify.md)
>>
>> [7] [Andrew Stone's article on Scripting](https://medium.com/@g.andrew.s=
tone/bitcoin-scripting-applications-decision-based-spending-8e7b93d7bdb9)
>>
>> [8] [Peer Review of Andrew Stone's Proposal](https://github.com/bitcoinc=
ashorg/bitcoincash.org/pull/10)
>>
>>
>> --
>> @JeremyRubin <https://twitter.com/JeremyRubin>
>> <https://twitter.com/JeremyRubin>
>> _______________________________________________
>> bitcoin-dev mailing list
>> bitcoin-dev@lists.linuxfoundation.org
>> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>>
>

--000000000000f945a705c63c4597
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto"><div>Awesome to hear that!<div dir=3D"auto"><br></div><di=
v dir=3D"auto">Actually I don&#39;t think I did know (or I forgot/didn&#39;=
t catch it) that there was an updated spec for elements, I searched around =
for what I could find and came up empty handed. Do you have any links for t=
hat? That sounds perfect=C2=A0to me.</div><br><br><div class=3D"gmail_quote=
"><div dir=3D"ltr" class=3D"gmail_attr">On Sat, Jul 3, 2021, 10:50 AM Russe=
ll O&#39;Connor &lt;<a href=3D"mailto:roconnor@blockstream.com">roconnor@bl=
ockstream.com</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div d=
ir=3D"ltr"><div>Hi Jermy,</div><div><br></div><div>As you are aware, we, an=
d by we I mean mostly Sanket, are developing an updated OP_CHECKSIGFROMSTAC=
K implementation for tapscript on elements.=C2=A0 The plan here would be to=
 effectively support the an interface to the variable-length extension of B=
IP-0340 schnorr signatures.</div><div><br></div><div>BIP-0340 would dispens=
e with DER encoding (good riddance).</div><div>BIP-0340 signatures are batc=
h verifiable along with other BIP-0340 transaction signatures and taproot t=
weak verification.</div><div>Support for variable length messages in BIP-03=
40 has been discussed in &lt;<a href=3D"https://github.com/sipa/bips/issues=
/207" target=3D"_blank" rel=3D"noreferrer">https://github.com/sipa/bips/iss=
ues/207</a>&gt; and an implementation has recently been merged in &lt;<a hr=
ef=3D"https://github.com/bitcoin-core/secp256k1/pull/844" target=3D"_blank"=
 rel=3D"noreferrer">https://github.com/bitcoin-core/secp256k1/pull/844</a>&=
gt;.=C2=A0 The BIP has not yet been updated but the difference is that the =
message m does not have to be 32-bytes (it is recommended that the message =
be a 32-bit tagged hash or a message with a 64-bit application specific pre=
fix). The CHECKSIGFROMSTACK operation (in tapscript) would use a stack item=
 for this m value to BIP-0340 signature verification and would not necessar=
ily have to be 32 bytes.<br></div><div><br></div><div>I think this design w=
e are aiming for would be perfectly suited for Bitcoin as well.<br></div></=
div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On=
 Sat, Jul 3, 2021 at 12:32 PM Jeremy via bitcoin-dev &lt;<a href=3D"mailto:=
bitcoin-dev@lists.linuxfoundation.org" target=3D"_blank" rel=3D"noreferrer"=
>bitcoin-dev@lists.linuxfoundation.org</a>&gt; wrote:<br></div><blockquote =
class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px sol=
id rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_=
default">Reproduced below is the BIP text from Bitcoin Cash&#39;s (MIT-Lice=
nsed) specification for &quot;CheckDataSig&quot;, more or less the same thi=
ng as CHECKSIGFROMSTACK <a href=3D"https://github.com/bitcoincashorg/bitcoi=
ncash.org/blob/master/spec/op_checkdatasig.md" target=3D"_blank" rel=3D"nor=
eferrer">https://github.com/bitcoincashorg/bitcoincash.org/blob/master/spec=
/op_checkdatasig.md</a>. In contrast to Element&#39;s implementation, it do=
es not have Element&#39;s bugs around verify semantics and uses the nullfai=
l rule, and there is a specification document so it seemed like the easiest=
 starting point for discussion v.s. drafting something from scratch.</div><=
div class=3D"gmail_default"><br>Does anyone have any issue with adapting th=
is exact text and implementation to a BIP for Bitcoin using 2 OP_SUCCESSX o=
pcodes?</div><div class=3D"gmail_default"><br></div><div class=3D"gmail_def=
ault">Note that with *just* CheckSigFromStack, while you can do some very v=
aluable use cases, but without OP_CAT it does not enable sophisticated cove=
nants (and as per=C2=A0<a href=3D"https://www.wpsoftware.net/andrew/blog/ca=
t-and-schnorr-tricks-i.html" target=3D"_blank" rel=3D"noreferrer">https://w=
ww.wpsoftware.net/andrew/blog/cat-and-schnorr-tricks-i.html</a> just CAT al=
one enables such uses).<br><br>Design questions worth considering as modifi=
cations:</div><div class=3D"gmail_default"><br>1. Should CSFS require some =
sort of tagged hash? Very likely answer is no =E2=80=93 tags interfere with=
 certain use cases<br>2. Should CSFS split the signature=E2=80=99s R &amp; =
S value stack items for some applications that otherwise may require OP_CAT=
? E.g. using a pinned R value allows you to extract a private key if ever d=
ouble signed, using 2 R values allows pay-to-reveal-key contracts. Most lik=
ely answer is no, if that is desired then OP_CAT can be introduced<br>3. Sh=
ould CSFS support a cheap way to reference the taproot internal or external=
 key? Perhaps, can be handled with undefined upgradeable keytypes. One migh=
t want to use the internal key, if the signed data should be valid independ=
ent of the tapscript tree. One might want to use the external key, if the d=
ata should only be valid for a single tapscript key + tree.<br>4. Should in=
valid public keys types be a NOP to support future extended pubkey types?</=
div><div class=3D"gmail_default"><br></div><div class=3D"gmail_default"><br=
><br></div><div class=3D"gmail_default">Best,<br><br><br>Jeremy<pre style=
=3D"color:rgb(0,0,0);font-family:arial,helvetica,sans-serif;font-size:small=
;white-space:pre-wrap"><br></pre><pre style=3D"color:rgb(0,0,0);font-family=
:arial,helvetica,sans-serif;font-size:small;white-space:pre-wrap">---
layout: specification
title: OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY Specification
category: spec
date: 2018-08-20
activation: 1542300000
version: 0.6
---

OP_CHECKDATASIG
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY check whether a signature is vali=
d with respect to a message and a public key.

OP_CHECKDATASIG permits data to be imported into a script, and have its val=
idity checked against some signing authority such as an &quot;Oracle&quot;.

OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY are designed to be implemented si=
milarly to OP_CHECKSIG [1]. Conceptually, one could imagine OP_CHECKSIG fun=
ctionality 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 we=
ll formed, the stack must contain at least three elements [`&lt;sig&gt;`, `=
&lt;msg&gt;`, `&lt;pubKey&gt;`] in this order where `&lt;pubKey&gt;` is the=
 top element and
  * `&lt;pubKey&gt;` must be a validly encoded public key
  * `&lt;msg&gt;` can be any string
  * `&lt;sig&gt;` must follow the strict DER encoding as described in [2] a=
nd the S-value of `&lt;sig&gt;` 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 elemen=
ts [`&lt;sig&gt;`, `&lt;msg&gt;`, `&lt;pubKey&gt;`] from the stack and push=
es true onto the stack if `&lt;sig&gt;` is valid with respect to the raw si=
ngle-SHA256 hash of `&lt;msg&gt;` and `&lt;pubKey&gt;` using the secp256k1 =
elliptic curve. Otherwise, it pops three elements and pushes false onto the=
 stack in the case that `&lt;sig&gt;` 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 n=
ot an empty byte array, the entire script fails.

### Opcode Number

OP_CHECKDATASIG uses the previously unused opcode number 186 (0xba in hex e=
ncoding)

### 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

 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIG` fails if 15 Nov=
ember 2018 protocol upgrade is not yet activated.
 - `&lt;sig&gt; &lt;msg&gt; OP_CHECKDATASIG` fails if there are fewer than =
3 items on stack.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIG` fails if `&lt;p=
ubKey&gt;` is not a validly encoded public key.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIG` fails if `&lt;s=
ig&gt;` is not a validly encoded signature with strict DER encoding.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIG` fails if signat=
ure `&lt;sig&gt;` is not empty and does not pass the Low S check.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIG` fails if signat=
ure `&lt;sig&gt;` is not empty and does not pass signature validation of `&=
lt;msg&gt;` and `&lt;pubKey&gt;`.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIG` pops three elem=
ents and pushes false onto the stack if `&lt;sig&gt;` is an empty byte arra=
y.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIG` pops three elem=
ents and pushes true onto the stack if `&lt;sig&gt;` is a valid signature o=
f `&lt;msg&gt;` with respect to `&lt;pubKey&gt;`.

OP_CHECKDATASIGVERIFY Specification
-----------------------------------

### Semantics

OP_CHECKDATASIGVERIFY is equivalent to OP_CHECKDATASIG followed by OP_VERIF=
Y. It leaves nothing on the stack, and will cause the script to fail immedi=
ately 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 calculat=
ed the same as OP_CHECKSIGVERIFY. This means that each OP_CHECKDATASIGVERIF=
Y 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

 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIGVERIFY` fails if =
15 November 2018 protocol upgrade is not yet activated.
 - `&lt;sig&gt; &lt;msg&gt; OP_CHECKDATASIGVERIFY` fails if there are fewer=
 than 3 item on stack.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIGVERIFY`fails if `=
&lt;pubKey&gt;` is not a validly encoded public key.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIGVERIFY` fails if =
`&lt;sig&gt;` is not a validly encoded signature with strict DER encoding.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIGVERIFY` fails if =
signature `&lt;sig&gt;` is not empty and does not pass the Low S check.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIGVERIFY` fails if =
`&lt;sig&gt;` is not a valid signature of `&lt;msg&gt;` with respect to `&l=
t;pubKey&gt;`.
 - `&lt;sig&gt; &lt;msg&gt; &lt;pubKey&gt; OP_CHECKDATASIGVERIFY` pops the =
top three stack elements if `&lt;sig&gt;` is a valid signature of `&lt;msg&=
gt;` with respect to `&lt;pubKey&gt;`.

Sample Implementation [4, 5]
----------------------------

```c++
                    case OP_CHECKDATASIG:
                    case OP_CHECKDATASIGVERIFY: {
                        // Make sure this remains an error before activatio=
n.
                        if ((flags &amp; SCRIPT_ENABLE_CHECKDATASIG) =3D=3D=
 0) {
                            return set_error(serror, SCRIPT_ERR_BAD_OPCODE)=
;
                        }

                        // (sig message pubkey -- bool)
                        if (stack.size() &lt; 3) {
                            return set_error(
                                serror, SCRIPT_ERR_INVALID_STACK_OPERATION)=
;
                        }

                        valtype &amp;vchSig =3D stacktop(-3);
                        valtype &amp;vchMessage =3D stacktop(-2);
                        valtype &amp;vchPubKey =3D stacktop(-1);

                        if (!CheckDataSignatureEncoding(vchSig, flags,
                                                        serror) ||
                            !CheckPubKeyEncoding(vchPubKey, flags, serror))=
 {
                            // serror is set
                            return false;
                        }

                        bool fSuccess =3D false;
                        if (vchSig.size()) {
                            valtype vchHash(32);
                            CSHA256()
                                .Write(vchMessage.data(), vchMessage.size()=
)
                                .Finalize(vchHash.data());
                            uint256 message(vchHash);
                            CPubKey pubkey(vchPubKey);
                            fSuccess =3D pubkey.Verify(message, vchSig);
                        }

                        if (!fSuccess &amp;&amp; (flags &amp; SCRIPT_VERIFY=
_NULLFAIL) &amp;&amp;
                            vchSig.size()) {
                            return set_error(serror, SCRIPT_ERR_SIG_NULLFAI=
L);
                        }

                        popstack(stack);
                        popstack(stack);
                        popstack(stack);
                        stack.push_back(fSuccess ? vchTrue : vchFalse);
                        if (opcode =3D=3D OP_CHECKDATASIGVERIFY) {
                            if (fSuccess) {
                                popstack(stack);
                            } else {
                                return set_error(serror,
                                                 SCRIPT_ERR_CHECKDATASIGVER=
IFY);
                            }
                        }
                    } break;
```

Sample Usage
------------

The following example shows a spend and redeem script for a basic use of CH=
ECKDATASIG.  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 &lt;p2pkh spend address&gt;    (txsig, txpubkey, address, p2pkh spen=
d address)
  OP_EQUALVERIFY                (txsig, txpubkey)
  OP_CHECKSIG
OP_ELSE
  (same as if clause but a different &lt;p2pkh spend address&gt;)
OP_ENDIF
```

History
-------

This specification is based on Andrew Stone=E2=80=99s OP_DATASIGVERIFY prop=
osal [6, 7]. It is modified from Stone&#39;s original proposal based on a s=
ynthesis of all the peer-review and feedback received [8].

References
----------

[1] [OP_CHECKSIG](<a href=3D"https://en.bitcoin.it/wiki/OP_CHECKSIG" target=
=3D"_blank" rel=3D"noreferrer">https://en.bitcoin.it/wiki/OP_CHECKSIG</a>)

[2] [Strict DER Encoding](<a href=3D"https://github.com/bitcoin/bips/blob/m=
aster/bip-0066.mediawiki" target=3D"_blank" rel=3D"noreferrer">https://gith=
ub.com/bitcoin/bips/blob/master/bip-0066.mediawiki</a>)

[3] [Low-S and Nullfail Specification](<a href=3D"https://github.com/bitcoi=
n/bips/blob/master/bip-0146.mediawiki" target=3D"_blank" rel=3D"noreferrer"=
>https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki</a>)

[4] [Bitcoin ABC implementation](<a href=3D"https://reviews.bitcoinabc.org/=
D1621" target=3D"_blank" rel=3D"noreferrer">https://reviews.bitcoinabc.org/=
D1621</a>)

[5] [Bitcoin ABC implementation update](<a href=3D"https://reviews.bitcoina=
bc.org/D1646" target=3D"_blank" rel=3D"noreferrer">https://reviews.bitcoina=
bc.org/D1646</a>)

[6] [Andrew Stone=E2=80=99s OP_DATASIGVERIFY](<a href=3D"https://github.com=
/BitcoinUnlimited/BitcoinUnlimited/blob/bucash1.3.0.0/doc/opdatasigverify.m=
d" target=3D"_blank" rel=3D"noreferrer">https://github.com/BitcoinUnlimited=
/BitcoinUnlimited/blob/bucash1.3.0.0/doc/opdatasigverify.md</a>)

[7] [Andrew Stone&#39;s article on Scripting](<a href=3D"https://medium.com=
/@g.andrew.stone/bitcoin-scripting-applications-decision-based-spending-8e7=
b93d7bdb9" target=3D"_blank" rel=3D"noreferrer">https://medium.com/@g.andre=
w.stone/bitcoin-scripting-applications-decision-based-spending-8e7b93d7bdb9=
</a>)

[8] [Peer Review of Andrew Stone&#39;s Proposal](<a href=3D"https://github.=
com/bitcoincashorg/bitcoincash.org/pull/10" target=3D"_blank" rel=3D"norefe=
rrer">https://github.com/bitcoincashorg/bitcoincash.org/pull/10</a>)</pre><=
/div><br clear=3D"all"><div><div dir=3D"ltr"><div dir=3D"ltr">--<br><a href=
=3D"https://twitter.com/JeremyRubin" target=3D"_blank" rel=3D"noreferrer">@=
JeremyRubin</a><a href=3D"https://twitter.com/JeremyRubin" target=3D"_blank=
" rel=3D"noreferrer"></a></div></div></div></div>
_______________________________________________<br>
bitcoin-dev mailing list<br>
<a href=3D"mailto:bitcoin-dev@lists.linuxfoundation.org" target=3D"_blank" =
rel=3D"noreferrer">bitcoin-dev@lists.linuxfoundation.org</a><br>
<a href=3D"https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev" =
rel=3D"noreferrer noreferrer" target=3D"_blank">https://lists.linuxfoundati=
on.org/mailman/listinfo/bitcoin-dev</a><br>
</blockquote></div>
</blockquote></div></div></div>

--000000000000f945a705c63c4597--