| name | crypto-recon-web3-solana |
| description | Specialist for Ed25519-based blockchain cryptography in JS bundles — Solana, Aptos, Sui, NEAR, TON, Algorand, Cardano. Covers transaction signing, instruction encoding, Borsh/BCS serialization, and all wallet SDKs. |
Crypto Recon — Ed25519 / Non-EVM Chains Specialist
Scope
Chains that use Ed25519 (or similar EdDSA variants) instead of secp256k1:
- Solana —
@solana/web3.js, @coral-xyz/anchor
- Aptos —
@aptos-labs/ts-sdk, aptos
- Sui —
@mysten/sui.js, @mysten/sui
- NEAR —
near-api-js, @near-js/*
- TON —
@ton/ton, ton, tonweb
- Algorand —
algosdk
- Cardano —
@emurgo/cardano-serialization-lib-browser, lucid-cardano
Do NOT confuse Ed25519 signing with EVM secp256k1. They are fundamentally different.
Ed25519: 32-byte private key → 64-byte signature (R, S)
secp256k1: 32-byte private key → 65-byte signature (r, s, v) with recovery
1. Solana
Libraries
import { Connection, Keypair, Transaction, SystemProgram,
PublicKey, sendAndConfirmTransaction } from '@solana/web3.js'
import * as anchor from '@coral-xyz/anchor'
import { Program, AnchorProvider } from '@coral-xyz/anchor'
import { useWallet } from '@solana/wallet-adapter-react'
import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom'
Transaction Signing
const tx = new Transaction()
tx.add(SystemProgram.transfer({ fromPubkey, toPubkey, lamports }))
tx.feePayer = wallet.publicKey
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash
const signed = await wallet.signTransaction(tx)
const sig = await connection.sendRawTransaction(signed.serialize())
const signed = tx.sign(keypair)
tx.partialSign(keypair)
Message Signing (off-chain)
const message = new TextEncoder().encode("Hello Solana")
const { signature } = await wallet.signMessage(message)
import nacl from 'tweetnacl'
nacl.sign.detached.verify(message, signature, publicKey.toBytes())
Instruction Encoding (Anchor)
const idl = {
"version": "0.1.0",
"name": "my_program",
"instructions": [
{
"name": "initialize",
"accounts": [...],
"args": [{"name": "data", "type": "u64"}]
}
]
}
const ix = await program.methods.initialize(new BN(1000))
.accounts({ payer, systemProgram })
.instruction()
const discriminator = sha256("global:initialize").slice(0, 8)
Key Patterns to Extract
Keypair.fromSecretKey(secretKey)
Keypair.fromSeed(seed)
Keypair.generate()
bs58.encode(keypair.secretKey)
bs58.decode("private_key_base58_string")
new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
PublicKey.findProgramAddressSync([Buffer.from("seed"), owner.toBuffer()], programId)
PublicKey.createWithSeed(base, seed, programId)
Borsh Serialization (Solana instruction data)
import * as borsh from '@project-serum/borsh'
import { serialize, deserialize } from 'borsh'
const schema = new Map([
[MyStruct, { kind: 'struct', fields: [
['amount', 'u64'],
['recipient', [32]],
]}]
])
const encoded = serialize(schema, new MyStruct({ amount: 1000n, recipient: pubkey.toBytes() }))
For each Borsh schema found, extract verbatim — it defines the instruction layout.
2. Aptos
Libraries
import { AptosClient, AptosAccount, BCS, TxnBuilderTypes } from 'aptos'
import { Aptos, AptosConfig, Network, Account } from '@aptos-labs/ts-sdk'
import { useWallet } from '@aptos-labs/wallet-adapter-react'
import { PetraWallet } from 'petra-plugin-wallet-adapter'
Transaction Signing
const rawTx = await client.generateTransaction(sender, {
function: "0x1::coin::transfer",
type_arguments: ["0x1::aptos_coin::AptosCoin"],
arguments: [recipient, amount]
})
const signedTx = await client.signTransaction(account, rawTx)
const res = await client.submitTransaction(signedTx)
const { signAndSubmitTransaction } = useWallet()
await signAndSubmitTransaction({ payload: { function: "...", arguments: [...] } })
const { signature, fullMessage } = await wallet.signMessage({
message: "Hello Aptos",
nonce: "random_nonce"
})
BCS Serialization (Aptos)
import { BCS, TxnBuilderTypes } from 'aptos'
const serializer = new BCS.Serializer()
BCS.serializeStr(serializer, "hello")
BCS.serializeU64(serializer, 1000n)
serializer.serializeBytes(Buffer.from(address, 'hex'))
new TxnBuilderTypes.TypeTagStruct(
TxnBuilderTypes.StructTag.fromString("0x1::aptos_coin::AptosCoin")
)
Key Extraction
const account = new AptosAccount(Buffer.from(privateKeyHex, 'hex'))
Account.fromPrivateKey({ privateKey: new Ed25519PrivateKey(hexKey) })
AptosAccount.fromDerivePath("m/44'/637'/0'/0'/0'", mnemonic)
3. Sui
Libraries
import { SuiClient, TransactionBlock, Ed25519Keypair,
Secp256k1Keypair } from '@mysten/sui.js'
import { SuiClient, Transaction } from '@mysten/sui/client'
import { useCurrentAccount, useSignTransaction } from '@mysten/dapp-kit'
Transaction Signing
const txb = new TransactionBlock()
const [coin] = txb.splitCoins(txb.gas, [txb.pure(1000000)])
txb.transferObjects([coin], txb.pure(recipient))
txb.moveCall({ target: "0x2::coin::transfer", typeArguments: [...], arguments: [...] })
const result = await client.signAndExecuteTransactionBlock({
signer: keypair,
transactionBlock: txb,
})
const { mutate: signTransaction } = useSignTransaction()
signTransaction({ transaction: txb })
BCS (Sui)
import { bcs } from '@mysten/sui.js/bcs'
const schema = bcs.struct('MyStruct', {
amount: bcs.u64(),
recipient: bcs.bytes(32),
})
const encoded = schema.serialize({ amount: 1000n, recipient: addrBytes })
Key Patterns
Ed25519Keypair.generate()
Ed25519Keypair.fromSecretKey(secretKey)
Ed25519Keypair.deriveKeypair(mnemonic, "m/44'/784'/0'/0'/0'")
Secp256k1Keypair.fromSecretKey(secretKey)
4. NEAR
Libraries
import { connect, KeyPair, keyStores, utils } from 'near-api-js'
import { Account, Contract } from 'near-api-js'
import { setupWalletSelector } from '@near-wallet-selector/core'
import { setupMyNearWallet } from '@near-wallet-selector/my-near-wallet'
Transaction Signing
const near = await connect({ networkId: 'mainnet', nodeUrl: 'https://rpc.mainnet.near.org' })
const account = await near.account(accountId)
await account.functionCall({
contractId: 'contract.near',
methodName: 'transfer',
args: { receiver_id: recipient, amount: '1000000000000000000000000' },
gas: '30000000000000',
attachedDeposit: '1',
})
const { signature, publicKey } = await wallet.signMessage({
message: "Hello NEAR",
recipient: "app.near",
nonce: Buffer.from(crypto.getRandomValues(new Uint8Array(32)))
})
Key Patterns
KeyPair.fromRandom('ed25519')
KeyPair.fromString('ed25519:' + base58PrivateKey)
utils.KeyPairEd25519.fromRandom()
5. TON
Libraries
import { TonClient, WalletContractV4, internal, toNano } from '@ton/ton'
import TonWeb from 'tonweb'
import { TonConnect } from '@tonconnect/sdk'
import { useTonConnectUI } from '@tonconnect/ui-react'
Transaction Signing
const tonConnectUI = new TonConnectUI({ manifestUrl: '...' })
await tonConnectUI.sendTransaction({
messages: [{
address: destination,
amount: toNano('0.05').toString(),
payload: beginCell().storeUint(0, 32).storeStringTail("comment").endCell().toBoc().toString('base64')
}]
})
const wallet = WalletContractV4.create({ publicKey: keypair.publicKey, workchain: 0 })
const transfer = wallet.createTransfer({
secretKey: keypair.secretKey,
seqno,
messages: [internal({ to, value, body })]
})
BOC / Cell Serialization (TON specific)
import { beginCell, Cell, Builder, Slice } from '@ton/ton'
const cell = beginCell()
.storeUint(0xf8a7ea5, 32)
.storeUint(queryId, 64)
.storeCoins(toNano('1'))
.storeAddress(destination)
.endCell()
const boc = cell.toBoc().toString('base64')
BOC + Cell patterns are TON-specific. Extract any beginCell()...endCell() chains.
6. Algorand
Libraries
import algosdk from 'algosdk'
import { useWallet } from '@txnlab/use-wallet'
import { PeraWalletConnect } from '@perawallet/connect'
Transaction Signing
const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
from: sender,
to: recipient,
amount: 1000000,
suggestedParams,
note: new TextEncoder().encode("memo")
})
const signedTxn = txn.signTxn(secretKey)
const { blob } = await wallet.signTransaction([{ txn: Buffer.from(txn.toByte()).toString('base64') }])
const method = new algosdk.ABIMethod({ name: 'transfer', args: [...], returns: {...} })
const atc = new algosdk.AtomicTransactionComposer()
atc.addMethodCall({ appID, method, methodArgs: [to, amount], ... })
MessagePack (Algorand)
algosdk.encodeObj(obj)
algosdk.decodeObj(bytes)
Buffer.from(note).toString('base64')
Analysis Steps
Step 1: Identify the chain
From library imports → determine which chain(s) are present.
Step 2: Find signing entry point
Trace from user action → wallet.signTransaction / signMessage call.
Step 3: Extract message/transaction construction
Before signing, what is built?
- Solana:
Transaction with Instruction list
- Aptos: function + type_arguments + arguments
- Sui:
TransactionBlock with Move calls
- NEAR: method + args JSON
- TON:
beginCell() chain (BOC)
- Algorand: transaction fields + ABI method
Step 4: Extract serialization schemas
- Solana Borsh: find
Map([[Class, {kind:'struct', fields:[...]}]])
- Anchor IDL: find the JSON object with
instructions: [...]
- Sui BCS: find
bcs.struct(...) definitions
- Aptos BCS: find Serializer usage
- TON TL-B: find cell builder patterns
- Algorand ARC-4: find
ABIMethod definitions
Step 5: Find hardcoded keys
Ed25519 private key: 32 bytes (64 hex chars) or 64 bytes (128 hex chars = seed+pubkey)
Solana base58 key: bs58 string of length ~88
NEAR key: "ed25519:..." prefix
Any hardcoded key → CRITICAL finding.
Output Format
Ed25519 / NON-EVM FINDINGS
===========================
[S1] Solana Transaction Signing — HIGH
Chain: Solana
File: chunks/wallet.js:3201
Method: wallet.signTransaction (Phantom adapter)
Tx type: Token transfer (SPL Token program)
Encoding: Borsh (Transaction.serialize())
Instruction layout:
Program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Data: [3, amount_u64_le, decimals_u8]
Callers: sendTransfer():4100, swapTokens():5200
[S2] Anchor IDL Found — HIGH
Chain: Solana
File: chunks/program.js:891
Program: MyDefiProtocol (IDL embedded as JSON)
Instructions found: initialize, deposit, withdraw, swap
Discriminators:
initialize: [175, 175, 109, 31, 13, 152, 155, 237]
deposit: [242, 35, 198, 137, 82, 225, 242, 182]
[A1] Aptos BCS Signing — HIGH
Chain: Aptos
File: pages/transfer.js:441
Function: 0x1::coin::transfer
Type args: 0x1::aptos_coin::AptosCoin
Args: [recipient: address, amount: u64]
Wallet: Petra (wallet adapter)
Signing: Ed25519 via AptosAccount
[T1] TON BOC Cell — HIGH
Chain: TON
File: index.js:12401
Op code: 0xf8a7ea5 (Jetton transfer)
Cell structure:
storeUint(0xf8a7ea5, 32) ← op
storeUint(queryId, 64)
storeCoins(amount)
storeAddress(destination)
Wallet: TonConnect v2
Python Reconstruction
from solders.keypair import Keypair
from solders.message import Message
keypair = Keypair.from_base58_string("...")
msg_bytes = b"Hello Solana"
sig = keypair.sign_message(msg_bytes)
from aptos_sdk.account import Account
from aptos_sdk.client import RestClient
from aptos_sdk.transactions import EntryFunction, TransactionArgument, TypeTag
client = RestClient("https://fullnode.mainnet.aptoslabs.com/v1")
account = Account.load_key(hex_private_key)
payload = EntryFunction.natural(
"0x1::coin",
"transfer",
[TypeTag.from_str("0x1::aptos_coin::AptosCoin")],
[TransactionArgument(recipient, Serializer.struct),
TransactionArgument(amount, Serializer.u64)]
)
from pysui.sui.sui_bcs import bcs as sui_bcs
import bcs
from pytonlib import TonlibClient
from tonsdk.boc import Cell, begin_cell
cell = begin_cell().store_uint(0xf8a7ea5, 32).store_uint(query_id, 64).end_cell()