Remove dependencies by switching to simplified API with a callback interface (#157)

* created zcash_script_verify_prehashed; compiles

* removed unneded code; callback API

* revert formatting changes to interpreter.cpp/.h

* remove prehashed code

* moving code around

* use #if 0 instead of commenting out to make diff clearer

* tmp

* remove debug prints

* cleanups

* deleted unneeded rust files

* remove unneeded dependencies

* remove more unneeded files

* add new tests and remove old ones

* remove unneded params; add sighashLen to callback

* remove unneeded code

* msvc fixes
This commit is contained in:
Conrado Gouvea 2024-06-04 18:52:11 -03:00 committed by GitHub
parent ef2a7fdd5d
commit 4924030059
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 237 additions and 3015 deletions

1590
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -16,29 +16,40 @@ include = [
"build.rs",
"src/*.rs",
"/depend/check_uint128_t.c",
"/depend/zcash/src/script/zcash_script.h",
"/depend/zcash/src/script/zcash_script.cpp",
"/depend/zcash/src/utilstrencodings.cpp",
"/depend/zcash/src/uint256.cpp",
"/depend/zcash/src/pubkey.cpp",
"/depend/zcash/src/hash.cpp",
"/depend/zcash/src/primitives/transaction.cpp",
"/depend/zcash/src/amount.cpp",
"/depend/zcash/src/amount.h",
"/depend/zcash/src/compat/byteswap.h",
"/depend/zcash/src/compat/endian.h",
"/depend/zcash/src/consensus/consensus.h",
"/depend/zcash/src/crypto/common.h",
"/depend/zcash/src/crypto/ripemd160.cpp",
"/depend/zcash/src/crypto/ripemd160.h",
"/depend/zcash/src/crypto/sha1.cpp",
"/depend/zcash/src/crypto/sha1.h",
"/depend/zcash/src/crypto/sha256.cpp",
"/depend/zcash/src/crypto/sha512.cpp",
"/depend/zcash/src/crypto/hmac_sha512.cpp",
"/depend/zcash/src/crypto/sha256.h",
"/depend/zcash/src/hash.h",
"/depend/zcash/src/key_constants.h",
"/depend/zcash/src/prevector.h",
"/depend/zcash/src/primitives/transaction.h",
"/depend/zcash/src/pubkey.cpp",
"/depend/zcash/src/pubkey.h",
"/depend/zcash/src/script/interpreter.cpp",
"/depend/zcash/src/script/script.cpp",
"/depend/zcash/src/script/interpreter.h",
"/depend/zcash/src/script/script_error.cpp",
"/depend/zcash/src/",
"/depend/zcash/src/rust/include/",
"/depend/zcash/src/secp256k1/include/",
"/depend/zcash/src/script/script_error.h",
"/depend/zcash/src/script/script.cpp",
"/depend/zcash/src/script/script.h",
"/depend/zcash/src/script/zcash_script.cpp",
"/depend/zcash/src/script/zcash_script.h",
"/depend/zcash/src/secp256k1/",
"/depend/zcash/src/support/cleanse.cpp",
"/depend/zcash/src/support/cleanse.h",
"/depend/zcash/src/rust/gen/",
"/depend/expected/include/",
"/depend/zcash/src/serialize.h",
"/depend/zcash/src/tinyformat.h",
"/depend/zcash/src/uint256.cpp",
"/depend/zcash/src/uint256.h",
"/depend/zcash/src/util/strencodings.cpp",
"/depend/zcash/src/util/strencodings.h",
"/depend/zcash/src/version.h",
]
[lib]
@ -49,35 +60,6 @@ path = "src/lib.rs"
external-secp = []
[dependencies]
# All these dependencies must match the versions in:
# https://github.com/zcash/zcash/blob/<git subtree version>/Cargo.toml
bellman = "0.14"
blake2b_simd = "1"
blake2s_simd = "1"
bls12_381 = "0.8"
byteorder = "1"
crossbeam-channel = "0.5"
cxx = { version = "=1.0.113", features = ["c++17"] }
group = "0.13"
incrementalmerkletree = "0.5"
jubjub = "0.10"
libc = "0.2"
memuse = "0.2"
metrics = "0.21"
orchard = "0.7"
rand_core = "0.6"
rayon = "1.5"
redjubjub = "0.7"
sapling = { package = "sapling-crypto", version = "0.1", features = ["temporary-zcashd"] }
subtle = "2.2"
tracing = "0.1"
zcash_address = "0.3"
zcash_encoding = "0.2"
zcash_note_encryption = "0.4"
zcash_primitives = { version = "=0.14.0", features = ["temporary-zcashd", "transparent-inputs"] }
zcash_proofs = { version = "=0.14.0", features = ["directories"] }
bridgetree = "0.4"
rand = "0.8"
[build-dependencies]
# The `bindgen` dependency should automatically upgrade to match the version used by zebra-state's `rocksdb` dependency in:
@ -90,9 +72,6 @@ bindgen = ">= 0.64.0"
# so they are configured to automatically upgrade to match Zebra.
# But we try to use the latest versions here, to catch any bugs in `zcash_script`'s CI.
cc = { version = "1.0.94", features = ["parallel"] }
# Treat minor versions with a zero major version as compatible (cargo doesn't by default).
cxx-gen = ">= 0.7.107"
syn = { version = "1.0.109", features = ["full", "printing"] }
[dev-dependencies]
# These dependencies are shared with a lot of other Zebra dependencies.
@ -101,8 +80,6 @@ syn = { version = "1.0.109", features = ["full", "printing"] }
# Treat minor versions with a zero major version as compatible (cargo doesn't by default).
hex = ">= 0.4.3"
lazy_static = "1.4.0"
incrementalmerkletree = { version = "0.5", features = ["test-dependencies"] }
zcash_primitives = { version = "=0.14.0", features = ["temporary-zcashd", "transparent-inputs", "test-dependencies"] }
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"

145
build.rs
View File

@ -1,8 +1,6 @@
//! Build script for zcash_script.
use std::{env, fmt, fs, io::Read, path::PathBuf};
use syn::__private::ToTokens;
use std::{env, fmt, path::PathBuf};
type Result<T, E = Error> = std::result::Result<T, E>;
@ -47,125 +45,8 @@ fn bindgen_headers() -> Result<()> {
Ok(())
}
/// Use cxx_gen to generate headers and source files for FFI bindings,
/// just like zcash does (see depend/zcash/src/Makefile.am).
/// (Note that zcash uses the cxxbridge-cmd binary, while we use the
/// cxx_gen library, but the result is the same.)
///
/// We could use [`cxx_build`](https://cxx.rs/tutorial.html#compiling-the-c-code-with-cargo)
/// to do this automatically. But zcash uses the
/// [manual approach](https://cxx.rs/tutorial.html#c-generated-code) which
/// creates the headers with non-standard names and paths (e.g. "blake2b.h",
/// instead of "blake2b.rs.h" which what cxx_build would create). This would
/// requires us to rename/link files which is awkward.
///
/// Note that we must generate the files in the target dir (OUT_DIR) and not in
/// any source folder, because `cargo package` does not allow that.
/// (This is in contrast to zcash which generates in `depend/zcash/src/rust/gen/`)
fn gen_cxxbridge() -> Result<()> {
let out_path = env::var("OUT_DIR").map_err(Error::Env)?;
let out_path = PathBuf::from(out_path).join("gen");
let src_out_path = PathBuf::from(&out_path).join("src");
let header_out_path = PathBuf::from(&out_path).join("include").join("rust");
// These must match `CXXBRIDGE_RS` in depend/zcash/src/Makefile.am
let filenames = [
"blake2b",
"ed25519",
"equihash",
"streams",
"bridge",
"sapling/zip32",
];
// The output folder must exist
fs::create_dir_all(&src_out_path).unwrap();
fs::create_dir_all(&header_out_path).unwrap();
// Generate the generic header file
fs::write(header_out_path.join("cxx.h"), cxx_gen::HEADER).unwrap();
// Generate the source and header for each bridge file
for filename in filenames {
println!(
"cargo:rerun-if-changed=depend/zcash/src/rust/src/{}.rs",
filename
);
let mut file =
fs::File::open(format!("depend/zcash/src/rust/src/{}.rs", filename).as_str()).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
let ast = syn::parse_file(&content).unwrap();
let token_stream = ast.to_token_stream();
let mut opt = cxx_gen::Opt::default();
opt.include.push(cxx_gen::Include {
path: "rust/cxx.h".to_string(),
kind: cxx_gen::IncludeKind::Quoted,
});
let output = cxx_gen::generate_header_and_cc(token_stream, &opt).unwrap_or_else(|err| {
panic!(
"invalid bridge file {filename}: {err}. Try updating `filenames` to match zcashd"
)
});
let header_path = header_out_path.join(format!("{}.h", filename));
// Create output dir if does not exist (since `filename` can have a subdir)
fs::create_dir_all(header_path.parent().unwrap()).unwrap();
fs::write(header_path, output.header).unwrap();
let src_path = src_out_path.join(format!("{}.cpp", filename));
// Create output dir if does not exist (since `filename` can have a subdir)
fs::create_dir_all(src_path.parent().unwrap()).unwrap();
fs::write(src_path, output.implementation).unwrap();
}
Ok(())
}
fn main() -> Result<()> {
bindgen_headers()?;
gen_cxxbridge()?;
let rust_path = env::var("OUT_DIR").map_err(Error::Env)?;
let rust_path = PathBuf::from(rust_path).join("rust");
// We want to compile `depend/zcash/src/rust/src/sapling.rs`, which we used
// to do in `src/sapling.rs` by just including it. However, now that it has
// submodules, that approach doesn't work because for some reason Rust
// searches for the submodules in `depend/zcash/src/rust/src/` instead of
// `depend/zcash/src/rust/src/sapling/` where they are located. This can
// be solved if `depend/zcash/src/rust/src/sapling.rs` is renamed to
// `depend/zcash/src/rust/src/sapling/mod.rs`. But we can't do that directly
// because we can't change the source tree inside `build.rs`. Therefore we
// copy the required files to OUT_DIR, with a renamed sapling.rs, and include
// the copied file instead (see src/sapling.rs).
// See also https://stackoverflow.com/questions/77310390/how-to-include-a-source-file-that-has-modules
fs::create_dir_all(rust_path.join("sapling")).unwrap();
for filename in &["sapling.rs", "sapling/spec.rs", "sapling/zip32.rs"] {
println!(
"cargo:rerun-if-changed=depend/zcash/src/rust/src/{}.rs",
filename
);
}
fs::copy(
"depend/zcash/src/rust/src/sapling.rs",
rust_path.join("sapling/mod.rs"),
)
.unwrap();
fs::copy(
"depend/zcash/src/rust/src/sapling/spec.rs",
rust_path.join("sapling/spec.rs"),
)
.unwrap();
fs::copy(
"depend/zcash/src/rust/src/sapling/zip32.rs",
rust_path.join("sapling/zip32.rs"),
)
.unwrap();
let gen_path = env::var("OUT_DIR").map_err(Error::Env)?;
let gen_path = PathBuf::from(gen_path).join("gen");
let target = env::var("TARGET").expect("TARGET was not set");
let mut base_config = cc::Build::new();
@ -177,7 +58,6 @@ fn main() -> Result<()> {
.include("depend/zcash/src/rust/include/")
.include("depend/zcash/src/secp256k1/include/")
.include("depend/expected/include/")
.include(&gen_path.join("include"))
.flag_if_supported("-Wno-implicit-fallthrough")
.flag_if_supported("-Wno-catch-value")
.flag_if_supported("-Wno-reorder")
@ -201,30 +81,17 @@ fn main() -> Result<()> {
}
base_config
.file("depend/zcash/src/script/zcash_script.cpp")
.file("depend/zcash/src/util/strencodings.cpp")
.file("depend/zcash/src/amount.cpp")
.file("depend/zcash/src/uint256.cpp")
.file("depend/zcash/src/pubkey.cpp")
.file("depend/zcash/src/hash.cpp")
.file("depend/zcash/src/streams_rust.cpp")
.file("depend/zcash/src/zip317.cpp")
.file("depend/zcash/src/primitives/transaction.cpp")
.file("depend/zcash/src/crypto/ripemd160.cpp")
.file("depend/zcash/src/crypto/sha1.cpp")
.file("depend/zcash/src/crypto/sha256.cpp")
.file("depend/zcash/src/crypto/sha512.cpp")
.file("depend/zcash/src/crypto/hmac_sha512.cpp")
.file("depend/zcash/src/pubkey.cpp")
.file("depend/zcash/src/script/interpreter.cpp")
.file("depend/zcash/src/script/script.cpp")
.file("depend/zcash/src/script/script_error.cpp")
.file("depend/zcash/src/support/cleanse.cpp")
.file("depend/zcash/src/zcash/cache.cpp")
// A subset of the files generated by gen_cxxbridge
// which are required by zcash_script.
.file(gen_path.join("src/blake2b.cpp"))
.file(gen_path.join("src/bridge.cpp"))
.file(gen_path.join("src/streams.cpp"))
.file("depend/zcash/src/script/script.cpp")
.file("depend/zcash/src/script/zcash_script.cpp")
.file("depend/zcash/src/uint256.cpp")
.file("depend/zcash/src/util/strencodings.cpp")
.compile("libzcash_script.a");
Ok(())

View File

@ -16,10 +16,6 @@
#include <vector>
#include <rust/blake2b.h>
#include <rust/constants.h>
#include <rust/cxx.h>
typedef uint256 ChainCode;
/** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */
@ -157,50 +153,6 @@ public:
};
/** A writer stream (for serialization) that computes a 256-bit BLAKE2b hash. */
class CBLAKE2bWriter
{
private:
rust::Box<blake2b::State> state;
public:
int nType;
int nVersion;
CBLAKE2bWriter(int nTypeIn, int nVersionIn, const unsigned char* personal) :
nType(nTypeIn),
nVersion(nVersionIn),
state(blake2b::init(32, {personal, blake2b::PERSONALBYTES})) {}
int GetType() const { return nType; }
int GetVersion() const { return nVersion; }
void write_u8(const unsigned char* pch, size_t size)
{
state->update({pch, size});
}
CBLAKE2bWriter& write(const char *pch, size_t size) {
state->update({(const unsigned char*)pch, size});
return (*this);
}
// invalidates the object
uint256 GetHash() {
uint256 result;
state->finalize({result.begin(), result.size()});
return result;
}
template<typename T>
CBLAKE2bWriter& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj);
return (*this);
}
};
/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)

