mirror of
https://github.com/ZmnSCPxj/clboss.git
synced 2026-08-13 12:33:20 +02:00
128 lines
3 KiB
C++
128 lines
3 KiB
C++
#include"Bitcoin/Tx.hpp"
|
|
#include"Bitcoin/le.hpp"
|
|
#include"Bitcoin/sighash.hpp"
|
|
#include"Ln/Amount.hpp"
|
|
#include"Sha256/Hash.hpp"
|
|
#include"Sha256/HasherStream.hpp"
|
|
#include"Sha256/fun.hpp"
|
|
|
|
namespace {
|
|
|
|
void feed_hash(std::ostream& hasher, Sha256::Hash const& hash) {
|
|
std::uint8_t buf[32];
|
|
hash.to_buffer(buf);
|
|
for (auto i = std::size_t(0); i < sizeof(buf); ++i)
|
|
hasher.put(buf[i]);
|
|
}
|
|
|
|
using ::Bitcoin::SighashFlags;
|
|
using ::Bitcoin::SIGHASH_ALL;
|
|
using ::Bitcoin::SIGHASH_NONE;
|
|
using ::Bitcoin::SIGHASH_SINGLE;
|
|
using ::Bitcoin::SIGHASH_ANYONECANPAY;
|
|
using ::Bitcoin::InvalidSighash;
|
|
|
|
void
|
|
sighash_core( Bitcoin::Tx const& tx
|
|
, SighashFlags flags
|
|
, std::size_t nIn
|
|
, Ln::Amount amount
|
|
, std::vector<std::uint8_t> const& scriptCode
|
|
, std::ostream& hasher
|
|
) {
|
|
|
|
auto loflags = flags & 0x1F;
|
|
auto hiflags = flags & 0xE0;
|
|
|
|
switch (loflags) {
|
|
case SIGHASH_ALL:
|
|
case SIGHASH_NONE:
|
|
case SIGHASH_SINGLE:
|
|
break;
|
|
default:
|
|
throw InvalidSighash("Invalid SIGHASH flag");
|
|
}
|
|
switch (hiflags) {
|
|
case 0:
|
|
case SIGHASH_ANYONECANPAY:
|
|
break;
|
|
default:
|
|
throw InvalidSighash("Invalid SIGHASH flag");
|
|
}
|
|
|
|
if (nIn >= tx.inputs.size())
|
|
throw InvalidSighash("nIn out of range");
|
|
|
|
auto hashPrevouts = Sha256::Hash();
|
|
if (!(hiflags & SIGHASH_ANYONECANPAY)) {
|
|
Sha256::HasherStream hasher;
|
|
for (auto const& i : tx.inputs)
|
|
hasher << i.prevTxid
|
|
<< Bitcoin::le(i.prevOut)
|
|
;
|
|
hashPrevouts = Sha256::fun(std::move(hasher).finalize());
|
|
}
|
|
|
|
auto hashSequence = Sha256::Hash();
|
|
if ( !(hiflags & SIGHASH_ANYONECANPAY)
|
|
&& (loflags != SIGHASH_SINGLE)
|
|
&& (loflags != SIGHASH_NONE)
|
|
) {
|
|
Sha256::HasherStream hasher;
|
|
for (auto const& i : tx.inputs)
|
|
hasher << Bitcoin::le(i.nSequence);
|
|
hashSequence = Sha256::fun(std::move(hasher).finalize());
|
|
}
|
|
|
|
auto hashOutputs = Sha256::Hash();
|
|
if ( (loflags != SIGHASH_SINGLE)
|
|
&& (loflags != SIGHASH_NONE)
|
|
) {
|
|
Sha256::HasherStream hasher;
|
|
for (auto const& o : tx.outputs)
|
|
hasher << o;
|
|
hashOutputs = Sha256::fun(std::move(hasher).finalize());
|
|
} else if ((loflags == SIGHASH_SINGLE) && nIn < tx.outputs.size()) {
|
|
Sha256::HasherStream hasher;
|
|
hasher << tx.outputs[nIn];
|
|
hashOutputs = Sha256::fun(std::move(hasher).finalize());
|
|
}
|
|
|
|
/* Hashing sequence. */
|
|
hasher << Bitcoin::le(tx.nVersion);
|
|
feed_hash(hasher, hashPrevouts);
|
|
feed_hash(hasher, hashSequence);
|
|
|
|
/* Input being signed. */
|
|
hasher << tx.inputs[nIn].prevTxid
|
|
<< Bitcoin::le(tx.inputs[nIn].prevOut)
|
|
;
|
|
for (auto b : scriptCode)
|
|
hasher.put(b);
|
|
hasher << Bitcoin::le(amount)
|
|
<< Bitcoin::le(tx.inputs[nIn].nSequence)
|
|
;
|
|
|
|
feed_hash(hasher, hashOutputs);
|
|
hasher << Bitcoin::le(tx.nLockTime)
|
|
<< Bitcoin::le(std::uint32_t(flags))
|
|
;
|
|
}
|
|
|
|
}
|
|
|
|
namespace Bitcoin {
|
|
|
|
Sha256::Hash
|
|
sighash( Bitcoin::Tx const& tx
|
|
, SighashFlags flags
|
|
, std::size_t nIn
|
|
, Ln::Amount amount
|
|
, std::vector<std::uint8_t> const& scriptCode
|
|
) {
|
|
Sha256::HasherStream hasher;
|
|
sighash_core(tx, flags, nIn, amount, scriptCode, hasher);
|
|
return Sha256::fun(std::move(hasher).finalize());
|
|
}
|
|
|
|
}
|