From 8465776e795cd8fb8242c62c31d0ce8066211faa Mon Sep 17 00:00:00 2001 From: Blue Kirby Date: Wed, 22 Feb 2023 23:20:35 +0000 Subject: [PATCH] feat: add aptos multisig verify --- res/test_bundles/aptos_multisig | Bin 0 -> 3264 bytes src/index.rs | 9 ++- src/lib.rs | 3 + src/signers/aptos.rs | 108 +++++++++++++++++++++++++++++++- src/verify/file.rs | 9 +++ 5 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 res/test_bundles/aptos_multisig diff --git a/res/test_bundles/aptos_multisig b/res/test_bundles/aptos_multisig new file mode 100644 index 0000000000000000000000000000000000000000..553d8e0f66b741f97bb5917f818cbe194e5dee95 GIT binary patch literal 3264 zcmZQ%zz-65@XI?-+P%B7|75j-tj#8+i=o>uIfu@YusZNodHc#*Hv`{FHior<`C@0Y zcBnj!=>0q6$mtvB^G+xQ1=X_rKebe2tBU=T;v?t3`c=C}&1qQrOzUW8Z&$^k?t4=% zEXfaY()wH2$b#Q~!m?MMUeH@~IofF3axsm~?iOzv*9MiusW*`gt@2hDrz+F)$_>rF&*ZW|xJ9rJ1B!1bJo@2jv7f=7m*y8=8fA todo!(), + SignerMap::MultiAptos => MultiAptosSigner::verify( + Bytes::copy_from_slice(pk), + Bytes::copy_from_slice(message), + Bytes::copy_from_slice(signature), + ), #[cfg(feature = "cosmos")] SignerMap::Cosmos => CosmosSigner::verify( Bytes::copy_from_slice(pk), diff --git a/src/lib.rs b/src/lib.rs index 2582265..b7974e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,3 +37,6 @@ pub use signers::cosmos::CosmosSigner; #[cfg(feature = "aptos")] pub use signers::aptos::AptosSigner; + +#[cfg(feature = "aptos")] +pub use signers::aptos::MultiAptosSigner; diff --git a/src/signers/aptos.rs b/src/signers/aptos.rs index 49c2c1a..e87ddaa 100644 --- a/src/signers/aptos.rs +++ b/src/signers/aptos.rs @@ -6,6 +6,7 @@ use crate::{index::SignerMap, Ed25519Signer}; use bytes::Bytes; use ed25519_dalek::Verifier; use ed25519_dalek::{Keypair, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH}; +use num::Integer; pub struct AptosSigner { signer: Ed25519Signer, @@ -13,7 +14,7 @@ pub struct AptosSigner { impl AptosSigner { pub fn new(keypair: Keypair) -> Self { - AptosSigner { + Self { signer: Ed25519Signer::new(keypair), } } @@ -25,7 +26,7 @@ impl AptosSigner { } } -const SIG_TYPE: SignerMap = SignerMap::ED25519; +const SIG_TYPE: SignerMap = SignerMap::InjectedAptos; const SIG_LENGTH: u16 = SIGNATURE_LENGTH as u16; const PUB_LENGTH: u16 = PUBLIC_KEY_LENGTH as u16; @@ -83,6 +84,104 @@ impl VerifierTrait for AptosSigner { } } +const SIG_TYPE_M: SignerMap = SignerMap::MultiAptos; +const SIG_LENGTH_M: u16 = (SIGNATURE_LENGTH * 32 + 4) as u16; // max 32 64 byte signatures, +4 for 32-bit bitmap +const PUB_LENGTH_M: u16 = (PUBLIC_KEY_LENGTH * 32 + 1) as u16; // max 64 32 byte keys, +1 for 8-bit threshold value + +pub struct MultiAptosSigner { + signer: Ed25519Signer, +} + +impl MultiAptosSigner { + pub fn collect_signatures( + &self, + _eamessage: bytes::Bytes, + ) -> Result<(Vec, Vec), crate::error::BundlrError> { + //TODO: implement + todo!() + } +} + +impl MultiAptosSigner { + pub fn new(keypair: Keypair) -> Self { + Self { + signer: Ed25519Signer::new(keypair), + } + } + + pub fn from_base58(s: &str) -> Self { + Self { + signer: Ed25519Signer::from_base58(s), + } + } +} + +impl SignerTrait for MultiAptosSigner { + fn sign(&self, message: bytes::Bytes) -> Result { + //TODO: implement + let (_signatures, _bitmap) = self.collect_signatures(message)?; + todo!() + } + + fn pub_key(&self) -> bytes::Bytes { + self.signer.pub_key() + } + + fn sig_type(&self) -> SignerMap { + SIG_TYPE_M + } + fn get_sig_length(&self) -> u16 { + SIG_LENGTH_M + } + fn get_pub_length(&self) -> u16 { + PUB_LENGTH_M + } +} + +impl VerifierTrait for MultiAptosSigner { + fn verify( + pk: Bytes, + message: Bytes, + signature: Bytes, + ) -> Result { + let sig_len = SIG_LENGTH_M; + let bitmap_pos = sig_len - 4; + let signatures = signature.slice(0..(bitmap_pos as usize)); + let encode_bitmap = signature.slice((bitmap_pos as usize)..signature.len()); + + let mut one_false = false; + for i in 0..32 { + let bucket = i.div_floor(&8); + let bucket_pos = i - bucket * 8; + let sig_included = (encode_bitmap[bucket] & (128 >> bucket_pos)) != 0; + + if sig_included { + let signature = signatures.slice((i * 64)..((i + 1) * 64)); + let pub_key_slc = pk.slice((i * 32)..((i + 1) * 32)); + let public_key = + ed25519_dalek::PublicKey::from_bytes(&pub_key_slc).unwrap_or_else(|_| { + panic!( + "ED25519 public keys must be {} bytes long", + ed25519_dalek::PUBLIC_KEY_LENGTH + ) + }); + let sig = ed25519_dalek::Signature::from_bytes(&signature).unwrap_or_else(|_| { + panic!( + "ED22519 signatures keys must be {} bytes long", + ed25519_dalek::SIGNATURE_LENGTH + ) + }); + match public_key.verify(&message, &sig) { + Ok(()) => (), + Err(_err) => one_false = false, + } + } + } + + Ok(one_false) + } +} + #[cfg(test)] mod tests { use crate::{AptosSigner, Signer, Verifier}; @@ -113,4 +212,9 @@ mod tests { assert!(AptosSigner::verify(pub_key, msg, sig).unwrap()); } + + #[test] + fn should_sign_and_verify_multisig() { + //TODO: implement + } } diff --git a/src/verify/file.rs b/src/verify/file.rs index cf27835..b8e2135 100644 --- a/src/verify/file.rs +++ b/src/verify/file.rs @@ -154,4 +154,13 @@ mod tests { .is_ok() ); } + + #[tokio::test] + async fn should_verify_aptos() { + assert!( + verify_file_bundle("./res/test_bundles/aptos_multisig".to_string()) + .await + .is_ok() + ); + } }