#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
use sha3::{Digest, Sha3_256};
use crate::keypair::PublicKey;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SingleKeyAddress(String);
impl SingleKeyAddress {
pub fn from_public_key(pk: &PublicKey) -> Self {
let hash = Sha3_256::digest(pk.as_bytes());
Self(format!("0x{}", hex::encode(&hash[..20])))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl core::fmt::Display for SingleKeyAddress {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(&self.0)
}
}
impl AsRef<str> for SingleKeyAddress {
fn as_ref(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MultisigAddress(String);
impl MultisigAddress {
pub fn derive(public_keys: &[PublicKey], required: usize, total: usize) -> Self {
let mut sorted: Vec<&[u8]> = public_keys.iter().map(PublicKey::as_bytes).collect();
sorted.sort_unstable();
let mut hasher = Sha3_256::new();
hasher.update(&[required as u8, total as u8]);
for key in &sorted {
hasher.update(key);
}
let hash = hasher.finalize();
Self(format!("ms{}", hex::encode(&hash[..20])))
}
pub fn from_string(s: String) -> Self {
Self(s)
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl core::fmt::Display for MultisigAddress {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(&self.0)
}
}
impl AsRef<str> for MultisigAddress {
fn as_ref(&self) -> &str {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::keypair::KeyPair;
#[test]
fn single_key_address_prefix() {
let kp = KeyPair::generate();
let addr = SingleKeyAddress::from_public_key(kp.public_key());
assert!(addr.as_str().starts_with("0x"), "single-key address must start with 0x");
assert_eq!(addr.as_str().len(), 42, "0x + 40 hex chars = 42");
}
#[test]
fn single_key_address_is_deterministic() {
let kp = KeyPair::generate();
let addr1 = SingleKeyAddress::from_public_key(kp.public_key());
let addr2 = SingleKeyAddress::from_public_key(kp.public_key());
assert_eq!(addr1, addr2);
}
#[test]
fn multisig_address_prefix() {
let keys: Vec<PublicKey> = (0..3)
.map(|_| KeyPair::generate().public_key().clone())
.collect();
let addr = MultisigAddress::derive(&keys, 2, 3);
assert!(addr.as_str().starts_with("ms"), "multisig address must start with ms");
assert_eq!(addr.as_str().len(), 42, "ms + 40 hex chars = 42");
}
#[test]
fn multisig_address_order_independent() {
let k0 = KeyPair::generate().public_key().clone();
let k1 = KeyPair::generate().public_key().clone();
let k2 = KeyPair::generate().public_key().clone();
let order_a = vec![k0.clone(), k1.clone(), k2.clone()];
let order_b = vec![k2.clone(), k0.clone(), k1.clone()];
let order_c = vec![k1.clone(), k2.clone(), k0.clone()];
let addr_a = MultisigAddress::derive(&order_a, 2, 3);
let addr_b = MultisigAddress::derive(&order_b, 2, 3);
let addr_c = MultisigAddress::derive(&order_c, 2, 3);
assert_eq!(addr_a, addr_b);
assert_eq!(addr_b, addr_c);
}
#[test]
fn different_policies_different_addresses() {
let keys: Vec<PublicKey> = (0..3)
.map(|_| KeyPair::generate().public_key().clone())
.collect();
let addr_2of3 = MultisigAddress::derive(&keys, 2, 3);
let addr_3of3 = MultisigAddress::derive(&keys, 3, 3);
assert_ne!(
addr_2of3, addr_3of3,
"2-of-3 and 3-of-3 must produce different addresses for the same keyset"
);
}
#[test]
fn different_keysets_different_addresses() {
let keys_a: Vec<PublicKey> = (0..3)
.map(|_| KeyPair::generate().public_key().clone())
.collect();
let keys_b: Vec<PublicKey> = (0..3)
.map(|_| KeyPair::generate().public_key().clone())
.collect();
let addr_a = MultisigAddress::derive(&keys_a, 2, 3);
let addr_b = MultisigAddress::derive(&keys_b, 2, 3);
assert_ne!(addr_a, addr_b);
}
#[test]
fn multisig_address_is_deterministic() {
let keys: Vec<PublicKey> = (0..3)
.map(|_| KeyPair::generate().public_key().clone())
.collect();
let a1 = MultisigAddress::derive(&keys, 2, 3);
let a2 = MultisigAddress::derive(&keys, 2, 3);
assert_eq!(a1, a2);
}
}