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:
parent
ef2a7fdd5d
commit
4924030059
File diff suppressed because it is too large
Load Diff
79
Cargo.toml
79
Cargo.toml
|
@ -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
145
build.rs
|
@ -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(())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/blake2b.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/bridge.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/builder_ffi.rs");
|
|
@ -1,3 +0,0 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
include!("../depend/zcash/src/rust/src/bundlecache.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/incremental_merkle_tree.rs");
|
313
src/lib.rs
313
src/lib.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/merkle_frontier.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/note_encryption.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/orchard_bundle.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/orchard_ffi.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/params.rs");
|
|
@ -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"));
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/streams.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/streams_ffi.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/test_harness_ffi.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/transaction_ffi.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/wallet.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/wallet_scanner.rs");
|
|
@ -1 +0,0 @@
|
|||
include!("../depend/zcash/src/rust/src/zcashd_orchard.rs");
|
Loading…
Reference in New Issue