Skip to content

Commit

Permalink
wallet-core: Add basic setup with keys generation
Browse files Browse the repository at this point in the history
  • Loading branch information
moCello committed Aug 13, 2024
1 parent c7eaecb commit 6920355
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 0 deletions.
16 changes: 16 additions & 0 deletions wallet-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "wallet-core"
version = "0.1.0"
edition = "2021"

[dependencies]
dusk-bytes = "0.1"
bytecheck = { version = "0.6", default-features = false }
execution-core = { version = "0.1", path = "../execution-core/" }
zeroize = { version = "1", default-features = false, features = ["derive"] }
rand_chacha = { version = "0.3", default-features = false }
sha2 = { version = "0.10", default-features = false }

[dev-dependencies]

[features]
17 changes: 17 additions & 0 deletions wallet-core/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
all: ## Build the ABI
cargo build

help: ## Display this help screen
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'

test:
cargo test --release

clippy: ## Run clippy
@cargo clippy --release -- -D warnings
@cargo clippy --no-default-features --release -- -D warnings

doc: ## Run doc gen
@cargo doc --release

.PHONY: all help test
98 changes: 98 additions & 0 deletions wallet-core/src/keys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

//! Utilities to derive keys from the seed.
use rand_chacha::{rand_core::SeedableRng, ChaCha12Rng};
use sha2::{Digest, Sha256};

use execution_core::{
signatures::bls::SecretKey as BlsSecretKey,
transfer::phoenix::{
PublicKey as PhoenixPublicKey, SecretKey as PhoenixSecretKey,
ViewKey as PhoenixViewKey,
},
};
use zeroize::Zeroize;

use crate::RNG_SEED;

/// Generates a [`BlsSecretKey`] from a seed and index that can be used for
/// staking.
///
/// The randomness is generated using [`rng_with_index`].
#[must_use]
pub fn derive_stake_sk(seed: &[u8; RNG_SEED], index: u64) -> BlsSecretKey {
// note that if we change the string used for the rng, all previously
// generated keys will become invalid
BlsSecretKey::random(&mut rng_with_index(seed, index, b"SK"))
}

/// Generates a [`PhoenixSecretKey`] from a seed and index.
///
/// The randomness is generated using [`rng_with_index`].
#[must_use]
pub fn derive_phoenix_sk(
seed: &[u8; RNG_SEED],
index: u64,
) -> PhoenixSecretKey {
// note that if we change the string used for the rng, all previously
// generated keys will become invalid
PhoenixSecretKey::random(&mut rng_with_index(seed, index, b"SSK"))
}

/// Generates a [`PheonixPublicKey`] from its seed and index.
///
/// First the [`PhoenixSecretKey`] is derived with [`derive_phoenix_sk`], then
/// the public key is generated from it and the secret key is erased from
/// memory.
#[must_use]
pub fn derive_phoenix_pk(
seed: &[u8; RNG_SEED],
index: u64,
) -> PhoenixPublicKey {
let mut sk = derive_phoenix_sk(seed, index);
let pk = PhoenixPublicKey::from(&sk);
sk.zeroize();

pk
}

/// Generates a [`PhoenixViewKey`] from its seed and index.
///
/// First the [`PhoenixSecretKey`] is derived with [`derive_phoenix_sk`], then
/// the view key is generated from it and the secret key is erased from memory.
#[must_use]
pub fn derive_phoenix_vk(seed: &[u8; RNG_SEED], index: u64) -> PhoenixViewKey {
let mut sk = derive_phoenix_sk(seed, index);
let vk = PhoenixViewKey::from(&sk);
sk.zeroize();

vk
}

/// Creates a secure RNG from a seed with embedded index and termination
/// constant.
///
/// First the `seed` and then the little-endian representation of the key's
/// `index` are passed through SHA-256. A constant is then mixed in and the
/// resulting hash is then used to seed a `ChaCha12` CSPRNG, which is
/// subsequently used to generate the key.
#[must_use]
pub fn rng_with_index(
seed: &[u8; RNG_SEED],
index: u64,
termination: &[u8],
) -> ChaCha12Rng {
let mut hash = Sha256::new();

hash.update(seed);
hash.update(index.to_le_bytes());
hash.update(termination);

let hash = hash.finalize().into();
ChaCha12Rng::from_seed(hash)
}
17 changes: 17 additions & 0 deletions wallet-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

//! Types used for interacting with Dusk's transfer and stake contracts.
#![no_std]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::pedantic)]

pub mod keys;

/// Length of the seed of the generated rng.
pub const RNG_SEED: usize = 64;
63 changes: 63 additions & 0 deletions wallet-core/tests/keys_derive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use dusk_bytes::Serializable;
use wallet_core::keys::{
derive_phoenix_pk, derive_phoenix_sk, derive_phoenix_vk, derive_stake_sk,
};

const SEED: [u8; 64] = [0; 64];
const INDEX: u64 = 42;

#[test]
fn test_derive_phoenix_sk() {
// it is important that we always derive the same key from a fixed seed
let sk_bytes = [
12, 16, 72, 188, 33, 76, 44, 178, 86, 123, 107, 153, 230, 149, 238,
131, 87, 30, 94, 88, 52, 129, 247, 167, 30, 167, 163, 246, 68, 254, 14,
9, 218, 135, 245, 104, 11, 190, 143, 129, 83, 202, 64, 179, 157, 248,
175, 120, 157, 220, 98, 211, 141, 50, 224, 8, 1, 125, 29, 180, 206,
195, 34, 0,
];
assert_eq!(derive_phoenix_sk(&SEED, INDEX).to_bytes(), sk_bytes);
}

#[test]
fn test_derive_phoenix_pk() {
// it is important that we always derive the same key from a fixed seed
let pk_bytes = [
51, 204, 45, 112, 212, 44, 118, 183, 148, 176, 254, 135, 253, 117, 230,
62, 177, 139, 2, 57, 21, 150, 41, 86, 118, 239, 75, 194, 148, 129, 225,
38, 132, 140, 106, 77, 181, 217, 196, 50, 135, 177, 158, 153, 43, 147,
159, 217, 0, 160, 89, 95, 67, 160, 42, 74, 19, 1, 221, 216, 126, 204,
206, 209,
];
assert_eq!(derive_phoenix_pk(&SEED, INDEX).to_bytes(), pk_bytes);
}

#[test]
fn test_derive_phoenix_vk() {
// it is important that we always derive the same key from a fixed seed
let vk_bytes = [
12, 16, 72, 188, 33, 76, 44, 178, 86, 123, 107, 153, 230, 149, 238,
131, 87, 30, 94, 88, 52, 129, 247, 167, 30, 167, 163, 246, 68, 254, 14,
9, 132, 140, 106, 77, 181, 217, 196, 50, 135, 177, 158, 153, 43, 147,
159, 217, 0, 160, 89, 95, 67, 160, 42, 74, 19, 1, 221, 216, 126, 204,
206, 209,
];
assert_eq!(derive_phoenix_vk(&SEED, INDEX).to_bytes(), vk_bytes);
}

#[test]
fn test_derive_stake_sk() {
// it is important that we always derive the same key from a fixed seed
let sk_bytes = [
95, 35, 167, 191, 106, 171, 71, 158, 159, 39, 84, 1, 132, 238, 152,
235, 154, 5, 250, 158, 255, 195, 79, 95, 193, 58, 36, 189, 0, 99, 230,
86,
];
assert_eq!(derive_stake_sk(&SEED, INDEX).to_bytes(), sk_bytes);
}

0 comments on commit 6920355

Please sign in to comment.