Auto merge of #5213 - str4d:5201-zip-216, r=str4d
Implement ZIP 216 consensus rules In addition to the specified consensus rules, we unconditionally enable ZIP 216 in the following situations: - Wallet code - Transaction building - Nullifiers for wallet notes - Tests - Benchmarks Closes zcash/zcash#5201.
This commit is contained in:
commit
1249659a3b
|
@ -473,7 +473,7 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
|
|||
[[package]]
|
||||
name = "equihash"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=2ba80739710f2511b18b67a7f9e082d390427a00#2ba80739710f2511b18b67a7f9e082d390427a00"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb#3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
|
@ -1683,7 +1683,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_note_encryption"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=2ba80739710f2511b18b67a7f9e082d390427a00#2ba80739710f2511b18b67a7f9e082d390427a00"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb#3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
|
@ -1697,7 +1697,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=2ba80739710f2511b18b67a7f9e082d390427a00#2ba80739710f2511b18b67a7f9e082d390427a00"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb#3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bitvec",
|
||||
|
@ -1727,7 +1727,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_proofs"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=2ba80739710f2511b18b67a7f9e082d390427a00#2ba80739710f2511b18b67a7f9e082d390427a00"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb#3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb"
|
||||
dependencies = [
|
||||
"bellman",
|
||||
"blake2b_simd",
|
||||
|
|
|
@ -58,5 +58,5 @@ codegen-units = 1
|
|||
[patch.crates-io]
|
||||
ed25519-zebra = { git = "https://github.com/ZcashFoundation/ed25519-zebra.git", rev = "d3512400227a362d08367088ffaa9bd4142a69c7" }
|
||||
orchard = { git = "https://github.com/zcash/orchard.git", rev = "cd1e72bbcd9f2e873408aa365537c89824cb7430" }
|
||||
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "2ba80739710f2511b18b67a7f9e082d390427a00" }
|
||||
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "2ba80739710f2511b18b67a7f9e082d390427a00" }
|
||||
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb" }
|
||||
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "3915abd0a1ee5b7e757c3fec0509d71f5e08fdfb" }
|
||||
|
|
|
@ -102,7 +102,7 @@ static void SaplingSpend(benchmark::State& state)
|
|||
ss >> spend;
|
||||
uint256 dataToBeSigned = uint256S("0x2dbf83fe7b88a7cbd80fac0c719483906bb9a0c4fc69071e4780d5f2c76e592c");
|
||||
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init();
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(true);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
librustzcash_sapling_check_spend(
|
||||
|
@ -128,7 +128,7 @@ static void SaplingOutput(benchmark::State& state)
|
|||
PROTOCOL_VERSION);
|
||||
ss >> output;
|
||||
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init();
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(true);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
librustzcash_sapling_check_output(
|
||||
|
|
|
@ -819,6 +819,7 @@ bool ContextualCheckTransaction(
|
|||
bool beforeOverwinter = !overwinterActive;
|
||||
bool heartwoodActive = consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_HEARTWOOD);
|
||||
bool canopyActive = consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_CANOPY);
|
||||
bool nu5Active = consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_NU5);
|
||||
bool futureActive = consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_ZFUTURE);
|
||||
|
||||
assert(!saplingActive || overwinterActive); // Sapling cannot be active unless Overwinter is
|
||||
|
@ -1121,7 +1122,12 @@ bool ContextualCheckTransaction(
|
|||
if (!tx.vShieldedSpend.empty() ||
|
||||
!tx.vShieldedOutput.empty())
|
||||
{
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init();
|
||||
// The nu5Active flag passed in here enables the new consensus rules from ZIP 216
|
||||
// (https://zips.z.cash/zip-0216#specification) on the following fields:
|
||||
//
|
||||
// - spendAuthSig in Sapling Spend descriptions
|
||||
// - bindingSigSapling
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(nu5Active);
|
||||
|
||||
for (const SpendDescription &spend : tx.vShieldedSpend) {
|
||||
if (!librustzcash_sapling_check_spend(
|
||||
|
|
|
@ -156,7 +156,9 @@ extern "C" {
|
|||
|
||||
/// Creates a Sapling verification context. Please free this
|
||||
/// when you're done.
|
||||
void * librustzcash_sapling_verification_ctx_init();
|
||||
void * librustzcash_sapling_verification_ctx_init(
|
||||
bool zip216Enabled
|
||||
);
|
||||
|
||||
/// Check the validity of a Sapling Spend description,
|
||||
/// accumulating the value commitment into the context.
|
||||
|
@ -218,6 +220,7 @@ extern "C" {
|
|||
/// The result is also of length 32 and placed in `result`.
|
||||
/// Returns false if the diversifier or pk_d is not valid
|
||||
bool librustzcash_sapling_compute_cmu(
|
||||
bool zip216_enabled,
|
||||
const unsigned char *diversifier,
|
||||
const unsigned char *pk_d,
|
||||
const uint64_t value,
|
||||
|
@ -231,6 +234,7 @@ extern "C" {
|
|||
/// the result is written to the 32-byte
|
||||
/// `result` buffer.
|
||||
bool librustzcash_sapling_ka_agree(
|
||||
bool zip216_enabled,
|
||||
const unsigned char *p,
|
||||
const unsigned char *sk,
|
||||
unsigned char *result
|
||||
|
|
|
@ -316,6 +316,7 @@ pub extern "C" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32]) {
|
|||
|
||||
// Private utility function to get Note from C parameters
|
||||
fn priv_get_note(
|
||||
zip216_enabled: bool,
|
||||
diversifier: *const [c_uchar; 11],
|
||||
pk_d: *const [c_uchar; 32],
|
||||
value: u64,
|
||||
|
@ -324,7 +325,12 @@ fn priv_get_note(
|
|||
let diversifier = Diversifier(unsafe { *diversifier });
|
||||
let g_d = diversifier.g_d().ok_or(())?;
|
||||
|
||||
let pk_d = de_ct(jubjub::ExtendedPoint::from_bytes(unsafe { &*pk_d })).ok_or(())?;
|
||||
let pk_d = de_ct(if zip216_enabled {
|
||||
jubjub::ExtendedPoint::from_bytes(unsafe { &*pk_d })
|
||||
} else {
|
||||
jubjub::AffinePoint::from_bytes_pre_zip216_compatibility(unsafe { *pk_d }).map(|p| p.into())
|
||||
})
|
||||
.ok_or(())?;
|
||||
|
||||
let pk_d = de_ct(pk_d.into_subgroup()).ok_or(())?;
|
||||
|
||||
|
@ -360,7 +366,9 @@ pub extern "C" fn librustzcash_sapling_compute_nf(
|
|||
position: u64,
|
||||
result: *mut [c_uchar; 32],
|
||||
) -> bool {
|
||||
let note = match priv_get_note(diversifier, pk_d, value, rcm) {
|
||||
// ZIP 216: Nullifier derivation is not consensus-critical
|
||||
// (nullifiers are revealed, not calculated by consensus).
|
||||
let note = match priv_get_note(true, diversifier, pk_d, value, rcm) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
@ -401,13 +409,14 @@ pub extern "C" fn librustzcash_sapling_compute_nf(
|
|||
/// Returns false if `diversifier` or `pk_d` is not valid.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sapling_compute_cmu(
|
||||
zip216_enabled: bool,
|
||||
diversifier: *const [c_uchar; 11],
|
||||
pk_d: *const [c_uchar; 32],
|
||||
value: u64,
|
||||
rcm: *const [c_uchar; 32],
|
||||
result: *mut [c_uchar; 32],
|
||||
) -> bool {
|
||||
let note = match priv_get_note(diversifier, pk_d, value, rcm) {
|
||||
let note = match priv_get_note(zip216_enabled, diversifier, pk_d, value, rcm) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
@ -424,12 +433,17 @@ pub extern "C" fn librustzcash_sapling_compute_cmu(
|
|||
/// the 32-byte `result` buffer.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sapling_ka_agree(
|
||||
zip216_enabled: bool,
|
||||
p: *const [c_uchar; 32],
|
||||
sk: *const [c_uchar; 32],
|
||||
result: *mut [c_uchar; 32],
|
||||
) -> bool {
|
||||
// Deserialize p
|
||||
let p = match de_ct(jubjub::ExtendedPoint::from_bytes(unsafe { &*p })) {
|
||||
let p = match de_ct(if zip216_enabled {
|
||||
jubjub::ExtendedPoint::from_bytes(unsafe { &*p })
|
||||
} else {
|
||||
jubjub::AffinePoint::from_bytes_pre_zip216_compatibility(unsafe { *p }).map(|p| p.into())
|
||||
}) {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
@ -505,8 +519,10 @@ pub extern "C" fn librustzcash_eh_isvalid(
|
|||
|
||||
/// Creates a Sapling verification context. Please free this when you're done.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sapling_verification_ctx_init() -> *mut SaplingVerificationContext {
|
||||
let ctx = Box::new(SaplingVerificationContext::new());
|
||||
pub extern "C" fn librustzcash_sapling_verification_ctx_init(
|
||||
zip216_enabled: bool,
|
||||
) -> *mut SaplingVerificationContext {
|
||||
let ctx = Box::new(SaplingVerificationContext::new(zip216_enabled));
|
||||
|
||||
Box::into_raw(ctx)
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ fn test_key_agreement() {
|
|||
let addr_pk_d = addr.pk_d().to_bytes();
|
||||
|
||||
assert!(librustzcash_sapling_ka_agree(
|
||||
true,
|
||||
&addr_pk_d,
|
||||
&esk,
|
||||
&mut shared_secret_sender
|
||||
|
@ -61,6 +62,7 @@ fn test_key_agreement() {
|
|||
// Create sharedSecret with ephemeral key
|
||||
let mut shared_secret_recipient = [0u8; 32];
|
||||
assert!(librustzcash_sapling_ka_agree(
|
||||
true,
|
||||
&epk,
|
||||
&ivk_serialized,
|
||||
&mut shared_secret_recipient
|
||||
|
|
|
@ -649,6 +649,7 @@ fn notes() {
|
|||
// Compute commitment and compare with test vector
|
||||
let mut result = [0u8; 32];
|
||||
assert!(librustzcash_sapling_compute_cmu(
|
||||
true,
|
||||
&tv.default_d,
|
||||
&tv.default_pk_d,
|
||||
tv.note_v,
|
||||
|
|
|
@ -2453,6 +2453,8 @@ std::optional<std::pair<
|
|||
SaplingPaymentAddress>> CWalletTx::RecoverSaplingNoteWithoutLeadByteCheck(SaplingOutPoint op, std::set<uint256>& ovks) const
|
||||
{
|
||||
auto output = this->vShieldedOutput[op.n];
|
||||
// ZIP 216: This wallet method is not called from consensus rules.
|
||||
bool zip216Enabled = true;
|
||||
|
||||
for (auto ovk : ovks) {
|
||||
auto outPt = SaplingOutgoingPlaintext::decrypt(
|
||||
|
@ -2466,13 +2468,15 @@ std::optional<std::pair<
|
|||
continue;
|
||||
}
|
||||
|
||||
auto optDeserialized = SaplingNotePlaintext::attempt_sapling_enc_decryption_deserialization(output.encCiphertext, output.ephemeralKey, outPt->esk, outPt->pk_d);
|
||||
auto optDeserialized = SaplingNotePlaintext::attempt_sapling_enc_decryption_deserialization(
|
||||
zip216Enabled, output.encCiphertext, output.ephemeralKey, outPt->esk, outPt->pk_d);
|
||||
|
||||
// The transaction would not have entered the wallet unless
|
||||
// its plaintext had been successfully decrypted previously.
|
||||
assert(optDeserialized != std::nullopt);
|
||||
|
||||
auto maybe_pt = SaplingNotePlaintext::plaintext_checks_without_height(
|
||||
zip216Enabled,
|
||||
*optDeserialized,
|
||||
output.ephemeralKey,
|
||||
outPt->esk,
|
||||
|
|
|
@ -66,7 +66,9 @@ SaplingNote::SaplingNote(
|
|||
std::optional<uint256> SaplingNote::cmu() const {
|
||||
uint256 result;
|
||||
uint256 rcm_tmp = rcm();
|
||||
// ZIP 216: This method is only called from test code.
|
||||
if (!librustzcash_sapling_compute_cmu(
|
||||
true,
|
||||
d.data(),
|
||||
pk_d.begin(),
|
||||
value(),
|
||||
|
@ -276,6 +278,8 @@ std::optional<SaplingNotePlaintext> SaplingNotePlaintext::plaintext_checks_witho
|
|||
const uint256 &cmu
|
||||
)
|
||||
{
|
||||
// ZIP 216: pk_d here is serialized from Rust,
|
||||
// and thus has always used the canonical encoding.
|
||||
uint256 pk_d;
|
||||
if (!librustzcash_ivk_to_pkd(ivk.begin(), plaintext.d.data(), pk_d.begin())) {
|
||||
return std::nullopt;
|
||||
|
@ -284,6 +288,7 @@ std::optional<SaplingNotePlaintext> SaplingNotePlaintext::plaintext_checks_witho
|
|||
uint256 cmu_expected;
|
||||
uint256 rcm = plaintext.rcm();
|
||||
if (!librustzcash_sapling_compute_cmu(
|
||||
true,
|
||||
plaintext.d.data(),
|
||||
pk_d.begin(),
|
||||
plaintext.value(),
|
||||
|
@ -325,7 +330,12 @@ std::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
|
|||
const uint256 &cmu
|
||||
)
|
||||
{
|
||||
auto ret = attempt_sapling_enc_decryption_deserialization(ciphertext, epk, esk, pk_d);
|
||||
// The nu5Active flag passed in here enables the new consensus rules from ZIP 216
|
||||
// (https://zips.z.cash/zip-0216#specification) on the following fields:
|
||||
//
|
||||
// - pk_d in the outCiphertext field of Sapling coinbase outputs.
|
||||
bool nu5Active = params.NetworkUpgradeActive(height, Consensus::UPGRADE_NU5);
|
||||
auto ret = attempt_sapling_enc_decryption_deserialization(nu5Active, ciphertext, epk, esk, pk_d);
|
||||
|
||||
if (!ret) {
|
||||
return std::nullopt;
|
||||
|
@ -339,18 +349,19 @@ std::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
return plaintext_checks_without_height(plaintext, epk, esk, pk_d, cmu);
|
||||
return plaintext_checks_without_height(nu5Active, plaintext, epk, esk, pk_d, cmu);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<SaplingNotePlaintext> SaplingNotePlaintext::attempt_sapling_enc_decryption_deserialization(
|
||||
bool zip216Enabled,
|
||||
const SaplingEncCiphertext &ciphertext,
|
||||
const uint256 &epk,
|
||||
const uint256 &esk,
|
||||
const uint256 &pk_d
|
||||
)
|
||||
{
|
||||
auto encPlaintext = AttemptSaplingEncDecryption(ciphertext, epk, esk, pk_d);
|
||||
auto encPlaintext = AttemptSaplingEncDecryption(zip216Enabled, ciphertext, epk, esk, pk_d);
|
||||
|
||||
if (!encPlaintext) {
|
||||
return std::nullopt;
|
||||
|
@ -372,6 +383,7 @@ std::optional<SaplingNotePlaintext> SaplingNotePlaintext::attempt_sapling_enc_de
|
|||
}
|
||||
|
||||
std::optional<SaplingNotePlaintext> SaplingNotePlaintext::plaintext_checks_without_height(
|
||||
bool zip216Enabled,
|
||||
const SaplingNotePlaintext &plaintext,
|
||||
const uint256 &epk,
|
||||
const uint256 &esk,
|
||||
|
@ -401,6 +413,7 @@ std::optional<SaplingNotePlaintext> SaplingNotePlaintext::plaintext_checks_witho
|
|||
uint256 cmu_expected;
|
||||
uint256 rcm = plaintext.rcm();
|
||||
if (!librustzcash_sapling_compute_cmu(
|
||||
zip216Enabled,
|
||||
plaintext.d.data(),
|
||||
pk_d.begin(),
|
||||
plaintext.value(),
|
||||
|
|
|
@ -193,6 +193,7 @@ public:
|
|||
);
|
||||
|
||||
static std::optional<SaplingNotePlaintext> plaintext_checks_without_height(
|
||||
bool zip216Enabled,
|
||||
const SaplingNotePlaintext &plaintext,
|
||||
const uint256 &epk,
|
||||
const uint256 &esk,
|
||||
|
@ -201,6 +202,7 @@ public:
|
|||
);
|
||||
|
||||
static std::optional<SaplingNotePlaintext> attempt_sapling_enc_decryption_deserialization(
|
||||
bool zip216Enabled,
|
||||
const SaplingEncCiphertext &ciphertext,
|
||||
const uint256 &epk,
|
||||
const uint256 &esk,
|
||||
|
|
|
@ -116,7 +116,10 @@ std::optional<SaplingEncCiphertext> SaplingNoteEncryption::encrypt_to_recipient(
|
|||
|
||||
uint256 dhsecret;
|
||||
|
||||
if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) {
|
||||
// The new consensus rules from ZIP 216 (https://zips.z.cash/zip-0216#specification)
|
||||
// on pk_d are enabled unconditionally, as they MAY be enforced in advance of NU5
|
||||
// activation.
|
||||
if (!librustzcash_sapling_ka_agree(true, pk_d.begin(), esk.begin(), dhsecret.begin())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -149,7 +152,9 @@ std::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
|
|||
{
|
||||
uint256 dhsecret;
|
||||
|
||||
if (!librustzcash_sapling_ka_agree(epk.begin(), ivk.begin(), dhsecret.begin())) {
|
||||
// ZIP 216: We can enable the rules unconditionally, because ephemeralKey has always
|
||||
// been required to not be small-order (https://zips.z.cash/zip-0216#specification).
|
||||
if (!librustzcash_sapling_ka_agree(true, epk.begin(), ivk.begin(), dhsecret.begin())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -177,6 +182,7 @@ std::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
|
|||
}
|
||||
|
||||
std::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption (
|
||||
bool zip216Enabled,
|
||||
const SaplingEncCiphertext &ciphertext,
|
||||
const uint256 &epk,
|
||||
const uint256 &esk,
|
||||
|
@ -185,7 +191,7 @@ std::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption (
|
|||
{
|
||||
uint256 dhsecret;
|
||||
|
||||
if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) {
|
||||
if (!librustzcash_sapling_ka_agree(zip216Enabled, pk_d.begin(), esk.begin(), dhsecret.begin())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ std::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
|
|||
// Attempts to decrypt a Sapling note using outgoing plaintext.
|
||||
// This will not check that the contents of the ciphertext are correct.
|
||||
std::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption (
|
||||
bool zip216Enabled,
|
||||
const SaplingEncCiphertext &ciphertext,
|
||||
const uint256 &epk,
|
||||
const uint256 &esk,
|
||||
|
|
|
@ -697,7 +697,7 @@ double benchmark_verify_sapling_spend()
|
|||
ss >> spend;
|
||||
uint256 dataToBeSigned = uint256S("0x2dbf83fe7b88a7cbd80fac0c719483906bb9a0c4fc69071e4780d5f2c76e592c");
|
||||
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init();
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(true);
|
||||
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
|
@ -730,7 +730,7 @@ double benchmark_verify_sapling_output()
|
|||
CDataStream ss(ParseHex("edd742af18857e5ec2d71d346a7fe2ac97c137339bd5268eea86d32e0ff4f38f76213fa8cfed3347ac4e8572dd88aff395c0c10a59f8b3f49d2bc539ed6c726667e29d4763f914ddd0abf1cdfa84e44de87c233434c7e69b8b5b8f4623c8aa444163425bae5cef842972fed66046c1c6ce65c866ad894d02e6e6dcaae7a962d9f2ef95757a09c486928e61f0f7aed90ad0a542b0d3dc5fe140dfa7626b9315c77e03b055f19cbacd21a866e46f06c00e0c7792b2a590a611439b510a9aaffcf1073bad23e712a9268b36888e3727033eee2ab4d869f54a843f93b36ef489fb177bf74b41a9644e5d2a0a417c6ac1c8869bc9b83273d453f878ed6fd96b82a5939903f7b64ecaf68ea16e255a7fb7cc0b6d8b5608a1c6b0ed3024cc62c2f0f9c5cfc7b431ae6e9d40815557aa1d010523f9e1960de77b2274cb6710d229d475c87ae900183206ba90cb5bbc8ec0df98341b82726c705e0308ca5dc08db4db609993a1046dfb43dfd8c760be506c0bed799bb2205fc29dc2e654dce731034a23b0aaf6da0199248702ee0523c159f41f4cbfff6c35ace4dd9ae834e44e09c76a0cbdda1d3f6a2c75ad71212daf9575ab5f09ca148718e667f29ddf18c8a330a86ace18a86e89454653902aa393c84c6b694f27d0d42e24e7ac9fe34733de5ec15f5066081ce912c62c1a804a2bb4dedcef7cc80274f6bb9e89e2fce91dc50d6a73c8aefb9872f1cf3524a92626a0b8f39bbf7bf7d96ca2f770fc04d7f457021c536a506a187a93b2245471ddbfb254a71bc4a0d72c8d639a31c7b1920087ffca05c24214157e2e7b28184e91989ef0b14f9b34c3dc3cc0ac64226b9e337095870cb0885737992e120346e630a416a9b217679ce5a778fb15779c136bcecca5efe79012013d77d90b4e99dd22c8f35bc77121716e160d05bd30d288ee8886390ee436f85bdc9029df888a3a3326d9d4ddba5cb5318b3274928829d662e96fea1d601f7a306251ed8c6cc4e5a3a7a98c35a3650482a0eee08f3b4c2da9b22947c96138f1505c2f081f8972d429f3871f32bef4aaa51aa6945df8e9c9760531ac6f627d17c1518202818a91ca304fb4037875c666060597976144fcbbc48a776a2c61beb9515fa8f3ae6d3a041d320a38a8ac75cb47bb9c866ee497fc3cd13299970c4b369c1c2ceb4220af082fbecdd8114492a8e4d713b5a73396fd224b36c1185bd5e20d683e6c8db35346c47ae7401988255da7cfffdced5801067d4d296688ee8fe424b4a8a69309ce257eefb9345ebfda3f6de46bb11ec94133e1f72cd7ac54934d6cf17b3440800e70b80ebc7c7bfc6fb0fc2c"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> output;
|
||||
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init();
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(true);
|
||||
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
|
|
Loading…
Reference in New Issue