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

[Rust]: Implement Private and Public keys #3107

Merged
merged 24 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e5e8836
Save dev state
satoshiotomakan Apr 18, 2023
821d95a
[wip] Save dev state
satoshiotomakan Apr 19, 2023
4fe5649
[wip] Save dev state
satoshiotomakan Apr 19, 2023
6efe740
[wip] Integrate 'Rust::tw_private_key_sign' into C++ code
satoshiotomakan Apr 20, 2023
15406f5
[wip] Rename `tw_keeper` crate to `tw_keypair`
satoshiotomakan Apr 20, 2023
4ea61be
[wip] Make `TWPrivateKey` and `TWPublicKey` available for end-user
satoshiotomakan Apr 21, 2023
44d7f67
[wip] Integrate Rust public key verifying into C++
satoshiotomakan Apr 21, 2023
c888285
Merge branch 'master' into s/rust-keeper
satoshiotomakan Apr 21, 2023
675880b
[wip] Split `secp256k1` module into submodules
satoshiotomakan Apr 21, 2023
6cbbe98
[wip] Fix secp256k1 getting shared key
satoshiotomakan Apr 21, 2023
cbb85db
[wip] Move starkex curve from `tw_starnet` to `tw_keypair` crate
satoshiotomakan Apr 22, 2023
359ff33
[wip] Document FFIs
satoshiotomakan Apr 22, 2023
8ef0662
Merge branch 'master' into s/rust-keeper
satoshiotomakan Apr 22, 2023
36e16ef
[wip] Update starknet-crypto and starknet-ff crate
satoshiotomakan Apr 24, 2023
c33ce5b
Merge branch 'dev' into s/rust-keeper
satoshiotomakan Apr 24, 2023
720b364
[r2r] Minor refactoring
satoshiotomakan Apr 24, 2023
0119618
[r2r] Update code coverage
satoshiotomakan Apr 24, 2023
0f5be1f
[r2r] Disable k256 default features to fix WASM
satoshiotomakan Apr 24, 2023
dafd136
[r2r] Document `tw_keypair` structures and methods
satoshiotomakan Apr 24, 2023
9017ed2
[r2r] Zeroize secrets
satoshiotomakan Apr 25, 2023
dbefeb3
[r2r] Fix Rust CI
satoshiotomakan Apr 25, 2023
977fcad
[r2r] Add secp256k1 tests
satoshiotomakan Apr 25, 2023
d80eee3
[r2r] Remove `TW` prefixes
satoshiotomakan Apr 25, 2023
1b2695f
[r2r] Rename `tw_utils` to `tw_misc`
satoshiotomakan Apr 26, 2023
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
658 changes: 210 additions & 448 deletions rust/Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
members = [
"tw_encoding",
"tw_hash",
"tw_keypair",
"tw_memory",
"tw_move_parser",
"tw_proto",
"tw_starknet",
"tw_utils",
hewigovens marked this conversation as resolved.
Show resolved Hide resolved
"wallet_core_rs",
]
2 changes: 1 addition & 1 deletion rust/coverage.stats
Original file line number Diff line number Diff line change
@@ -1 +1 @@
93.7
95.1
1 change: 1 addition & 0 deletions rust/tw_encoding/src/base32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::HashMap;

/// cbindgen:ignore
const ALPHABET_RFC4648: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

type EncodingMap = HashMap<EncodingParams, Encoding>;
Expand Down
4 changes: 2 additions & 2 deletions rust/tw_encoding/src/hex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ pub fn decode(data: &str) -> Result<Vec<u8>, FromHexError> {
hex::decode(hex_string)
}

pub fn encode(data: &[u8], prefixed: bool) -> String {
let encoded = hex::encode(data);
pub fn encode<T: AsRef<[u8]>>(data: T, prefixed: bool) -> String {
let encoded = hex::encode(data.as_ref());
if prefixed {
return format!("0x{encoded}");
}
Expand Down
4 changes: 1 addition & 3 deletions rust/tw_hash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,5 @@ ripemd = "0.1.3"
sha1 = "0.10.5"
sha2 = "0.10.6"
sha3 = "0.10.6"
tw_encoding = { path = "../tw_encoding" }
tw_memory = { path = "../tw_memory" }

[dev-dependencies]
hex = "0.4.3"
160 changes: 160 additions & 0 deletions rust/tw_hash/src/hash_array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

use crate::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use tw_encoding::hex;

pub type H256 = Hash<32>;
pub type H264 = Hash<33>;
pub type H512 = Hash<64>;
pub type H520 = Hash<65>;

#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub struct Hash<const N: usize>([u8; N]);

impl<const N: usize> Hash<N> {
hewigovens marked this conversation as resolved.
Show resolved Hide resolved
pub const fn new() -> Self {
Hash([0; N])
}

pub fn as_slice(&self) -> &[u8] {
&self.0
}

pub fn into_vec(self) -> Vec<u8> {
self.0.to_vec()
}

pub const fn take(self) -> [u8; N] {
self.0
}

pub const fn len() -> usize {
N
}
}

/// Implement `str` -> `Hash<N>` conversion for test purposes.
impl<const N: usize> From<&'static str> for Hash<N> {
fn from(hex: &'static str) -> Self {
hex.parse().expect("Expected a valid hex-encoded hash")
}
}

impl<const N: usize> From<[u8; N]> for Hash<N> {
fn from(data: [u8; N]) -> Self {
Hash(data)
}
}

impl<'a, const N: usize> TryFrom<&'a [u8]> for Hash<N> {
type Error = Error;

fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
if data.len() != N {
return Err(Error::InvalidHashLength);
}

let mut dest = Hash::default();
dest.0.copy_from_slice(data);
Ok(dest)
}
}

