Merge pull request #329 from nuttycom/ivk_payment_addresses

Introduce SaplingIvk newtype & use IVKs where possible.
This commit is contained in:
str4d 2021-03-04 07:04:05 +13:00 committed by GitHub
commit 36e4b0d51a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 34 deletions

View File

@ -292,6 +292,7 @@ where
let txs: Vec<WalletTx> = {
let mut witness_refs: Vec<_> = witnesses.iter_mut().map(|w| &mut w.1).collect();
scan_block(
params,
block,

View File

@ -7,7 +7,7 @@ use zcash_primitives::{
consensus::{self, BlockHeight},
merkle_tree::{CommitmentTree, IncrementalWitness},
note_encryption::try_sapling_compact_note_decryption,
primitives::Nullifier,
primitives::{Nullifier, SaplingIvk},
sapling::Node,
transaction::TxId,
};
@ -27,7 +27,7 @@ fn scan_output<P: consensus::Parameters>(
params: &P,
height: BlockHeight,
(index, output): (usize, CompactOutput),
ivks: &[(AccountId, jubjub::Fr)],
ivks: &[(AccountId, SaplingIvk)],
spent_from_accounts: &HashSet<AccountId>,
tree: &mut CommitmentTree<Node>,
existing_witnesses: &mut [&mut IncrementalWitness<Node>],
@ -53,7 +53,7 @@ fn scan_output<P: consensus::Parameters>(
for (account, ivk) in ivks.iter() {
let (note, to) =
match try_sapling_compact_note_decryption(params, height, ivk, &epk, &cmu, &ct) {
match try_sapling_compact_note_decryption(params, height, &ivk, &epk, &cmu, &ct) {
Some(ret) => ret,
None => continue,
};
@ -90,7 +90,7 @@ fn scan_output<P: consensus::Parameters>(
pub fn scan_block<P: consensus::Parameters>(
params: &P,
block: CompactBlock,
ivks: &[(AccountId, jubjub::Fr)],
ivks: &[(AccountId, SaplingIvk)],
nullifiers: &[(AccountId, Nullifier)],
tree: &mut CommitmentTree<Node>,
existing_witnesses: &mut [&mut IncrementalWitness<Node>],
@ -163,7 +163,7 @@ pub fn scan_block<P: consensus::Parameters>(
params,
block_height,
to_scan,
&ivks,
ivks,
&spent_from_accounts,
tree,
existing_witnesses,

View File

@ -4,7 +4,7 @@ use rand_core::OsRng;
use zcash_primitives::{
consensus::{NetworkUpgrade::Canopy, Parameters, TEST_NETWORK},
note_encryption::{try_sapling_note_decryption, Memo, SaplingNoteEncryption},
primitives::{Diversifier, PaymentAddress, ValueCommitment},
primitives::{Diversifier, PaymentAddress, SaplingIvk, ValueCommitment},
transaction::components::{OutputDescription, GROTH_PROOF_SIZE},
util::generate_random_rseed,
};
@ -13,13 +13,13 @@ fn bench_note_decryption(c: &mut Criterion) {
let mut rng = OsRng;
let height = TEST_NETWORK.activation_height(Canopy).unwrap();
let valid_ivk = jubjub::Fr::random(&mut rng);
let invalid_ivk = jubjub::Fr::random(&mut rng);
let valid_ivk = SaplingIvk(jubjub::Fr::random(&mut rng));
let invalid_ivk = SaplingIvk(jubjub::Fr::random(&mut rng));
// Construct a fake Sapling output as if we had just deserialized a transaction.
let output = {
let diversifier = Diversifier([0; 11]);
let pk_d = diversifier.g_d().unwrap() * valid_ivk;
let pk_d = diversifier.g_d().unwrap() * valid_ivk.0;
let pa = PaymentAddress::from_parts(diversifier, pk_d).unwrap();
let rseed = generate_random_rseed(&TEST_NETWORK, height, &mut rng);

View File

@ -2,7 +2,7 @@
use crate::{
consensus::{self, BlockHeight, NetworkUpgrade::Canopy, ZIP212_GRACE_PERIOD},
primitives::{Diversifier, Note, PaymentAddress, Rseed},
primitives::{Diversifier, Note, PaymentAddress, Rseed, SaplingIvk},
};
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
@ -375,7 +375,7 @@ impl<R: RngCore> SaplingNoteEncryption<R> {
fn parse_note_plaintext_without_memo<P: consensus::Parameters>(
params: &P,
height: BlockHeight,
ivk: &jubjub::Fr,
ivk: &SaplingIvk,
epk: &jubjub::ExtendedPoint,
cmu: &bls12_381::Scalar,
plaintext: &[u8],
@ -402,7 +402,7 @@ fn parse_note_plaintext_without_memo<P: consensus::Parameters>(
};
let diversifier = Diversifier(d);
let pk_d = diversifier.g_d()? * ivk;
let pk_d = diversifier.g_d()? * ivk.0;
let to = PaymentAddress::from_parts(diversifier, pk_d)?;
let note = to.create_note(v, rseed).unwrap();
@ -458,14 +458,14 @@ pub fn plaintext_version_is_valid<P: consensus::Parameters>(
pub fn try_sapling_note_decryption<P: consensus::Parameters>(
params: &P,
height: BlockHeight,
ivk: &jubjub::Fr,
ivk: &SaplingIvk,
epk: &jubjub::ExtendedPoint,
cmu: &bls12_381::Scalar,
enc_ciphertext: &[u8],
) -> Option<(Note, PaymentAddress, Memo)> {
assert_eq!(enc_ciphertext.len(), ENC_CIPHERTEXT_SIZE);
let shared_secret = sapling_ka_agree(ivk, &epk);
let shared_secret = sapling_ka_agree(&ivk.0, &epk);
let key = kdf_sapling(shared_secret, &epk);
let mut plaintext = [0; ENC_CIPHERTEXT_SIZE];
@ -502,14 +502,14 @@ pub fn try_sapling_note_decryption<P: consensus::Parameters>(
pub fn try_sapling_compact_note_decryption<P: consensus::Parameters>(
params: &P,
height: BlockHeight,
ivk: &jubjub::Fr,
ivk: &SaplingIvk,
epk: &jubjub::ExtendedPoint,
cmu: &bls12_381::Scalar,
enc_ciphertext: &[u8],
) -> Option<(Note, PaymentAddress)> {
assert_eq!(enc_ciphertext.len(), COMPACT_NOTE_SIZE);
let shared_secret = sapling_ka_agree(ivk, epk);
let shared_secret = sapling_ka_agree(&ivk.0, epk);
let key = kdf_sapling(shared_secret, &epk);
// Start from block 1 to skip over Poly1305 keying output
@ -683,7 +683,7 @@ mod tests {
Parameters, TEST_NETWORK, ZIP212_GRACE_PERIOD,
},
keys::OutgoingViewingKey,
primitives::{Diversifier, PaymentAddress, Rseed, ValueCommitment},
primitives::{Diversifier, PaymentAddress, Rseed, SaplingIvk, ValueCommitment},
util::generate_random_rseed,
};
@ -809,17 +809,17 @@ mod tests {
) -> (
OutgoingViewingKey,
OutgoingCipherKey,
jubjub::Fr,
SaplingIvk,
jubjub::ExtendedPoint,
bls12_381::Scalar,
jubjub::ExtendedPoint,
[u8; ENC_CIPHERTEXT_SIZE],
[u8; OUT_CIPHERTEXT_SIZE],
) {
let ivk = jubjub::Fr::random(&mut rng);
let ivk = SaplingIvk(jubjub::Fr::random(&mut rng));
let (ovk, ock, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext) =
random_enc_ciphertext_with(height, ivk, rng);
let (ovk, ock, cv, cmu, epk, enc_ciphertext, out_ciphertext) =
random_enc_ciphertext_with(height, &ivk, rng);
assert!(try_sapling_note_decryption(
&TEST_NETWORK,
@ -869,12 +869,11 @@ mod tests {
fn random_enc_ciphertext_with<R: RngCore + CryptoRng>(
height: BlockHeight,
ivk: jubjub::Fr,
ivk: &SaplingIvk,
mut rng: &mut R,
) -> (
OutgoingViewingKey,
OutgoingCipherKey,
jubjub::Fr,
jubjub::ExtendedPoint,
bls12_381::Scalar,
jubjub::ExtendedPoint,
@ -882,7 +881,7 @@ mod tests {
[u8; OUT_CIPHERTEXT_SIZE],
) {
let diversifier = Diversifier([0; 11]);
let pk_d = diversifier.g_d().unwrap() * ivk;
let pk_d = diversifier.g_d().unwrap() * ivk.0;
let pa = PaymentAddress::from_parts_unchecked(diversifier, pk_d);
// Construct the value commitment for the proof instance
@ -905,7 +904,7 @@ mod tests {
let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu);
let ock = prf_ock(&ovk, &cv, &cmu, &epk);
(ovk, ock, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext)
(ovk, ock, cv, cmu, epk, enc_ciphertext, out_ciphertext)
}
fn reencrypt_enc_ciphertext(
@ -1006,7 +1005,7 @@ mod tests {
try_sapling_note_decryption(
&TEST_NETWORK,
height,
&jubjub::Fr::random(&mut rng),
&SaplingIvk(jubjub::Fr::random(&mut rng)),
&epk,
&cmu,
&enc_ciphertext
@ -1217,7 +1216,7 @@ mod tests {
try_sapling_compact_note_decryption(
&TEST_NETWORK,
height,
&jubjub::Fr::random(&mut rng),
&SaplingIvk(jubjub::Fr::random(&mut rng)),
&epk,
&cmu,
&enc_ciphertext[..COMPACT_NOTE_SIZE]
@ -1792,9 +1791,9 @@ mod tests {
];
for &height in heights.iter() {
let ivk = jubjub::Fr::zero();
let (ovk, ock, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) =
random_enc_ciphertext_with(height, ivk, &mut rng);
let ivk = SaplingIvk(jubjub::Fr::zero());
let (ovk, ock, cv, cmu, epk, enc_ciphertext, out_ciphertext) =
random_enc_ciphertext_with(height, &ivk, &mut rng);
assert_eq!(
try_sapling_output_recovery(
@ -1853,7 +1852,7 @@ mod tests {
// Load the test vector components
//
let ivk = read_jubjub_scalar!(tv.ivk);
let ivk = SaplingIvk(read_jubjub_scalar!(tv.ivk));
let pk_d = read_point!(tv.default_pk_d).into_subgroup().unwrap();
let rcm = read_jubjub_scalar!(tv.rcm);
let cv = read_point!(tv.cv);

View File

@ -59,7 +59,7 @@ impl ViewingKey {
self.ak + constants::SPENDING_KEY_GENERATOR * ar
}
pub fn ivk(&self) -> jubjub::Fr {
pub fn ivk(&self) -> SaplingIvk {
let mut h = [0; 32];
h.copy_from_slice(
Blake2sParams::new()
@ -75,16 +75,28 @@ impl ViewingKey {
// Drop the most significant five bits, so it can be interpreted as a scalar.
h[31] &= 0b0000_0111;
jubjub::Fr::from_repr(h).expect("should be a valid scalar")
SaplingIvk(jubjub::Fr::from_repr(h).expect("should be a valid scalar"))
}
pub fn to_payment_address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
self.ivk().to_payment_address(diversifier)
}
}
pub struct SaplingIvk(pub jubjub::Fr);
impl SaplingIvk {
pub fn to_payment_address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
diversifier.g_d().and_then(|g_d| {
let pk_d = g_d * self.ivk();
let pk_d = g_d * self.0;
PaymentAddress::from_parts(diversifier, pk_d)
})
}
pub fn to_repr(&self) -> [u8; 32] {
self.0.to_repr()
}
}
#[derive(Copy, Clone, Debug, PartialEq)]