Skip to content

Commit

Permalink
Merge pull request #40 from fjarri/kfrag_id
Browse files Browse the repository at this point in the history
Introduce KeyFragID instead of using a Scalar for this purpose
  • Loading branch information
fjarri authored Mar 12, 2021
2 parents 125a2c6 + 768de65 commit 128eb0c
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 60 deletions.
67 changes: 50 additions & 17 deletions umbral-pre/src/capsule_frag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,45 @@ use crate::capsule::Capsule;
use crate::curve::{CurvePoint, CurveScalar};
use crate::curve::{PublicKey, Signature};
use crate::hashing::{ScalarDigest, SignatureDigest};
use crate::key_frag::KeyFrag;
use crate::hashing_ds::hash_metadata;
use crate::key_frag::{KeyFrag, KeyFragID};
use crate::traits::SerializableToArray;

use generic_array::sequence::Concat;
use generic_array::GenericArray;
use typenum::op;
use typenum::{op, U32};

// The compiler will ensure that's the array length we are getting from the hash function.
// Hardcoding here for the purposes of the formal specification.
type HashedMetadataSize = U32;

#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct HashedMetadata(GenericArray<u8, HashedMetadataSize>);

impl HashedMetadata {
fn new(maybe_metadata: Option<&[u8]>) -> Self {
let metadata = maybe_metadata.unwrap_or(b"");
Self(hash_metadata(metadata))
}
}

impl AsRef<[u8]> for HashedMetadata {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}

impl SerializableToArray for HashedMetadata {
type Size = HashedMetadataSize;

fn to_array(&self) -> GenericArray<u8, Self::Size> {
self.0
}

fn from_array(arr: &GenericArray<u8, Self::Size>) -> Option<Self> {
Some(Self(*arr))
}
}

