Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add derive_parent methods #75

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::{
Fr, G1Affine, G2Affine, DST, PK_SIZE, SIG_SIZE, SK_SIZE,
};

use group::ff::Field;

pub(crate) fn derivation_index_into_fr(index: &[u8]) -> Fr {
hash_to_field(index).unwrap_or_else(|_| {
// If the new fr is zero (which should in practice never happen!) do a
Expand All @@ -18,6 +20,14 @@ pub(crate) fn derivation_index_into_fr(index: &[u8]) -> Fr {
})
}

pub(crate) fn derivation_index_into_fr_inv(index: &[u8]) -> Fr {
let index_fr = derivation_index_into_fr(index);
// invert will fail if index_fr is zero, which will never happen (see
// comment in fn derivation_index_into_fr)
// so it's safe to use unwrap after invert here.
index_fr.invert().unwrap()
}

/// Generates a scalar as described in IETF hash to curve
/// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#name-hashing-to-a-finite-field-2
/// There are two main candidates for converting arbitrary bytes to scalar:
Expand Down
106 changes: 105 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ use serde::{Deserialize, Serialize};
use zeroize::Zeroize;

use crate::cmp_pairing::cmp_affine;
use crate::convert::{derivation_index_into_fr, fr_from_bytes, g1_from_bytes, g2_from_bytes};
use crate::convert::{
derivation_index_into_fr, derivation_index_into_fr_inv, fr_from_bytes, g1_from_bytes,
g2_from_bytes,
};
pub use crate::error::{Error, Result};
pub use crate::into_fr::IntoFr;
use crate::poly::{Commitment, Poly};
Expand Down Expand Up @@ -175,6 +178,14 @@ impl PublicKey {
PublicKey(child_g1)
}

/// Derives a parent public key for a given index.
pub fn derive_parent(&self, index: &[u8]) -> Self {
let index_inv = derivation_index_into_fr_inv(index);
let mut parent_g1 = self.0;
parent_g1.mul_assign(index_inv);
PublicKey(parent_g1)
}

/// Returns the key with the given representation, if valid.
pub fn from_bytes(bytes: [u8; PK_SIZE]) -> Result<Self> {
let g1 = g1_from_bytes(bytes)?;
Expand Down Expand Up @@ -233,6 +244,11 @@ impl PublicKeyShare {
PublicKeyShare(self.0.derive_child(index))
}

/// Derives a parent public key share for a given index.
pub fn derive_parent(&self, index: &[u8]) -> Self {
PublicKeyShare(self.0.derive_parent(index))
}

/// Returns the key share with the given representation, if valid.
pub fn from_bytes(bytes: [u8; PK_SIZE]) -> Result<Self> {
Ok(PublicKeyShare(PublicKey::from_bytes(bytes)?))
Expand Down Expand Up @@ -479,6 +495,13 @@ impl SecretKey {
index_fr.mul_assign(&self.0);
SecretKey(index_fr)
}

/// Derives a parent secret key for a given index.
pub fn derive_parent(&self, index: &[u8]) -> Self {
let mut index_inv = derivation_index_into_fr_inv(index);
index_inv.mul_assign(&self.0);
SecretKey(index_inv)
}
}

/// A secret key share.
Expand Down Expand Up @@ -556,6 +579,11 @@ impl SecretKeyShare {
SecretKeyShare(self.0.derive_child(index))
}

/// Derives a parent secret key share for a given index.
pub fn derive_parent(&self, index: &[u8]) -> Self {
SecretKeyShare(self.0.derive_parent(index))
}

/// Serializes to big endian bytes
pub fn to_bytes(&self) -> [u8; SK_SIZE] {
self.0.to_bytes()
Expand Down Expand Up @@ -797,6 +825,22 @@ impl PublicKeySet {
PublicKeySet::from(Commitment::from(child_coeffs))
}

/// Derives a parent public key set for a given index.
pub fn derive_parent(&self, index: &[u8]) -> Self {
let index_inv = derivation_index_into_fr_inv(index);
let parent_coeffs: Vec<G1Affine> = self
.commit
.coeff
.iter()
.map(|coeff| {
let mut parent_coeff = *coeff;
parent_coeff.mul_assign(index_inv);
parent_coeff
})
.collect();
PublicKeySet::from(Commitment::from(parent_coeffs))
}

/// Serializes to big endian bytes
pub fn to_bytes(&self) -> Vec<u8> {
self.commit.to_bytes()
Expand Down Expand Up @@ -893,6 +937,22 @@ impl SecretKeySet {
SecretKeySet::from(Poly::from(child_coeffs))
}

/// Derives a parent secret key set for a given index.
pub fn derive_parent(&self, index: &[u8]) -> Self {
let index_inv = derivation_index_into_fr_inv(index);
let parent_coeffs: Vec<Fr> = self
.poly
.coeff
.iter()
.map(|coeff| {
let mut parent_coeff = *coeff;
parent_coeff.mul_assign(&index_inv);
parent_coeff
})
.collect();
SecretKeySet::from(Poly::from(parent_coeffs))
}

/// Serializes to big endian bytes
pub fn to_bytes(&self) -> Vec<u8> {
self.poly.to_bytes()
Expand Down Expand Up @@ -1922,4 +1982,48 @@ mod tests {
// check that verify_g2 is protected against this attack
assert!(!rogue_public_key.verify_g2(&rogue_sig, hash));
}

#[test]
fn test_pubkey_derive_parent() {
let sk = SecretKey::random();
let pk = sk.public_key();
let index = [0, 1, 2, 3];
let child = pk.derive_child(&index);
let parent = child.derive_parent(&index);
// check that the parent of the child is the original key
assert_eq!(pk, parent);
}

#[test]
fn test_secretkey_derive_parent() {
let sk = SecretKey::random();
let index = [0, 1, 2, 3];
let child = sk.derive_child(&index);
let parent = child.derive_parent(&index);
// check that the parent of the child is the original key
assert_eq!(sk, parent);
}

#[test]
fn test_pubkeyset_derive_parent() {
let mut rng = rand::thread_rng();
let sks = SecretKeySet::random(3, &mut rng);
let pks = sks.public_keys();
let index = [0, 1, 2, 3];
let child = pks.derive_child(&index);
let parent = child.derive_parent(&index);
// check that the parent of the child is the original key
assert_eq!(pks, parent);
}

#[test]
fn test_secretkeyset_derive_parent() {
let mut rng = rand::thread_rng();
let sks = SecretKeySet::random(3, &mut rng);
let index = [0, 1, 2, 3];
let child = sks.derive_child(&index);
let parent = child.derive_parent(&index);
// check that the parent of the child is the original key
assert_eq!(sks.to_bytes(), parent.to_bytes());
}
}