Skip to content

Commit

Permalink
[gh-1314] refactor crypto encoding hash functions (#1315)
Browse files Browse the repository at this point in the history
* [gh-1314] generalize base58 and bech32 in rust.

* [gh-1314] add decode algorithm.

* [gh-1314] adjust encode & decode lengths.

* [gh-1314] add checksum to bs58 encode function.

* [gh-1314] update docs.

---------

Co-authored-by: Feliciss <[email protected]>
  • Loading branch information
ghpZ54K8ZRwU62zGVSePPs97yAv9swuAY0mVDR4 and Feliciss authored Jan 25, 2024
1 parent 097af05 commit f0fadb9
Show file tree
Hide file tree
Showing 16 changed files with 151 additions and 259 deletions.
13 changes: 1 addition & 12 deletions Cargo.lock

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

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ tower-http = { version = "0.3.4", features = ["cors", "full", "trace", "set-head
mirai-annotations = "1.12.0"
lru = "0.11.0"
accumulator = { path = "moveos/moveos-commons/accumulator" }
bitcoin-bech32 = "0.13.0"
bs58 = "0.5.0"
dirs-next = "2.0.0"
anstream = { version = "0.3" }
Expand Down
3 changes: 1 addition & 2 deletions crates/rooch-framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ serde_bytes = { workspace = true }
sha3 = { workspace = true }
smallvec = { workspace = true }
hex = { workspace = true }
bitcoin = { workspace = true }
bitcoin-bech32 = { workspace = true }
bech32 = { workspace = true }
bs58 = { workspace = true, features = ["check"] }
http = { workspace = true }
tracing = { workspace = true }
Expand Down
24 changes: 19 additions & 5 deletions crates/rooch-framework/doc/decoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Module which defines decoding functions.
- [Constants](#@Constants_0)
- [Function `base58`](#0x3_decoding_base58)
- [Function `base58check`](#0x3_decoding_base58check)
- [Function `bech32`](#0x3_decoding_bech32)


<pre><code></code></pre>
Expand All @@ -34,8 +35,8 @@ Failed to decode an address

## Function `base58`

@param encoded_address_bytes: encoded Bitcoin address bytes on the Bitcoin network
Decode the Bitcoin address bytes with Base58 algorithm and returns a raw address bytes
@param encoded_address_bytes: encoded base58 address bytes
Decode the base58 address bytes with Base58 algorithm and returns a raw base58 address bytes


<pre><code><b>public</b> <b>fun</b> <a href="decoding.md#0x3_decoding_base58">base58</a>(encoded_address_bytes: &<a href="">vector</a>&lt;u8&gt;): <a href="">vector</a>&lt;u8&gt;
Expand All @@ -47,10 +48,23 @@ Decode the Bitcoin address bytes with Base58 algorithm and returns a raw address

## Function `base58check`

@param encoded_address_bytes: encoded Bitcoin address bytes on the Bitcoin network
@param version_byte: version byte used on Bitcoin network for verification of different types of addresses
Decode the Bitcoin address bytes with Base58Check algorithm and returns a raw address bytes without checksum
@param encoded_address_bytes: encoded base58 address bytes
@param version_byte: version byte used for verification of different types of base58 addresses
Decode the base58 address bytes with Base58Check algorithm and returns a raw address bytes without checksum


<pre><code><b>public</b> <b>fun</b> <a href="decoding.md#0x3_decoding_base58check">base58check</a>(encoded_address_bytes: &<a href="">vector</a>&lt;u8&gt;, version_byte: u8): <a href="">vector</a>&lt;u8&gt;
</code></pre>



<a name="0x3_decoding_bech32"></a>

## Function `bech32`

@param encoded_bech32_address_bytes: 42 or 62 length Bech32 or Bech32m addresses
Decode the encoded 42 or 62 length Bech32 or Bech32m addresses with Bech32 or Bech32m decoding algorithm and returns 20 or 32 bytes of public keys.


<pre><code><b>public</b> <b>fun</b> <a href="decoding.md#0x3_decoding_bech32">bech32</a>(encoded_bech32_address_bytes: &<a href="">vector</a>&lt;u8&gt;): <a href="">vector</a>&lt;u8&gt;
</code></pre>
40 changes: 6 additions & 34 deletions crates/rooch-framework/doc/encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ Module which defines encoding functions.
- [Function `base58`](#0x3_encoding_base58)
- [Function `base58check`](#0x3_encoding_base58check)
- [Function `bech32`](#0x3_encoding_bech32)
- [Function `p2sh`](#0x3_encoding_p2sh)
- [Function `p2pkh`](#0x3_encoding_p2pkh)


<pre><code></code></pre>
Expand Down Expand Up @@ -67,8 +65,8 @@ Invalid script version

## Function `base58`

@param address_bytes: address bytes on the Bitcoin network
Encode the address bytes with Base58 algorithm and returns an encoded Bitcoin address
@param address_bytes: address bytes for base58 format
Encode the address bytes with Base58 algorithm and returns an encoded base58 bytes


<pre><code><b>public</b> <b>fun</b> <a href="encoding.md#0x3_encoding_base58">base58</a>(address_bytes: &<a href="">vector</a>&lt;u8&gt;): <a href="">vector</a>&lt;u8&gt;
Expand All @@ -80,9 +78,9 @@ Encode the address bytes with Base58 algorithm and returns an encoded Bitcoin ad

## Function `base58check`

@param address_bytes: address bytes on the Bitcoin network
@param version_byte: version byte used on Bitcoin network for verification of different types of addresses
Encode the address bytes with Base58Check algorithm and returns an encoded Bitcoin address with checksum
@param address_bytes: address bytes on the base58 checksum format
@param version_byte: version byte used for verification of different types of checksum addresses
Encode the address bytes with Base58Check algorithm and returns an encoded base58 bytes with checksum


<pre><code><b>public</b> <b>fun</b> <a href="encoding.md#0x3_encoding_base58check">base58check</a>(address_bytes: &<a href="">vector</a>&lt;u8&gt;, version_byte: u8): <a href="">vector</a>&lt;u8&gt;
Expand All @@ -96,34 +94,8 @@ Encode the address bytes with Base58Check algorithm and returns an encoded Bitco

@param public_key: 20 or 32 bytes public keys
@param version: 0 for bech32 encoding and 1 for bech32m encoding. 2-16 are held.
Encode the public key with Bech32 or Bech32m encoding algorithm and returns 42 or 62 length Bitcoin Bech32 address.
Encode the public keys with Bech32 or Bech32m encoding algorithm and returns 42 or 62 length Bech32 or Bech32m addresses.


<pre><code><b>public</b> <b>fun</b> <a href="encoding.md#0x3_encoding_bech32">bech32</a>(public_key: &<a href="">vector</a>&lt;u8&gt;, version: u8): <a href="">vector</a>&lt;u8&gt;
</code></pre>



<a name="0x3_encoding_p2sh"></a>

## Function `p2sh`

@param public_key: 33 bytes compressed public key
Creates a pay to script hash P2SH address from a script converted from a compressed public key.


<pre><code><b>public</b> <b>fun</b> <a href="encoding.md#0x3_encoding_p2sh">p2sh</a>(public_key: &<a href="">vector</a>&lt;u8&gt;): <a href="">vector</a>&lt;u8&gt;
</code></pre>



<a name="0x3_encoding_p2pkh"></a>

## Function `p2pkh`

@param public_key: 33 bytes compressed public key
Creates a pay to (compressed) public key hash address from a public key.


<pre><code><b>public</b> <b>fun</b> <a href="encoding.md#0x3_encoding_p2pkh">p2pkh</a>(public_key: &<a href="">vector</a>&lt;u8&gt;): <a href="">vector</a>&lt;u8&gt;
</code></pre>
43 changes: 38 additions & 5 deletions crates/rooch-framework/sources/crypto/decoding.move
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@ module rooch_framework::decoding {
/// Failed to decode an address
const ErrorDecodeFailed: u64 = 1;

/// @param encoded_address_bytes: encoded Bitcoin address bytes on the Bitcoin network
/// Decode the Bitcoin address bytes with Base58 algorithm and returns a raw address bytes
/// @param encoded_address_bytes: encoded base58 address bytes
/// Decode the base58 address bytes with Base58 algorithm and returns a raw base58 address bytes
native public fun base58(encoded_address_bytes: &vector<u8>): vector<u8>;

/// @param encoded_address_bytes: encoded Bitcoin address bytes on the Bitcoin network
/// @param version_byte: version byte used on Bitcoin network for verification of different types of addresses
/// Decode the Bitcoin address bytes with Base58Check algorithm and returns a raw address bytes without checksum
/// @param encoded_address_bytes: encoded base58 address bytes
/// @param version_byte: version byte used for verification of different types of base58 addresses
/// Decode the base58 address bytes with Base58Check algorithm and returns a raw address bytes without checksum
native public fun base58check(encoded_address_bytes: &vector<u8>, version_byte: u8): vector<u8>;

/// @param encoded_bech32_address_bytes: 42 or 62 length Bech32 or Bech32m addresses
/// Decode the encoded 42 or 62 length Bech32 or Bech32m addresses with Bech32 or Bech32m decoding algorithm and returns 20 or 32 bytes of public keys.
native public fun bech32(encoded_bech32_address_bytes: &vector<u8>): vector<u8>;

#[test]
/// This test can be verified at http://lenschulwitz.com/base58.
fun test_base58_decoding() {
Expand All @@ -35,4 +39,33 @@ module rooch_framework::decoding {

assert!(decoded_address_bytes == expected_decoded_address_bytes, 1001);
}

#[test]
fun test_bech32_decoding_to_52_public_key() {
let encoded_address = b"bech321qvdcf32k0vfxgsyet5ldt246q4jaw8scx3sysx0lnstlt6w4m5rsl7wnyw";
// TODO handle bech32 and bech32m public key's difference
let expected_public_key = bech32(&encoded_address);

let public_key = x"000c0d1809110a160f0c0906081004190b141f0d0b0a151a0015121d0e0710180611100410060f1f13100b1f0b1a0e151b140310"; // 52-bytes raw public key for a Bech32 address
assert!(public_key == expected_public_key, 1002);
}

#[test]
fun test_bech32_decoding_to_32_public_key() {
let encoded_address = b"bech321q302rl92lgujmvlk5h6pf63zn6wekcjqxj30hr";
let expected_public_key = bech32(&encoded_address);

let public_key = x"00110f0a031f050a1f081c121b0c1f1614171a01091a1102131a0e1916181200"; // 32-bytes raw public key for a Bech32 address
assert!(public_key == expected_public_key, 1003);
}

#[test]
fun test_bech32_decoding_to_52_bech32m_public_key() {
let encoded_address = b"bech32m1qvdcf32k0vfxgsyet5ldt246q4jaw8scx3sysx0lnstlt6w4m5rs6l85rk";
// TODO handle bech32 and bech32m public key's difference
let expected_public_key = bech32(&encoded_address);

let public_key = x"000c0d1809110a160f0c0906081004190b141f0d0b0a151a0015121d0e0710180611100410060f1f13100b1f0b1a0e151b140310"; // 52-bytes public key for a Bech32m address
assert!(public_key == expected_public_key, 1004);
}
}
71 changes: 18 additions & 53 deletions crates/rooch-framework/sources/crypto/encoding.move
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,20 @@ module rooch_framework::encoding {
/// Invalid script version
const ErrorInvalidScriptVersion: u64 = 4;

/// @param address_bytes: address bytes on the Bitcoin network
/// Encode the address bytes with Base58 algorithm and returns an encoded Bitcoin address
/// @param address_bytes: address bytes for base58 format
/// Encode the address bytes with Base58 algorithm and returns an encoded base58 bytes
native public fun base58(address_bytes: &vector<u8>): vector<u8>;

/// @param address_bytes: address bytes on the Bitcoin network
/// @param version_byte: version byte used on Bitcoin network for verification of different types of addresses
/// Encode the address bytes with Base58Check algorithm and returns an encoded Bitcoin address with checksum
/// @param address_bytes: address bytes on the base58 checksum format
/// @param version_byte: version byte used for verification of different types of checksum addresses
/// Encode the address bytes with Base58Check algorithm and returns an encoded base58 bytes with checksum
native public fun base58check(address_bytes: &vector<u8>, version_byte: u8): vector<u8>;

/// @param public_key: 20 or 32 bytes public keys
/// @param version: 0 for bech32 encoding and 1 for bech32m encoding. 2-16 are held.
/// Encode the public key with Bech32 or Bech32m encoding algorithm and returns 42 or 62 length Bitcoin Bech32 address.
/// Encode the public keys with Bech32 or Bech32m encoding algorithm and returns 42 or 62 length Bech32 or Bech32m addresses.
native public fun bech32(public_key: &vector<u8>, version: u8): vector<u8>;

/// @param public_key: 33 bytes compressed public key
/// Creates a pay to script hash P2SH address from a script converted from a compressed public key.
native public fun p2sh(public_key: &vector<u8>): vector<u8>;

/// @param public_key: 33 bytes compressed public key
/// Creates a pay to (compressed) public key hash address from a public key.
native public fun p2pkh(public_key: &vector<u8>): vector<u8>;

#[test]
/// This test can be verified at http://lenschulwitz.com/base58.
fun test_base58_encoding() {
Expand Down Expand Up @@ -69,62 +61,35 @@ module rooch_framework::encoding {
}

#[test]
/// This test is verified at https://www.blockchain.com/explorer/addresses/btc/bc1qqvdcf32k0vfxgsyet5ldt246q4jaw8scx3sysx0lnstlt6w4m5rsgej0cd.
fun test_bech32_encoding_to_p2wsh_address() {
let public_key = x"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd07"; // 32-bytes public key for a Bech32 (P2WSH) address
let version = 0; // version 0 for a Bech32 (P2WSH) address
fun test_bech32_encoding_with_32_public_key() {
let public_key = x"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd07"; // 32-bytes public key for a Bech32 address
let version = 0; // version 0 for a Bech32 address

let encoded_address = bech32(&public_key, version);
let expected_encoded_address = b"bc1qqvdcf32k0vfxgsyet5ldt246q4jaw8scx3sysx0lnstlt6w4m5rsgej0cd";
let expected_encoded_address = b"bech321qvdcf32k0vfxgsyet5ldt246q4jaw8scx3sysx0lnstlt6w4m5rsl7wnyw";

assert!(encoded_address == expected_encoded_address, 1002);
}

#[test]
/// This test is verified at https://www.blockchain.com/explorer/addresses/btc/bc1qq302rl92lgujmvlk5h6pf63zn6wekcjql6cmum.
fun test_bech32_encoding_to_p2wpkh_address() {
let public_key = x"045ea1fcaafa392db3f6a5f414ea229e9d9b6240"; // 20-bytes public key for a Bech32 (P2WPKH) address
let version = 0; // version 0 for a Bech32 (P2WPKH) address
fun test_bech32_encoding_with_20_public_key() {
let public_key = x"045ea1fcaafa392db3f6a5f414ea229e9d9b6240"; // 20-bytes public key for a Bech32 address
let version = 0; // version 0 for a Bech32 address

let encoded_address = bech32(&public_key, version);
let expected_encoded_address = b"bc1qq302rl92lgujmvlk5h6pf63zn6wekcjql6cmum";
let expected_encoded_address = b"bech321q302rl92lgujmvlk5h6pf63zn6wekcjqxj30hr";

assert!(encoded_address == expected_encoded_address, 1003);
}

#[test]
/// This test is verified at https://www.blockchain.com/explorer/addresses/btc/bc1pqvdcf32k0vfxgsyet5ldt246q4jaw8scx3sysx0lnstlt6w4m5rszwjxq3.
fun test_bech32_encoding_to_p2tr_address() {
let public_key = x"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd07"; // 32-bytes public key for a Bech32 (Taproot) address
let version = 1; // version 1 for a Bech32 (Taproot) address
fun test_bech32_encoding_with_version_1_32_public_key() {
let public_key = x"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd07"; // 32-bytes public key for a Bech32m address
let version = 1; // version 1 for a Bech32m address

let encoded_address = bech32(&public_key, version);
let expected_encoded_address = b"bc1pqvdcf32k0vfxgsyet5ldt246q4jaw8scx3sysx0lnstlt6w4m5rszwjxq3";
let expected_encoded_address = b"bech32m1qvdcf32k0vfxgsyet5ldt246q4jaw8scx3sysx0lnstlt6w4m5rs6l85rk";

assert!(encoded_address == expected_encoded_address, 1004);
}

// Test function for P2SH address generation
#[test]
/// This test is verified at https://www.blockchain.com/explorer/addresses/btc/3FrvSxCNmbGbYxvaBY9rhTWKauCXWPpLh9.
fun test_p2sh_address() {
let public_key = x"0345c567b17d2e69c8b91b3503f0fb50ebb88f1806e9133f62d3d3501efcedf8d3"; // 33-byte compressed public key
let p2sh_address = p2sh(&public_key);

let expected_p2sh_address = b"3FrvSxCNmbGbYxvaBY9rhTWKauCXWPpLh9"; // Sample P2SH address

assert!(p2sh_address == expected_p2sh_address, 1005);
}

// Test function for P2PKH address generation
#[test]
/// This test is verified at https://www.blockchain.com/explorer/addresses/btc/1Dnv7vKt2JEK7tQnbmYBq3Sfuckz7wFS6e.
fun test_p2pkh_address() {
let public_key = x"03a819b6f0eb5f22167fffa53e1628cfbf645db9a4c50b3a226e5d20c9984e63a2"; // 33-byte compressed public key
let p2pkh_address = p2pkh(&public_key);

let expected_p2pkh_address = b"1Dnv7vKt2JEK7tQnbmYBq3Sfuckz7wFS6e"; // Sample P2PKH address

assert!(p2pkh_address == expected_p2pkh_address, 1006);
}
}
2 changes: 2 additions & 0 deletions crates/rooch-framework/src/natives/gas_parameter/decoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ crate::natives::gas_parameter::native::define_gas_parameters_for_natives!(GasPar
[.base58.per_byte, "base58.per_byte", 30 * MUL],
[.base58check.base, "base58check.base", 1000 * MUL],
[.base58check.per_byte, "base58check.per_byte", 30 * MUL],
[.bech32.base, "bech32.base", 1000 * MUL],
[.bech32.per_byte, "bech32.per_byte", 30 * MUL]
]);
6 changes: 1 addition & 5 deletions crates/rooch-framework/src/natives/gas_parameter/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,5 @@ crate::natives::gas_parameter::native::define_gas_parameters_for_natives!(GasPar
[.base58check.base, "base58check.base", 1000 * MUL],
[.base58check.per_byte, "base58check.per_byte", 30 * MUL],
[.bech32.base, "bech32.base", 1000 * MUL],
[.bech32.per_byte, "bech32.per_byte", 30 * MUL],
[.p2pkh.base, "p2pkh.base", 1000 * MUL],
[.p2pkh.per_byte, "p2pkh.per_byte", 30 * MUL],
[.p2sh.base, "p2sh.base", 1000 * MUL],
[.p2sh.per_byte, "p2sh.per_byte", 30 * MUL],
[.bech32.per_byte, "bech32.per_byte", 30 * MUL]
]);
27 changes: 0 additions & 27 deletions crates/rooch-framework/src/natives/gas_parameter/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,28 +74,6 @@ macro_rules! expand_kv_for_native_gas_params {
}
}

#[cfg(test)]
macro_rules! extract_key_for_native_gas_params {
(test_only $(.$field: ident)+, $(optional)? $key: literal, $initial_val: expr) => {
#[cfg(feature = "testing")]
$key
};
($(.$field: ident)+, $(optional)? $key: literal, $initial_val: expr) => {
$key
};
}

#[cfg(test)]
macro_rules! extract_path_for_native_gas_params {
(test_only $(.$field: ident)+, $(optional)? $key: literal, $initial_val: expr) => {
#[cfg(feature = "testing")]
stringify!($($field).*)
};
($(.$field: ident)+, $(optional)? $key: literal, $initial_val: expr) => {
stringify!($($field).*)
};
}

#[macro_export]
macro_rules! define_gas_parameters_for_natives {
($param_ty: ty, $package_name: literal, [$([$($t: tt)*]),* $(,)?] $(, allow_unmapped = $allow_unmapped: expr)?) => {
Expand Down Expand Up @@ -145,11 +123,6 @@ macro_rules! define_gas_parameters_for_natives {
};
}

#[cfg(test)]
pub(crate) use extract_key_for_native_gas_params;
#[cfg(test)]
pub(crate) use extract_path_for_native_gas_params;

pub use define_gas_parameters_for_natives;
pub use expand_get_for_native_gas_params;
pub use expand_get_impl_for_native_gas_params;
Expand Down
Loading

0 comments on commit f0fadb9

Please sign in to comment.