#[derive(Clone, Debug, PartialEq)]
pub struct CapsuleFragProof {
Expand All @@ -17,7 +50,7 @@ pub struct CapsuleFragProof {
kfrag_pok: CurvePoint,
signature: CurveScalar,
kfrag_signature: Signature,
metadata: CurveScalar,
metadata: HashedMetadata,
}

type PointSize = <CurvePoint as SerializableToArray>::Size;
Expand Down Expand Up @@ -47,7 +80,7 @@ impl SerializableToArray for CapsuleFragProof {
let (kfrag_pok, rest) = CurvePoint::take(rest)?;
let (signature, rest) = CurveScalar::take(rest)?;
let (kfrag_signature, rest) = Signature::take(rest)?;
let metadata = CurveScalar::take_last(rest)?;
let metadata = HashedMetadata::take_last(rest)?;
Some(Self {
point_e2,
point_v2,
Expand All @@ -67,7 +100,7 @@ impl CapsuleFragProof {
kfrag: &KeyFrag,
cfrag_e1: &CurvePoint,
cfrag_v1: &CurvePoint,
metadata: &CurveScalar,
metadata: &HashedMetadata,
) -> Self {
let params = capsule.params;

Expand All @@ -91,7 +124,7 @@ impl CapsuleFragProof {

let h = ScalarDigest::new()
.chain_points(&[e, *e1, e2, v, *v1, v2, u, u1, u2])
.chain_scalar(metadata)
.chain_bytes(metadata)
.finalize();

////////
Expand All @@ -115,7 +148,7 @@ impl CapsuleFragProof {
pub struct CapsuleFrag {
pub(crate) point_e1: CurvePoint,
pub(crate) point_v1: CurvePoint,
pub(crate) kfrag_id: CurveScalar,
pub(crate) kfrag_id: KeyFragID,
pub(crate) precursor: CurvePoint,
pub(crate) proof: CapsuleFragProof,
}
Expand All @@ -137,7 +170,7 @@ impl SerializableToArray for CapsuleFrag {
fn from_array(arr: &GenericArray<u8, Self::Size>) -> Option<Self> {
let (point_e1, rest) = CurvePoint::take(*arr)?;
let (point_v1, rest) = CurvePoint::take(rest)?;
let (kfrag_id, rest) = CurveScalar::take(rest)?;
let (kfrag_id, rest) = KeyFragID::take(rest)?;
let (precursor, rest) = CurvePoint::take(rest)?;
let proof = CapsuleFragProof::take_last(rest)?;
Some(Self {
Expand All @@ -151,16 +184,16 @@ impl SerializableToArray for CapsuleFrag {
}

impl CapsuleFrag {
pub(crate) fn reencrypted(capsule: &Capsule, kfrag: &KeyFrag, metadata: Option<&[u8]>) -> Self {
pub(crate) fn reencrypted(
capsule: &Capsule,
kfrag: &KeyFrag,
maybe_metadata: Option<&[u8]>,
) -> Self {
let rk = kfrag.key;
let e1 = &capsule.point_e * &rk;
let v1 = &capsule.point_v * &rk;
let metadata_scalar = match metadata {
Some(s) => ScalarDigest::new().chain_bytes(s).finalize(),
None => CurveScalar::default(),
};
let proof =
CapsuleFragProof::from_kfrag_and_cfrag(&capsule, &kfrag, &e1, &v1, &metadata_scalar);
let metadata = HashedMetadata::new(maybe_metadata);
let proof = CapsuleFragProof::from_kfrag_and_cfrag(&capsule, &kfrag, &e1, &v1, &metadata);

Self {
point_e1: e1,
Expand Down Expand Up @@ -200,7 +233,7 @@ impl CapsuleFrag {

let h = ScalarDigest::new()
.chain_points(&[e, e1, e2, v, v1, v2, u, u1, u2])
.chain_scalar(&self.proof.metadata)
.chain_bytes(&self.proof.metadata)
.finalize();

///////
Expand All @@ -209,7 +242,7 @@ impl CapsuleFrag {
let kfrag_id = self.kfrag_id;

let valid_kfrag_signature = SignatureDigest::new()
.chain_scalar(&kfrag_id)
.chain_bytes(&kfrag_id)
.chain_pubkey(delegating_pk)
.chain_pubkey(receiving_pk)
.chain_point(&u1)
Expand Down
5 changes: 1 addition & 4 deletions umbral-pre/src/dem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ fn kdf(seed: &[u8], salt: Option<&[u8]>, info: Option<&[u8]>) -> GenericArray<u8

let mut okm = GenericArray::<u8, KdfSize>::default();

let def_info = match info {
Some(x) => x,
None => &[],
};
let def_info = info.unwrap_or(&[]);

// We can only get an error here if `KdfSize` is too large, and it's known at compile-time.
hk.expand(&def_info, &mut okm).unwrap();
Expand Down
92 changes: 65 additions & 27 deletions umbral-pre/src/hashing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,8 @@ impl ScalarDigest {
Self(digest::Digest::chain(self.0, bytes))
}

pub fn chain_bytes(self, bytes: &[u8]) -> Self {
self.chain_impl(bytes)
}

pub fn chain_scalar(self, scalar: &CurveScalar) -> Self {
self.chain_impl(&scalar.to_array())
pub fn chain_bytes<T: AsRef<[u8]>>(self, bytes: T) -> Self {
self.chain_impl(bytes.as_ref())
}

pub fn chain_point(self, point: &CurvePoint) -> Self {
Expand Down Expand Up @@ -108,8 +104,8 @@ impl SignatureDigest {
Self(digest::Digest::chain(self.0, bytes))
}

pub fn chain_scalar(self, scalar: &CurveScalar) -> Self {
self.chain_impl(&scalar.to_array())
pub fn chain_bytes<T: AsRef<[u8]>>(self, bytes: T) -> Self {
self.chain_impl(bytes.as_ref())
}

pub fn chain_point(self, point: &CurvePoint) -> Self {
Expand All @@ -133,51 +129,77 @@ impl SignatureDigest {
}
}

pub(crate) struct BytesDigest(Sha256);

// Can't be put in the `impl` in the current version of Rust.
pub type BytesDigestOutputSize = <Sha256 as Digest>::OutputSize;

impl BytesDigest {
fn new() -> Self {
Self(Sha256::new())
}

pub fn new_with_dst(bytes: &[u8]) -> Self {
Self::new().chain_bytes(bytes)
}

fn chain_impl(self, bytes: &[u8]) -> Self {
Self(digest::Digest::chain(self.0, bytes))
}

pub fn chain_bytes(self, bytes: &[u8]) -> Self {
self.chain_impl(bytes)
}

pub fn finalize(self) -> GenericArray<u8, BytesDigestOutputSize> {
self.0.finalize()
}
}

#[cfg(test)]
mod tests {

use super::{unsafe_hash_to_point, ScalarDigest, SignatureDigest};
use crate::curve::{CurvePoint, CurveScalar, PublicKey, SecretKey};
use super::{
unsafe_hash_to_point, BytesDigest, BytesDigestOutputSize, ScalarDigest, SignatureDigest,
};
use crate::curve::{CurvePoint, CurveScalar, PublicKey, SecretKey, Signature};
use generic_array::GenericArray;

#[test]
fn test_unsafe_hash_to_point() {
let data = b"abcdefg";
let dst = b"sdasdasd";
let p = unsafe_hash_to_point(&dst[..], &data[..]);
let p_same = unsafe_hash_to_point(&dst[..], &data[..]);
let p: Option<CurvePoint> = unsafe_hash_to_point(&dst[..], &data[..]);
let p_same: Option<CurvePoint> = unsafe_hash_to_point(&dst[..], &data[..]);
assert_eq!(p, p_same);

let data2 = b"abcdefgh";
let p_data2 = unsafe_hash_to_point(&dst[..], &data2[..]);
let p_data2: Option<CurvePoint> = unsafe_hash_to_point(&dst[..], &data2[..]);
assert_ne!(p, p_data2);

let dst2 = b"sdasdasds";
let p_dst2 = unsafe_hash_to_point(&dst2[..], &data[..]);
let p_dst2: Option<CurvePoint> = unsafe_hash_to_point(&dst2[..], &data[..]);
assert_ne!(p, p_dst2);
}

#[test]
fn test_scalar_digest() {
let p1 = CurvePoint::generator();
let p2 = &p1 + &p1;
let rs = CurveScalar::random_nonzero();
let bytes: &[u8] = b"foobar";

let s = ScalarDigest::new()
let s: CurveScalar = ScalarDigest::new()
.chain_points(&[p1, p2])
.chain_scalar(&rs)
.chain_bytes(bytes)
.finalize();
let s_same = ScalarDigest::new()
let s_same: CurveScalar = ScalarDigest::new()
.chain_points(&[p1, p2])
.chain_scalar(&rs)
.chain_bytes(bytes)
.finalize();
assert_eq!(s, s_same);

let s_diff = ScalarDigest::new()
let s_diff: CurveScalar = ScalarDigest::new()
.chain_points(&[p2, p1])
.chain_scalar(&rs)
.chain_bytes(bytes)
.finalize();
assert_ne!(s, s_diff);
Expand All @@ -187,31 +209,31 @@ mod tests {
fn test_signature_digest() {
let p1 = CurvePoint::generator();
let p2 = &p1 + &p1;
let rs = CurveScalar::random_nonzero();
let bytes = b"asdfghjk";
let b = true;
let pk = PublicKey::from_secret_key(&SecretKey::random());

let signing_sk = SecretKey::random();
let signing_pk = PublicKey::from_secret_key(&signing_sk);

let signature = SignatureDigest::new()
let signature: Signature = SignatureDigest::new()
.chain_point(&p2)
.chain_scalar(&rs)
.chain_bytes(&bytes)
.chain_bool(b)
.chain_pubkey(&pk)
.sign(&signing_sk);

let same_values_same_key = SignatureDigest::new()
.chain_point(&p2)
.chain_scalar(&rs)
.chain_bytes(&bytes)
.chain_bool(b)
.chain_pubkey(&pk)
.verify(&signing_pk, &signature);
assert!(same_values_same_key);

let same_values_different_key = SignatureDigest::new()
.chain_point(&p2)
.chain_scalar(&rs)
.chain_bytes(&bytes)
.chain_bool(b)
.chain_pubkey(&pk)
.verify(&pk, &signature);
Expand All @@ -220,11 +242,27 @@ mod tests {

let different_values_same_key = SignatureDigest::new()
.chain_point(&p1)
.chain_scalar(&rs)
.chain_bytes(&bytes)
.chain_bool(b)
.chain_pubkey(&pk)
.verify(&signing_pk, &signature);

assert!(!different_values_same_key);
}

#[test]
fn test_bytes_digest() {
let bytes: &[u8] = b"foobar";
let bytes2: &[u8] = b"barbaz";

let s: GenericArray<u8, BytesDigestOutputSize> =
BytesDigest::new().chain_bytes(bytes).finalize();
let s_same: GenericArray<u8, BytesDigestOutputSize> =
BytesDigest::new().chain_bytes(bytes).finalize();
assert_eq!(s, s_same);

let s_diff: GenericArray<u8, BytesDigestOutputSize> =
BytesDigest::new().chain_bytes(bytes2).finalize();
assert_ne!(s, s_diff);
}
}
15 changes: 12 additions & 3 deletions umbral-pre/src/hashing_ds.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
//! This module contains hashing sequences with included domain separation tags
//! shared between different parts of the code.

use generic_array::GenericArray;

use crate::curve::{CurvePoint, CurveScalar};
use crate::hashing::ScalarDigest;
use crate::hashing::{BytesDigest, BytesDigestOutputSize, ScalarDigest};
use crate::key_frag::KeyFragID;

// TODO (#39): Ideally this should return a non-zero scalar.
pub(crate) fn hash_to_polynomial_arg(
precursor: &CurvePoint,
pubkey: &CurvePoint,
dh_point: &CurvePoint,
id: &CurveScalar,
kfrag_id: &KeyFragID,
) -> CurveScalar {
ScalarDigest::new_with_dst(b"POLYNOMIAL_ARG")
.chain_point(precursor)
.chain_point(pubkey)
.chain_point(dh_point)
.chain_scalar(id)
.chain_bytes(kfrag_id)
.finalize()
}

Expand All @@ -32,3 +35,9 @@ pub(crate) fn hash_to_shared_secret(
.chain_point(dh_point)
.finalize()
}

pub(crate) fn hash_metadata(bytes: &[u8]) -> GenericArray<u8, BytesDigestOutputSize> {
BytesDigest::new_with_dst(b"METADATA")
.chain_bytes(bytes)
.finalize()
}
Loading

0 comments on commit 128eb0c

Please sign in to comment.