View File

@ -41,6 +41,8 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS
return secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pubkey);
}
#if 0
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
return false;
@ -138,6 +140,7 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
out.nChild = _nChild;
return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode);
}
#endif
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
secp256k1_ecdsa_signature sig;
@ -149,6 +152,7 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_static, NULL, &sig));
}
#if 0
/* static */ std::optional<CChainablePubKey> CChainablePubKey::FromParts(ChainCode chaincode, CPubKey pubkey) {
if (pubkey.IsCompressed()) {
return CChainablePubKey(chaincode, pubkey);
@ -156,3 +160,5 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
return std::nullopt;
}
}
#endif

View File

@ -173,8 +173,10 @@ public:
return size() > 0;
}
#if 0
//! fully validate whether this is a valid public key (more expensive than IsValid())
bool IsFullyValid() const;
#endif
//! Check whether this is a compressed public key.
bool IsCompressed() const
@ -193,6 +195,7 @@ public:
*/
static bool CheckLowS(const std::vector<unsigned char>& vchSig);
#if 0
//! Recover a public key from a compact signature.
bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);
@ -201,8 +204,10 @@ public:
//! Derive BIP32 child pubkey.
bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
#endif
};
#if 0
class CChainablePubKey {
private:
ChainCode chaincode;
@ -303,5 +308,6 @@ struct CExtPubKey {
Decode(code);
}
};
#endif
#endif // BITCOIN_PUBKEY_H

View File

