diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dbf06f..10eb698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ and this library adheres to Rust's notion of - `group::{WnafBase, WnafScalar}` structs for caching precomputations of both bases and scalars, for improved many-base many-scalar multiplication performance. +- `impl memuse::DynamicUsage for group::{Wnaf WnafBase, WnafScalar}`, behind the + new `wnaf-memuse` feature flag, to enable the heap usage of these types to be + measured at runtime. ## [0.12.0] - 2022-05-04 ### Changed diff --git a/Cargo.toml b/Cargo.toml index f15fdb6..edf6071 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,14 @@ rand_core = { version = "0.6", default-features = false } rand_xorshift = { version = "0.3", optional = true } subtle = { version = "2.2.1", default-features = false } +# Crate for exposing the dynamic memory usage of the w-NAF structs. +memuse = { version = "0.2", optional = true } + [features] default = ["alloc"] alloc = [] tests = ["alloc", "rand", "rand_xorshift"] +wnaf-memuse = ["alloc", "memuse"] [badges] maintenance = { status = "actively-developed" } diff --git a/src/wnaf.rs b/src/wnaf.rs index b48071e..175d676 100644 --- a/src/wnaf.rs +++ b/src/wnaf.rs @@ -266,6 +266,23 @@ impl Wnaf<(), Vec, Vec> { } } +#[cfg(feature = "wnaf-memuse")] +impl memuse::DynamicUsage for Wnaf<(), Vec, Vec> { + fn dynamic_usage(&self) -> usize { + self.base.dynamic_usage() + self.scalar.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + let (base_lower, base_upper) = self.base.dynamic_usage_bounds(); + let (scalar_lower, scalar_upper) = self.scalar.dynamic_usage_bounds(); + + ( + base_lower + scalar_lower, + base_upper.zip(scalar_upper).map(|(a, b)| a + b), + ) + } +} + impl Wnaf<(), Vec, Vec> { /// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that /// can perform exponentiations with `.scalar(..)`. @@ -316,6 +333,18 @@ impl<'a, G: Group> Wnaf> { } } +#[cfg(feature = "wnaf-memuse")] +impl<'a, G: Group> memuse::DynamicUsage for Wnaf> { + fn dynamic_usage(&self) -> usize { + // The heap memory for the window table is counted in the parent `Wnaf`. + self.scalar.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.scalar.dynamic_usage_bounds() + } +} + impl<'a, G: Group> Wnaf, &'a [i64]> { /// Constructs new space for the window table while borrowing /// the computed scalar representation, for sending the scalar representation @@ -329,6 +358,18 @@ impl<'a, G: Group> Wnaf, &'a [i64]> { } } +#[cfg(feature = "wnaf-memuse")] +impl<'a, G: Group + memuse::DynamicUsage> memuse::DynamicUsage for Wnaf, &'a [i64]> { + fn dynamic_usage(&self) -> usize { + // The heap memory for the scalar representation is counted in the parent `Wnaf`. + self.base.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.base.dynamic_usage_bounds() + } +} + impl> Wnaf { /// Performs exponentiation given a base. pub fn base(&mut self, base: G) -> G @@ -363,6 +404,17 @@ pub struct WnafScalar { field: PhantomData, } +#[cfg(feature = "wnaf-memuse")] +impl memuse::DynamicUsage for WnafScalar { + fn dynamic_usage(&self) -> usize { + self.wnaf.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.wnaf.dynamic_usage_bounds() + } +} + impl WnafScalar { /// Computes the w-NAF representation of the given scalar with the specified /// `WINDOW_SIZE`. @@ -418,6 +470,19 @@ pub struct WnafBase { table: Vec, } +#[cfg(feature = "wnaf-memuse")] +impl memuse::DynamicUsage + for WnafBase +{ + fn dynamic_usage(&self) -> usize { + self.table.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.table.dynamic_usage_bounds() + } +} + impl WnafBase { /// Computes a window table for the given base with the specified `WINDOW_SIZE`. pub fn new(base: G) -> Self {