Skip to content

Commit

Permalink
wallet-core: Add basic setup with keys generation
Browse files Browse the repository at this point in the history
Resolves #2116
  • Loading branch information
moCello committed Aug 13, 2024
1 parent c335730 commit 35eae5a
Show file tree
Hide file tree
Showing 5 changed files with 223 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]
29 changes: 29 additions & 0 deletions wallet-core/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
TARGET_DIR:="../../target/dusk"

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


wasm: ## Build the WASM files
@RUSTFLAGS="$(RUSTFLAGS) --remap-path-prefix $(HOME)= -C link-args=-zstack-size=65536" \
CARGO_TARGET_DIR=$(TARGET_DIR) \
cargo +dusk build \
--release \
--color=always \
-Z build-std=core,alloc \
--target wasm64-unknown-unknown

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_bls_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"BSK"))
}

/// 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"PSK"))
}

/// 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.
#![cfg_attr(target_family = "wasm", 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_bls_sk, derive_phoenix_pk, derive_phoenix_sk, derive_phoenix_vk,
};

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 = [
192, 40, 206, 139, 173, 105, 38, 165, 46, 165, 183, 119, 137, 5, 199,
231, 100, 116, 106, 20, 186, 4, 219, 4, 166, 176, 224, 205, 194, 144,
29, 4, 178, 57, 113, 176, 185, 83, 92, 81, 64, 162, 29, 109, 62, 46,
187, 89, 67, 203, 201, 29, 226, 183, 28, 242, 72, 0, 125, 186, 224,
122, 118, 8,
];
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 = [
41, 66, 141, 44, 149, 148, 109, 187, 53, 86, 81, 73, 144, 160, 221, 82,
102, 38, 97, 140, 252, 41, 202, 58, 239, 18, 147, 255, 52, 192, 236,
22, 168, 125, 132, 85, 254, 91, 12, 47, 95, 1, 145, 82, 53, 84, 63,
140, 110, 187, 85, 142, 241, 70, 3, 40, 102, 246, 30, 186, 24, 146, 4,
85,
];
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 = [
192, 40, 206, 139, 173, 105, 38, 165, 46, 165, 183, 119, 137, 5, 199,
231, 100, 116, 106, 20, 186, 4, 219, 4, 166, 176, 224, 205, 194, 144,
29, 4, 168, 125, 132, 85, 254, 91, 12, 47, 95, 1, 145, 82, 53, 84, 63,
140, 110, 187, 85, 142, 241, 70, 3, 40, 102, 246, 30, 186, 24, 146, 4,
85,
];
assert_eq!(derive_phoenix_vk(&SEED, INDEX).to_bytes(), vk_bytes);
}

#[test]
fn test_derive_bls_sk() {
// it is important that we always derive the same key from a fixed seed
let sk_bytes = [
42, 224, 186, 247, 133, 35, 202, 126, 255, 156, 236, 121, 214, 145,
228, 32, 100, 62, 129, 203, 16, 27, 213, 244, 143, 5, 123, 23, 202, 17,
162, 90,
];
assert_eq!(derive_bls_sk(&SEED, INDEX).to_bytes(), sk_bytes);
}

0 comments on commit 35eae5a

Please sign in to comment.