Skip to content

Commit

Permalink
Merge pull request #64 from fjarri/skf-constructors
Browse files Browse the repository at this point in the history
Additional `SecretKeyFactory` constructors
  • Loading branch information
fjarri authored Aug 19, 2021
2 parents 283dbf5 + 6a5f615 commit 849f468
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `SecretKey`, `SecretKeyFactory` and `Signer` do not implement `PartialEq` anymore. Corresponding methods in the bindings were removed as well. ([#53])
- Bumped `k256` to `0.9` and `ecdsa` to `0.12.2`. ([#53])
- Bumped `pyo3` to `0.14`. ([#65])
- Reduced the size of key material in `SecretKeyFactory` from 64 to 32 bytes. ([#64])


### Added
Expand All @@ -21,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Feature `default-rng` (enabled by default). When disabled, the library can be compiled on targets not supported by `getrandom` (e.g., ARM), but only the functions taking an explicit RNG as a parameter will be available. ([#55])
- Added benchmarks for the main usage scenario and a feature `bench-internals` to expose some internals for benchmarking. ([#54])
- Added `VerifiedCapsuleFrag::from_verified_bytes()`. ([#63])
- Added `SecretKeyFactory::secret_key_factory_by_label()`. ([#64])
- Added `SecretKeyFactory::from_secure_randomness()` and `seed_size()`. ([#64])


### Fixed
Expand All @@ -35,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#56]: https://github.com/nucypher/rust-umbral/pull/56
[#60]: https://github.com/nucypher/rust-umbral/pull/60
[#63]: https://github.com/nucypher/rust-umbral/pull/63
[#64]: https://github.com/nucypher/rust-umbral/pull/64
[#65]: https://github.com/nucypher/rust-umbral/pull/65


Expand Down
18 changes: 17 additions & 1 deletion umbral-pre-python/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,26 @@ API reference
Generates a new random factory.

.. py:method:: secret_key_by_label(label: bytes) -> SecretKeyFactory
.. py:staticmethod:: seed_size() -> int
Returns the seed size required by :py:meth:`~SecretKeyFactory.from_secure_randomness`.

.. py:staticmethod:: from_secure_randomness(seed: bytes) -> SecretKeyFactory
Creates a secret key factory using the given random bytes.
The length of the bytestring must be the one returned by :py:meth:`~SecretKeyFactory.seed_size`.

**Warning:** make sure the given seed has been obtained
from a cryptographically secure source of randomness!

.. py:method:: secret_key_by_label(label: bytes) -> SecretKey
Generates a new :py:class:`SecretKey` using ``label`` as a seed.

.. py:method:: secret_key_factory_by_label(label: bytes) -> SecretKeyFactory
Generates a new :py:class:`SecretKeyFactory` using ``label`` as a seed.

.. py:method:: to_secret_bytes() -> bytes
Serializes the object into a bytestring.
Expand Down
20 changes: 20 additions & 0 deletions umbral-pre-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ impl SecretKeyFactory {
}
}

#[staticmethod]
pub fn seed_size() -> usize {
umbral_pre::SecretKeyFactory::seed_size()
}

#[staticmethod]
pub fn from_secure_randomness(seed: &[u8]) -> PyResult<SecretKeyFactory> {
umbral_pre::SecretKeyFactory::from_secure_randomness(seed)
.map(|backend_sk| SecretKeyFactory {
backend: backend_sk,
})
.map_err(|err| PyValueError::new_err(format!("{}", err)))
}

pub fn secret_key_by_label(&self, label: &[u8]) -> PyResult<SecretKey> {
self.backend
.secret_key_by_label(label)
Expand All @@ -178,6 +192,12 @@ impl SecretKeyFactory {
.map_err(|err| PyValueError::new_err(format!("{}", err)))
}

pub fn secret_key_factory_by_label(&self, label: &[u8]) -> Self {
Self {
backend: self.backend.secret_key_factory_by_label(label),
}
}

pub fn to_secret_bytes(&self) -> PyResult<PyObject> {
to_secret_bytes(self)
}
Expand Down
11 changes: 11 additions & 0 deletions umbral-pre-python/umbral_pre/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,20 @@ class SecretKeyFactory:
def random() -> SecretKeyFactory:
...

@staticmethod
def seed_size() -> int:
...

@staticmethod
def from_secure_randomness(seed: bytes) -> SecretKeyFactory:
...

def secret_key_by_label(self, label: bytes) -> SecretKey:
...

def secret_key_factory_by_label(self, label: bytes) -> SecretKeyFactory:
...

def to_secret_bytes(self) -> bytes:
...

Expand Down
17 changes: 17 additions & 0 deletions umbral-pre-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ impl SecretKeyFactory {
Self(umbral_pre::SecretKeyFactory::random())
}

#[wasm_bindgen(js_name = seedSize)]
pub fn seed_size() -> usize {
umbral_pre::SecretKeyFactory::seed_size()
}

#[wasm_bindgen(js_name = fromSecureRandomness)]
pub fn from_secure_randomness(seed: &[u8]) -> Result<SecretKeyFactory, JsValue> {
umbral_pre::SecretKeyFactory::from_secure_randomness(seed)
.map(Self)
.map_err(map_js_err)
}

#[wasm_bindgen(js_name = secretKeyByLabel)]
pub fn secret_key_by_label(&self, label: &[u8]) -> Result<SecretKey, JsValue> {
self.0
Expand All @@ -79,6 +91,11 @@ impl SecretKeyFactory {
.map_err(map_js_err)
}

#[wasm_bindgen(js_name = secretKeyFactoryByLabel)]
pub fn secret_key_factory_by_label(&self, label: &[u8]) -> Self {
Self(self.0.secret_key_factory_by_label(label))
}

#[wasm_bindgen(js_name = toSecretBytes)]
pub fn to_secret_bytes(&self) -> Box<[u8]> {
self.0
Expand Down
45 changes: 41 additions & 4 deletions umbral-pre/src/keys.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::cmp::Ordering;
use core::fmt;

use digest::Digest;
Expand All @@ -8,7 +9,7 @@ use elliptic_curve::{PublicKey as BackendPublicKey, SecretKey as BackendSecretKe
use generic_array::GenericArray;
use rand_core::{CryptoRng, RngCore};
use signature::{DigestVerifier, RandomizedDigestSigner, Signature as SignatureTrait};
use typenum::{U32, U64};
use typenum::{Unsigned, U32, U64};

#[cfg(feature = "default-rng")]
use rand_core::OsRng;
Expand All @@ -19,7 +20,7 @@ use crate::hashing::{BackendDigest, Hash, ScalarDigest};
use crate::secret_box::{CanBeZeroizedOnDrop, SecretBox};
use crate::traits::{
fmt_public, fmt_secret, ConstructionError, DeserializableFromArray, HasTypeName,
RepresentableAsArray, SerializableToArray, SerializableToSecretArray,
RepresentableAsArray, SerializableToArray, SerializableToSecretArray, SizeMismatchError,
};

/// ECDSA signature object.
Expand Down Expand Up @@ -265,7 +266,7 @@ impl fmt::Display for SecretKeyFactoryError {
}
}

type SecretKeyFactorySeedSize = U64; // the size of the seed material for key derivation
type SecretKeyFactorySeedSize = U32; // the size of the seed material for key derivation
type SecretKeyFactoryDerivedSize = U64; // the size of the derived key (before hashing to scalar)
type SecretKeyFactorySeed = GenericArray<u8, SecretKeyFactorySeedSize>;

Expand All @@ -288,7 +289,30 @@ impl SecretKeyFactory {
Self::random_with_rng(&mut OsRng)
}

/// Creates a `SecretKey` from the given label.
/// Returns the seed size required by
/// [`from_secure_randomness`](`SecretKeyFactory::from_secure_randomness`).
pub fn seed_size() -> usize {
SecretKeyFactorySeedSize::to_usize()
}

/// Creates a secret key factory using the given random bytes.
///
/// **Warning:** make sure the given seed has been obtained
/// from a cryptographically secure source of randomness!
pub fn from_secure_randomness(seed: &[u8]) -> Result<Self, SizeMismatchError> {
let received_size = seed.len();
let expected_size = Self::seed_size();
match received_size.cmp(&expected_size) {
Ordering::Greater | Ordering::Less => {
Err(SizeMismatchError::new(received_size, expected_size))
}
Ordering::Equal => Ok(Self(SecretBox::new(*SecretKeyFactorySeed::from_slice(
seed,
)))),
}
}

/// Creates a `SecretKey` deterministically from the given label.
pub fn secret_key_by_label(&self, label: &[u8]) -> Result<SecretKey, SecretKeyFactoryError> {
let prefix = b"KEY_DERIVATION/";
let info: Vec<u8> = prefix
Expand All @@ -304,6 +328,19 @@ impl SecretKeyFactory {
// TODO (#39) when we can hash to nonzero scalars, we can get rid of returning Result
SecretKey::from_scalar(&scalar).ok_or(SecretKeyFactoryError::ZeroHash)
}

/// Creates a `SecretKeyFactory` deterministically from the given label.
pub fn secret_key_factory_by_label(&self, label: &[u8]) -> Self {
let prefix = b"FACTORY_DERIVATION/";
let info: Vec<u8> = prefix
.iter()
.cloned()
.chain(label.iter().cloned())
.collect();
let derived_seed =
kdf::<SecretKeyFactorySeed, SecretKeyFactorySeedSize>(&self.0, None, Some(&info));
Self(derived_seed)
}
}

#[cfg(test)]
Expand Down

0 comments on commit 849f468

Please sign in to comment.