impl<const N: usize> FromStr for Hash<N> {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let data = hex::decode(s)?;
Hash::try_from(data.as_slice())
}
}

impl<const N: usize> Default for Hash<N> {
fn default() -> Self {
Hash::new()
}
}

impl<const N: usize> AsRef<[u8]> for Hash<N> {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl<const N: usize> Deref for Hash<N> {
type Target = [u8];

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<const N: usize> DerefMut for Hash<N> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl<const N: usize> fmt::Display for Hash<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let prefixed = false;
write!(f, "{}", hex::encode(self.0, prefixed))
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_hash_from_str() {
let actual = H256::from("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5");
let expected = [
175u8, 238, 252, 167, 77, 154, 50, 92, 241, 214, 182, 145, 29, 97, 166, 92, 50, 175,
168, 224, 43, 213, 231, 142, 46, 74, 194, 145, 11, 171, 69, 245,
];
assert_eq!(actual.0[..], expected[..]);
}

#[test]
fn test_hash_display() {
let str = "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5";
assert_eq!(H256::from(str).to_string(), str);
}

#[test]
#[should_panic]
fn test_from_hex_literal_invalid() {
let _ = H256::from("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45x5");
}

#[test]
fn test_from_hex_invalid() {
let err =
H256::from_str("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45x5")
.unwrap_err();

match err {
Error::FromHexError(_) => (),
other => panic!("Expected 'FromHexError', found: {other:?}"),
}
}

#[test]
fn test_from_hex_invalid_len() {
let err = H256::from_str("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45")
.unwrap_err();

match err {
Error::InvalidHashLength => (),
other => panic!("Expected 'Error::InvalidHashLength', found: {other:?}"),
}
}
}
19 changes: 19 additions & 0 deletions rust/tw_hash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,23 @@ pub mod sha1;
pub mod sha2;
pub mod sha3;

mod hash_array;
mod hash_wrapper;

pub use hash_array::{H256, H264, H512, H520};

use tw_encoding::hex::FromHexError;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
FromHexError(FromHexError),
InvalidHashLength,
}

impl From<FromHexError> for Error {
fn from(e: FromHexError) -> Self {
Error::FromHexError(e)
}
}
7 changes: 4 additions & 3 deletions rust/tw_hash/tests/hash_ffi_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

use tw_encoding::hex;
use tw_hash::ffi::{
blake2_b, blake2_b_personal, blake_256, groestl_512, hmac__sha256, keccak256, keccak512,
ripemd_160, sha1, sha256, sha3__256, sha3__512, sha512, sha512_256,
Expand All @@ -15,7 +16,7 @@ type ExternFn = unsafe extern "C" fn(*const u8, usize) -> CByteArray;
#[track_caller]
pub fn test_hash_helper(hash: ExternFn, input: &[u8], expected: &str) {
let decoded = unsafe { hash(input.as_ptr(), input.len()).into_vec() };
assert_eq!(hex::encode(decoded), expected);
assert_eq!(hex::encode(decoded, false), expected);
}

#[test]
Expand Down Expand Up @@ -47,7 +48,7 @@ fn test_blake2b_personal() {
.into_vec()
};
let expected = "20d9cd024d4fb086aae819a1432dd2466de12947831b75c5a30cf2676095d3b4";
assert_eq!(hex::encode(actual), expected);
assert_eq!(hex::encode(actual, false), expected);
}

#[test]
Expand Down Expand Up @@ -81,7 +82,7 @@ fn test_hmac_sha256() {
let actual =
unsafe { hmac__sha256(key.as_ptr(), key.len(), data.as_ptr(), data.len()).into_vec() };
let expected = "a7301d5563614e3955750e4480aabf7753f44b4975308aeb8e23c31e114962ab".to_string();
assert_eq!(hex::encode(actual), expected);
assert_eq!(hex::encode(actual, false), expected);
}

#[test]
Expand Down
14 changes: 14 additions & 0 deletions rust/tw_keypair/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "tw_keypair"
version = "0.1.0"
edition = "2021"

[dependencies]
lazy_static = "1.4.0"
k256 = { version = "0.13.0", features = ["ecdh"] }
starknet-crypto = "0.4.3"
starknet-ff = "0.3.1"
tw_encoding = { path = "../tw_encoding" }
tw_hash = { path = "../tw_hash" }
tw_memory = { path = "../tw_memory" }
tw_utils = { path = "../tw_utils" }
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

pub mod ffi;
pub mod key_pair;
pub mod privkey;
pub mod pubkey;
Loading