mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-11-02 04:17:02 +00:00
Update master
This commit is contained in:
@@ -1,20 +1,25 @@
|
||||
[package]
|
||||
name = "zcash_client_backend"
|
||||
version = "0.0.0"
|
||||
description = "APIs for creating shielded Zcash light clients"
|
||||
version = "0.2.0"
|
||||
authors = [
|
||||
"Jack Grigg <jack@z.cash>",
|
||||
]
|
||||
homepage = "https://github.com/zcash/librustzcash"
|
||||
repository = "https://github.com/zcash/librustzcash"
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bech32 = "0.7"
|
||||
bs58 = { version = "0.2", features = ["check"] }
|
||||
ff = { path = "../ff" }
|
||||
ff = { version = "0.6", path = "../ff" }
|
||||
hex = "0.3"
|
||||
pairing = { path = "../pairing" }
|
||||
pairing = { version = "0.16", path = "../pairing" }
|
||||
protobuf = "2"
|
||||
subtle = "2"
|
||||
zcash_primitives = { path = "../zcash_primitives" }
|
||||
zcash_primitives = { version = "0.2", path = "../zcash_primitives" }
|
||||
|
||||
[build-dependencies]
|
||||
protobuf-codegen-pure = "2"
|
||||
@@ -23,3 +28,6 @@ protobuf-codegen-pure = "2"
|
||||
rand_core = "0.5"
|
||||
rand_os = "0.2"
|
||||
rand_xorshift = "0.2"
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
# zcash_client_backend
|
||||
|
||||
This library contains Rust structs and traits for creating shielded Zcash light clients.
|
||||
This library contains Rust structs and traits for creating shielded Zcash light
|
||||
clients.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Zcash global and per-network constants.
|
||||
|
||||
pub mod mainnet;
|
||||
pub mod testnet;
|
||||
pub mod regtest;
|
||||
pub mod testnet;
|
||||
|
||||
pub const SPROUT_CONSENSUS_BRANCH_ID: u32 = 0;
|
||||
pub const OVERWINTER_CONSENSUS_BRANCH_ID: u32 = 0x5ba8_1b19;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Constants for the Zcash main network.
|
||||
|
||||
/// The mainnet coin type for ZEC, as defined by [SLIP 44].
|
||||
///
|
||||
/// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
||||
@@ -23,7 +25,7 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviews";
|
||||
///
|
||||
/// Defined in section 5.6.4 of the [Zcash Protocol Specification].
|
||||
///
|
||||
/// [`PaymentAddress`]: sapling_crypto::primitives::PaymentAddress
|
||||
/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress
|
||||
/// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
|
||||
pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "zs";
|
||||
|
||||
|
||||
@@ -1,38 +1,45 @@
|
||||
/// The testnet coin type for ZEC, as defined by [SLIP 44].
|
||||
///
|
||||
/// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
||||
//! # Regtest constants
|
||||
//!
|
||||
//! `regtest` is a `zcashd`-specific environment used for local testing. They mostly reuse
|
||||
//! the testnet constants.
|
||||
//! These constants are defined in [the `zcashd` codebase].
|
||||
//! [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L482-L496
|
||||
|
||||
/// The regtest cointype reuses the testnet cointype
|
||||
pub const COIN_TYPE: u32 = 1;
|
||||
|
||||
/// The HRP for a Bech32-encoded testnet [`ExtendedSpendingKey`].
|
||||
/// The HRP for a Bech32-encoded regtest [`ExtendedSpendingKey`].
|
||||
///
|
||||
/// Defined in [ZIP 32].
|
||||
/// It is defined in [the `zcashd` codebase].
|
||||
///
|
||||
/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey
|
||||
/// [ZIP 32]: https://github.com/zcash/zips/blob/master/zip-0032.rst
|
||||
/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L496
|
||||
pub const HRP_SAPLING_EXTENDED_SPENDING_KEY: &str = "secret-extended-key-regtest";
|
||||
|
||||
/// The HRP for a Bech32-encoded testnet [`ExtendedFullViewingKey`].
|
||||
/// The HRP for a Bech32-encoded regtest [`ExtendedFullViewingKey`].
|
||||
///
|
||||
/// Defined in [ZIP 32].
|
||||
/// It is defined in [the `zcashd` codebase].
|
||||
///
|
||||
/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey
|
||||
/// [ZIP 32]: https://github.com/zcash/zips/blob/master/zip-0032.rst
|
||||
/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L494
|
||||
pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewregtestsapling";
|
||||
|
||||
/// The HRP for a Bech32-encoded testnet [`PaymentAddress`].
|
||||
/// The HRP for a Bech32-encoded regtest [`PaymentAddress`].
|
||||
///
|
||||
/// Defined in section 5.6.4 of the [Zcash Protocol Specification].
|
||||
/// It is defined in [the `zcashd` codebase].
|
||||
///
|
||||
/// [`PaymentAddress`]: sapling_crypto::primitives::PaymentAddress
|
||||
/// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
|
||||
/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress
|
||||
/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L493
|
||||
pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "zregtestsapling";
|
||||
|
||||
/// The prefix for a Base58Check-encoded testnet [`TransparentAddress::PublicKey`].
|
||||
/// The prefix for a Base58Check-encoded regtest [`TransparentAddress::PublicKey`].
|
||||
/// Same as the testnet prefix.
|
||||
///
|
||||
/// [`TransparentAddress::PublicKey`]: zcash_primitives::legacy::TransparentAddress::PublicKey
|
||||
pub const B58_PUBKEY_ADDRESS_PREFIX: [u8; 2] = [0x1d, 0x25];
|
||||
|
||||
/// The prefix for a Base58Check-encoded testnet [`TransparentAddress::Script`].
|
||||
/// The prefix for a Base58Check-encoded regtest [`TransparentAddress::Script`].
|
||||
/// Same as the testnet prefix.
|
||||
///
|
||||
/// [`TransparentAddress::Script`]: zcash_primitives::legacy::TransparentAddress::Script
|
||||
pub const B58_SCRIPT_ADDRESS_PREFIX: [u8; 2] = [0x1c, 0xba];
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Constants for the Zcash test network.
|
||||
|
||||
/// The testnet coin type for ZEC, as defined by [SLIP 44].
|
||||
///
|
||||
/// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
||||
@@ -23,7 +25,7 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewtestsapling";
|
||||
///
|
||||
/// Defined in section 5.6.4 of the [Zcash Protocol Specification].
|
||||
///
|
||||
/// [`PaymentAddress`]: sapling_crypto::primitives::PaymentAddress
|
||||
/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress
|
||||
/// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
|
||||
pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "ztestsapling";
|
||||
|
||||
|
||||
76
zcash_client_backend/src/decrypt.rs
Normal file
76
zcash_client_backend/src/decrypt.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use pairing::bls12_381::Bls12;
|
||||
use zcash_primitives::{
|
||||
note_encryption::{try_sapling_note_decryption, try_sapling_output_recovery, Memo},
|
||||
primitives::{Note, PaymentAddress},
|
||||
transaction::Transaction,
|
||||
zip32::ExtendedFullViewingKey,
|
||||
JUBJUB,
|
||||
};
|
||||
|
||||
/// A decrypted shielded output.
|
||||
pub struct DecryptedOutput {
|
||||
/// The index of the output within [`shielded_outputs`].
|
||||
///
|
||||
/// [`shielded_outputs`]: zcash_primitives::transaction::TransactionData
|
||||
pub index: usize,
|
||||
/// The note within the output.
|
||||
pub note: Note<Bls12>,
|
||||
/// The address the note was sent to.
|
||||
pub to: PaymentAddress<Bls12>,
|
||||
/// The memo included with the note.
|
||||
pub memo: Memo,
|
||||
/// True if this output was recovered using an [`OutgoingViewingKey`], meaning that
|
||||
/// this is a logical output of the transaction.
|
||||
///
|
||||
/// [`OutgoingViewingKey`]: zcash_primitives::keys::OutgoingViewingKey
|
||||
pub outgoing: bool,
|
||||
}
|
||||
|
||||
/// Scans a [`Transaction`] for any information that can be decrypted by the set of
|
||||
/// [`ExtendedFullViewingKey`]s.
|
||||
pub fn decrypt_transaction(
|
||||
tx: &Transaction,
|
||||
extfvks: &[ExtendedFullViewingKey],
|
||||
) -> Vec<DecryptedOutput> {
|
||||
let mut decrypted = vec![];
|
||||
|
||||
// Cache IncomingViewingKey calculation
|
||||
let vks: Vec<_> = extfvks
|
||||
.iter()
|
||||
.map(|extfvk| (extfvk.fvk.vk.ivk(), extfvk.fvk.ovk))
|
||||
.collect();
|
||||
|
||||
for (index, output) in tx.shielded_outputs.iter().enumerate() {
|
||||
let epk = match output.ephemeral_key.as_prime_order(&JUBJUB) {
|
||||
Some(p) => p,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
for (ivk, ovk) in &vks {
|
||||
let ((note, to, memo), outgoing) =
|
||||
match try_sapling_note_decryption(ivk, &epk, &output.cmu, &output.enc_ciphertext) {
|
||||
Some(ret) => (ret, false),
|
||||
None => match try_sapling_output_recovery(
|
||||
ovk,
|
||||
&output.cv,
|
||||
&output.cmu,
|
||||
&epk,
|
||||
&output.enc_ciphertext,
|
||||
&output.out_ciphertext,
|
||||
) {
|
||||
Some(ret) => (ret, true),
|
||||
None => continue,
|
||||
},
|
||||
};
|
||||
decrypted.push(DecryptedOutput {
|
||||
index,
|
||||
note,
|
||||
to,
|
||||
memo,
|
||||
outgoing,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
decrypted
|
||||
}
|
||||
@@ -2,17 +2,14 @@
|
||||
//!
|
||||
//! Human-Readable Prefixes (HRPs) for Bech32 encodings are located in the [`constants`]
|
||||
//! module.
|
||||
//!
|
||||
//! [`constants`]: crate::constants
|
||||
|
||||
use bech32::{self, Error, FromBase32, ToBase32};
|
||||
use bs58::{self, decode::DecodeError};
|
||||
use pairing::bls12_381::Bls12;
|
||||
use std::io::{self, Write};
|
||||
use zcash_primitives::{
|
||||
jubjub::edwards,
|
||||
primitives::{Diversifier, PaymentAddress},
|
||||
};
|
||||
use zcash_primitives::{
|
||||
legacy::TransparentAddress,
|
||||
primitives::{PaymentAddress},
|
||||
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
|
||||
JUBJUB,
|
||||
};
|
||||
@@ -115,10 +112,11 @@ pub fn decode_extended_full_viewing_key(
|
||||
/// 0xbc, 0xe5,
|
||||
/// ]);
|
||||
///
|
||||
/// let pa = PaymentAddress {
|
||||
/// diversifier: Diversifier([0u8; 11]),
|
||||
/// pk_d: edwards::Point::<Bls12, _>::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB),
|
||||
/// };
|
||||
/// let pa = PaymentAddress::from_parts(
|
||||
/// Diversifier([0u8; 11]),
|
||||
/// edwards::Point::<Bls12, _>::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB),
|
||||
/// )
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &pa),
|
||||
@@ -126,10 +124,7 @@ pub fn decode_extended_full_viewing_key(
|
||||
/// );
|
||||
/// ```
|
||||
pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress<Bls12>) -> String {
|
||||
bech32_encode(hrp, |w| {
|
||||
w.write_all(&addr.diversifier.0)?;
|
||||
addr.pk_d.write(w)
|
||||
})
|
||||
bech32_encode(hrp, |w| w.write_all(&addr.to_bytes()))
|
||||
}
|
||||
|
||||
/// Decodes a [`PaymentAddress`] from a Bech32-encoded string.
|
||||
@@ -155,10 +150,11 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress<Bls12>) -> String
|
||||
/// 0xbc, 0xe5,
|
||||
/// ]);
|
||||
///
|
||||
/// let pa = PaymentAddress {
|
||||
/// diversifier: Diversifier([0u8; 11]),
|
||||
/// pk_d: edwards::Point::<Bls12, _>::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB),
|
||||
/// };
|
||||
/// let pa = PaymentAddress::from_parts(
|
||||
/// Diversifier([0u8; 11]),
|
||||
/// edwards::Point::<Bls12, _>::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB),
|
||||
/// )
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// decode_payment_address(
|
||||
@@ -170,127 +166,16 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress<Bls12>) -> String
|
||||
/// ```
|
||||
pub fn decode_payment_address(hrp: &str, s: &str) -> Result<Option<PaymentAddress<Bls12>>, Error> {
|
||||
bech32_decode(hrp, s, |data| {
|
||||
let mut diversifier = Diversifier([0; 11]);
|
||||
diversifier.0.copy_from_slice(&data[0..11]);
|
||||
// Check that the diversifier is valid
|
||||
if diversifier.g_d::<Bls12>(&JUBJUB).is_none() {
|
||||
if data.len() != 43 {
|
||||
return None;
|
||||
}
|
||||
|
||||
edwards::Point::<Bls12, _>::read(&data[11..], &JUBJUB)
|
||||
.ok()?
|
||||
.as_prime_order(&JUBJUB)
|
||||
.map(|pk_d| PaymentAddress { pk_d, diversifier })
|
||||
let mut bytes = [0; 43];
|
||||
bytes.copy_from_slice(&data);
|
||||
PaymentAddress::<Bls12>::from_bytes(&bytes, &JUBJUB)
|
||||
})
|
||||
}
|
||||
|
||||
/// Writes a [`TransparentAddress`] as a Base58Check-encoded string.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use zcash_client_backend::{
|
||||
/// constants::testnet::{B58_PUBKEY_ADDRESS_PREFIX, B58_SCRIPT_ADDRESS_PREFIX},
|
||||
/// encoding::encode_transparent_address,
|
||||
/// };
|
||||
/// use zcash_primitives::legacy::TransparentAddress;
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// encode_transparent_address(
|
||||
/// &B58_PUBKEY_ADDRESS_PREFIX,
|
||||
/// &B58_SCRIPT_ADDRESS_PREFIX,
|
||||
/// &TransparentAddress::PublicKey([0; 20]),
|
||||
/// ),
|
||||
/// "tm9iMLAuYMzJ6jtFLcA7rzUmfreGuKvr7Ma",
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// encode_transparent_address(
|
||||
/// &B58_PUBKEY_ADDRESS_PREFIX,
|
||||
/// &B58_SCRIPT_ADDRESS_PREFIX,
|
||||
/// &TransparentAddress::Script([0; 20]),
|
||||
/// ),
|
||||
/// "t26YoyZ1iPgiMEWL4zGUm74eVWfhyDMXzY2",
|
||||
/// );
|
||||
/// ```
|
||||
pub fn encode_transparent_address(
|
||||
pubkey_version: &[u8],
|
||||
script_version: &[u8],
|
||||
addr: &TransparentAddress,
|
||||
) -> String {
|
||||
let decoded = match addr {
|
||||
TransparentAddress::PublicKey(key_id) => {
|
||||
let mut decoded = vec![0; pubkey_version.len() + 20];
|
||||
decoded[..pubkey_version.len()].copy_from_slice(pubkey_version);
|
||||
decoded[pubkey_version.len()..].copy_from_slice(key_id);
|
||||
decoded
|
||||
}
|
||||
TransparentAddress::Script(script_id) => {
|
||||
let mut decoded = vec![0; script_version.len() + 20];
|
||||
decoded[..script_version.len()].copy_from_slice(script_version);
|
||||
decoded[script_version.len()..].copy_from_slice(script_id);
|
||||
decoded
|
||||
}
|
||||
};
|
||||
bs58::encode(decoded).with_check().into_string()
|
||||
}
|
||||
|
||||
/// Decodes a [`TransparentAddress`] from a Base58Check-encoded string.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use zcash_client_backend::{
|
||||
/// constants::testnet::{B58_PUBKEY_ADDRESS_PREFIX, B58_SCRIPT_ADDRESS_PREFIX},
|
||||
/// encoding::decode_transparent_address,
|
||||
/// };
|
||||
/// use zcash_primitives::legacy::TransparentAddress;
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// decode_transparent_address(
|
||||
/// &B58_PUBKEY_ADDRESS_PREFIX,
|
||||
/// &B58_SCRIPT_ADDRESS_PREFIX,
|
||||
/// "tm9iMLAuYMzJ6jtFLcA7rzUmfreGuKvr7Ma",
|
||||
/// ),
|
||||
/// Ok(Some(TransparentAddress::PublicKey([0; 20]))),
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// decode_transparent_address(
|
||||
/// &B58_PUBKEY_ADDRESS_PREFIX,
|
||||
/// &B58_SCRIPT_ADDRESS_PREFIX,
|
||||
/// "t26YoyZ1iPgiMEWL4zGUm74eVWfhyDMXzY2",
|
||||
/// ),
|
||||
/// Ok(Some(TransparentAddress::Script([0; 20]))),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn decode_transparent_address(
|
||||
pubkey_version: &[u8],
|
||||
script_version: &[u8],
|
||||
s: &str,
|
||||
) -> Result<Option<TransparentAddress>, DecodeError> {
|
||||
let decoded = bs58::decode(s).with_check(None).into_vec()?;
|
||||
if &decoded[..pubkey_version.len()] == pubkey_version {
|
||||
if decoded.len() == pubkey_version.len() + 20 {
|
||||
let mut data = [0; 20];
|
||||
data.copy_from_slice(&decoded[pubkey_version.len()..]);
|
||||
Ok(Some(TransparentAddress::PublicKey(data)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else if &decoded[..script_version.len()] == script_version {
|
||||
if decoded.len() == script_version.len() + 20 {
|
||||
let mut data = [0; 20];
|
||||
data.copy_from_slice(&decoded[script_version.len()..]);
|
||||
Ok(Some(TransparentAddress::Script(data)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pairing::bls12_381::Bls12;
|
||||
@@ -300,11 +185,95 @@ mod tests {
|
||||
use zcash_primitives::{
|
||||
jubjub::edwards,
|
||||
primitives::{Diversifier, PaymentAddress},
|
||||
zip32::ExtendedSpendingKey,
|
||||
};
|
||||
|
||||
use super::{decode_payment_address, encode_payment_address};
|
||||
use super::{
|
||||
decode_extended_full_viewing_key, decode_extended_spending_key, decode_payment_address,
|
||||
encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address,
|
||||
};
|
||||
use crate::constants;
|
||||
|
||||
#[test]
|
||||
fn extended_spending_key() {
|
||||
let extsk = ExtendedSpendingKey::master(&[0; 32][..]);
|
||||
|
||||
let encoded_main = "secret-extended-key-main1qqqqqqqqqqqqqq8n3zjjmvhhr854uy3qhpda3ml34haf0x388z5r7h4st4kpsf6qysqws3xh6qmha7gna72fs2n4clnc9zgyd22s658f65pex4exe56qjk5pqj9vfdq7dfdhjc2rs9jdwq0zl99uwycyrxzp86705rk687spn44e2uhm7h0hsagfvkk4n7n6nfer6u57v9cac84t7nl2zth0xpyfeg0w2p2wv2yn6jn923aaz0vdaml07l60ahapk6efchyxwysrvjs87qvlj";
|
||||
let encoded_test = "secret-extended-key-test1qqqqqqqqqqqqqq8n3zjjmvhhr854uy3qhpda3ml34haf0x388z5r7h4st4kpsf6qysqws3xh6qmha7gna72fs2n4clnc9zgyd22s658f65pex4exe56qjk5pqj9vfdq7dfdhjc2rs9jdwq0zl99uwycyrxzp86705rk687spn44e2uhm7h0hsagfvkk4n7n6nfer6u57v9cac84t7nl2zth0xpyfeg0w2p2wv2yn6jn923aaz0vdaml07l60ahapk6efchyxwysrvjsvzyw8j";
|
||||
|
||||
assert_eq!(
|
||||
encode_extended_spending_key(
|
||||
constants::mainnet::HRP_SAPLING_EXTENDED_SPENDING_KEY,
|
||||
&extsk
|
||||
),
|
||||
encoded_main
|
||||
);
|
||||
assert_eq!(
|
||||
decode_extended_spending_key(
|
||||
constants::mainnet::HRP_SAPLING_EXTENDED_SPENDING_KEY,
|
||||
encoded_main
|
||||
)
|
||||
.unwrap(),
|
||||
Some(extsk.clone())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
encode_extended_spending_key(
|
||||
constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY,
|
||||
&extsk
|
||||
),
|
||||
encoded_test
|
||||
);
|
||||
assert_eq!(
|
||||
decode_extended_spending_key(
|
||||
constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY,
|
||||
encoded_test
|
||||
)
|
||||
.unwrap(),
|
||||
Some(extsk)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extended_full_viewing_key() {
|
||||
let extfvk = (&ExtendedSpendingKey::master(&[0; 32][..])).into();
|
||||
|
||||
let encoded_main = "zxviews1qqqqqqqqqqqqqq8n3zjjmvhhr854uy3qhpda3ml34haf0x388z5r7h4st4kpsf6qy3zw4wc246aw9rlfyg5ndlwvne7mwdq0qe6vxl42pqmcf8pvmmd5slmjxduqa9evgej6wa3th2505xq4nggrxdm93rxk4rpdjt5nmq2vn44e2uhm7h0hsagfvkk4n7n6nfer6u57v9cac84t7nl2zth0xpyfeg0w2p2wv2yn6jn923aaz0vdaml07l60ahapk6efchyxwysrvjsxmansf";
|
||||
let encoded_test = "zxviewtestsapling1qqqqqqqqqqqqqq8n3zjjmvhhr854uy3qhpda3ml34haf0x388z5r7h4st4kpsf6qy3zw4wc246aw9rlfyg5ndlwvne7mwdq0qe6vxl42pqmcf8pvmmd5slmjxduqa9evgej6wa3th2505xq4nggrxdm93rxk4rpdjt5nmq2vn44e2uhm7h0hsagfvkk4n7n6nfer6u57v9cac84t7nl2zth0xpyfeg0w2p2wv2yn6jn923aaz0vdaml07l60ahapk6efchyxwysrvjs8evfkz";
|
||||
|
||||
assert_eq!(
|
||||
encode_extended_full_viewing_key(
|
||||
constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||
&extfvk
|
||||
),
|
||||
encoded_main
|
||||
);
|
||||
assert_eq!(
|
||||
decode_extended_full_viewing_key(
|
||||
constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||
encoded_main
|
||||
)
|
||||
.unwrap(),
|
||||
Some(extfvk.clone())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
encode_extended_full_viewing_key(
|
||||
constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||
&extfvk
|
||||
),
|
||||
encoded_test
|
||||
);
|
||||
assert_eq!(
|
||||
decode_extended_full_viewing_key(
|
||||
constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||
encoded_test
|
||||
)
|
||||
.unwrap(),
|
||||
Some(extfvk)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payment_address() {
|
||||
let rng = &mut XorShiftRng::from_seed([
|
||||
@@ -312,10 +281,11 @@ mod tests {
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let addr = PaymentAddress {
|
||||
diversifier: Diversifier([0u8; 11]),
|
||||
pk_d: edwards::Point::<Bls12, _>::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB),
|
||||
};
|
||||
let addr = PaymentAddress::from_parts(
|
||||
Diversifier([0u8; 11]),
|
||||
edwards::Point::<Bls12, _>::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let encoded_main =
|
||||
"zs1qqqqqqqqqqqqqqqqqrjq05nyfku05msvu49mawhg6kr0wwljahypwyk2h88z6975u563j8nfaxd";
|
||||
@@ -356,10 +326,11 @@ mod tests {
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let addr = PaymentAddress {
|
||||
diversifier: Diversifier([1u8; 11]),
|
||||
pk_d: edwards::Point::<Bls12, _>::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB),
|
||||
};
|
||||
let addr = PaymentAddress::from_parts(
|
||||
Diversifier([1u8; 11]),
|
||||
edwards::Point::<Bls12, _>::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let encoded_main =
|
||||
encode_payment_address(constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS, &addr);
|
||||
|
||||
@@ -5,6 +5,10 @@ use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey};
|
||||
/// Derives the ZIP 32 [`ExtendedSpendingKey`] for a given coin type and account from the
|
||||
/// given seed.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `seed` is shorter than 32 bytes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@@ -13,6 +17,10 @@ use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey};
|
||||
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0);
|
||||
/// ```
|
||||
pub fn spending_key(seed: &[u8], coin_type: u32, account: u32) -> ExtendedSpendingKey {
|
||||
if seed.len() < 32 {
|
||||
panic!("ZIP 32 seeds MUST be at least 32 bytes");
|
||||
}
|
||||
|
||||
ExtendedSpendingKey::from_path(
|
||||
&ExtendedSpendingKey::master(&seed),
|
||||
&[
|
||||
@@ -22,3 +30,14 @@ pub fn spending_key(seed: &[u8], coin_type: u32, account: u32) -> ExtendedSpendi
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::spending_key;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn spending_key_panics_on_short_seed() {
|
||||
let _ = spending_key(&[0; 31][..], 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,15 @@
|
||||
//! `zcash_client_backend` contains Rust structs and traits for creating shielded Zcash
|
||||
//! light clients.
|
||||
|
||||
// Catch documentation errors caused by code changes.
|
||||
#![deny(intra_doc_link_resolution_failure)]
|
||||
|
||||
pub mod constants;
|
||||
mod decrypt;
|
||||
pub mod encoding;
|
||||
pub mod keys;
|
||||
pub mod proto;
|
||||
pub mod wallet;
|
||||
pub mod welding_rig;
|
||||
|
||||
pub use decrypt::{decrypt_transaction, DecryptedOutput};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Generated code for handling light client protobuf structs.
|
||||
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use ff::{PrimeField};
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use zcash_primitives::{
|
||||
block::{BlockHash, BlockHeader},
|
||||
@@ -67,8 +67,8 @@ impl compact_formats::CompactOutput {
|
||||
/// [`CompactOutput.cmu`]: #structfield.cmu
|
||||
pub fn cmu(&self) -> Result<Fr, ()> {
|
||||
let mut repr = FrRepr::default();
|
||||
repr.read_le(&self.cmu[..]).map_err(|_| ())?;
|
||||
Fr::from_repr(repr).map_err(|_| ())
|
||||
repr.as_mut().copy_from_slice(&self.cmu[..]);
|
||||
Fr::from_repr(repr).ok_or(())
|
||||
}
|
||||
|
||||
/// Returns the ephemeral public key for this output.
|
||||
|
||||
@@ -36,7 +36,7 @@ fn scan_output(
|
||||
let ct = output.ciphertext;
|
||||
|
||||
// Increment tree and witnesses
|
||||
let node = Node::new(cmu.into_repr());
|
||||
let node = Node::new(cmu.to_repr());
|
||||
for witness in existing_witnesses {
|
||||
witness.append(node).unwrap();
|
||||
}
|
||||
@@ -134,12 +134,11 @@ pub fn scan_block(
|
||||
// mutable references to wtxs for too long.
|
||||
let mut block_witnesses: Vec<_> = wtxs
|
||||
.iter_mut()
|
||||
.map(|tx| {
|
||||
.flat_map(|tx| {
|
||||
tx.shielded_outputs
|
||||
.iter_mut()
|
||||
.map(|output| &mut output.witness)
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
for to_scan in tx.outputs.into_iter().enumerate() {
|
||||
@@ -184,10 +183,9 @@ pub fn scan_block(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
use ff::{Field, PrimeField};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand_core::RngCore;
|
||||
use rand_os::OsRng;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
use zcash_primitives::{
|
||||
jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform},
|
||||
merkle_tree::CommitmentTree,
|
||||
@@ -209,9 +207,7 @@ mod tests {
|
||||
};
|
||||
let fake_cmu = {
|
||||
let fake_cmu = Fr::random(rng);
|
||||
let mut bytes = vec![];
|
||||
fake_cmu.into_repr().write_le(&mut bytes).unwrap();
|
||||
bytes
|
||||
fake_cmu.to_repr().as_ref().to_owned()
|
||||
};
|
||||
let fake_epk = {
|
||||
let mut buffer = vec![0; 64];
|
||||
@@ -254,8 +250,8 @@ mod tests {
|
||||
// Create a fake Note for the account
|
||||
let mut rng = OsRng;
|
||||
let note = Note {
|
||||
g_d: to.diversifier.g_d::<Bls12>(&JUBJUB).unwrap(),
|
||||
pk_d: to.pk_d.clone(),
|
||||
g_d: to.diversifier().g_d::<Bls12>(&JUBJUB).unwrap(),
|
||||
pk_d: to.pk_d().clone(),
|
||||
value: value.into(),
|
||||
r: Fs::random(&mut rng),
|
||||
};
|
||||
@@ -266,8 +262,7 @@ mod tests {
|
||||
Memo::default(),
|
||||
&mut rng,
|
||||
);
|
||||
let mut cmu = vec![];
|
||||
note.cm(&JUBJUB).into_repr().write_le(&mut cmu).unwrap();
|
||||
let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_owned();
|
||||
let mut epk = vec![];
|
||||
encryptor.epk().write(&mut epk).unwrap();
|
||||
let enc_ciphertext = encryptor.encrypt_note_plaintext();
|
||||
|
||||
Reference in New Issue
Block a user