@ -6,8 +6,6 @@
#include "interpreter.h"
#include "consensus/upgrades.h"
#include "primitives/transaction.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
@ -15,10 +13,6 @@
#include "script/script.h"
#include "uint256.h"
#include <librustzcash.h>
#include <rust/constants.h>
#include <rust/transaction.h>
using namespace std;
typedef vector<unsigned char> valtype;
@ -962,428 +956,15 @@ bool EvalScript(
return set_success(serror);
}
namespace {
/**
* Wrapper that serializes like CTransaction, but with the modifications
* required for the signature hash done in-place
*/
class CTransactionSignatureSerializer {
private:
const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized)
const CScript& scriptCode; //!< output script being consumed
const unsigned int nIn; //!< input index of txTo being signed
const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set
const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE
const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE
public:
CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {}
/** Serialize the passed scriptCode */
template<typename S>
void SerializeScriptCode(S &s) const {
auto size = scriptCode.size();
::WriteCompactSize(s, size);
s.write((char*)&scriptCode.begin()[0], size);
}
/** Serialize an input of txTo */
template<typename S>
void SerializeInput(S &s, unsigned int nInput) const {
// In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized
if (fAnyoneCanPay)
nInput = nIn;
// Serialize the prevout
::Serialize(s, txTo.vin[nInput].prevout);
// Serialize the script
assert(nInput != NOT_AN_INPUT);
if (nInput != nIn)
// Blank out other inputs' signatures
::Serialize(s, CScriptBase());
else
SerializeScriptCode(s);
// Serialize the nSequence
if (nInput != nIn && (fHashSingle || fHashNone))
// let the others update at will
::Serialize(s, (int)0);
else
::Serialize(s, txTo.vin[nInput].nSequence);
}
/** Serialize an output of txTo */
template<typename S>
void SerializeOutput(S &s, unsigned int nOutput) const {
if (fHashSingle && nOutput != nIn)
// Do not lock-in the txout payee at other indices as txin
::Serialize(s, CTxOut());
else
::Serialize(s, txTo.vout[nOutput]);
}
/** Serialize txTo */
template<typename S>
void Serialize(S &s) const {
// Serialize nVersion
::Serialize(s, txTo.nVersion);
// Serialize vin
unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size();
::WriteCompactSize(s, nInputs);
for (unsigned int nInput = 0; nInput < nInputs; nInput++)
SerializeInput(s, nInput);
// Serialize vout
unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size());
::WriteCompactSize(s, nOutputs);
for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++)
SerializeOutput(s, nOutput);
// Serialize nLockTime
::Serialize(s, txTo.nLockTime);
// Serialize vJoinSplit
if (txTo.nVersion >= 2) {
//
// SIGHASH_* functions will hash portions of
// the transaction for use in signatures. This
// keeps the JoinSplit cryptographically bound
// to the transaction.
//
::Serialize(s, txTo.vJoinSplit);
if (txTo.vJoinSplit.size() > 0) {
::Serialize(s, txTo.joinSplitPubKey);
CTransaction::joinsplit_sig_t nullSig = {};
::Serialize(s, nullSig);
}
}
}
};
const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[blake2b::PERSONALBYTES] =
{'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'};
const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[blake2b::PERSONALBYTES] =
{'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'};
const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[blake2b::PERSONALBYTES] =
{'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'};
const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[blake2b::PERSONALBYTES] =
{'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'};
const unsigned char ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION[blake2b::PERSONALBYTES] =
{'Z','c','a','s','h','S','S','p','e','n','d','s','H','a','s','h'};
const unsigned char ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[blake2b::PERSONALBYTES] =
{'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'};
uint256 GetPrevoutHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
ss << txTo.vin[n].prevout;
}
return ss.GetHash();
}
uint256 GetSequenceHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
ss << txTo.vin[n].nSequence;
}
return ss.GetHash();
}
uint256 GetOutputsHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vout.size(); n++) {
ss << txTo.vout[n];
}
return ss.GetHash();
}
uint256 GetJoinSplitsHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, static_cast<int>(txTo.GetHeader()), ZCASH_JOINSPLITS_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vJoinSplit.size(); n++) {
ss << txTo.vJoinSplit[n];
}
ss << txTo.joinSplitPubKey;
return ss.GetHash();
}
uint256 GetShieldedSpendsHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION);
for (const auto& spend : txTo.GetSaplingSpends()) {
ss << spend.cv();
ss << spend.anchor();
ss << spend.nullifier();
ss << spend.rk();
ss << spend.zkproof();
}
return ss.GetHash();
}
uint256 GetShieldedOutputsHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION);
auto ssRs = ToRustStream(ss);
for (const auto& output : txTo.GetSaplingOutputs()) {
output.serialize_v4(*ssRs);
}
return ss.GetHash();
}
} // anon namespace
PrecomputedTransactionData::PrecomputedTransactionData(
const CTransaction& txTo,
const std::vector<CTxOut>& allPrevOutputs) :
preTx(nullptr, zcash_transaction_precomputed_free)
{
CDataStream sAllPrevOutputs(SER_NETWORK, PROTOCOL_VERSION);
sAllPrevOutputs << allPrevOutputs;
SetPrecomputed(
txTo,
reinterpret_cast<const unsigned char*>(sAllPrevOutputs.data()),
sAllPrevOutputs.size());
}
PrecomputedTransactionData::PrecomputedTransactionData(
const CTransaction& txTo,
const unsigned char* allPrevOutputs,
size_t allPrevOutputsLen) :
preTx(nullptr, zcash_transaction_precomputed_free)
{
SetPrecomputed(txTo, allPrevOutputs, allPrevOutputsLen);
}
void PrecomputedTransactionData::SetPrecomputed(
const CTransaction& txTo,
const unsigned char* allPrevOutputs,
size_t allPrevOutputsLen)
{
bool isOverwinterV3 =
txTo.fOverwintered &&
txTo.nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
txTo.nVersion == OVERWINTER_TX_VERSION;
bool isSaplingV4 =
txTo.fOverwintered &&
txTo.nVersionGroupId == SAPLING_VERSION_GROUP_ID &&
txTo.nVersion == SAPLING_TX_VERSION;
if (!txTo.fOverwintered || isOverwinterV3 || isSaplingV4) {
hashPrevouts = GetPrevoutHash(txTo);
hashSequence = GetSequenceHash(txTo);
hashOutputs = GetOutputsHash(txTo);
hashJoinSplits = GetJoinSplitsHash(txTo);
hashShieldedSpends = GetShieldedSpendsHash(txTo);
hashShieldedOutputs = GetShieldedOutputsHash(txTo);
} else {
// TODO: If we already have this serialized, use it.
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << txTo;
preTx.reset(zcash_transaction_precomputed_init(
reinterpret_cast<const unsigned char*>(ss.data()),
ss.size(), allPrevOutputs, allPrevOutputsLen));
if (preTx == nullptr) {
throw std::ios_base::failure("Invalid arguments to PrecomputedTransactionData");
}
}
}
SigVersion SignatureHashVersion(const CTransaction& txTo)
{
if (txTo.fOverwintered) {
if (txTo.nVersionGroupId == ZIP225_VERSION_GROUP_ID) {
return SIGVERSION_ZIP244;
} else if (txTo.nVersionGroupId == SAPLING_VERSION_GROUP_ID) {
return SIGVERSION_SAPLING;
} else {
return SIGVERSION_OVERWINTER;
}
} else {
return SIGVERSION_SPROUT;
}
}
uint256 SignatureHash(
const CScript& scriptCode,
const CTransaction& txTo,
unsigned int nIn,
int nHashType,
const CAmount& amount,
uint32_t consensusBranchId,
const PrecomputedTransactionData& txdata)
{
if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) {
// nIn out of range
throw logic_error("input index is out of range");
}
auto sigversion = SignatureHashVersion(txTo);
if (sigversion == SIGVERSION_ZIP244) {
// ZIP 244, S.2: transparent_sig_digest
//
// If we are producing a hash for either a coinbase transaction, or a
// non-coinbase transaction that has no transparent inputs, the value of
// transparent_sig_digest is identical to the value specified in section
// T.2.
//
// https://zips.z.cash/zip-0244#s-2-transparent-sig-digest
if (txTo.IsCoinBase() || txTo.vin.empty()) {
// This situation only applies to shielded signatures.
assert(nIn == NOT_AN_INPUT);
assert(nHashType == SIGHASH_ALL);
// The signature digest is just the txid! No need to cross the FFI.
return txTo.GetHash();
} else {
// S.2a: hash_type
//
// The following restrictions apply, which cause validation failure
// if violated:
// - Using any undefined hash_type (not 0x01, 0x02, 0x03, 0x81,
// 0x82, or 0x83).
// - Using SIGHASH_SINGLE without a "corresponding output" (an
// output with the same index as the input being verified).
switch (nHashType) {
case SIGHASH_SINGLE:
case SIGHASH_ANYONECANPAY | SIGHASH_SINGLE:
if (nIn >= txTo.vout.size()) {
throw std::logic_error(
"ZIP 244: Used SIGHASH_SINGLE without a corresponding output");
}
case SIGHASH_ALL:
case SIGHASH_NONE:
case SIGHASH_ANYONECANPAY | SIGHASH_ALL:
case SIGHASH_ANYONECANPAY | SIGHASH_NONE:
break;
default:
throw std::logic_error("ZIP 244: Used undefined hash_type");
}
// The amount parameter is ignored; we extract it from allPrevOutputs.
// - Note to future developers: if we ever replace the C++ logic for
// pre-v5 transactions with Rust logic, make sure signrawtransaction
// is updated to know about it!
// The consensusBranchId parameter is ignored; we use the value stored
// in the transaction itself.
uint256 hash;
if (!zcash_transaction_zip244_signature_digest(
txdata.preTx.get(),
nHashType,
nIn,
hash.begin()))
{
throw std::logic_error("We should not reach here.");
}
return hash;
}
} else if (sigversion == SIGVERSION_OVERWINTER || sigversion == SIGVERSION_SAPLING) {
uint256 hashPrevouts;
uint256 hashSequence;
uint256 hashOutputs;
uint256 hashJoinSplits;
uint256 hashShieldedSpends;
uint256 hashShieldedOutputs;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
hashPrevouts = txdata.hashPrevouts;
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashSequence = txdata.hashSequence;
}
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashOutputs = txdata.hashOutputs;
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
ss << txTo.vout[nIn];
hashOutputs = ss.GetHash();
}
if (!txTo.vJoinSplit.empty()) {
hashJoinSplits = txdata.hashJoinSplits;
}
if (txTo.GetSaplingSpendsCount() > 0) {
hashShieldedSpends = txdata.hashShieldedSpends;
}
if (txTo.GetSaplingOutputsCount() > 0) {
hashShieldedOutputs = txdata.hashShieldedOutputs;
}
uint32_t leConsensusBranchId = htole32(consensusBranchId);
unsigned char personalization[16] = {};
memcpy(personalization, "ZcashSigHash", 12);
memcpy(personalization+12, &leConsensusBranchId, 4);
CBLAKE2bWriter ss(SER_GETHASH, 0, personalization);
// Header
ss << txTo.GetHeader();
// Version group ID
ss << txTo.nVersionGroupId;
// Input prevouts/nSequence (none/all, depending on flags)
ss << hashPrevouts;
ss << hashSequence;
// Outputs (none/one/all, depending on flags)
ss << hashOutputs;
// JoinSplits
ss << hashJoinSplits;
if (sigversion == SIGVERSION_SAPLING) {
// Spend descriptions
ss << hashShieldedSpends;
// Output descriptions
ss << hashShieldedOutputs;
}
// Locktime
ss << txTo.nLockTime;
// Expiry height
ss << txTo.nExpiryHeight;
if (sigversion == SIGVERSION_SAPLING) {
// Sapling value balance
ss << txTo.GetValueBalanceSapling();
}
// Sighash type
ss << nHashType;
// If this hash is for a transparent input signature
// (i.e. not for txTo.joinSplitSig):
if (nIn != NOT_AN_INPUT){
// The input being signed (replacing the scriptSig with scriptCode + amount)
// The prevout may already be contained in hashPrevout, and the nSequence
// may already be contained in hashSequence.
ss << txTo.vin[nIn].prevout;
ss << static_cast<const CScriptBase&>(scriptCode);
ss << amount;
ss << txTo.vin[nIn].nSequence;
}
return ss.GetHash();
}
// Check for invalid use of SIGHASH_SINGLE
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
if (nIn >= txTo.vout.size()) {
// nOut out of range
throw logic_error("no matching output for SIGHASH_SINGLE");
}
}
// Wrapper to serialize only the necessary parts of the transaction being signed
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);
// Serialize and hash
CHashWriter ss(SER_GETHASH, 0);
ss << txTmp << nHashType;
return ss.GetHash();
}
bool TransactionSignatureChecker::VerifySignature(
const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
bool CallbackTransactionSignatureChecker::VerifySignature(
const std::vector<unsigned char>& vchSig,
const CPubKey& pubkey,
const uint256& sighash) const
{
return pubkey.Verify(sighash, vchSig);
}
bool TransactionSignatureChecker::CheckSig(
bool CallbackTransactionSignatureChecker::CheckSig(
const vector<unsigned char>& vchSigIn,
const vector<unsigned char>& vchPubKey,
const CScript& scriptCode,
@ -1402,7 +983,10 @@ bool TransactionSignatureChecker::CheckSig(
uint256 sighash;
try {
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata);
std::array<uint8_t, 32> sighashArray;
auto scriptBase = static_cast<const CScriptBase&>(scriptCode);
this->sighash(sighashArray.data(), sighashArray.size(), this->tx, &scriptBase[0], scriptBase.size(), nHashType);
sighash = uint256::FromRawBytes(sighashArray);
} catch (logic_error ex) {
return false;
}
@ -1413,7 +997,7 @@ bool TransactionSignatureChecker::CheckSig(
return true;
}
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
bool CallbackTransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
{
// There are two times of nLockTime: lock-by-blockheight
// and lock-by-blocktime, distinguished by whether
@ -1423,14 +1007,13 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
// unless the type of nLockTime being tested is the same as
// the nLockTime in the transaction.
if (!(
(txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
(txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
))
(this->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
(this->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)))
return false;
// Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one.
if (nLockTime > (int64_t)txTo->nLockTime)
if (nLockTime > this->nLockTime)
return false;
// Finally the nLockTime feature can be disabled and thus
@ -1443,13 +1026,12 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
// prevent this condition. Alternatively we could test all
// inputs, but testing just this input minimizes the data
// required to prove correct CHECKLOCKTIMEVERIFY execution.
if (txTo->vin[nIn].IsFinal())
if (this->isFinal)
return false;
return true;
}
bool VerifyScript(
const CScript& scriptSig,
const CScript& scriptPubKey,

View File

@ -8,18 +8,17 @@
#define BITCOIN_SCRIPT_INTERPRETER_H
#include "script_error.h"
#include "primitives/transaction.h"
#include <rust/transaction.h>
#include <vector>
#include <stdint.h>
#include <string>
#include <climits>
#include "script/script.h"
#include "amount.h"
class CPubKey;
class CScript;
class CTransaction;
class uint256;
/** Special case nIn for signing JoinSplits. */
@ -93,28 +92,6 @@ enum
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
struct PrecomputedTransactionData
{
uint256 hashPrevouts, hashSequence, hashOutputs, hashJoinSplits, hashShieldedSpends, hashShieldedOutputs;
/** Precomputed transaction parts. */
std::unique_ptr<PrecomputedTxParts, decltype(&zcash_transaction_precomputed_free)> preTx;
PrecomputedTransactionData(
const CTransaction& tx,
const std::vector<CTxOut>& allPrevOutputs);
PrecomputedTransactionData(
const CTransaction& tx,
const unsigned char* allPrevOutputs,
size_t allPrevOutputsLen);
private:
void SetPrecomputed(
const CTransaction& tx,
const unsigned char* allPrevOutputs,
size_t allPrevOutputsLen);
};
enum SigVersion
{
SIGVERSION_SPROUT = 0,
@ -123,15 +100,6 @@ enum SigVersion
SIGVERSION_ZIP244 = 3,
};
uint256 SignatureHash(
const CScript &scriptCode,
const CTransaction& txTo,
unsigned int nIn,
int nHashType,
const CAmount& amount,
uint32_t consensusBranchId,
const PrecomputedTransactionData& txdata);
class BaseSignatureChecker
{
public:
@ -152,31 +120,23 @@ public:
virtual ~BaseSignatureChecker() {}
};
class TransactionSignatureChecker : public BaseSignatureChecker
class CallbackTransactionSignatureChecker : public BaseSignatureChecker
{
private:
const CTransaction* txTo;
unsigned int nIn;
const CAmount amount;
const PrecomputedTransactionData& txdata;
const void* tx;
void (*sighash)(unsigned char* sighash, unsigned int sighashLen, const void* tx, const unsigned char* scriptCode, unsigned int scriptCodeLen, int hashType);
const CScriptNum& nLockTime;
bool isFinal;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
TransactionSignatureChecker(const CTransaction* txToIn, const PrecomputedTransactionData& txdataIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(txdataIn) {}
CallbackTransactionSignatureChecker(const void* tx, void (*sighash)(unsigned char* sighash, unsigned int sighashLen, const void* tx, const unsigned char* scriptCode, unsigned int scriptCodeLen, int hashType), const CScriptNum& nLockTime, bool isFinal) : tx(tx), sighash(sighash), nLockTime(nLockTime), isFinal(isFinal) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
};
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
{
private:
const CTransaction txTo;
public:
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, const PrecomputedTransactionData& txdataIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, txdataIn, nInIn, amount), txTo(*txToIn) {}
};
bool EvalScript(
std::vector<std::vector<unsigned char> >& stack,

View File

@ -6,9 +6,6 @@
#include "zcash_script.h"
#include "consensus/upgrades.h"
#include "primitives/transaction.h"
#include "pubkey.h"
#include "script/interpreter.h"
#include "version.h"
@ -19,262 +16,6 @@ inline int set_error(zcash_script_error* ret, zcash_script_error serror)
*ret = serror;
return 0;
}
// Copy of GetLegacySigOpCount from main.cpp commit c4b2ef7c4.
// Replace with the copy from src/consensus/tx_verify.{cpp,h} after backporting that refactor.
unsigned int GetLegacySigOpCount(const CTransaction& tx)
{
unsigned int nSigOps = 0;
for (const CTxIn& txin : tx.vin)
{
nSigOps += txin.scriptSig.GetSigOpCount(false);
}
for (const CTxOut& txout : tx.vout)
{
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
}
return nSigOps;
}
}
struct PrecomputedTransaction {
const CTransaction tx;
const PrecomputedTransactionData txdata;
PrecomputedTransaction(
CTransaction txIn,
const unsigned char* allPrevOutputs,
size_t allPrevOutputsLen) : tx(txIn), txdata(txIn, allPrevOutputs, allPrevOutputsLen) {}
};
void* zcash_script_new_precomputed_tx(
const unsigned char* txTo,
unsigned int txToLen,
zcash_script_error* err)
{
try {
const char* txToEnd = (const char *)(txTo + txToLen);
RustDataStream stream((const char *)txTo, txToEnd, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
stream >> tx;
if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen) {
set_error(err, zcash_script_ERR_TX_SIZE_MISMATCH);
return nullptr;
}
if (tx.nVersion >= ZIP225_TX_VERSION) {
set_error(err, zcash_script_ERR_TX_VERSION);
return nullptr;
}
// Deserializing the tx did not error.
set_error(err, zcash_script_ERR_OK);
// This is a pre-v5 tx, so the PrecomputedTransactionData constructor
// field `allPrevOutputs` is not used.
auto preTx = new PrecomputedTransaction(tx, nullptr, 0);
return preTx;
} catch (const std::exception&) {
set_error(err, zcash_script_ERR_TX_DESERIALIZE); // Error deserializing
return nullptr;
}
}
void* zcash_script_new_precomputed_tx_v5(
const unsigned char* txTo,
unsigned int txToLen,
const unsigned char* allPrevOutputs,
unsigned int allPrevOutputsLen,
zcash_script_error* err)
{
CTransaction tx;
try {
const char* txToEnd = (const char *)(txTo + txToLen);
RustDataStream stream((const char *)txTo, txToEnd, SER_NETWORK, PROTOCOL_VERSION);
stream >> tx;
if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen) {
set_error(err, zcash_script_ERR_TX_SIZE_MISMATCH);
return nullptr;
}
} catch (const std::exception&) {
set_error(err, zcash_script_ERR_TX_DESERIALIZE); // Error deserializing
return nullptr;
}
try {
auto preTx = new PrecomputedTransaction(tx, allPrevOutputs, allPrevOutputsLen);
// Deserializing the tx did not error.
set_error(err, zcash_script_ERR_OK);
return preTx;
} catch (const std::exception&) {
// We had some error when parsing allPrevOutputs inside the
// PrecomputedTransactionData constructor.
set_error(err, zcash_script_ERR_ALL_PREV_OUTPUTS_DESERIALIZE);
return nullptr;
}
}
void zcash_script_free_precomputed_tx(void* pre_preTx)
{
PrecomputedTransaction* preTx = static_cast<PrecomputedTransaction*>(pre_preTx);
delete preTx;
preTx = nullptr;
}
int zcash_script_verify_precomputed(
const void* pre_preTx,
unsigned int nIn,
const unsigned char* scriptPubKey,
unsigned int scriptPubKeyLen,
int64_t amount,
unsigned int flags,
uint32_t consensusBranchId,
zcash_script_error* err)
{
const PrecomputedTransaction* preTx = static_cast<const PrecomputedTransaction*>(pre_preTx);
if (nIn >= preTx->tx.vin.size())
return set_error(err, zcash_script_ERR_TX_INDEX);
// Regardless of the verification result, the tx did not error.
set_error(err, zcash_script_ERR_OK);
return VerifyScript(
preTx->tx.vin[nIn].scriptSig,
CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen),
flags,
TransactionSignatureChecker(&preTx->tx, preTx->txdata, nIn, amount),
consensusBranchId,
NULL);
}
int zcash_script_verify(
const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
int64_t amount,
const unsigned char *txTo, unsigned int txToLen,
unsigned int nIn, unsigned int flags,
uint32_t consensusBranchId,
zcash_script_error* err)
{
try {
const char* txToEnd = (const char *)(txTo + txToLen);
RustDataStream stream((const char *)txTo, txToEnd, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
stream >> tx;
if (nIn >= tx.vin.size())
return set_error(err, zcash_script_ERR_TX_INDEX);
if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen)
return set_error(err, zcash_script_ERR_TX_SIZE_MISMATCH);
if (tx.nVersion >= ZIP225_TX_VERSION) {
return set_error(err, zcash_script_ERR_TX_VERSION);
}
// Regardless of the verification result, the tx did not error.
set_error(err, zcash_script_ERR_OK);
// This is a pre-v5 tx, so the PrecomputedTransactionData constructor
// field `allPrevOutputs` is not used.
PrecomputedTransactionData txdata(tx, {});
return VerifyScript(
tx.vin[nIn].scriptSig,
CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen),
flags,
TransactionSignatureChecker(&tx, txdata, nIn, amount),
consensusBranchId,
NULL);
} catch (const std::exception&) {
return set_error(err, zcash_script_ERR_TX_DESERIALIZE); // Error deserializing
}
}
int zcash_script_verify_v5(
const unsigned char* txTo,
unsigned int txToLen,
const unsigned char* allPrevOutputs,
unsigned int allPrevOutputsLen,
unsigned int nIn,
unsigned int flags,
uint32_t consensusBranchId,
zcash_script_error* err)
{
CTransaction tx;
try {
const char* txToEnd = (const char *)(txTo + txToLen);
RustDataStream stream((const char *)txTo, txToEnd, SER_NETWORK, PROTOCOL_VERSION);
stream >> tx;
if (nIn >= tx.vin.size())
return set_error(err, zcash_script_ERR_TX_INDEX);
if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen)
return set_error(err, zcash_script_ERR_TX_SIZE_MISMATCH);
} catch (const std::exception&) {
return set_error(err, zcash_script_ERR_TX_DESERIALIZE); // Error deserializing
}
std::vector<CTxOut> prevOutputs;
try {
// TODO: we can swap this second deserialization for an FFI call by
// fetching this through PrecomputedTransactionData. Simplicity for now.
CDataStream sAllPrevOutputs(
reinterpret_cast<const char*>(allPrevOutputs),
reinterpret_cast<const char*>(allPrevOutputs + allPrevOutputsLen),
SER_NETWORK,
PROTOCOL_VERSION);
sAllPrevOutputs >> prevOutputs;
if (!(tx.IsCoinBase() ? prevOutputs.empty() : tx.vin.size() == prevOutputs.size())) {
return set_error(err, zcash_script_ERR_ALL_PREV_OUTPUTS_SIZE_MISMATCH);
}
} catch (const std::exception&) {
// We had some error when parsing allPrevOutputs inside the
// PrecomputedTransactionData constructor.
return set_error(err, zcash_script_ERR_ALL_PREV_OUTPUTS_DESERIALIZE);
}
try {
// Regardless of the verification result, the tx did not error.
set_error(err, zcash_script_ERR_OK);
PrecomputedTransactionData txdata(tx, allPrevOutputs, allPrevOutputsLen);
return VerifyScript(
tx.vin[nIn].scriptSig,
prevOutputs[nIn].scriptPubKey,
flags,
TransactionSignatureChecker(&tx, txdata, nIn, prevOutputs[nIn].nValue),
consensusBranchId,
NULL);
} catch (const std::exception&) {
return set_error(err, zcash_script_ERR_VERIFY_SCRIPT); // Error during script verification
}
}
unsigned int zcash_script_legacy_sigop_count_precomputed(
const void* pre_preTx,
zcash_script_error* err)
{
const PrecomputedTransaction* preTx = static_cast<const PrecomputedTransaction*>(pre_preTx);
// The current implementation of this method never errors.
set_error(err, zcash_script_ERR_OK);
return GetLegacySigOpCount(preTx->tx);
}
unsigned int zcash_script_legacy_sigop_count(
const unsigned char *txTo,
unsigned int txToLen,
zcash_script_error* err)
{
try {
const char* txToEnd = (const char *)(txTo + txToLen);
RustDataStream stream((const char *)txTo, txToEnd, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
stream >> tx;
if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen) {
set_error(err, zcash_script_ERR_TX_SIZE_MISMATCH);
return UINT_MAX;
}
// Deserializing the tx did not error.
set_error(err, zcash_script_ERR_OK);
return GetLegacySigOpCount(tx);
} catch (const std::exception&) {
set_error(err, zcash_script_ERR_TX_DESERIALIZE); // Error deserializing
return UINT_MAX;
}
}
unsigned int zcash_script_version()
@ -282,3 +23,41 @@ unsigned int zcash_script_version()
// Just use the API version for now
return ZCASH_SCRIPT_API_VER;
}
unsigned int zcash_script_legacy_sigop_count_script(
const unsigned char* script,
unsigned int scriptLen)
{
CScript cscript = CScript(script, script + scriptLen);
return cscript.GetSigOpCount(false);
}
int zcash_script_verify_callback(
const void* ctx,
void (*sighash)(unsigned char* sighash, unsigned int sighashLen, const void* ctx, const unsigned char* scriptCode, unsigned int scriptCodeLen, int hashType),
int64_t nLockTime,
uint8_t isFinal,
const unsigned char* scriptPubKey,
unsigned int scriptPubKeyLen,
const unsigned char* scriptSig,
unsigned int scriptSigLen,
unsigned int flags,
zcash_script_error* err)
{
try {
set_error(err, zcash_script_ERR_OK);
CScriptNum nLockTimeNum = CScriptNum(nLockTime);
ScriptError script_err = SCRIPT_ERR_OK;
return VerifyScript(
CScript(scriptSig, scriptSig + scriptSigLen),
CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen),
flags,
CallbackTransactionSignatureChecker(ctx, sighash, nLockTimeNum, isFinal != 0),
// consensusBranchId is not longer used with the callback API; the argument
// was left there to minimize changes to interpreter.cpp
0,
&script_err);
} catch (const std::exception&) {
return set_error(err, zcash_script_ERR_VERIFY_SCRIPT);
}
}

