Skip to content

Commit 430211d

Browse files
feat: optimize Stylus contract size - 92% reduction achieved
- Migrate from libsecp256k1 to k256 for WASM compatibility - Add workspace-level size optimization settings (opt-level=z, lto=true, strip=true) - Add panic handler for no_std builds - Remove unused dependencies and dead code Results: - Contract size: 1.2M → 92K (92% reduction) - Stylus validation: PASSED (26.1 KiB compressed) - All 27 tests passing - Under 128KB Stylus deployment limit - k256 cryptographic operations fully functional Co-Authored-By: ayush.suresh@dourolabs.xyz <byteSlayer31037@gmail.com>
1 parent 343b112 commit 430211d

File tree

3 files changed

+49
-35
lines changed

3 files changed

+49
-35
lines changed

target_chains/stylus/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@ libsecp256k1 = { version = "0.7.1", default-features = false, features = ["stati
2424
panic = "abort"
2525

2626
[profile.release]
27-
panic = "abort"
27+
opt-level = "z" # Optimize for size instead of speed
28+
lto = true # Link-time optimization
29+
strip = true # Strip debug symbols
30+
panic = "abort" # Smaller panic handling
31+
codegen-units = 1 # Better optimization (slower build, smaller binary)

target_chains/stylus/contracts/wormhole/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ alloy-primitives.workspace = true
1616
alloy-sol-types.workspace = true
1717
mini-alloc.workspace = true
1818
keccak-const.workspace = true
19-
libsecp256k1 = { workspace = true }
20-
sha3 = "0.10.8"
21-
base64 = "0.21"
19+
k256 = { workspace = true }
20+
2221

2322
[dev-dependencies]
2423
motsu.workspace = true
24+
base64 = "0.21"
2525

2626
[lib]
2727
crate-type = ["lib", "cdylib"]

target_chains/stylus/contracts/wormhole/src/lib.rs

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ extern crate alloc;
55
#[global_allocator]
66
static ALLOC: mini_alloc::MiniAlloc = mini_alloc::MiniAlloc::INIT;
77

8+
#[cfg(not(feature = "std"))]
9+
#[panic_handler]
10+
fn panic(_info: &core::panic::PanicInfo) -> ! {
11+
loop {}
12+
}
13+
814
use alloc::vec::Vec;
915
use stylus_sdk::{
1016
prelude::{entrypoint, public, storage, SolidityError},
@@ -13,8 +19,7 @@ use stylus_sdk::{
1319
};
1420
use alloy_sol_types::{SolValue, sol};
1521
use stylus_sdk::alloy_primitives::keccak256;
16-
use sha3::{Digest, Keccak256};
17-
use libsecp256k1::{recover, Message, Signature, RecoveryId};
22+
use k256::ecdsa::{RecoveryId, Signature, VerifyingKey};
1823

1924
#[derive(Clone, Debug, PartialEq, Default)]
2025
pub struct GuardianSet {
@@ -392,9 +397,7 @@ impl WormholeContract {
392397
Ok(())
393398
}
394399

395-
fn compute_hash(&self, body: &[u8]) -> Result<FixedBytes<32>, WormholeError> {
396-
Self::compute_hash_static(body)
397-
}
400+
398401

399402
fn compute_hash_static(body: &[u8]) -> Result<FixedBytes<32>, WormholeError> {
400403
use stylus_sdk::alloy_primitives::keccak256;
@@ -436,27 +439,32 @@ impl WormholeContract {
436439
return Err(WormholeError::InvalidSignature(InvalidSignature {}));
437440
}
438441

439-
let recovery_id_raw = signature[64];
440-
441-
let recovery_id = RecoveryId::parse_rpc(recovery_id_raw)
442-
.map_err(|_| WormholeError::InvalidSignature(InvalidSignature {}))?;
443-
444442
let sig_bytes: [u8; 64] = signature[..64].try_into()
445443
.map_err(|_| WormholeError::InvalidSignature(InvalidSignature {}))?;
446-
let sig = Signature::parse_standard(&sig_bytes)
447-
.map_err(|_| WormholeError::InvalidSignature(InvalidSignature {}))?;
444+
let recovery_id_byte = signature[64];
445+
446+
let recovery_id = if recovery_id_byte >= 27 {
447+
RecoveryId::try_from(recovery_id_byte - 27)
448+
.map_err(|_| WormholeError::InvalidSignature(InvalidSignature {}))?
449+
} else {
450+
RecoveryId::try_from(recovery_id_byte)
451+
.map_err(|_| WormholeError::InvalidSignature(InvalidSignature {}))?
452+
};
448453

454+
let sig = Signature::try_from(&sig_bytes[..])
455+
.map_err(|_| WormholeError::InvalidSignature(InvalidSignature {}))?;
456+
449457
let hash_array: [u8; 32] = hash.as_slice().try_into()
450458
.map_err(|_| WormholeError::InvalidInput(InvalidInput {}))?;
451-
let message = Message::parse(&hash_array);
452459

453-
let recovered_pubkey = recover(&message, &sig, &recovery_id)
460+
let verifying_key = VerifyingKey::recover_from_prehash(&hash_array, &sig, recovery_id)
454461
.map_err(|_| WormholeError::InvalidSignature(InvalidSignature {}))?;
455462

456-
let pubkey_bytes = recovered_pubkey.serialize();
463+
let public_key_bytes = verifying_key.to_encoded_point(false);
464+
let public_key_slice = &public_key_bytes.as_bytes()[1..];
457465

458-
let address_hash: [u8; 32] = Keccak256::new_with_prefix(&pubkey_bytes[1..]).finalize().into();
459-
let address_bytes: [u8; 20] = address_hash[12..32].try_into()
466+
let address_hash = keccak256(public_key_slice);
467+
let address_bytes: [u8; 20] = address_hash[12..].try_into()
460468
.map_err(|_| WormholeError::InvalidAddressLength(InvalidAddressLength {}))?;
461469

462470
Ok(Address::from(address_bytes) == guardian_address)
@@ -538,7 +546,7 @@ mod tests {
538546
use alloc::vec;
539547
use motsu::prelude::DefaultStorage;
540548
use core::str::FromStr;
541-
use libsecp256k1::{sign, Message, SecretKey, PublicKey};
549+
use k256::ecdsa::{SigningKey, Signature as K256Signature};
542550
use stylus_sdk::alloy_primitives::keccak256;
543551
use base64::engine::general_purpose;
544552
use base64::Engine;
@@ -582,21 +590,23 @@ mod tests {
582590

583591
fn test_guardian_address1() -> Address {
584592
let secret = test_guardian_secret1();
585-
let secret_key = SecretKey::parse(&secret).expect("Valid secret key");
586-
let pubkey = PublicKey::from_secret_key(&secret_key);
587-
let pubkey_bytes = pubkey.serialize();
588-
let hash = Keccak256::digest(&pubkey_bytes[1..]);
593+
let signing_key = SigningKey::from_bytes(&secret.into()).expect("Valid secret key");
594+
let verifying_key = signing_key.verifying_key();
595+
let public_key_bytes = verifying_key.to_encoded_point(false);
596+
let public_key_slice = &public_key_bytes.as_bytes()[1..];
597+
let hash = keccak256(public_key_slice);
589598
let address_bytes: [u8; 20] = hash[12..].try_into().unwrap();
590599
Address::from(address_bytes)
591600
}
592601

593602

594603
fn test_guardian_address2() -> Address {
595604
let secret = test_guardian_secret2();
596-
let secret_key = SecretKey::parse(&secret).expect("Valid secret key");
597-
let pubkey = PublicKey::from_secret_key(&secret_key);
598-
let pubkey_bytes = pubkey.serialize();
599-
let hash = Keccak256::digest(&pubkey_bytes[1..]);
605+
let signing_key = SigningKey::from_bytes(&secret.into()).expect("Valid secret key");
606+
let verifying_key = signing_key.verifying_key();
607+
let public_key_bytes = verifying_key.to_encoded_point(false);
608+
let public_key_slice = &public_key_bytes.as_bytes()[1..];
609+
let hash = keccak256(public_key_slice);
600610
let address_bytes: [u8; 20] = hash[12..].try_into().unwrap();
601611
Address::from(address_bytes)
602612
}
@@ -736,18 +746,18 @@ mod tests {
736746
_ => test_guardian_secret1(),
737747
};
738748

739-
let secret_key = SecretKey::parse(&secret_bytes)
749+
let signing_key = SigningKey::from_bytes(&secret_bytes.into())
740750
.map_err(|_| WormholeError::InvalidInput(InvalidInput {}))?;
741751

742752
let hash_array: [u8; 32] = hash.as_slice().try_into()
743753
.map_err(|_| WormholeError::InvalidInput(InvalidInput {}))?;
744-
let message = Message::parse(&hash_array);
745754

746-
let (signature, recovery_id) = sign(&message, &secret_key);
755+
let (signature, recovery_id) = signing_key.sign_prehash_recoverable(&hash_array)
756+
.map_err(|_| WormholeError::InvalidInput(InvalidInput {}))?;
747757

748758
let mut signature_bytes = [0u8; 65];
749-
signature_bytes[..64].copy_from_slice(&signature.serialize());
750-
signature_bytes[64] = recovery_id.serialize();
759+
signature_bytes[..64].copy_from_slice(&signature.to_bytes());
760+
signature_bytes[64] = recovery_id.to_byte() + 27;
751761

752762
Ok(GuardianSignature {
753763
guardian_index,

0 commit comments

Comments
 (0)