Skip to content

Commit

Permalink
UIP 4: Thread spend backrefs through planning/pcli
Browse files Browse the repository at this point in the history
  • Loading branch information
redshiftzero committed Nov 13, 2024
1 parent 789ee1b commit f958fc3
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 18 deletions.
4 changes: 2 additions & 2 deletions crates/bin/pcli/src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ fn pretty_print_transaction_plan(
balance_commitment: dummy_commitment(),
nullifier: Nullifier(Fq::default()),
rk: dummy_pk(),
// todo: populate property
encrypted_backref: EncryptedBackref { bytes: vec![] },
encrypted_backref: EncryptedBackref::try_from([0u8; 0])
.expect("can create dummy encrypted backref"),
},
auth_sig: dummy_sig(),
proof: dummy_proof_spend(),
Expand Down
58 changes: 53 additions & 5 deletions crates/core/component/shielded-pool/src/backref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ use penumbra_tct as tct;
pub const ENCRYPTED_BACKREF_LEN: usize = 48;

pub struct Backref {
pub note_commitment: tct::StateCommitment,
note_commitment: tct::StateCommitment,
}

#[derive(Clone, Debug)]
pub struct EncryptedBackref {
pub bytes: Vec<u8>,
/// The inner bytes can either have 0 or `ENCRYPTED_BACKREF_LEN` bytes.
bytes: Vec<u8>,
}

impl Backref {
pub fn new(note_commitment: tct::StateCommitment) -> Self {
Self { note_commitment }
}

pub fn encrypt(
&self,
brk: &BackreferenceKey,
Expand All @@ -43,6 +48,13 @@ impl Backref {

impl EncryptedBackref {
pub fn decrypt(&self, brk: &BackreferenceKey, nullifier: &Nullifier) -> Result<Backref> {
// We might have a 0-length encrypted backref, which
// is treated as a valid value and means that the note has no backref.
if self.bytes.is_empty() {
let zero_commitment = tct::StateCommitment::try_from([0u8; 32])?;
return Ok(Backref::new(zero_commitment));
}

let cipher = ChaCha20Poly1305::new(&brk.0);

let nonce_bytes = &nullifier.to_bytes()[..12];
Expand All @@ -56,9 +68,45 @@ impl EncryptedBackref {
.try_into()
.map_err(|_| anyhow::anyhow!("decryption error"))?;

Ok(Backref {
note_commitment: tct::StateCommitment::try_from(note_commitment_bytes)
.map_err(|_| anyhow::anyhow!("decryption error"))?,
Backref::try_from(note_commitment_bytes).map_err(|_| anyhow::anyhow!("decryption error"))
}
}

impl TryFrom<[u8; 32]> for Backref {
type Error = anyhow::Error;

fn try_from(bytes: [u8; 32]) -> Result<Self> {
Ok(Self {
note_commitment: tct::StateCommitment::try_from(bytes)
.map_err(|_| anyhow::anyhow!("invalid note commitment"))?,
})
}
}

// EncryptedBackrefs can either have 0 or ENCRYPTED_BACKREF_LEN bytes.

impl TryFrom<[u8; ENCRYPTED_BACKREF_LEN]> for EncryptedBackref {
type Error = anyhow::Error;

fn try_from(bytes: [u8; ENCRYPTED_BACKREF_LEN]) -> Result<Self> {
Ok(Self {
bytes: bytes.to_vec(),
})
}
}

impl TryFrom<[u8; 0]> for EncryptedBackref {
type Error = anyhow::Error;

fn try_from(bytes: [u8; 0]) -> Result<Self> {
Ok(Self {
bytes: bytes.to_vec(),
})
}
}

impl From<EncryptedBackref> for Vec<u8> {
fn from(encrypted_backref: EncryptedBackref) -> Vec<u8> {
encrypted_backref.bytes
}
}
20 changes: 13 additions & 7 deletions crates/core/component/shielded-pool/src/spend/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl From<Body> for pb::SpendBody {
balance_commitment: Some(msg.balance_commitment.into()),
nullifier: Some(msg.nullifier.into()),
rk: Some(msg.rk.into()),
encrypted_backref: msg.encrypted_backref.bytes,
encrypted_backref: msg.encrypted_backref.into(),
}
}
}
Expand Down Expand Up @@ -121,14 +121,20 @@ impl TryFrom<pb::SpendBody> for Body {
.context("malformed rk")?;

// `EncryptedBackref` must have 0 or `ENCRYPTED_BACKREF_LEN` bytes.
if proto.encrypted_backref.len() != ENCRYPTED_BACKREF_LEN
&& proto.encrypted_backref.len() != 0
{
let encrypted_backref: EncryptedBackref;
if proto.encrypted_backref.len() == ENCRYPTED_BACKREF_LEN {
let bytes: [u8; ENCRYPTED_BACKREF_LEN] = proto
.encrypted_backref
.try_into()
.map_err(|_| anyhow::anyhow!("invalid encrypted backref"))?;
encrypted_backref = EncryptedBackref::try_from(bytes)
.map_err(|_| anyhow::anyhow!("invalid encrypted backref"))?;
} else if proto.encrypted_backref.len() == 0 {
encrypted_backref = EncryptedBackref::try_from([0u8; ENCRYPTED_BACKREF_LEN])
.context("invalid encrypted backref")?;
} else {
return Err(anyhow::anyhow!("invalid encrypted backref length"));
}
let encrypted_backref = EncryptedBackref {
bytes: proto.encrypted_backref,
};

Ok(Body {
balance_commitment,
Expand Down
11 changes: 8 additions & 3 deletions crates/core/component/shielded-pool/src/spend/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};

use super::{Body, Spend, SpendProof};
use crate::{EncryptedBackref, Note, Rseed, SpendProofPrivate, SpendProofPublic};
use crate::{Backref, Note, Rseed, SpendProofPrivate, SpendProofPublic};

/// A planned [`Spend`](Spend).
#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -75,12 +75,17 @@ impl SpendPlan {

/// Construct the [`spend::Body`] described by this [`SpendPlan`].
pub fn spend_body(&self, fvk: &FullViewingKey) -> Body {
// Construct the backreference for this spend.
let backref = Backref::new(self.note.commit());
// TODO: This is fallible
let encrypted_backref = backref
.encrypt(&fvk.backref_key(), &self.nullifier(fvk))
.expect("can encrypt");
Body {
balance_commitment: self.balance().commit(self.value_blinding),
nullifier: self.nullifier(fvk),
rk: self.rk(fvk),
// todo: populate property
encrypted_backref: EncryptedBackref { bytes: vec![] },
encrypted_backref,
}
}

Expand Down
7 changes: 6 additions & 1 deletion crates/core/keys/src/keys/fvk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::keys::wallet_id::WalletId;
use crate::{
fmd, ka, prf,
rdsa::{SpendAuth, VerificationKey},
Address, AddressView,
Address, AddressView, BackreferenceKey,
};

use super::{AddressIndex, DiversifierKey, IncomingViewingKey, NullifierKey, OutgoingViewingKey};
Expand Down Expand Up @@ -120,6 +120,11 @@ impl FullViewingKey {
&self.ak
}

/// Construct the backreference key for this full viewing key.
pub fn backref_key(&self) -> BackreferenceKey {
BackreferenceKey::derive(self.outgoing()).clone()
}

/// Hashes the full viewing key into an [`WalletId`].
pub fn wallet_id(&self) -> WalletId {
let hash_result = hash_2(
Expand Down

0 comments on commit f958fc3

Please sign in to comment.