From 6920355c95519e6664e2d1310ca623cb8fa5528a Mon Sep 17 00:00:00 2001 From: moana Date: Tue, 13 Aug 2024 11:56:07 +0200 Subject: [PATCH] wallet-core: Add basic setup with keys generation --- wallet-core/Cargo.toml | 16 ++++++ wallet-core/Makefile | 17 ++++++ wallet-core/src/keys.rs | 98 ++++++++++++++++++++++++++++++++ wallet-core/src/lib.rs | 17 ++++++ wallet-core/tests/keys_derive.rs | 63 ++++++++++++++++++++ 5 files changed, 211 insertions(+) create mode 100644 wallet-core/Cargo.toml create mode 100644 wallet-core/Makefile create mode 100644 wallet-core/src/keys.rs create mode 100644 wallet-core/src/lib.rs create mode 100644 wallet-core/tests/keys_derive.rs diff --git a/wallet-core/Cargo.toml b/wallet-core/Cargo.toml new file mode 100644 index 0000000000..f4e3630552 --- /dev/null +++ b/wallet-core/Cargo.toml @@ -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] diff --git a/wallet-core/Makefile b/wallet-core/Makefile new file mode 100644 index 0000000000..1069de5d3d --- /dev/null +++ b/wallet-core/Makefile @@ -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 diff --git a/wallet-core/src/keys.rs b/wallet-core/src/keys.rs new file mode 100644 index 0000000000..32653c55a8 --- /dev/null +++ b/wallet-core/src/keys.rs @@ -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) +} diff --git a/wallet-core/src/lib.rs b/wallet-core/src/lib.rs new file mode 100644 index 0000000000..5c030eb691 --- /dev/null +++ b/wallet-core/src/lib.rs @@ -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; diff --git a/wallet-core/tests/keys_derive.rs b/wallet-core/tests/keys_derive.rs new file mode 100644 index 0000000000..ce5e37eddb --- /dev/null +++ b/wallet-core/tests/keys_derive.rs @@ -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); +}