Skip to content

Commit

Permalink
[Base58]: Move base58 implementation to rust (#2944)
Browse files Browse the repository at this point in the history
  • Loading branch information
Milerius authored Feb 22, 2023
1 parent 1dabdbe commit 90b1883
Show file tree
Hide file tree
Showing 58 changed files with 376 additions and 469 deletions.
7 changes: 7 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ starknet-signers = "0.1.0"
bcs = "0.1.4"
hex = "0.4.3"
base64 = "0.21.0"
bs58 = "0.4.0"

[dev-dependencies]
12 changes: 4 additions & 8 deletions rust/src/encoding/base32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ fn base32_decode(input: &str, alphabet: Option<&[u8]>, padding: bool) -> Result<
}

if output == vec![0] {
return Ok(vec![])
return Ok(vec![]);
}
Ok(output)
}
Expand All @@ -106,15 +106,11 @@ pub extern "C" fn decode_base32(input: *const c_char, alphabet: *const c_char, p

match base32_decode(input, alphabet, padding) {
Ok(decoded) => {
let size = decoded.len();
let mut decoded_vec = decoded.to_vec();
let ptr = decoded_vec.as_mut_ptr();
std::mem::forget(decoded_vec);
CByteArray { data: ptr, size }
},
decoded.into()
}
Err(_) => {
CByteArray { data: std::ptr::null_mut(), size: 0 }
},
}
}
}

Expand Down
99 changes: 99 additions & 0 deletions rust/src/encoding/base58.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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 std::ffi::{c_char, CStr, CString};
use bs58::{encode, decode, Alphabet};
use crate::memory::CByteArray;

#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum Base58Alphabet {
Bitcoin = 1,
Ripple = 2,
}

impl From<Base58Alphabet> for &Alphabet {
fn from(value: Base58Alphabet) -> Self {
match value {
Base58Alphabet::Bitcoin => Alphabet::BITCOIN,
Base58Alphabet::Ripple => Alphabet::RIPPLE
}
}
}

fn base58_encode(input: &[u8], alphabet: Base58Alphabet) -> String {
encode(input)
.with_alphabet(alphabet.into())
.into_string()
}

#[no_mangle]
pub extern "C" fn encode_base58(input: *const u8, input_len: usize, alphabet: Base58Alphabet) -> *mut c_char {
let input = unsafe { std::slice::from_raw_parts(input, input_len) };
CString::new(base58_encode(input, alphabet)).unwrap().into_raw()
}

fn base58_decode(input: &str, alphabet: Base58Alphabet) -> decode::Result<Vec<u8>> {
decode(input).with_alphabet(alphabet.into()).into_vec()
}

#[no_mangle]
pub extern "C" fn decode_base58(input: *const c_char, alphabet: Base58Alphabet) -> CByteArray {
let input = unsafe { CStr::from_ptr(input).to_str().unwrap() };

match base58_decode(input, alphabet) {
Ok(decoded) => {
decoded.into()
},
Err(_) => {
CByteArray { data: std::ptr::null_mut(), size: 0 }
},
}
}

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

#[test]
fn test_base58_encode() {
let data = b"Hello, world!";
let expected = "72k1xXWG59wUsYv7h2";

let result = base58_encode(data, Base58Alphabet::Bitcoin);
assert_eq!(result, expected);
}

#[test]
fn test_base58_decode() {
let data = "72k1xXWG59wUsYv7h2";
let expected = b"Hello, world!";

let result = base58_decode(data, Base58Alphabet::Bitcoin).unwrap();
assert_eq!(result, expected.to_vec());
}

#[test]
fn test_base58_encode_ffi() {
let data = b"Hello, world!";
let expected = "72k1xXWG59wUsYv7h2";

let result_ptr = encode_base58(data.as_ptr(), data.len(), Base58Alphabet::Bitcoin);
let result = unsafe { CString::from_raw(result_ptr) };
assert_eq!(result.to_str().unwrap(), expected);
}

#[test]
fn test_base58_decode_ffi() {
let data = "72k1xXWG59wUsYv7h2";
let expected = b"Hello, world!";

let input = CString::new(data).unwrap();
let decoded_ptr = decode_base58(input.as_ptr(), Base58Alphabet::Bitcoin);
let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) };
assert_eq!(decoded_slice, expected);
}
}
1 change: 1 addition & 0 deletions rust/src/encoding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
// file LICENSE at the root of the source code distribution tree.

mod base32;
mod base58;
mod base64;
mod hex;
10 changes: 10 additions & 0 deletions rust/src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ pub struct CByteArray {
pub size: usize,
}

impl From<Vec<u8>> for CByteArray {
fn from(value: Vec<u8>) -> Self {
let size = value.len();
let mut mut_vec = value.to_vec();
let ptr = mut_vec.as_mut_ptr();
std::mem::forget(mut_vec);
CByteArray { data: ptr, size }
}
}

#[no_mangle]
pub unsafe extern fn free_string(ptr: *const c_char) {
// Take the ownership back to rust and drop the owner
Expand Down
6 changes: 3 additions & 3 deletions src/Aeternity/Address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,20 @@ Address::Address(const std::string& string) {
}

auto payload = string.substr(Identifiers::prefixAccountPubkey.size(), string.size());
bytes = Base58::bitcoin.decodeCheck(payload);
bytes = Base58::decodeCheck(payload);
}

/// Returns a string representation of the Aeternity address.
std::string Address::string() const {
return Identifiers::prefixAccountPubkey + Base58::bitcoin.encodeCheck(bytes);
return Identifiers::prefixAccountPubkey + Base58::encodeCheck(bytes);
}

bool Address::checkType(const std::string& type) {
return type == Identifiers::prefixAccountPubkey;
}

bool Address::checkPayload(const std::string& payload) {
unsigned long base58 = Base58::bitcoin.decodeCheck(payload).size();
unsigned long base58 = Base58::decodeCheck(payload).size();
return base58 == size;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Aeternity/Signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Proto::SigningOutput Signer::sign(const TW::PrivateKey& privateKey, Transaction&

/// sign ed25519
auto sigRaw = privateKey.sign(msg, TWCurveED25519);
auto signature = Identifiers::prefixSignature + Base58::bitcoin.encodeCheck(sigRaw);
auto signature = Identifiers::prefixSignature + Base58::encodeCheck(sigRaw);

/// encode the message using rlp
auto rlpTxRaw = buildRlpTxRaw(txRlp, sigRaw);
Expand Down
2 changes: 1 addition & 1 deletion src/Aeternity/Transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ TW::Data Transaction::buildTag(const std::string& address) {

auto data = Data();
append(data, Identifiers::iDTagAccount);
append(data, Base58::bitcoin.decodeCheck(payload));
append(data, Base58::decodeCheck(payload));

return data;
}
Expand Down
Loading

0 comments on commit 90b1883

Please sign in to comment.