View File

@ -34,7 +34,7 @@
extern "C" {
#endif
#define ZCASH_SCRIPT_API_VER 3
#define ZCASH_SCRIPT_API_VER 4
typedef enum zcash_script_error_t
{
@ -57,130 +57,56 @@ enum
zcash_script_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
};
/// Deserializes the given transaction and precomputes values to improve
/// script verification performance.
///
/// This API cannot be used for v5+ transactions, and will return an error.
///
/// Returns a pointer to the precomputed transaction. Free this with
/// zcash_script_free_precomputed_tx once you are done.
/// The precomputed transaction is guaranteed to not keep a reference to any
/// part of the input buffers, so they can be safely overwritten or deallocated
/// after this function returns.
///
/// If not NULL, err will contain an error/success code for the operation.
void* zcash_script_new_precomputed_tx(
const unsigned char* txTo,
unsigned int txToLen,
zcash_script_error* err);
/// Deserializes the given transaction and precomputes values to improve
/// script verification performance. Must be used for V5 transactions;
/// may also be used for previous versions.
///
/// allPrevOutputs must point to the encoding of the vector of all outputs
/// from previous transactions that are spent by the inputs of the given transaction.
/// The outputs must be encoded as specified by Bitcoin. The full encoding will thus
/// consist of a CompactSize prefix containing the number of outputs, followed by
/// the concatenated outputs, each of them encoded as (value, CompactSize, pk_script).
///
/// Returns a pointer to the precomputed transaction. Free this with
/// zcash_script_free_precomputed_tx once you are done.
///
/// If not NULL, err will contain an error/success code for the operation.
void* zcash_script_new_precomputed_tx_v5(
const unsigned char* txTo,
unsigned int txToLen,
const unsigned char* allPrevOutputs,
unsigned int allPrevOutputsLen,
zcash_script_error* err);
/// Frees a precomputed transaction previously created with
/// zcash_script_new_precomputed_tx.
void zcash_script_free_precomputed_tx(void* preTx);
/// Returns 1 if the input nIn of the precomputed transaction pointed to by
/// preTx correctly spends the scriptPubKey pointed to by scriptPubKey under
/// the additional constraints specified by flags.
///
/// If not NULL, err will contain an error/success code for the operation.
/// Note that script verification failure is indicated by err being set to
/// zcash_script_ERR_OK and a return value of 0.
EXPORT_SYMBOL int zcash_script_verify_precomputed(
const void* preTx,
unsigned int nIn,
const unsigned char* scriptPubKey,
unsigned int scriptPubKeyLen,
int64_t amount,
unsigned int flags,
uint32_t consensusBranchId,
zcash_script_error* err);
/// Returns 1 if the input nIn of the serialized transaction pointed to by
/// txTo correctly spends the scriptPubKey pointed to by scriptPubKey under
/// the additional constraints specified by flags.
///
/// This API cannot be used for v5+ transactions, and will return an error.
///
/// If not NULL, err will contain an error/success code for the operation.
/// Note that script verification failure is indicated by err being set to
/// zcash_script_ERR_OK and a return value of 0.
EXPORT_SYMBOL int zcash_script_verify(
const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
int64_t amount,
const unsigned char *txTo, unsigned int txToLen,
unsigned int nIn, unsigned int flags,
uint32_t consensusBranchId,
zcash_script_error* err);
/// Returns 1 if the input nIn of the serialized transaction pointed to by
/// txTo correctly spends the matching output in allPrevOutputs under
/// the additional constraints specified by flags. Must be used for V5 transactions;
/// may also be used for previous versions.
///
/// allPrevOutputs must point to the encoding of the vector of all outputs
/// from previous transactions that are spent by the inputs of the given transaction.
/// The outputs must be encoded as specified by Bitcoin. The full encoding will thus
/// consist of a CompactSize prefix containing the number of outputs, followed by
/// the concatenated outputs, each of them encoded as (value, CompactSize, pk_script).
///
/// If not NULL, err will contain an error/success code for the operation.
/// Note that script verification failure is indicated by err being set to
/// zcash_script_ERR_OK and a return value of 0.
EXPORT_SYMBOL int zcash_script_verify_v5(
const unsigned char* txTo,
unsigned int txToLen,
const unsigned char* allPrevOutputs,
unsigned int allPrevOutputsLen,
unsigned int nIn,
unsigned int flags,
uint32_t consensusBranchId,
zcash_script_error* err);
/// Returns the number of transparent signature operations in the
/// transparent inputs and outputs of the precomputed transaction
/// pointed to by preTx.
///
/// Returns UINT_MAX on error, so that invalid transactions don't pass the Zcash consensus rules.
/// If not NULL, err will contain an error/success code for the operation.
EXPORT_SYMBOL unsigned int zcash_script_legacy_sigop_count_precomputed(
const void* preTx,
zcash_script_error* err);
/// Returns the number of transparent signature operations in the
/// transparent inputs and outputs of the serialized transaction
/// pointed to by txTo.
///
/// Returns UINT_MAX on error.
/// If not NULL, err will contain an error/success code for the operation.
EXPORT_SYMBOL unsigned int zcash_script_legacy_sigop_count(
const unsigned char *txTo,
unsigned int txToLen,
zcash_script_error* err);
/// Returns the current version of the zcash_script library.
EXPORT_SYMBOL unsigned int zcash_script_version();
/// Returns the number of transparent signature operations in the input or
/// output script pointed to by script.
EXPORT_SYMBOL unsigned int zcash_script_legacy_sigop_count_script(
const unsigned char* script,
unsigned int scriptLen);
/// Returns 1 if the a transparent input correctly spends the matching output
/// under the additional constraints specified by flags. This function
/// receives only the required information to validate the spend and not
/// the transaction itself. In particular, the sighash for the spend
/// is obtained using a callback function.
///
/// - ctx: an opaque pointer which is forwarded to the callback. It can be used
/// to store context regarding the spend (i.e. the transaction itself,
/// and any precomputed data).
/// - sighash: a callback function which is called to obtain the sighash.
/// - sighash: pointer to a buffer where the sighash must be written to.
/// - sighashLen: the length of the buffer. Will be 32.
/// - ctx: the same opaque pointer
/// - scriptCode: the scriptCode being validated. Note that this not always
/// matches scriptSig, i.e. for P2SH.
/// - scriptCodeLen: the length of the script.
/// - hashType: the hash type being used.
/// - nLockTime: the lock time of the transaction being validated.
/// - isFinal: a boolean indicating whether the input being validated is final
/// (i.e. its sequence number is 0xFFFFFFFF).
/// - scriptPubKey: the scriptPubKey of the output being spent.
/// - scriptPubKeyLen: the length of scriptPubKey.
/// - scriptSig: the scriptSig of the input being validated.
/// - scriptSigLen: the length of scriptSig.
/// - flags: the script verification flags to use.
/// - err: if not NULL, err will contain an error/success code for the operation.
///
/// Note that script verification failure is indicated by err being set to
/// zcash_script_ERR_OK and a return value of 0.
EXPORT_SYMBOL int zcash_script_verify_callback(
const void* ctx,
void (*sighash)(unsigned char* sighash, unsigned int sighashLen, const void* ctx, const unsigned char* scriptCode, unsigned int scriptCodeLen, int hashType),
int64_t nLockTime,
uint8_t isFinal,
const unsigned char* scriptPubKey,
unsigned int scriptPubKeyLen,
const unsigned char* scriptSig,
unsigned int scriptSigLen,
unsigned int flags,
zcash_script_error* err);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -26,8 +26,6 @@
#include <vector>
#include <rust/ed25519.h>
#include "prevector.h"
static const unsigned int MAX_SIZE = 0x02000000;
@ -587,25 +585,6 @@ template<typename Stream, typename T> void Unserialize(Stream& os, std::shared_p
template<typename Stream, typename T> void Serialize(Stream& os, const std::unique_ptr<const T>& p);
template<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p);
/**
* ed25519::SigningKey
*/
template<typename Stream> void Serialize(Stream& os, const ed25519::SigningKey& item);
template<typename Stream> void Unserialize(Stream& is, ed25519::SigningKey& item);
/**
* ed25519::VerificationKey
*/
template<typename Stream> void Serialize(Stream& os, const ed25519::VerificationKey& item);
template<typename Stream> void Unserialize(Stream& is, ed25519::VerificationKey& item);
/**
* ed25519::Signature
*/
template<typename Stream> void Serialize(Stream& os, const ed25519::Signature& item);
template<typename Stream> void Unserialize(Stream& is, ed25519::Signature& item);
/**
* If none of the specialized versions above matched, default to calling member function.
@ -975,57 +954,6 @@ void Unserialize(Stream& is, std::shared_ptr<const T>& p)
/**
* ed25519::SigningKey
*/
template<typename Stream>
void Serialize(Stream& os, const ed25519::SigningKey& sk)
{
Serialize(os, sk.bytes);
}
template<typename Stream>
void Unserialize(Stream& is, ed25519::SigningKey& sk)
{
Unserialize(is, sk.bytes);
}
/**
* ed25519::VerificationKey
*/
template<typename Stream>
void Serialize(Stream& os, const ed25519::VerificationKey& vk)
{
Serialize(os, vk.bytes);
}
template<typename Stream>
void Unserialize(Stream& is, ed25519::VerificationKey& vk)
{
Unserialize(is, vk.bytes);
}
/**
* ed25519::Signature
*/
template<typename Stream>
void Serialize(Stream& os, const ed25519::Signature& sig)
{
Serialize(os, sig.bytes);
}
template<typename Stream>
void Unserialize(Stream& is, ed25519::Signature& sig)
{
Unserialize(is, sig.bytes);
}
/**
* Support for ADD_SERIALIZE_METHODS and READWRITE macro
*/

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/blake2b.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/bridge.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/builder_ffi.rs");

View File

@ -1,3 +0,0 @@
#![allow(dead_code)]
include!("../depend/zcash/src/rust/src/bundlecache.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/incremental_merkle_tree.rs");

View File

@ -13,266 +13,105 @@
// Use the generated C++ bindings
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
// Include the items from depend/zcash/src/rust/src/rustzcash.rs (librustzcash/lib.rs)
// that we need
use ::sapling::circuit::{
OutputParameters, OutputVerifyingKey, SpendParameters, SpendVerifyingKey,
};
/// The code that uses this constant is not called by zcash_script.
static mut SAPLING_SPEND_VK: Option<SpendVerifyingKey> = None;
/// The code that uses this constant is not called by zcash_script.
static mut SAPLING_OUTPUT_VK: Option<OutputVerifyingKey> = None;
/// The code that uses this constant is not called by zcash_script.
static mut SAPLING_SPEND_PARAMS: Option<SpendParameters> = None;
/// The code that uses this constant is not called by zcash_script.
static mut SAPLING_OUTPUT_PARAMS: Option<OutputParameters> = None;
/// The code that uses this constant is not called by zcash_script.
static mut ORCHARD_PK: Option<orchard::circuit::ProvingKey> = None;
/// The code that uses this constant is not called by zcash_script.
static mut ORCHARD_VK: Option<orchard::circuit::VerifyingKey> = None;
/// Converts CtOption<t> into Option<T>
fn de_ct<T>(ct: subtle::CtOption<T>) -> Option<T> {
if ct.is_some().into() {
Some(ct.unwrap())
} else {
None
}
}
/// The size of a Groth16 Sapling proof.
const GROTH_PROOF_SIZE: usize = 48 // π_A
+ 96 // π_B
+ 48; // π_C
// Include the modules from depend/zcash/src/rust (librustzcash) that we need
mod blake2b;
mod bridge;
mod bundlecache;
mod incremental_merkle_tree;
mod merkle_frontier;
mod note_encryption;
mod orchard_bundle;
mod params;
mod sapling;
mod streams;
mod test_harness_ffi;
mod wallet;
mod wallet_scanner;
mod zcashd_orchard;
mod builder_ffi;
mod orchard_ffi;
mod streams_ffi;
mod transaction_ffi;
#[cfg(test)]
mod tests {
use std::ffi::{c_int, c_uint, c_void};
pub use super::zcash_script_error_t;
use hex::FromHex;
lazy_static::lazy_static! {
pub static ref SCRIPT_PUBKEY: Vec<u8> = <Vec<u8>>::from_hex("76a914f47cac1e6fec195c055994e8064ffccce0044dd788ac").unwrap();
pub static ref SCRIPT_TX: Vec<u8> = <Vec<u8>>::from_hex("0400008085202f8901fcaf44919d4a17f6181a02a7ebe0420be6f7dad1ef86755b81d5a9567456653c010000006a473044022035224ed7276e61affd53315eca059c92876bc2df61d84277cafd7af61d4dbf4002203ed72ea497a9f6b38eb29df08e830d99e32377edb8a574b8a289024f0241d7c40121031f54b095eae066d96b2557c1f99e40e967978a5fd117465dbec0986ca74201a6feffffff020050d6dc0100000017a9141b8a9bda4b62cd0d0582b55455d0778c86f8628f870d03c812030000001976a914e4ff5512ffafe9287992a1cd177ca6e408e0300388ac62070d0095070d000000000000000000000000").expect("Block bytes are in valid hex representation");
pub static ref SCRIPT_PUBKEY: Vec<u8> = <Vec<u8>>::from_hex("a914c117756dcbe144a12a7c33a77cfa81aa5aeeb38187").unwrap();
pub static ref SCRIPT_SIG: Vec<u8> = <Vec<u8>>::from_hex("00483045022100d2ab3e6258fe244fa442cfb38f6cef9ac9a18c54e70b2f508e83fa87e20d040502200eead947521de943831d07a350e45af8e36c2166984a8636f0a8811ff03ed09401473044022013e15d865010c257eef133064ef69a780b4bc7ebe6eda367504e806614f940c3022062fdbc8c2d049f91db2042d6c9771de6f1ef0b3b1fea76c1ab5542e44ed29ed8014c69522103b2cc71d23eb30020a4893982a1e2d352da0d20ee657fa02901c432758909ed8f21029d1e9a9354c0d2aee9ffd0f0cea6c39bbf98c4066cf143115ba2279d0ba7dabe2103e32096b63fd57f3308149d238dcbb24d8d28aad95c0e4e74e3e5e6a11b61bcc453ae").expect("Block bytes are in valid hex representation");
}
/// Manually encode all previous outputs for a single output.
fn encode_all_prev_outputs(amount: i64, script_pub_key: &[u8]) -> (Vec<u8>, *const u8) {
// Number of transactions (CompactSize)
let mut all_prev_outputs = vec![1];
// Amount as 8 little-endian bytes
all_prev_outputs.extend(amount.to_le_bytes().iter().cloned());
// Length of the pub key script (CompactSize)
all_prev_outputs.push(script_pub_key.len() as u8);
// Pub key script
all_prev_outputs.extend(script_pub_key.iter().cloned());
let all_prev_outputs_ptr = all_prev_outputs.as_ptr();
(all_prev_outputs, all_prev_outputs_ptr)
}
pub fn verify_script(
script_pub_key: &[u8],
amount: i64,
tx_to: &[u8],
nIn: u32,
flags: u32,
consensus_branch_id: u32,
) -> Result<(), zcash_script_error_t> {
let script_ptr = script_pub_key.as_ptr();
let script_len = script_pub_key.len();
let tx_to_ptr = tx_to.as_ptr();
let tx_to_len = tx_to.len();
let mut err = 0;
let ret = unsafe {
super::zcash_script_verify(
script_ptr,
script_len as u32,
amount,
tx_to_ptr,
tx_to_len as u32,
nIn,
flags,
consensus_branch_id,
&mut err,
)
};
if ret != 1 {
return Err(err);
}
// Also test with the V5 API
let (all_prev_outputs, all_prev_outputs_ptr) =
encode_all_prev_outputs(amount, script_pub_key);
let ret = unsafe {
super::zcash_script_verify_v5(
tx_to_ptr,
tx_to_len as u32,
all_prev_outputs_ptr,
all_prev_outputs.len() as _,
nIn,
flags,
consensus_branch_id,
&mut err,
)
};
if ret == 1 {
Ok(())
} else {
Err(err)
extern "C" fn sighash(
sighash_out: *mut u8,
sighash_out_len: c_uint,
ctx: *const c_void,
_script_code: *const u8,
_script_code_len: c_uint,
_hash_type: c_int,
) {
unsafe {
assert!(ctx.is_null());
let sighash =
hex::decode("e8c7bdac77f6bb1f3aba2eaa1fada551a9c8b3b5ecd1ef86e6e58a5f1aab952c")
.unwrap();
assert!(sighash_out_len == sighash.len() as c_uint);
std::ptr::copy_nonoverlapping(sighash.as_ptr(), sighash_out, sighash.len());
}
}
pub fn verify_script_precompute(
script_pub_key: &[u8],
amount: i64,
tx_to: &[u8],
nIn: u32,
flags: u32,
consensus_branch_id: u32,
) -> Result<(), zcash_script_error_t> {
let script_ptr = script_pub_key.as_ptr();
let script_len = script_pub_key.len();
let tx_to_ptr = tx_to.as_ptr();
let tx_to_len = tx_to.len();
let mut err = 0;
let precomputed =
unsafe { super::zcash_script_new_precomputed_tx(tx_to_ptr, tx_to_len as _, &mut err) };
let ret = unsafe {
super::zcash_script_verify_precomputed(
precomputed,
nIn,
script_ptr,
script_len as _,
amount,
flags,
consensus_branch_id,
&mut err,
)
};
unsafe { super::zcash_script_free_precomputed_tx(precomputed) };
if ret != 1 {
return Err(err);
}
// Also test with the V5 API
let (all_prev_outputs, all_prev_outputs_ptr) =
encode_all_prev_outputs(amount, script_pub_key);
let precomputed = unsafe {
super::zcash_script_new_precomputed_tx_v5(
tx_to_ptr,
tx_to_len as _,
all_prev_outputs_ptr,
all_prev_outputs.len() as _,
&mut err,
)
};
let ret = unsafe {
super::zcash_script_verify_precomputed(
precomputed,
nIn,
script_ptr,
script_len as u32,
amount,
flags,
consensus_branch_id,
&mut err,
)
};
unsafe { super::zcash_script_free_precomputed_tx(precomputed) };
if ret == 1 {
Ok(())
} else {
Err(err)
extern "C" fn invalid_sighash(
sighash_out: *mut u8,
sighash_out_len: c_uint,
ctx: *const c_void,
_script_code: *const u8,
_script_code_len: c_uint,
_hash_type: c_int,
) {
unsafe {
assert!(ctx.is_null());
let sighash =
hex::decode("08c7bdac77f6bb1f3aba2eaa1fada551a9c8b3b5ecd1ef86e6e58a5f1aab952c")
.unwrap();
assert!(sighash_out_len == sighash.len() as c_uint);
std::ptr::copy_nonoverlapping(sighash.as_ptr(), sighash_out, sighash.len());
}
}
#[test]
fn it_works() {
let coin = i64::pow(10, 8);
let nLockTime: i64 = 2410374;
let isFinal: u8 = 1;
let script_pub_key = &*SCRIPT_PUBKEY;
let amount = 212 * coin;
let tx_to = &*SCRIPT_TX;
let nIn = 0;
let flags = 1;
let branch_id = 0x2bb40e60;
let script_sig = &*SCRIPT_SIG;
let flags: c_uint = 513;
let mut err = 0;
verify_script(script_pub_key, amount, tx_to, nIn, flags, branch_id).unwrap();
let ret = unsafe {
super::zcash_script_verify_callback(
std::ptr::null(),
Some(sighash),
nLockTime,
isFinal,
script_pub_key.as_ptr(),
script_pub_key.len() as c_uint,
script_sig.as_ptr(),
script_sig.len() as c_uint,
flags,
&mut err,
)
};
assert!(ret == 1);
}
#[test]
fn it_works_precomputed() {
let coin = i64::pow(10, 8);
fn it_fails_on_invalid_sighash() {
let nLockTime: i64 = 2410374;
let isFinal: u8 = 1;
let script_pub_key = &*SCRIPT_PUBKEY;
let amount = 212 * coin;
let tx_to = &*SCRIPT_TX;
let nIn = 0;
let flags = 1;
let branch_id = 0x2bb40e60;
let script_sig = &*SCRIPT_SIG;
let flags: c_uint = 513;
let mut err = 0;
verify_script_precompute(script_pub_key, amount, tx_to, nIn, flags, branch_id).unwrap();
}
let ret = unsafe {
super::zcash_script_verify_callback(
std::ptr::null(),
Some(invalid_sighash),
nLockTime,
isFinal,
script_pub_key.as_ptr(),
script_pub_key.len() as c_uint,
script_sig.as_ptr(),
script_sig.len() as c_uint,
flags,
&mut err,
)
};
#[test]
fn it_doesnt_work() {
let coin = i64::pow(10, 8);
let script_pub_key = &*SCRIPT_PUBKEY;
let amount = 212 * coin;
let tx_to = &*SCRIPT_TX;
let nIn = 0;
let flags = 1;
let branch_id = 0x2bb40e61;
verify_script(script_pub_key, amount, tx_to, nIn, flags, branch_id).unwrap_err();
}
#[test]
fn it_doesnt_work_precomputed() {
let coin = i64::pow(10, 8);
let script_pub_key = &*SCRIPT_PUBKEY;
let amount = 212 * coin;
let tx_to = &*SCRIPT_TX;
let nIn = 0;
let flags = 1;
let branch_id = 0x2bb40e61;
verify_script_precompute(script_pub_key, amount, tx_to, nIn, flags, branch_id).unwrap_err();
assert!(ret != 1);
}
}

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/merkle_frontier.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/note_encryption.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/orchard_bundle.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/orchard_ffi.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/params.rs");

View File

@ -1,3 +0,0 @@
// Note that don't include the original file directly; but rather
// a copy of sapling.rs with name changed. See build.rs for the explanation.
include!(concat!(env!("OUT_DIR"), "/rust/sapling/mod.rs"));

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/streams.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/streams_ffi.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/test_harness_ffi.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/transaction_ffi.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/wallet.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/wallet_scanner.rs");

View File

@ -1 +0,0 @@
include!("../depend/zcash/src/rust/src/zcashd_orchard.rs");