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

feat: sign message v2 #74

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
69 changes: 69 additions & 0 deletions packages/kos-mobile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,28 @@ fn decrypt(data: String, password: String) -> Result<String, KOSError> {
Ok(String::from_utf8_lossy(&decrypted_data).to_string())
}

#[uniffi::export]
fn sign_message(account: KOSAccount, message: String) -> Result<Vec<u8>, KOSError> {
let chain = get_chain_by(account.chain_id)?;
let wallet = Wallet::from_private_key(chain, account.private_key.to_string())?;
let message = message.as_bytes();
let signature = wallet.sign_message(message)?;
Ok(signature)
}

#[uniffi::export]
fn verify_message_signature(
address: String,
chain_id: i32,
message: String,
signature: Vec<u8>,
) -> Result<bool, KOSError> {
let chain = get_chain_by(chain_id)?;
let message = message.as_bytes();
let is_valid = chain.verify_message_signature(message, &signature, &address)?;
Ok(is_valid)
}

fn get_chain_by(id: i32) -> Result<Chain, KOSError> {
let id_u8 = u8::try_from(id).map_err(|_| KOSError::UnsupportedChain { id: id.to_string() })?;
let chain = Chain::get_by_code(id_u8)
Expand Down Expand Up @@ -374,4 +396,51 @@ mod tests {
"The signature doesn't match"
);
}

#[test]
fn should_sign_message() {
let chain_id = 38;
let message = "Hello World".to_string();

let account = generate_wallet_from_mnemonic(
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".to_string(),
chain_id,
0,
false
).unwrap();

let signature = sign_message(account, message).unwrap();
assert_eq!(signature.len(), 64, "The signature length doesn't match");
}

#[test]
fn should_verify_message_signature() {
let chain_id = 38;
let message = "Hello World".to_string();

let account = generate_wallet_from_mnemonic(
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".to_string(),
chain_id,
0,
false
).unwrap();

let address = account.address.clone();
let chain_id = account.chain_id;
let signature = sign_message(account, message.clone()).unwrap();

let is_valid =
verify_message_signature(address.clone(), chain_id, message.clone(), signature)
.unwrap();
assert!(is_valid, "The signature is not valid");

let result = verify_message_signature(address, chain_id, message, vec![0; 64]);

match result {
Err(KOSError::KOSDelegate(err)) => {
assert_eq!(err, "Invalid signature: message verification fail", "Invalid error")
}
_ => panic!("Expected KOSDelegate error with message 'Invalid signature: message verification fail'")
}
}
}
53 changes: 49 additions & 4 deletions packages/kos-sdk/src/chains/tron/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,22 @@ impl TRX {

#[wasm_bindgen(js_name = "verifyDigest")]
/// Verify Message signature
pub fn verify_digest(_digest: &[u8], _signature: &[u8], _address: &str) -> Result<bool, Error> {
todo!()
pub fn verify_digest(digest: &[u8], signature: &[u8], address: &str) -> Result<bool, Error> {
let recovered = TRX::verify_message(digest, signature)?;
Ok(recovered == address)
}

#[wasm_bindgen(js_name = "verifyMessage")]
/// Verify Message signature
pub fn verify_message(digest: &[u8], signature: &[u8]) -> Result<String, Error> {
let pub_key = Secp256k1KeyPair::recover(digest, signature)
.map_err(|_| Error::InvalidSignature("failed to recover public key"))?;

let public: [u8; 64] = pub_key
.try_into()
.map_err(|_| Error::InvalidSignature("failed to convert public key"))?;

Ok(address::Address::from_public(public).to_string())
}

#[wasm_bindgen(js_name = "sign")]
Expand Down Expand Up @@ -154,8 +168,7 @@ impl TRX {
/// Append prefix and hash the message
pub fn message_hash(message: &[u8]) -> Result<Vec<u8>, Error> {
let to_sign = [SIGN_PREFIX, message.len().to_string().as_bytes(), message].concat();

TRX::hash(&to_sign)
Ok(Vec::from(kos_crypto::hash::keccak256(&to_sign)))
}

#[wasm_bindgen(js_name = "signMessage")]
Expand Down Expand Up @@ -719,4 +732,36 @@ mod tests {
"066b49fab01944699516efc5c3d636f150c12d7e157e4867c155b29d94edb018"
);
}

#[test]
fn test_sign_message() {
let message = "Hello, World!";
let keypair = get_default_secret();
let result = TRX::sign_message(message.as_bytes(), &keypair);
assert!(result.is_ok());
let sig = result.unwrap();
assert_eq!(sig.len(), 65);
}

#[test]
fn test_verify_message() {
let message = "Hello, World!";
let keypair = get_default_secret();
let sig = TRX::sign_message(message.as_bytes(), &keypair).unwrap();
let digest = TRX::message_hash(message.as_bytes()).unwrap();
let result = TRX::verify_message(digest.as_slice(), &sig);
assert!(result.is_ok());
let addr = result.unwrap();
assert_eq!(addr, DEFAULT_ADDRESS);
}

#[test]
fn test_verify_message_signature() {
let message = "Hello, World!";
let keypair = get_default_secret();
let sig = TRX::sign_message(message.as_bytes(), &keypair).unwrap();
let result = TRX::verify_message_signature(message.as_bytes(), &sig, DEFAULT_ADDRESS);
assert!(result.is_ok());
assert_eq!(result.unwrap(), true);
}
}
10 changes: 10 additions & 0 deletions packages/kos-sdk/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,16 @@ impl Wallet {
None => Err(Error::WalletManagerError("no keypair".to_string())),
}
}

#[wasm_bindgen(js_name = "verifyMessageSignature")]
pub fn verify_message_signature(
&self,
message: &[u8],
signature: &[u8],
) -> Result<bool, Error> {
self.chain
.verify_message_signature(message, signature, self.public_address.as_str())
}
}

#[wasm_bindgen]
Expand Down
Loading