Skip to content

Commit

Permalink
Fixed pubkey ambiguity (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
MissingNO57 authored Apr 17, 2024
1 parent 18c4b05 commit 812ebaf
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 37 deletions.
19 changes: 13 additions & 6 deletions src/crypto/cosmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,31 @@ use cosmwasm_std::Addr;

use crate::crypto::encoding::encode_bech32;
use crate::crypto::hashing::{ripemd160, sha256};
use crate::crypto::secp256k1::to_compressed_key;
use cosmwasm_std::StdResult;

pub type RawCosmosAddress = [u8; 20];

pub fn cosmos_raw_address(pubkey: &[u8]) -> RawCosmosAddress {
let hash = ripemd160(&sha256(pubkey));
pub fn cosmos_raw_address_from_pubkey_secp256k1(pubkey: &[u8]) -> StdResult<RawCosmosAddress> {
let compressed_pubkey = to_compressed_key(pubkey)?;

let hash = ripemd160(&sha256(&compressed_pubkey));

let mut addr = [0u8; 20];
addr.copy_from_slice(&hash[..]);

addr
Ok(addr)
}

pub fn cosmos_address(raw_address: &RawCosmosAddress, prefix: &str) -> Addr {
Addr::unchecked(encode_bech32(prefix, raw_address).unwrap())
}

pub fn cosmos_address_from_pubkey(pubkey: &[u8], prefix: &str) -> Addr {
cosmos_address(&cosmos_raw_address(pubkey), prefix)
pub fn cosmos_address_from_pubkey_secp256k1(pubkey: &[u8], prefix: &str) -> StdResult<Addr> {
Ok(cosmos_address(
&cosmos_raw_address_from_pubkey_secp256k1(pubkey)?,
prefix,
))
}

#[cfg(test)]
Expand All @@ -38,7 +45,7 @@ mod tests {
// Get pubkey in bytes
let pubkey_bytes = parse_bech32(&pubkey_str, "pub").unwrap();
// Convert pubkey bytes to address
let recovered_addr = cosmos_address_from_pubkey(&pubkey_bytes, "fetch");
let recovered_addr = cosmos_address_from_pubkey_secp256k1(&pubkey_bytes, "fetch").unwrap();

assert_eq!(recovered_addr, address);
}
Expand Down
23 changes: 19 additions & 4 deletions src/crypto/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ pub fn parse_eth_address(eth_address: &str) -> Result<EthAddress, StdError> {
Ok(address)
}

pub fn raw_eth_address_to_string(eth_address: &EthAddress) -> String {
let hex_string = hex::encode(eth_address);
format!("0x{}", hex_string)
}

/// Parse the input ETH style signature and split into raw signature and recovery code
///
/// # Arguments
Expand Down Expand Up @@ -169,8 +174,8 @@ pub fn addresses_error<T: std::fmt::Display>(err: &T) -> StdError {
#[cfg(test)]
mod tests {
use super::*;
use crate::crypto::cosmos::cosmos_address_from_pubkey;
use crate::crypto::hashing::compress_pubkey_secp256k1;
use crate::crypto::cosmos::cosmos_address_from_pubkey_secp256k1;
use crate::crypto::secp256k1::to_compressed_key;
use cosmwasm_std::testing::mock_dependencies;

#[test]
Expand Down Expand Up @@ -287,9 +292,19 @@ mod tests {
let eth_pubkey = hex::decode("5c084296dfaeaf815a3a7e4e8688ed4140e403f1cd2d2f545c7a3822007763ae0e547eb989d5eecbfc5acd0204531b38e3bcfab232c506db7a9353d68932ca61").unwrap();
let expected_fetch_address = "fetch1e6lpplutmnxae8u7le9xsr7r9r4y9rukaf4lx8";

let compressed_pubkey = compress_pubkey_secp256k1(&eth_pubkey).unwrap();
let compressed_pubkey = to_compressed_key(&eth_pubkey).unwrap();

let fetch_address = cosmos_address_from_pubkey(&compressed_pubkey, "fetch");
let fetch_address =
cosmos_address_from_pubkey_secp256k1(&compressed_pubkey, "fetch").unwrap();
assert_eq!(fetch_address, expected_fetch_address);
}

#[test]
fn test_address_parsing() {
let eth_address = "0xbaCf56506032e9f1BF4c9C92925460DE929fa8d8";
let raw_eth_address = parse_eth_address(eth_address).unwrap();
let converted_address = raw_eth_address_to_string(&raw_eth_address);

assert_eq!(eth_address.to_lowercase(), converted_address.to_lowercase());
}
}
27 changes: 0 additions & 27 deletions src/crypto/hashing.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use cosmwasm_std::StdError;
use ripemd::Ripemd160;
use sha2::{Digest, Sha256};
use tiny_keccak::Hasher;
Expand Down Expand Up @@ -32,29 +31,3 @@ pub fn ripemd160(data: &[u8]) -> Vec<u8> {
ripemd160.update(data);
ripemd160.finalize().to_vec()
}

pub fn compress_pubkey_secp256k1(uncompressed_pubkey_bytes: &[u8]) -> Result<Vec<u8>, StdError> {
if uncompressed_pubkey_bytes.len() != 64 {
return Err(pubkey_error(&"Wrong len"));
}

// The first byte is the prefix, followed by 32 bytes for X and 32 bytes for Y
let x_bytes = &uncompressed_pubkey_bytes[0..32];
let y_bytes = &uncompressed_pubkey_bytes[32..64];

// Determine if Y is even or odd for the prefix
// Y's last byte's least significant bit determines its evenness or oddness
let prefix_byte = if (y_bytes[31] & 1) == 0 { 0x02 } else { 0x03 };

// Create the compressed public key
let mut compressed_pubkey: Vec<u8> = Vec::with_capacity(33);
compressed_pubkey.push(prefix_byte);
compressed_pubkey.extend_from_slice(x_bytes);

Ok(compressed_pubkey)
}

// Error
pub fn pubkey_error<T: std::fmt::Display>(err: &T) -> StdError {
StdError::generic_err(format!("Eth pubkey error {}", err))
}
1 change: 1 addition & 0 deletions src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ pub mod cosmos;
pub mod encoding;
pub mod ethereum;
pub mod hashing;
pub mod secp256k1;
pub mod uagents;
41 changes: 41 additions & 0 deletions src/crypto/secp256k1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use cosmwasm_std::{StdError, StdResult};

pub type CompressedPubkey = [u8; 33];

fn compress_pubkey(uncompressed_pubkey_bytes: &[u8]) -> CompressedPubkey {
// The first byte is the prefix, followed by 32 bytes for X and 32 bytes for Y
let x_bytes = &uncompressed_pubkey_bytes[0..32];
let y_bytes = &uncompressed_pubkey_bytes[32..64];

// Determine if Y is even or odd for the prefix
// Y's last byte's least significant bit determines its evenness or oddness
let prefix_byte = if (y_bytes[31] & 1) == 0 { 0x02 } else { 0x03 };

// Create the compressed public key array
let mut compressed_pubkey = [0u8; 33];
compressed_pubkey[0] = prefix_byte;
compressed_pubkey[1..].copy_from_slice(x_bytes);

compressed_pubkey
}

pub fn to_compressed_key(pubkey: &[u8]) -> StdResult<CompressedPubkey> {
match pubkey.len() {
// Compressed pubkey
33 => pubkey
.try_into()
.map_err(|_| pubkey_error(&"Conversion error")),

// Uncompressed without checksum
64 => Ok(compress_pubkey(pubkey)),

// Uncompressed with checksum
65 => Ok(compress_pubkey(&pubkey[1..])),
_ => Err(pubkey_error(&"Wrong len")),
}
}

// Error
pub fn pubkey_error<T: std::fmt::Display>(err: &T) -> StdError {
StdError::generic_err(format!("Secp256k1 pubkey error {}", err))
}

0 comments on commit 812ebaf

Please sign in to comment.