2022-10-30 03:03:38 -07:00
|
|
|
use orchard::keys::Scope;
|
2022-10-28 06:02:34 -07:00
|
|
|
use orchard::note_encryption::OrchardDomain;
|
|
|
|
use zcash_primitives::consensus::{BlockHeight, Parameters};
|
|
|
|
use crate::chain::Nf;
|
2022-10-30 03:03:38 -07:00
|
|
|
use crate::{CompactTx, DbAdapterBuilder};
|
2022-10-28 06:02:34 -07:00
|
|
|
use crate::db::ReceivedNote;
|
|
|
|
use crate::sync::{CompactOutputBytes, DecryptedNote, Node, OutputPosition, TrialDecrypter, ViewKey};
|
|
|
|
use zcash_note_encryption;
|
2022-10-30 03:03:38 -07:00
|
|
|
use zcash_params::coin::CoinType;
|
2022-10-28 06:02:34 -07:00
|
|
|
|
2022-10-30 03:03:38 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2022-10-28 06:02:34 -07:00
|
|
|
pub struct OrchardViewKey {
|
|
|
|
pub account: u32,
|
|
|
|
pub fvk: orchard::keys::FullViewingKey,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ViewKey<OrchardDomain> for OrchardViewKey {
|
|
|
|
fn account(&self) -> u32 {
|
|
|
|
self.account
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ivk(&self) -> orchard::keys::IncomingViewingKey {
|
|
|
|
self.fvk.to_ivk(orchard::keys::Scope::External)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DecryptedOrchardNote {
|
|
|
|
pub vk: OrchardViewKey,
|
|
|
|
pub note: orchard::Note,
|
|
|
|
pub pa: orchard::Address,
|
|
|
|
pub output_position: OutputPosition,
|
|
|
|
pub cmx: Node,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DecryptedNote<OrchardDomain, OrchardViewKey> for DecryptedOrchardNote {
|
|
|
|
fn from_parts(vk: OrchardViewKey, note: orchard::Note, pa: orchard::Address, output_position: OutputPosition, cmx: Node) -> Self {
|
|
|
|
DecryptedOrchardNote {
|
|
|
|
vk,
|
|
|
|
note,
|
|
|
|
pa,
|
|
|
|
output_position,
|
|
|
|
cmx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn position(&self, block_offset: usize) -> usize {
|
|
|
|
block_offset + self.output_position.position_in_block
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cmx(&self) -> Node {
|
|
|
|
self.cmx
|
|
|
|
}
|
|
|
|
|
2022-10-30 03:03:38 -07:00
|
|
|
fn to_received_note(&self, _position: u64) -> ReceivedNote {
|
2022-10-28 06:02:34 -07:00
|
|
|
ReceivedNote {
|
|
|
|
account: self.vk.account,
|
|
|
|
height: self.output_position.height,
|
|
|
|
output_index: self.output_position.output_index as u32,
|
|
|
|
diversifier: self.pa.diversifier().as_array().to_vec(),
|
|
|
|
value: self.note.value().inner(),
|
|
|
|
rcm: self.note.rseed().as_bytes().to_vec(),
|
|
|
|
nf: self.note.nullifier(&self.vk.fvk).to_bytes().to_vec(),
|
|
|
|
rho: Some(self.note.rho().to_bytes().to_vec()),
|
|
|
|
spent: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct OrchardDecrypter<N> {
|
|
|
|
pub network: N,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <N> OrchardDecrypter<N> {
|
|
|
|
pub fn new(network: N) -> Self {
|
|
|
|
OrchardDecrypter {
|
|
|
|
network,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <N: Parameters> TrialDecrypter<N, OrchardDomain, OrchardViewKey, DecryptedOrchardNote> for OrchardDecrypter<N> {
|
|
|
|
fn domain(&self, _height: BlockHeight, cob: &CompactOutputBytes) -> OrchardDomain {
|
|
|
|
OrchardDomain::for_nullifier(orchard::note::Nullifier::from_bytes(&cob.nullifier).unwrap())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn spends(&self, vtx: &CompactTx) -> Vec<Nf> {
|
|
|
|
vtx.actions.iter().map(|co| {
|
|
|
|
let nf: [u8; 32] = co.nullifier.clone().try_into().unwrap();
|
|
|
|
Nf(nf)
|
|
|
|
}).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn outputs(&self, vtx: &CompactTx) -> Vec<CompactOutputBytes> {
|
|
|
|
vtx.actions.iter().map(|co| co.into()).collect()
|
|
|
|
}
|
|
|
|
}
|
2022-10-30 03:03:38 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn test_decrypt() -> anyhow::Result<()> {
|
|
|
|
// let mut nullifier = hex::decode("951ab285b0f4df3ff24f24470dbb8bafa3b5caeeb204fc4465f7ea9c3d5a980a").unwrap();
|
|
|
|
// let mut epk = hex::decode("182d698c3bb8b168d5f9420f1c2e32d94b4dbc0826181c1783ea47fedd31b710").unwrap();
|
|
|
|
// let mut cmx = hex::decode("df45e00eb39e4c281e2804a366d3010b7f663724472d12637e0a749e6ce22719").unwrap();
|
|
|
|
// let ciphertext = hex::decode("d9bc6ee09b0afde5dd69bfdf4b667a38da3e1084e84eb6752d54800b9f5110203b60496ab5313dba3f2acb9ef30bcaf68fbfcc59").unwrap();
|
|
|
|
|
|
|
|
let mut nullifier = hex::decode("ea1b97cc83d326db4130433022f68dd32a0bc707448b19b0980e4e6404412b29").unwrap();
|
|
|
|
let mut epk = hex::decode("e2f666e905666f29bb678c694602b2768bea655c0f2b18f9c342ad8b64b18c0c").unwrap();
|
|
|
|
let mut cmx = hex::decode("4a95dbf0d1d0cac1376a0b8fb0fc2ed2843d0e2670dd976a63386b293f30de25").unwrap();
|
|
|
|
let ciphertext = hex::decode("73640095a90bb03d14f687d6acf4822618a3def1da3b71a588da1c68e25042f7c9aa759778e73aa2bb39d1061e51c1e8cf5e0bce").unwrap();
|
|
|
|
|
|
|
|
let db_builder = DbAdapterBuilder {
|
|
|
|
coin_type: CoinType::Zcash,
|
|
|
|
db_path: "./zec.db".to_string()
|
|
|
|
};
|
|
|
|
let db = db_builder.build()?;
|
|
|
|
let keys = db.get_orchard_fvks()?.first().unwrap().clone();
|
|
|
|
let fvk = keys.fvk;
|
|
|
|
|
|
|
|
let output = CompactOutputBytes {
|
|
|
|
nullifier: nullifier.clone().try_into().unwrap(),
|
|
|
|
epk: epk.try_into().unwrap(),
|
|
|
|
cmx: cmx.try_into().unwrap(),
|
|
|
|
ciphertext: ciphertext.try_into().unwrap()
|
|
|
|
};
|
|
|
|
let domain = OrchardDomain::for_nullifier(orchard::note::Nullifier::from_bytes(&nullifier.try_into().unwrap()).unwrap());
|
|
|
|
let r = zcash_note_encryption::try_compact_note_decryption(&domain, &fvk.to_ivk(Scope::External), &output);
|
|
|
|
println!("{:?}", r);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|