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

wallet-core: Add workspace member with keys generation #2113

Merged
merged 2 commits into from
Aug 13, 2024
Merged
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ members = [
"contracts/license",

"execution-core",
"wallet-core",

"rusk-prover",

Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ keys: ## Create the keys for the circuits
state: keys wasm ## Create the network state
$(MAKE) -C ./rusk recovery-state

wasm: setup-compiler ## Generate the WASM for all the contracts
wasm: setup-compiler ## Generate the WASM for all the contracts and wallet-core
$(MAKE) -C ./contracts $@
$(MAKE) -C ./wallet-core $@

allcircuits: ## Build circuit crates
$(MAKE) -j -C ./circuits all
Expand All @@ -34,6 +35,7 @@ test: keys wasm ## Run the tests
$(MAKE) -C ./node-data $@
$(MAKE) -C ./consensus $@
$(MAKE) -C ./node $@
$(MAKE) -C ./wallet-core $@
$(MAKE) -C ./rusk/ $@

clippy: ## Run clippy
Expand All @@ -46,6 +48,7 @@ clippy: ## Run clippy
$(MAKE) -C ./node-data $@
$(MAKE) -C ./consensus $@
$(MAKE) -C ./node $@
$(MAKE) -C ./wallet-core $@
$(MAKE) -C ./rusk/ $@

doc: ## Run doc gen
Expand All @@ -59,6 +62,7 @@ doc: ## Run doc gen
$(MAKE) -C ./rusk-profile $@
$(MAKE) -C ./rusk-prover/ $@
$(MAKE) -C ./rusk-recovery $@
$(MAKE) -C ./wallet-core/ $@

run: keys state web-wallet ## Run the server
$(MAKE) -C ./rusk/ $@
Expand Down
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
91 changes: 91 additions & 0 deletions wallet-core/src/keys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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.
///
/// The randomness is generated using [`rng_with_index`].
#[must_use]
pub fn derive_bls_sk(seed: &[u8; RNG_SEED], index: u8) -> 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: u8) -> 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: u8) -> 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: u8) -> 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: u8,
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: u8 = 42;

#[test]
fn test_derive_phoenix_sk() {
// it is important that we always derive the same key from a fixed seed
let sk_bytes = [
160, 210, 234, 8, 94, 23, 76, 60, 130, 143, 137, 225, 37, 83, 68, 218,
207, 192, 171, 235, 252, 130, 133, 62, 18, 232, 6, 49, 245, 123, 220,
12, 250, 111, 39, 88, 24, 41, 156, 174, 241, 14, 118, 173, 11, 53, 192,
126, 7, 119, 70, 69, 212, 230, 124, 79, 223, 140, 93, 153, 33, 147,
163, 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 = [
59, 192, 170, 209, 99, 97, 60, 124, 218, 81, 61, 102, 25, 235, 14, 87,
219, 234, 56, 102, 10, 111, 22, 189, 171, 101, 180, 168, 17, 70, 72,
101, 135, 243, 55, 243, 138, 103, 185, 26, 196, 219, 84, 126, 33, 115,
84, 60, 38, 41, 79, 104, 232, 222, 105, 2, 60, 185, 149, 50, 207, 43,
89, 100,
];
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 = [
160, 210, 234, 8, 94, 23, 76, 60, 130, 143, 137, 225, 37, 83, 68, 218,
207, 192, 171, 235, 252, 130, 133, 62, 18, 232, 6, 49, 245, 123, 220,
12, 135, 243, 55, 243, 138, 103, 185, 26, 196, 219, 84, 126, 33, 115,
84, 60, 38, 41, 79, 104, 232, 222, 105, 2, 60, 185, 149, 50, 207, 43,
89, 100,
];
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 = [
130, 180, 24, 224, 131, 143, 97, 18, 120, 53, 37, 39, 251, 44, 121,
168, 4, 248, 29, 176, 142, 136, 224, 188, 159, 246, 73, 6, 112, 174, 6,
7,
];
assert_eq!(derive_bls_sk(&SEED, INDEX).to_bytes(), sk_bytes);
}
Loading