diff --git a/Cargo.lock b/Cargo.lock index 9fcb1bb..069575e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,10 +7,15 @@ name = "accounts" version = "0.1.0" dependencies = [ "anyhow", + "elliptic-curve", "env_logger", + "k256", "log", + "rand 0.8.5", "serde", "serde_json", + "sha2 0.10.8", + "storage", ] [[package]] @@ -329,12 +334,24 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bindgen" version = "0.65.1" @@ -517,6 +534,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -553,6 +576,18 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle 2.6.1", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -570,7 +605,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" dependencies = [ "generic-array 0.12.4", - "subtle", + "subtle 1.0.0", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", ] [[package]] @@ -611,7 +656,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", + "subtle 2.6.1", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array 0.14.7", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle 2.6.1", + "zeroize", ] [[package]] @@ -648,6 +728,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle 2.6.1", +] + [[package]] name = "fnv" version = "1.0.7" @@ -769,6 +859,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -805,6 +896,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle 2.6.1", +] + [[package]] name = "h2" version = "0.3.26" @@ -867,6 +969,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "http" version = "0.2.12" @@ -942,6 +1053,20 @@ dependencies = [ "libc", ] +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.8", + "signature", +] + [[package]] name = "keccak" version = "0.1.5" @@ -1387,6 +1512,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.31" @@ -1563,6 +1698,16 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle 2.6.1", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -1626,6 +1771,20 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle 2.6.1", + "zeroize", +] + [[package]] name = "semver" version = "1.0.23" @@ -1791,6 +1950,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "slab" version = "0.4.9" @@ -1826,6 +1995,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "storage" version = "0.1.0" @@ -1849,6 +2028,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.79" @@ -2206,6 +2391,12 @@ dependencies = [ "syn", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + [[package]] name = "zkvm" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 557344b..8b6d782 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,18 @@ rocksdb = { version = "0.21.0", default-features = false, features = ["snappy"] #ToDo: Add necessary risc0 submodules for zkvm module +[workspace.dependencies.rand] +features = ["std", "std_rng", "getrandom"] +version = "0.8.5" + +[workspace.dependencies.k256] +features = ["ecdsa-core", "arithmetic", "expose-field"] +version = "0.13.4" + +[workspace.dependencies.elliptic-curve] +features = ["arithmetic"] +version = "0.13.8" + [workspace.dependencies.serde] features = ["derive"] version = "1.0.60" diff --git a/accounts/Cargo.toml b/accounts/Cargo.toml index 013a49d..97ee1f9 100644 --- a/accounts/Cargo.toml +++ b/accounts/Cargo.toml @@ -8,4 +8,11 @@ anyhow.workspace = true serde_json.workspace = true env_logger.workspace = true log.workspace = true -serde.workspace = true \ No newline at end of file +serde.workspace = true +k256.workspace = true +sha2.workspace = true +rand.workspace = true +elliptic-curve.workspace = true + +[dependencies.storage] +path = "../storage" \ No newline at end of file diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs new file mode 100644 index 0000000..4dd6e78 --- /dev/null +++ b/accounts/src/key_management/mod.rs @@ -0,0 +1,196 @@ +use k256::elliptic_curve::group::GroupEncoding; +use k256::{elliptic_curve::PrimeField, AffinePoint, FieldBytes, Scalar}; +use rand::{rngs::OsRng, RngCore}; +use sha2::{digest::FixedOutput, Digest}; +use storage::merkle_tree_public::TreeHashType; + +pub const NULLIFIER_SECRET_CONST: [u8; 32] = [ + 38, 29, 97, 210, 148, 172, 75, 220, 36, 249, 27, 111, 73, 14, 250, 38, 55, 87, 164, 169, 95, + 101, 135, 28, 212, 241, 107, 46, 162, 60, 59, 93, +]; +pub const VIEVING_SECRET_CONST: [u8; 32] = [ + 97, 23, 175, 117, 11, 48, 215, 162, 150, 103, 46, 195, 179, 178, 93, 52, 137, 190, 202, 60, + 254, 87, 112, 250, 57, 242, 117, 206, 195, 149, 213, 206, +]; + +#[derive(Debug)] +///Seed holder. Non-clonable to ensure that different holders use different seeds. +/// Produces `TopSecretKeyHolder` objects. +pub struct SeedHolder { + seed: Scalar, +} + +#[derive(Debug, Clone)] +///Secret spending key holder. Produces `UTXOSecretKeyHolder` objects. +pub struct TopSecretKeyHolder { + secret_spending_key: Scalar, +} + +#[derive(Debug, Clone)] +///Nullifier secret key and viewing secret key holder. Produces public keys. Can produce address. Can produce shared secret for recepient. +pub struct UTXOSecretKeyHolder { + nullifier_secret_key: Scalar, + viewing_secret_key: Scalar, +} + +impl SeedHolder { + pub fn new_os_random() -> Self { + let mut bytes = FieldBytes::default(); + + OsRng.fill_bytes(&mut bytes); + + Self { + seed: Scalar::from_repr(bytes).unwrap(), + } + } + + pub fn generate_secret_spending_key_hash(&self) -> TreeHashType { + let mut hasher = sha2::Sha256::new(); + + hasher.update(self.seed.to_bytes()); + + ::from(hasher.finalize_fixed()) + } + + pub fn generate_secret_spending_key_scalar(&self) -> Scalar { + let hash = self.generate_secret_spending_key_hash(); + + Scalar::from_repr(hash.into()).unwrap() + } + + pub fn produce_top_secret_key_holder(&self) -> TopSecretKeyHolder { + TopSecretKeyHolder { + secret_spending_key: self.generate_secret_spending_key_scalar(), + } + } +} + +impl TopSecretKeyHolder { + pub fn generate_nullifier_secret_key(&self) -> Scalar { + let mut hasher = sha2::Sha256::new(); + + hasher.update(self.secret_spending_key.to_bytes()); + hasher.update(NULLIFIER_SECRET_CONST); + + let hash = ::from(hasher.finalize_fixed()); + + Scalar::from_repr(hash.into()).unwrap() + } + + pub fn generate_viewing_secret_key(&self) -> Scalar { + let mut hasher = sha2::Sha256::new(); + + hasher.update(self.secret_spending_key.to_bytes()); + hasher.update(VIEVING_SECRET_CONST); + + let hash = ::from(hasher.finalize_fixed()); + + Scalar::from_repr(hash.into()).unwrap() + } + + pub fn produce_utxo_secret_holder(&self) -> UTXOSecretKeyHolder { + UTXOSecretKeyHolder { + nullifier_secret_key: self.generate_nullifier_secret_key(), + viewing_secret_key: self.generate_viewing_secret_key(), + } + } +} + +impl UTXOSecretKeyHolder { + pub fn generate_nullifier_public_key(&self) -> AffinePoint { + (AffinePoint::GENERATOR * self.nullifier_secret_key).into() + } + + pub fn generate_viewing_public_key(&self) -> AffinePoint { + (AffinePoint::GENERATOR * self.viewing_secret_key).into() + } + + pub fn generate_address(&self) -> TreeHashType { + let npk = self.generate_nullifier_public_key(); + let vpk = self.generate_viewing_public_key(); + + let mut hasher = sha2::Sha256::new(); + + hasher.update(npk.to_bytes()); + hasher.update(vpk.to_bytes()); + + ::from(hasher.finalize_fixed()) + } +} + +#[derive(Debug)] +///Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral public keys. Can produce shared secret for sender. +pub struct EphemeralKeyHolder { + ephemeral_secret_key: Scalar, +} + +impl EphemeralKeyHolder { + pub fn new_os_random() -> Self { + let mut bytes = FieldBytes::default(); + + OsRng.fill_bytes(&mut bytes); + + Self { + ephemeral_secret_key: Scalar::from_repr(bytes).unwrap(), + } + } + + pub fn generate_ephemeral_public_key(&self) -> AffinePoint { + (AffinePoint::GENERATOR * self.ephemeral_secret_key).into() + } + + pub fn calculate_shared_secret_sender( + &self, + viewing_public_key_receiver: AffinePoint, + ) -> AffinePoint { + (viewing_public_key_receiver * self.ephemeral_secret_key).into() + } + + pub fn encrypt_data(&self) { + //ToDo: Implement that + //Need clarification on exact symmetric encoding, which we want to use for ECIES + todo!() + } +} + +#[derive(Debug)] +///Entrypoint to key management +pub struct AddressKeyHolder { + utxo_secret_key_holder: UTXOSecretKeyHolder, + pub address: TreeHashType, + pub nullifer_public_key: AffinePoint, + pub viewing_public_key: AffinePoint, +} + +impl AddressKeyHolder { + pub fn new_os_random() -> Self { + //Currently dropping SeedHolder and TopSecretKeyHolder at the end of initialization. + //Now entirely sure if we need them in the future. + let seed_holder = SeedHolder::new_os_random(); + let top_secret_key_holder = seed_holder.produce_top_secret_key_holder(); + + let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder(); + + let address = utxo_secret_key_holder.generate_address(); + let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); + let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); + + Self { + utxo_secret_key_holder, + address, + nullifer_public_key, + viewing_public_key, + } + } + + pub fn calculate_shared_secret_receiver( + &self, + ephemeral_public_key_sender: AffinePoint, + ) -> AffinePoint { + (ephemeral_public_key_sender * self.utxo_secret_key_holder.viewing_secret_key).into() + } + + pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder { + EphemeralKeyHolder::new_os_random() + } +} diff --git a/accounts/src/lib.rs b/accounts/src/lib.rs index c1dc991..a98b67c 100644 --- a/accounts/src/lib.rs +++ b/accounts/src/lib.rs @@ -1 +1 @@ -//ToDo: Add accounts module +pub mod key_management;