DCP: 0002 Title: SHA256 Opcode Author: Dave Collins <[email protected]> Status: Active Created: 2017-09-11 License: CC0-1.0 License-Code: ISC
This specifies a new opcode (SHA256) for the Decred script system that provides the ability to replace the top element of the data stack with its computed SHA-256 hash.
In order to support typical cross-chain operations such as atomic swaps, both chains involved often need to commit to the same secret in order to ensure that when one counterparty redeems a transaction they are required to reveal the secret, which in turn ensures the other counterparty can also redeem a separate transaction that requires the same secret. This implies that the hashing algorithm used by both chains must be identical so that both counterparties can prove that transactions involved require the same secret without actually having to reveal that secret until a later time. This behavior is also known as a hashlock and is a key component of Hash Time-Locked Contracts (HTLCs).
Hash Time-Locked Contracts extend the aforementioned hashlock behavior to provide an additional execution path with a timelock mechanism to ensure that funds can be redeemed by the initial funding party after a timeout is reached in the case the counterparty never reveals the secret.
An example HTLC script follows:
OP_IF OP_SHA256 <hash of secret> OP_EQUALVERIFY // Require disclosure of secret to redeem OP_DUP OP_HASH160 <counterparty2 public key hash> // Require signature from counterparty 2 OP_ELSE <locktime> OP_CHECKLOCKTIMEVERIFY OP_DROP // Prevent redemption until timeout OP_DUP OP_HASH160 <counterparty1 public key hash> // Require signature from counterparty 1 OP_ENDIF OP_EQUALVERIFY OP_CHECKSIG // Ensure signature is valid
The Lightning Network (LN) makes extensive use of HTLCs to setup atomic swaps
between payment channels which in turn is what provides the ability to transact
trustlessly through intermediate parties. While there is no need to support the
proposed SHA256
opcode for LN to function with normal
Decred-specific transactions, since all of the LN transactions can simply use
Blake-256 hashlocks for that purpose, it is useful to be able to interoperate
with other chains in order to perform "off-chain atomic swaps" which are
effectively a combination of the concepts of both cross-chain atomic swaps and
LN payment channels. In other words, the combination of techniques with
interoperable hashlocks provides the opportunity for creating instant,
trustless, decentralized cryptocurrency exchanges.
The new opcode SHA256
redefines the existing opcode
UNKNOWN192
, which has a value of 0xc0
(192
decimal).
When executed, the script execution must terminate with an error if the stack is empty.
Otherwise, the opcode must pop the top item from the stack as a byte array, compute its SHA-256, and push the resulting digest back to the stack as a byte array.
The following diagram illustrates an example partial Decred script that contains the new opcode and successful execution of it along with the associated stack transformations:
The SHA-256 algorithm was chosen because it is expected that it will become the dominant cross-chain hashing algorithm used for the purposes of providing interoperable hashes due to its ubiquitous nature and the fact it is the general hashing algorithm used for areas such as proof-of-work and deterministic key generation in many other prominent chains. It also provides 128 bits of security as compared to other common potential choices, such as HASH160 (the SHA-256 variant) which only provides 80 bits of security.
It is worth noting that the Decred script system currently already provides
opcodes which perform a similar function as the proposed opcode, such as
BLAKE256
, HASH160
, and HASH256
, however,
they involve computing either a Blake-256 hash or some combination of hashing
algorithms involving Blake-256 as opposed to computing a plain SHA-256 hash.
The design and semantics of the new proposed opcode were chosen to mirror the
existing BLAKE256
opcode.
This proposal will be deployed to mainnet using the standard Decred on-chain voting infrastructure as follows:
Name | Setting | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Deployment Version | 5 | ||||||||||||
Agenda ID | lnfeatures | ||||||||||||
Agenda Description | Enable features defined in DCP0002 and DCP0003 necessary to support Lightning Network (LN) | ||||||||||||
Start Time | 1505260800 (Sep 13th, 2017 00:00:00 +0000 UTC) | ||||||||||||
Expire Time | 1536796800 (Sep 13th, 2018 00:00:00 +0000 UTC) | ||||||||||||
Mask | 0x06 (Bits 1 and 2) | ||||||||||||
Choices |
|
This proposal was approved by the stakeholder voting process and is now active.
Implementations MAY optimize their enforcement activation logic to apply the new
rules specified by this proposal to the Active
block and all of its
descendants as opposed to tallying historical votes.
Status | Block Hash | Block Height |
---|---|---|
Voting Started | 0000000000000032798428af98f60111c12d0c4ffdedbce72b8143a0b4444a56 | 173440 |
Locked In | 000000000000006df125ef4afe8aaf87414cd40aff321f7a075a8c8aadb60b36 | 181504 |
Active | 000000000000006ffe775adf77b96f18c51fc6ca6f40d982abd4239be1922a0f | 189568 |
This is a hard-forking change to the Decred consensus. This means that once the agenda is voted in and becomes locked in, anybody running code that fully validates blocks must upgrade before the activation time or they will risk rejecting a chain containing a transaction which makes use of the new opcode.
Other software will need to upgrade their script system according to the specification herein.
// opcodeSha256 treats the top item of the data stack as raw bytes and replaces
// it with sha256(data).
//
// Stack transformation: [... x1] -> [... sha256(x1)]
func opcodeSha256(op *parsedOpcode, vm *Engine) error {
// Treat the opcode as OP_UNKNOWN192 if the flag to interpret it as the
// SHA256 opcode is not set.
if !vm.hasFlag(ScriptVerifySHA256) {
if vm.hasFlag(ScriptDiscourageUpgradableNops) {
return errors.New("OP_UNKNOWN192 reserved for upgrades")
}
return nil
}
buf, err := vm.dstack.PopByteArray()
if err != nil {
return err
}
hash := sha256.Sum256(buf)
vm.dstack.PushByteArray(hash[:])
return nil
}
A reference implementation of the required script engine changes is provided by pull request #851.
A reference implementation of the required agenda definition is implemented by pull request #848.
The following test vectors are provided in order to facilitate testing across implementations. These are the expected values for all networks.
Input Data | Expected Hash |
---|---|
"" (empty string) | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
"a" (0x61) | ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb |
"ab" (0x6162) | fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603 |
"abc" (0x616263) | ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad |
"abcd" (0x61626364) | 88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589 |
"abcde" (0x6162636465) | 36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c |
"abcdef" (0x616263646566) | bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721 |
"abcdefg" (0x61626364656667) | 7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a |
"abcdefgh" (0x6162636465666768) | 9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab |
"abcdefghi" (0x616263646566676869) | 19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f |
"abcdefghij" (0x6162636465666768696a) | 72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0 |
Raw Signature Script | Raw Public Key Script | Validity |
---|---|---|
00 | c020e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85587 | valid |
0161 | c020ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb87 | valid |
1a6162636465666768696a6b6c6d6e6f707172737475767778797a | c02071c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b7387 | valid |
00 | c0 | valid |
61 | c0 | invalid |
61 | c051 | invalid |
Same as above, but with human-readable scripts:
Human-readable Signature Script | Human-readable Public Key Script | Validity |
---|---|---|
0 | SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL | valid |
'a' | SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL | valid |
'abcdefghijklmnopqrstuvwxyz' | SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL | valid |
0 | SHA256 | valid |
NOP | SHA256 | invalid |
NOP | SHA256 TRUE | invalid |
Thanks to the following individuals who provided valuable feedback during the review process of this proposal (alphabetical order):
- Jake Yocom-Piatt
- Jonathan Zeppettini
- Josh Rickmar (@jrick)
- _miw (@MiWCryptoCurrency)
This document is licensed under the CC0-1.0: Creative Commons CC0 1.0 Universal license.
The code is licensed under the ISC License.