Skip to content

Commit

Permalink
Implement a newtype for Precision
Browse files Browse the repository at this point in the history
  • Loading branch information
cronokirby committed Apr 1, 2024
1 parent d012f17 commit 5914ecb
Show file tree
Hide file tree
Showing 21 changed files with 183 additions and 78 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/core/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ tracing = { workspace = true }
url = { workspace = true }

[dev-dependencies]
decaf377-fmd = { workspace = true, default-features = true }
ed25519-consensus = { workspace = true }
penumbra-mock-consensus = { workspace = true }
penumbra-mock-client = { workspace = true }
Expand Down
6 changes: 5 additions & 1 deletion crates/core/app/src/action_handler/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ mod tests {
OutputPlan::new(&mut OsRng, value, *test_keys::ADDRESS_1).into(),
],
detection_data: Some(DetectionDataPlan {
clue_plans: vec![CluePlan::new(&mut OsRng, *test_keys::ADDRESS_1, 1)],
clue_plans: vec![CluePlan::new(
&mut OsRng,
*test_keys::ADDRESS_1,
1.try_into().unwrap(),
)],
}),
memo: None,
};
Expand Down
10 changes: 5 additions & 5 deletions crates/core/app/src/action_handler/transaction/stateful.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub async fn fmd_parameters_valid<S: StateRead>(state: S, transaction: &Transact
#[tracing::instrument(
skip_all,
fields(
current_fmd.precision_bits = current_fmd_parameters.precision_bits,
previous_fmd.precision_bits = previous_fmd_parameters.precision_bits,
current_fmd.precision_bits = current_fmd_parameters.precision.bits(),
previous_fmd.precision_bits = previous_fmd_parameters.precision.bits(),
previous_fmd.as_of_block_height = previous_fmd_parameters.as_of_block_height,
block_height,
)
Expand All @@ -51,9 +51,9 @@ pub fn fmd_precision_within_grace_period(
{
// Clue must be using the current `fmd::Parameters`, or be within
// `FMD_GRACE_PERIOD_BLOCKS` of the previous `fmd::Parameters`.
let clue_precision = clue.precision_bits();
let using_current_precision = clue_precision == current_fmd_parameters.precision_bits;
let using_previous_precision = clue_precision == previous_fmd_parameters.precision_bits;
let clue_precision = clue.precision()?;
let using_current_precision = clue_precision == current_fmd_parameters.precision;
let using_previous_precision = clue_precision == previous_fmd_parameters.precision;
let within_grace_period =
block_height < previous_fmd_parameters.as_of_block_height + FMD_GRACE_PERIOD_BLOCKS;
if using_current_precision || (using_previous_precision && within_grace_period) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use decaf377_fmd::Precision;

mod common;

use {
Expand Down Expand Up @@ -164,7 +166,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> {
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
plan
};
let tx = client.witness_auth_build(&plan).await?;
Expand Down Expand Up @@ -275,7 +277,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> {
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
plan
};
let tx = client.witness_auth_build(&plan).await?;
Expand Down Expand Up @@ -440,7 +442,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> {
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
plan
};
let tx = client.witness_auth_build(&plan).await?;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use decaf377_fmd::Precision;

mod common;

use {
Expand Down Expand Up @@ -65,7 +67,7 @@ async fn app_can_spend_notes_and_detect_outputs() -> anyhow::Result<()> {
..Default::default()
},
};
plan.populate_detection_data(OsRng, 0);
plan.populate_detection_data(OsRng, Precision::default());

let tx = client.witness_auth_build(&plan).await?;

Expand Down
7 changes: 4 additions & 3 deletions crates/core/app/tests/app_can_undelegate_from_a_validator.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use decaf377_fmd::Precision;
use penumbra_num::fixpoint::U128x128;

mod common;
Expand Down Expand Up @@ -160,7 +161,7 @@ async fn app_can_undelegate_from_a_validator() -> anyhow::Result<()> {
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
(plan, note, staking_note_nullifier)
};
let tx = client.witness_auth_build(&plan).await?;
Expand Down Expand Up @@ -263,7 +264,7 @@ async fn app_can_undelegate_from_a_validator() -> anyhow::Result<()> {
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
(plan, undelegate_token_id)
};
let tx = client.witness_auth_build(&plan).await?;
Expand Down Expand Up @@ -345,7 +346,7 @@ async fn app_can_undelegate_from_a_validator() -> anyhow::Result<()> {
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
plan
};
let tx = client.witness_auth_build(&plan).await?;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use decaf377_fmd::Precision;

mod common;

use {
Expand Down Expand Up @@ -139,7 +141,7 @@ async fn app_tracks_uptime_for_validators_only_once_active() -> anyhow::Result<(
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
plan
};

Expand Down Expand Up @@ -214,7 +216,7 @@ async fn app_tracks_uptime_for_validators_only_once_active() -> anyhow::Result<(
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
plan
};
let tx = client.witness_auth_build(&plan).await?;
Expand Down Expand Up @@ -345,7 +347,7 @@ async fn app_tracks_uptime_for_validators_only_once_active() -> anyhow::Result<(
..Default::default()
},
};
plan.populate_detection_data(rand_core::OsRng, 0);
plan.populate_detection_data(rand_core::OsRng, Precision::default());
plan
};
let tx = client.witness_auth_build(&plan).await?;
Expand Down
11 changes: 6 additions & 5 deletions crates/core/component/shielded-pool/src/fmd.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use decaf377_fmd::Precision;
use penumbra_proto::{core::component::shielded_pool::v1 as pb, DomainType};
use serde::{Deserialize, Serialize};

Expand All @@ -6,8 +7,8 @@ pub mod state_key;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(try_from = "pb::FmdParameters", into = "pb::FmdParameters")]
pub struct Parameters {
/// Bits of precision.
pub precision_bits: u8,
/// FMD Precision.
pub precision: Precision,
/// The block height at which these parameters became effective.
pub as_of_block_height: u64,
}
Expand All @@ -21,7 +22,7 @@ impl TryFrom<pb::FmdParameters> for Parameters {

fn try_from(msg: pb::FmdParameters) -> Result<Self, Self::Error> {
Ok(Parameters {
precision_bits: msg.precision_bits.try_into()?,
precision: msg.precision_bits.try_into()?,
as_of_block_height: msg.as_of_block_height,
})
}
Expand All @@ -30,7 +31,7 @@ impl TryFrom<pb::FmdParameters> for Parameters {
impl From<Parameters> for pb::FmdParameters {
fn from(params: Parameters) -> Self {
pb::FmdParameters {
precision_bits: u32::from(params.precision_bits),
precision_bits: params.precision.bits() as u32,
as_of_block_height: params.as_of_block_height,
}
}
Expand All @@ -39,7 +40,7 @@ impl From<Parameters> for pb::FmdParameters {
impl Default for Parameters {
fn default() -> Self {
Self {
precision_bits: 0,
precision: Precision::default(),
as_of_block_height: 1,
}
}
Expand Down
9 changes: 5 additions & 4 deletions crates/core/transaction/src/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! creation.
use anyhow::Result;
use decaf377_fmd::Precision;
use penumbra_community_pool::{CommunityPoolDeposit, CommunityPoolOutput, CommunityPoolSpend};
use penumbra_dex::{
lp::action::{PositionClose, PositionOpen},
Expand Down Expand Up @@ -351,19 +352,19 @@ impl TransactionPlan {
pub fn populate_detection_data<R: CryptoRng + Rng>(
&mut self,
mut rng: R,
precision_bits: usize,
precision: Precision,
) {
// Add one clue per recipient.
let mut clue_plans = vec![];
for dest_address in self.dest_addresses() {
clue_plans.push(CluePlan::new(&mut rng, dest_address, precision_bits));
clue_plans.push(CluePlan::new(&mut rng, dest_address, precision));
}

// Now add dummy clues until we have one clue per output.
let num_dummy_clues = self.num_outputs() - clue_plans.len();
for _ in 0..num_dummy_clues {
let dummy_address = Address::dummy(&mut rng);
clue_plans.push(CluePlan::new(&mut rng, dummy_address, precision_bits));
clue_plans.push(CluePlan::new(&mut rng, dummy_address, precision));
}

if !clue_plans.is_empty() {
Expand Down Expand Up @@ -521,7 +522,7 @@ mod tests {
chain_id: "penumbra-test".to_string(),
},
detection_data: Some(DetectionDataPlan {
clue_plans: vec![CluePlan::new(&mut OsRng, addr, 1)],
clue_plans: vec![CluePlan::new(&mut OsRng, addr, 1.try_into().unwrap())],
}),
memo: Some(MemoPlan::new(&mut OsRng, memo_plaintext.clone()).unwrap()),
};
Expand Down
14 changes: 7 additions & 7 deletions crates/core/transaction/src/plan/clue.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use decaf377_fmd::Clue;
use decaf377_fmd::{Clue, Precision};
use penumbra_keys::Address;
use penumbra_proto::{core::transaction::v1 as pb, DomainType};

Expand All @@ -7,7 +7,7 @@ use rand::{CryptoRng, RngCore};
#[derive(Clone, Debug)]
pub struct CluePlan {
pub address: Address,
pub precision_bits: usize,
pub precision: Precision,
pub rseed: [u8; 32],
}

Expand All @@ -16,14 +16,14 @@ impl CluePlan {
pub fn new<R: CryptoRng + RngCore>(
rng: &mut R,
address: Address,
precision_bits: usize,
precision: Precision,
) -> CluePlan {
let mut rseed = [0u8; 32];
rng.fill_bytes(&mut rseed);
CluePlan {
address,
rseed,
precision_bits,
precision,
}
}

Expand All @@ -32,7 +32,7 @@ impl CluePlan {
let clue_key = self.address.clue_key();
let expanded_clue_key = clue_key.expand_infallible();
expanded_clue_key
.create_clue_deterministic(self.precision_bits, self.rseed)
.create_clue_deterministic(self.precision, self.rseed)
.expect("can construct clue key")
}
}
Expand All @@ -46,7 +46,7 @@ impl From<CluePlan> for pb::CluePlan {
Self {
address: Some(msg.address.into()),
rseed: msg.rseed.to_vec(),
precision_bits: msg.precision_bits as u64,
precision_bits: msg.precision.bits() as u64,
}
}
}
Expand All @@ -60,7 +60,7 @@ impl TryFrom<pb::CluePlan> for CluePlan {
.ok_or_else(|| anyhow::anyhow!("missing address"))?
.try_into()?,
rseed: msg.rseed.as_slice().try_into()?,
precision_bits: msg.precision_bits.try_into()?,
precision: msg.precision_bits.try_into()?,
})
}
}
13 changes: 7 additions & 6 deletions crates/crypto/decaf377-fmd/benches/fmd.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use fmd::Precision;
use rand_core::OsRng;

use decaf377_fmd as fmd;
Expand All @@ -7,7 +8,7 @@ fn detect_clues(dk: &fmd::DetectionKey, clues: &[fmd::Clue]) -> usize {
clues.iter().filter(|clue| dk.examine(clue)).count()
}

fn create_clues(ck: &fmd::ExpandedClueKey, precision: usize) -> Vec<fmd::Clue> {
fn create_clues(ck: &fmd::ExpandedClueKey, precision: Precision) -> Vec<fmd::Clue> {
(0..1024)
.map(|_| {
ck.create_clue(precision, OsRng)
Expand All @@ -24,11 +25,11 @@ fn bench(c: &mut Criterion) {
.expect("clue key bytes must be valid");

let clues = vec![
(4, create_clues(&ck, 4)),
(5, create_clues(&ck, 5)),
(6, create_clues(&ck, 6)),
(7, create_clues(&ck, 7)),
(8, create_clues(&ck, 8)),
(4, create_clues(&ck, 4.try_into().unwrap())),
(5, create_clues(&ck, 5.try_into().unwrap())),
(6, create_clues(&ck, 6.try_into().unwrap())),
(7, create_clues(&ck, 7.try_into().unwrap())),
(8, create_clues(&ck, 8.try_into().unwrap())),
];

let mut group = c.benchmark_group("fmd-detection");
Expand Down
26 changes: 22 additions & 4 deletions crates/crypto/decaf377-fmd/src/clue.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
use std::array::TryFromSliceError;

use crate::{error::Error, Precision};

/// A clue that allows probabilistic message detection.
#[derive(Debug, Clone)]
pub struct Clue(pub [u8; 68]);
pub struct Clue(pub(crate) [u8; 68]);

impl Clue {
/// The bits of precision for this `Clue`.
pub fn precision_bits(&self) -> u8 {
self.0[64]
/// The bits of precision for this `Clue`, if valid.
pub fn precision(&self) -> Result<Precision, Error> {
self.0[64].try_into()
}
}

impl From<Clue> for Vec<u8> {
fn from(value: Clue) -> Self {
value.0.into()
}
}

impl TryFrom<&[u8]> for Clue {
type Error = TryFromSliceError;

fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Ok(Self(value.try_into()?))
}
}
Loading

0 comments on commit 5914ecb

Please sign in to comment.