TSP-0008 CISA

Transaction Size Reduction via Aggregate Schnorr Signatures for Tondi

Proposal Number: TSP-0008
Proposal Name: Transaction Size Reduction via Aggregate Schnorr Signatures for Tondi
Category: Consensus (C) โ€” pre-Oct 2025 numbering retained as 000x
Status: Draft Author: Tondi Foundation Development Team
Created: 2025-09-05
Target: Tondi Frontier (v2026a)
Scope: On-chain payload schema, validation semantics, tapscript opcodes, transaction-level witness envelope, DAG/mempool policy, interoperability with TSP-0007 (ANYPREVOUT), governance & activation

This document uses RFC 2119 keywords (MUST/SHOULD/MAYโ€ฆ).

1. Abstract

CISA introduces cross-input signature aggregation: In a transaction, multiple inputs (from the same or different parties) that meet the conditions no longer carry individual Schnorr signatures but are covered by a single aggregated Schnorr signature for an "aggregation cohort."
This can significantly reduce transaction sizes and validation costs in Tondi's high-throughput DAG environment, improving block capacity and economics for micro-payments, consolidation spends, and coinjoin scenarios.

2. Background and Motivation

  • Size/Fee Benefits: Remove N 64B signatures and redundant overhead, replacing them with a single 64B aggregated signature + minimal metadata. Savings are substantial for larger N (>4).

  • Validation Efficiency: A single Schnorr verification after aggregation, more CPU/bandwidth-friendly; beneficial for high-TPS Tondi Flash on-chain settlement phases.

  • Privacy Gains: Homogenizes inputs in coinjoins/batch withdrawals, reducing the effectiveness of heuristic analysis.

Design Goals:

  • Soft fork (tapscript-only + OP_SUCCESSx tightening);
  • Schnorr-only, aligned with existing Taproot/tapscript;
  • Simple and Correct: v1 only supports SIGHASH_ALL aggregation, temporarily excluding complex combinations like APO/ANYSCRIPT/ANYONECANPAY.

3. Terminology and Overall Design

  • CISA Aggregation Cohort: An ordered set of inputs in the same transaction participating in aggregation.

  • TSP-0008 Public Key: Identified in scripts as 0x02 || pubkey32 (33 bytes, x-only), eligible for CISA.

  • CISA Witness Envelope: Transaction-level witness extension carrying the cohort's bitmap/index, aggregated nonce R, aggregated signature s, etc.

  • MuSig2: Multi-signature aggregation scheme resistant to rogue-key attacks; uses deterministic coefficients for public key aggregation.

3.1 Domain Separation Labels (Standardized)

MUST: Fixed byte strings for all domain separation labels (case-sensitive, exact spelling):

  • "TSP-0008/CISASighash" (20 bytes): 0x54 0x53 0x50 0x2d 0x30 0x30 0x30 0x38 0x2f 0x43 0x49 0x53 0x41 0x53 0x69 0x67 0x68 0x61 0x73 0x68
  • "TSP-0008/Cohort" (13 bytes): 0x54 0x53 0x50 0x2d 0x30 0x30 0x30 0x38 0x2f 0x43 0x6f 0x68 0x6f 0x72 0x74
  • "MuSig/KeyAggList" (16 bytes): 0x4d 0x75 0x53 0x69 0x67 0x2f 0x4b 0x65 0x79 0x41 0x67 0x67 0x4c 0x69 0x73 0x74
  • "MuSig/KeyCoeff" (14 bytes): 0x4d 0x75 0x53 0x69 0x67 0x2f 0x4b 0x65 0x79 0x43 0x6f 0x65 0x66 0x66
  • "BIP0340/challenge" (16 bytes): 0x42 0x49 0x50 0x30 0x33 0x34 0x30 0x2f 0x63 0x68 0x61 0x6c 0x6c 0x65 0x6e 0x67 0x65

v1 Scope (Strict Constraints for Simplicity and Safety):

  • Only tapscript script-path (no key-path impact; future extension);
  • Only SIGHASH_ALL;
  • Cannot mix with TSP-0007 APO in the same cohort;
  • At most 1 cohort per transaction (extensible, see appendix).

4. Specification

4.1 New Public Key and New Opcodes

  • TSP-0008 Public Key: x-only 32-byte Schnorr public key, identified in scripts as 0x02 || pubkey32.

  • New OPs (Implemented via OP_SUCCESSx encoding for soft fork):

    • OP_CHECKSIG_CISA (0xB5)

    • OP_CHECKSIGVERIFY_CISA (0xB6)

    • (Optional) OP_CHECKSIGADD_CISA (0xB7) Specific OP_SUCCESSx values are fixed to avoid implementation divergence.

    • Non-upgraded nodes: Encountering OP_SUCCESSx results in unconditional success;

    • Upgraded nodes: Execute cohort validation path (below), tightening "unconditional success" to "must pass CISA verification."

Script Convention: Inputs participating in CISA do not provide signature objects (witness is empty placeholder), but delegate validation to transaction-level CISA via the above OPs.

4.2 CISA Witness Envelope

MUST: CISA envelope is located at transaction-level witness-extension with unique position and fixed encoding to eliminate malleability and parsing divergence. The envelope is encoded as:

tx_wit_ext := varint(1) || cisa_envelope
cisa_envelope :=
  magic[4] = "CISA"                    // 0x43 0x49 0x53 0x41
  version[u8] = 0x01
  flags[u16]                          // bit0=1 (SIGHASH_ALL), others=0
  hash_type[u8] = 0x01               // MUST be SIGHASH_ALL
  cohort_bitmap[ceil(num_inputs/8)]  // 1 = input participates
  agg_nonce_R[32]                    // x-only, even-y required
  agg_sig_s[32]                      // Schnorr scalar s

MUST:

  • popcount(cohort_bitmap) >= 1 (non-empty cohort)
  • len(bitmap) == ceil(num_inputs/8) (exact length)
  • Last byte bits beyond num_inputs MUST be 0; otherwise consensus FAILS
  • Bitmap bit order: LSB-first (bit j of byte t corresponds to input index 8*t + j)
  • Transaction contains at most one cisa_envelope; otherwise consensus FAILS
  • MUST NOT place envelope in any input's witness stack

MUST: All inputs in the cohort's script must include at least one OP_CHECKSIGVERIFY_CISA (or OP_CHECKSIG_CISA with overall true logic). Inputs outside the cohort MUST NOT use the above CISA OPs.

4.3 Script Requirements for Inputs in Cohort

  • Public key stack element MUST be 0x02 || pubkey32.
  • OP_CHECKSIGVERIFY_CISA (or _CISA) does not consume a signature; its semantics are "add this input to the transaction's CISA validation set and await global validation."
  • Allows other constraints in the same script (e.g., CSV/CLTV, HASHLOCK), but must ensure the input path evaluates to true when CISA validation passes.

4.4 Aggregated Message and Bindings (Sighash & Bindings)

v1 only supports SIGHASH_ALL. To ensure each input's amount/script/leaf/sequence is bound in the message, define transaction-level signature message:

  • Use TaggedHash for domain separation:
    $H_{tag}(label, m) = SHA256(SHA256(label) | SHA256(label) | m)$
    where label = "TSP-0008/CISASighash".

  • Define two data segments:

    1. TxBase (Identical to tapscript SIGHASH_ALL base commitment):

      u8   : hash_type (=0x01)
      le32 : nVersion
      le32 : nLockTime
      H(Prevouts)   // Hash of all input outpoints concatenated
      H(Sequences)  // Hash of all input nSequences concatenated
      H(Outputs)    // Hash of all outputs CTxOut concatenated (incl. CompactSize)
      

      MUST: Encoding of Prevouts/Sequences/Outputs completely matches BIP-341 SIGHASH_ALL field-by-field serialization order and CompactSize encoding.

    2. CohortBindings (Per-input bindings for cohort members):
      For each input i in cohort (in ascending input index order), concatenate:

      le64 : amount_i
      varbytes : scriptPubKey_i (CompactSizeLen + RawScript)
      u8   : annex_flag_i       (0=no annex, 1=has annex)
      if annex_flag_i == 1:
         H(CompactSizeLen(annex_i) || annex_i)  // MUST match tapscript annex binding
      le32 : nSequence_i
      le32 : codesep_pos_i      (0xFFFFFFFF if no CODESEPARATOR)
      H32  : tapleaf_hash_i     // MUST include leaf_version: H_tag("TapLeaf", leaf_version || CompactSize(script_len) || script)
      
  • Full Message:
    $m = H_{tag}("TSP-0008/CISASighash", TxBase | H(CohortBindings) | CohortBitmapDigest)$
    where CohortBitmapDigest = $H_{tag}("TSP-0008/Cohort", cohort_bitmap)$ to prevent replay to different cohort selections.

MUST:

  • tapleaf_hash_i calculation MUST include leaf_version in TapLeaf construction
  • codesep_pos_i semantics MUST align with BIP-342 (0xFFFFFFFF when no CODESEPARATOR)
  • Annex binding MUST use identical method as tapscript single-signature annex binding
  • TxBase serialization MUST be byte-for-byte identical to BIP-341 SIGHASH_ALL

Explanation: Binding each input independently (amount/script/leaf/sequence) ensures single-sign โ†’ aggregate semantic equivalence, preventing aggregated signatures from being transplanted to different scripts/amounts.

4.5 Aggregated Public Key and Signature Validation (MuSig2)

  • Public Key Aggregation: Let TSP-0008 public keys in the cohort (ordered by input index) be $X_1 \dots X_k$ (x-only).
    Compute $L = H_{tag}("MuSig/KeyAggList", X_1|\dots|X_k)$, coefficients $a_i = H_{tag}("MuSig/KeyCoeff", L | X_i)$,
    aggregated public key $X = \sum_{i} a_i \cdot X_i$.

MUST:

  • Verify $X \neq \infty$ and each $X_i$ is a valid curve point (BIP-340 x-only with even-y reconstruction)

  • MuSig2 coefficient $a_i = int(Hash(...) \bmod n)$; if $a_i == 0$ (probability ~1/n), consensus FAILS

  • MUST prohibit duplicate input indices; for duplicate public keys, define consistent behavior (see security section)

  • Signature Validation: CISA envelope provides R (x-only 32B) and s (32B).
    MUST: R must be even-y x-only; if odd-y detected, consensus FAILS (no automatic flipping) Let $e = H_{tag}("BIP0340/challenge", R | X | m)$ (BIP-340 style), verify:
    $s \cdot G = R + e \cdot X$

  • Pass Condition: Equation holds, and envelope's bitmap exactly covers all inputs that used _CISA/_CISAVERIFY in actual script execution (prevents dead branch abuse).

Note: Nonce protocol (commit-reveal, anti-replay, optional adaptors) is off-chain; on-chain only validates aggregated signature.

4.6 Interoperability and Constraints (Relation to TSP-0007)

  • v1 prohibits using ANYPREVOUT/ANYSCRIPT/ANYONECANPAY etc. non-ALL flags in the same cohort.
  • If transaction includes APO inputs, they MUST NOT participate in CISA; they should use TSP-0007 independent signature paths.
  • MUST: Define determinable condition for "input uses APO" (e.g., witness contains APO-sig or tapscript contains APO-OP) for consensus-level "prohibit CISA + APO in same cohort" check
  • Future TSP-0008-EXT can define "CISA + APO" joint message spec (requiring extra per-input APO binding vectors and consistent hash_type).

4.7 Failure Conditions (Consensus MUST Fail)

  • Transaction has multiple CISA envelopes;
  • hash_type != 0x01;
  • Bitmap empty (popcount(cohort_bitmap) == 0) or inconsistent with script usage;
  • Bitmap length != ceil(num_inputs/8) or last byte bits beyond num_inputs are non-zero;
  • Any input in cohort lacks 0x02||pubkey32 or invalid OP usage;
  • R is not even-y x-only (odd-y detected);
  • X == โˆž or any X_i is invalid curve point;
  • Any MuSig2 coefficient a_i == 0;
  • tapleaf_hash_i calculation missing leaf_version;
  • Annex binding inconsistent with tapscript single-signature method;
  • Any _CISA OP executed in script but bitmap does not cover that input;
  • SINGLE out-of-bounds (not applicable but reserved check) or any non-v1 allowed flags;
  • Schnorr validation fails.

5. DAG / Mempool Policy (Non-Consensus, Default Policy)

  • Size/Fee Pricing: Based on actual bytes; CISA reduces witness volume โ†’ better fees.
  • Validation Cost: Aggregated tx validation time averages lower than N single signs; but requires script parsing for pubkeys โ†’ SHOULD set single-tx cohort size limit (default k_max = 1024, configurable).
  • DoS and Complexity Bounds: SHOULD implement formulaic budget:
    • Parsing cost: O(total_script_bytes + k)
    • Elliptic curve verification cost: โ‰ˆ 1 Schnorr verify + 2k scalar multiplications (MuSig2 pre-aggregation)
    • Nodes SHOULD reject transactions exceeding budget based on total bytes and k; P2P layer SHOULD apply separate rate limiting for "CISA-containing tx"
  • Replacement Policy RBF/RBS: Consistent with TSP-0007; CISA does not alter nSequence semantics.
  • Relay Policy: MUST NOT relay for non-tapscript or mixed APO cohorts.
  • P2P Rate Limiting: Enable per-peer transmission limits for large-cohort CISA txs to resist DoS.

5.6 Half-Aggregation (Non-Consensus Policy)

SHOULD: Nodes implement Half-Aggregation caching strategy in mempool:

  • Cache s components and R vectors from half-aggregated signatures
  • When blocks arrive with block-level half-aggregated signatures (s', R'_1..R'_m), perform s' โ† s' โˆ’ s and remove seen R values to skip duplicate verification
  • During reorgs, SHOULD retain cached values until transactions reach sufficient confirmation depth to avoid replay failures

Benefits: Non-interactive compression of n signatures to half-size aggregated signatures, compatible with block-level half-aggregation for improved verification efficiency.

Note: Half-aggregation is incompatible with adaptor signatures; adaptor-based protocols must use non-aggregated tapscript paths.

6. Security Analysis

6.1 Rogue-Key and Aggregation Security

  • Uses MuSig2 coefficients $a_i$ binding the entire pubkey set, resisting rogue-key attacks;
  • MUST use BIP-340 standard domain-separated challenge;
  • Off-chain MUST execute nonce commit/reveal process, MUST NOT reuse nonces.
  • SHOULD: In wallet SDK flow, enforce public key proofs (each signer proves possession of discrete logarithm for X_i) to resist external injection of malicious points (non-consensus requirement, but ecosystem security).

6.2 Replay and Misuse

  • CohortBindings bind each input (amount/script/leaf/sequence), plus CohortBitmapDigest, prevent cross-script/cross-cohort replays;
  • CISA v1 bans APO, effectively avoiding complex stacking risks with APO's weak bindings.

6.3 Malleability and Composite Protocols

  • Aggregated remains BIP-340-style; message binds Prevouts/Sequences/Outputs, no new txid malleability risks;
  • Complements coinjoin/batch withdrawals for privacy; but envelope bitmap size may expose participation scale (resolvable via padding/multi-cohort extension, see appendix).

6.4 Domain Separation and Label Standardization

SHOULD: Standardize domain separation labels in "Terminology" section with fixed byte strings (case/slash) and provide byte-by-byte examples in test vectors to avoid implementation spelling differences:

  • H_tag("TSP-0008/CISASighash", ...)
  • H_tag("TSP-0008/Cohort", bitmap)
  • H_tag("MuSig/KeyAggList", ...) and H_tag("MuSig/KeyCoeff", ...)
  • H_tag("BIP0340/challenge", R || X || m)

SHOULD: In TxBase, explicitly specify byte order (LE) and integer width for nVersion/nLockTime/sequences, providing cross-language consistent serialization description.

6.5 Duplicate Public Key Strategy (Key Reuse)

SHOULD: v1 prohibits duplicate x-only public keys within cohort; otherwise MUST define consistent "duplicate public key equivalent merging" behavior and add (index || Xi) to message m binding to prevent reordering/substitution.

6.6 Bitmap Privacy Padding

SHOULD: In v1, add optional "fixed-length bitmap" (rounded up to mempool limit k_max) policy-level switch, allowing at least policy-level zero padding to hide cohort size (consensus still allows compact encoding).

6.7 Adaptor Signatures Compatibility

Protocol Combination Matrix:

  • v1 CISA (Full Aggregation): Compatible with adaptor signatures when placed in non-aggregated tapscript paths
  • Half-Aggregation: Incompatible with adaptor signatures; adaptor-based protocols must use non-aggregated tapscript paths
  • Future g'root/Entroot: Key-path aggregation + script-path adaptor signatures remain compatible

MUST: Adaptor signatures MUST be placed in non-aggregated tapscript paths to preserve protocol functionality:

  • Cross-chain atomic swaps
  • Privacy protocols requiring adaptor signatures
  • Lightning Network and other adaptor-based constructions

Future Compatibility: When implementing g'root/Entroot, this pattern remains valid (key-path aggregation, script-path adaptor signatures).

7. Economic and Privacy Impacts

  • Size Savings Rough Calculation:

    • Without CISA: Per input ~64B (signature) + witness stack overhead;
    • CISA: Remove Nร—signatures, add 64B (s) + 32B (R) + bitmap (~N/8 B) + fixed header.
    • For N=8, savings โ‰ˆ 8ร—64 โˆ’ (64+32+1) โ‰ˆ ~415 B (excluding stack/index differences); higher for larger N.
  • Blockstream Research Savings (Informative):
    Based on Taproot v1 average transaction analysis:

    • Half-Aggregation: ~20.6% bytes / 7.6% weight units
    • Full Aggregation: ~26.1% bytes / 9.6% weight units
    • Combined: ~33.6% bytes / 12.4% weight units
    • Large Coinjoin: ~41.2% bytes / 15.2% weight units
  • Privacy: More homogeneous inputs, beneficial against heuristics; combinable with coinjoin protocols.

7.1 PSBT/Offline Flow

SHOULD: Define minimal PSBT extension fields for Half-Aggregation and Full Aggregation:

Core Fields:

  • psbt_cisa_partial_R[i]: Half-aggregation R components for each input
  • psbt_cisa_partial_s: Half-aggregation s contribution
  • psbt_cisa_bitmap_proposal: Proposed cohort bitmap
  • psbt_cisa_non_aggregatable: Flag for non-aggregatable paths (adaptor signatures)

Extended Fields:

  • Nonce commitments, partial nonces, aggregated nonce
  • Partial signatures, cohort bitmap proposals
  • Wallet interoperability minimum set specification

SHOULD: In coinjoin/batch withdrawal scenarios, provide failure attribution (blame) and retry recommended flow to reduce final rejection UX risk.

7.2 Error and Rejection Reasons

SHOULD: Standardize error codes for cross-implementation debugging:

  • ERR_CISA_R_ODD: R is odd-y (should be even-y)
  • ERR_CISA_BITMAP_LEN: Bitmap length mismatch
  • ERR_CISA_DUP_PUBKEY: Duplicate public keys in cohort
  • ERR_CISA_APO_MIXED: CISA and APO inputs in same transaction
  • ERR_CISA_COEFF_ZERO: MuSig2 coefficient a_i == 0
  • ERR_CISA_X_INFINITY: Aggregated public key X == โˆž
  • ERR_CISA_SCRIPT_MISMATCH: Script execution used _CISA but bitmap doesn't cover input

8. Compatibility and Deployment

8.1 Soft Fork Path

โš ๏ธ Risk Note: MUST NOT introduce cross-input aggregation validation through redefining OP_SUCCESSx opcodes, as this creates chain split risk. Unupgraded nodes treat OP_SUCCESS as unconditionally true, while upgraded nodes execute real aggregation validation, leading to inconsistent script execution paths.

Recommended Deployment Paths:

  • New SegWit Version: Introduce new witness version for key-path aggregation, avoiding OP_SUCCESS interaction
  • Generalized Taproot (g'root/Entroot): Move aggregatable public keys out of script system entirely, eliminating OP_SUCCESS conflicts

Current v1 Approach: Tapscript-only with script-path aggregation only; key-path aggregation deferred to future witness version or g'root implementation.

  • Testnet โ‰ฅ 3 months;
  • Version bit (non-conflicting with TSP-0007's bit, specifics in deployment params table);
  • SHOULD: Map "observation period/Speedy-Trial (LOT=true)" to DAG system (e.g., based on "blue set" or time window voting sampling) and provide timeline diagram
  • SHOULD: Define Tondi DAG-specific window definition and statistical method (different from Bitcoin's 2016 blocks/80% threshold)
  • Mainnet threshold 80% / 2016 blocks equivalent, observation period + Speedy-Trial (LOT=true) fallback plan.

8.3 Interoperability Regression Testing

SHOULD: During testnet 3-month period, include adversarial use cases:

  • Large cohort + low bandwidth nodes;
  • Malicious adversaries frequently submitting "bitmap inconsistency/high bit dirty data";
  • Coinjoin scenario rejection/timeout recovery and RBF;
  • Boundary interactions with APO appearing in same block but different transactions.

9. Reference Implementation (Pseudocode)

9.1 Transaction-Level Validation Process

use tondi_consensus_core::tx::{Transaction, TransactionInput, UtxoEntry, VerifiableTransaction};
use tondi_consensus_core::hashing::sighash::{SigHashReusedValues, SigHashReusedValuesUnsync};
use tondi_crypto_txscript::{TxScriptEngine, TxScriptError, caches::Cache, SigCacheKey};
use secp256k1::{XOnlyPublicKey, Secp256k1};
use tondi_hashes::{Hash, Hasher, HasherBase};

fn validate_cisa<T: VerifiableTransaction>(
    tx: &T, 
    utxo_entries: &[UtxoEntry],
    reused_values: &SigHashReusedValuesUnsync,
    sig_cache: &Cache<SigCacheKey, bool>
) -> Result<(), TxScriptError> {
    // 1) Parse envelope
    let env = parse_cisa_envelope(tx).ok_or(TxScriptError::InvalidSignature)?;
    ensure!(env.version == 1 && env.hash_type == 0x01);
    let cohort = bitmap_to_indices(&env.cohort_bitmap, tx.inputs().len())?;
    ensure!(!cohort.is_empty());

    // 2) Collect pubkeys and script constraints for inputs in cohort
    let mut xs: Vec<XOnlyPublicKey> = Vec::new();
    let mut bindings: Vec<[u8;32]> = Vec::new();
    for &idx in &cohort {
        let (x, bind_i) = extract_pubkey_and_binding(tx, idx, &utxo_entries[idx])?;
        xs.push(x);
        bindings.push(bind_i);
        ensure!(input_uses_cisa_op(tx, idx)); // Script includes *_CISA
        ensure!(input_hash_type_is_all(tx, idx)); // v1: ALL
        ensure!(!input_uses_anyprevout(tx, idx)); // v1: no APO
    }

    // 3) Compute aggregated pubkey X (MuSig2)
    let L = tag_hash("MuSig/KeyAggList", &concat_pubkeys(&xs));
    let coeffs: Vec<[u8;32]> = xs.iter().map(|Xi| tag_hash("MuSig/KeyCoeff", &L, Xi)).collect();
    let X = compute_aggregated_pubkey(&xs, &coeffs)?;

    // 4) Assemble message m
    let tx_base = build_txbase_sighash_all(tx, reused_values);
    let bind_digest = hash_bindings(&bindings);
    let cohort_digest = tag_hash("TSP-0008/Cohort", &env.cohort_bitmap);
    let m = tag_hash("TSP-0008/CISASighash", &tx_base, &bind_digest, &cohort_digest);

    // 5) Schnorr validation
    let e = tag_hash("BIP0340/challenge", &env.agg_nonce_r, &X.serialize(), &m);
    ensure!(schnorr_verify(&env.agg_sig_s, &env.agg_nonce_r, &X, &e));

    Ok(())
}

extract_pubkey_and_binding (Per-Input Binding Data):

use tondi_consensus_core::tx::{Transaction, UtxoEntry, ScriptPublicKey};
use secp256k1::XOnlyPublicKey;
use tondi_crypto_txscript::TxScriptError;
use tondi_hashes::{Hash, Hasher, HasherBase, TransactionSigningHash};

fn extract_pubkey_and_binding<T: VerifiableTransaction>(
    tx: &T, 
    i: usize, 
    utxo_entry: &UtxoEntry
) -> Result<(XOnlyPublicKey, [u8;32]), TxScriptError> {
    // Parse TSP-0008 pubkey from script (0x02||pubkey32)
    let pk = parse_tsp0008_pubkey_from_script(&tx.inputs()[i].signature_script)?;
    
    // Extract binding data for this input
    let amount = utxo_entry.amount;
    let spk = &utxo_entry.script_public_key.script;
    let seq = tx.inputs()[i].sequence;
    
    // Build binding data
    let mut binding_data = Vec::new();
    binding_data.extend_from_slice(&amount.to_le_bytes());
    binding_data.extend_from_slice(&compact_size_len(spk.len()));
    binding_data.extend_from_slice(spk);
    
    // Annex handling (Tondi doesn't have annex, so always 0)
    binding_data.push(0);
    
    binding_data.extend_from_slice(&seq.to_le_bytes());
    
    // CODESEPARATOR position (0xFFFFFFFF if none)
    binding_data.extend_from_slice(&0xFFFFFFFFu32.to_le_bytes());
    
    // Tapleaf hash (32 bytes) - compute from script
    let leaf_hash = compute_tapleaf_hash(spk);
    binding_data.extend_from_slice(&leaf_hash);
    
    // Hash the binding data
    let mut hasher = TransactionSigningHash::new();
    hasher.update(&binding_data);
    let binding_hash = hasher.finalize();
    
    Ok((pk, binding_hash))
}

9.2 Script Execution Engine Hook (Simplified)

use tondi_crypto_txscript::{TxScriptEngine, TxScriptError, caches::Cache, SigCacheKey};
use tondi_consensus_core::hashing::sighash::SigHashReusedValues;
use tondi_consensus_core::tx::VerifiableTransaction;
use secp256k1::XOnlyPublicKey;

/// TSP-0008 CISA Opcodes
pub const OP_CHECKSIG_CISA: u8 = 0xB5;
pub const OP_CHECKSIGVERIFY_CISA: u8 = 0xB6;
pub const OP_CHECKSIGADD_CISA: u8 = 0xB7;

// OP_CHECKSIGVERIFY_CISA implementation for Tondi client
impl<T: VerifiableTransaction, Reused: SigHashReusedValues> 
    OpCodeExecution<T, Reused> for OpCode<OP_CHECKSIGVERIFY_CISA> {
    
    fn execute(&self, vm: &mut TxScriptEngine<T, Reused>) -> OpCodeResult {
        // Check if top of stack is TSP-0008 pubkey (0x02||pubkey32)
        let pubkey_data = vm.dstack.pop()?;
        ensure_tsp0008_pubkey(&pubkey_data)?;
        
        // Mark current input as requiring CISA validation
        vm.mark_input_requires_cisa();
        
        // Push true - actual validation happens at transaction level
        vm.dstack.push_bool(true)?;
        
        // Execute VERIFY (pop and check if true)
        vm.op_verify()?;
        
        Ok(())
    }
}

fn ensure_tsp0008_pubkey(data: &[u8]) -> Result<XOnlyPublicKey, TxScriptError> {
    if data.len() != 33 || data[0] != 0x02 {
        return Err(TxScriptError::InvalidSignature);
    }
    
    let pubkey_bytes = &data[1..];
    XOnlyPublicKey::from_slice(pubkey_bytes)
        .map_err(|_| TxScriptError::InvalidSignature)
}

10. Test Vectors (Required Set)

10.1 Domain Separation Test Vectors

MUST: Provide SHA256("label") values for all labels and intermediate states of H_tag(label, m):

  • SHA256("TSP-0008/CISASighash") = 0x...
  • SHA256("TSP-0008/Cohort") = 0x...
  • SHA256("MuSig/KeyAggList") = 0x...
  • SHA256("MuSig/KeyCoeff") = 0x...
  • SHA256("BIP0340/challenge") = 0x...

10.2 R Even-y Validation Test Vectors

MUST: Provide example with odd-y R, verification should FAIL.

10.3 a_i == 0 Rare Case Test Vectors

MUST: Construct set causing some coefficient to be 0 (can artificially set to 0) and specify must FAIL.

10.4 Duplicate Public Key Test Vectors

MUST: If duplicate public keys allowed, provide equivalent/non-equivalent two use cases and expected results.

10.5 Annex Binding Test Vectors

MUST: Provide two sets of examples covering annex presence/absence, covering annex_flag==1 hash details.

10.6 Bitmap High Bit Non-zero Failure Test Vectors

MUST: Provide failure example with bitmap high bits non-zero.

10.7 X == โˆž Failure Test Vectors

MUST: Provide failure example with X == โˆž (can artificially construct two opposite private keys summing to 0 ideal scenario to demonstrate implementation branch).

10.8 Positive Examples

  1. 2 inputs (both 0x02||pk), SIGHASH_ALL, single cohort, correct R/s;
  2. 8-input coinjoin with varying script/amount/leaf, correct bindings;
  3. Mix with annex and CODESEPARATOR inputs;
  4. Large cohort (k=256) boundary performance test.

10.9 Negative Examples

  1. Bitmap inconsistent with script usage;
  2. hash_type โ‰  0x01;
  3. Cohort with APO input;
  4. Pubkey not 0x02||pk or missing;
  5. Invalid R/s, or rogue-key detection (altered pubkey order/set) fails;
  6. Single-input cohort (allowed but low value, as boundary) vs. empty cohort (must fail).

10.10 Benchmark Tests (Size/CPU)

SHOULD: Provide N โˆˆ {1,2,4,8,16,64,256,1024} byte savings and CPU estimation table (verification cost before/after aggregation) to help nodes and wallets tune parameters.

11. Interoperability and Evolution Roadmap

  • Key-Path CISA: Two deployment options requiring community evaluation:
    • New SegWit Version: Introduce new witness version for key-path aggregation
    • Generalized Taproot (g'root/Entroot): Move aggregatable public keys out of script system entirely
  • Multi-Cohort Transactions: Introduce cohort_id and multiple envelopes; must prevent cross-cohort mixing.
  • CISA + APO: Define per-input APO binding extensions (quantify ignored fields in ANYPREVOUT), proceed cautiously.
  • Half-Aggregation Integration: Block-level half-aggregation + script-path adaptor signatures paradigm
  • Privacy Padding: Bitmap padding or "index list + commitment" mode to hide participation scale.

12. Deployment and Governance Checklist

  • Community Evaluation: Assess New SegWit Version vs. g'root/Entroot deployment paths
  • Risk Mitigation: Avoid OP_SUCCESSx redefinition to prevent chain split risks
  • Release cross-implementation test vectors (Rust/Go/C++/Python);
  • Testnet Requirements (โ‰ฅ 3 months):
    • Adversarial aggregation/reorg/rate-limiting experiments
    • Half-aggregation caching and reorg testing
    • Adaptor signature compatibility testing
    • Block-level half-aggregation integration tests
  • Wallet SDK: Default enable CISA only in template scripts, secure MuSig2 nonces, PSBT/export mark CISA;
  • Network Policy: Cohort size limits, whitelisted templates, per-peer rate limits;
  • PSBT Extensions: Implement half-aggregation and adaptor signature field support
  • Third-Party Audit (consensus + cryptography implementation, constant-time).

13. Implementation Roadmap for Tondi Client

13.1 Current Tondi Client Analysis

Based on analysis of the Tondi client code, the following current state has been identified:

Implemented Features:

  • โœ… Complete Schnorr signature support (secp256k1::schnorr::Signature)
  • โœ… Taproot script path and key path support
  • โœ… Signature hash calculation (calc_schnorr_signature_hash)
  • โœ… Script execution engine (TxScriptEngine)
  • โœ… Signature caching mechanism (SigCacheKey)
  • โœ… Witness data structure support

Missing CISA Features:

  • โŒ CISA witness envelope parsing and validation
  • โŒ MuSig2 public key aggregation algorithm
  • โŒ Cross-input signature aggregation validation
  • โŒ TSP-0008 specific opcodes (OP_CHECKSIG_CISA, OP_CHECKSIGVERIFY_CISA)
  • โŒ Cohort binding and message construction
  • โŒ CISA-specific signature hash calculation

13.2 Implementation Steps

Phase 1: Core Infrastructure (4-6 weeks)

  1. CISA Witness Envelope Implementation

    • Create cisa.rs under crypto/txscript/src/standard/taproot/
    • Implement CisaEnvelope structure and parsing functions
    • Add envelope validation logic
  2. MuSig2 Integration

    • Integrate secp256k1-musig2 library or implement MuSig2 algorithm
    • Add CISA signature hash calculation in consensus/core/src/hashing/sighash.rs
    • Implement public key aggregation and coefficient calculation
  3. New Opcodes Implementation

    • Add CISA opcodes in crypto/txscript/src/opcodes/mod.rs
    • Implement OP_CHECKSIG_CISA and OP_CHECKSIGVERIFY_CISA
    • Use OP_SUCCESSx encoding for soft fork compatibility

Phase 2: Transaction-Level Validation (3-4 weeks)

  1. CISA Validation Engine

    • Extend TxScriptEngine in crypto/txscript/src/lib.rs
    • Implement transaction-level CISA validation logic
    • Add cohort member detection and constraint validation
  2. Signature Aggregation Logic

    • Implement cross-input signature aggregation validation
    • Add BIP-340 style challenge calculation
    • Integrate with existing signature caching mechanism

Phase 3: Integration and Testing (3-4 weeks)

  1. Wallet Integration

    • Add CISA support in wallet/core/src/
    • Implement CISA transaction construction and signing
    • Update PSBT support to handle CISA envelopes
  2. Mempool and Consensus Integration

    • Add CISA policies in mining/mempool/
    • Implement cohort size limits and fee calculation
    • Add CISA-specific relay rules
  3. Testing and Validation

    • Create comprehensive test vectors
    • Implement integration tests and performance benchmarks
    • Add fuzz testing and edge case testing

13.3 Code Structure Updates

New Files:

crypto/txscript/src/standard/taproot/cisa.rs
consensus/core/src/hashing/cisa_sighash.rs
wallet/core/src/cisa/
testing/integration/src/cisa_tests.rs

Modified Files:

crypto/txscript/src/lib.rs                    # Add CISA validation
crypto/txscript/src/opcodes/mod.rs           # New opcodes
consensus/core/src/hashing/sighash.rs        # CISA signature hash
wallet/core/src/tx/generator/generator.rs    # CISA transaction construction
mining/src/mempool/manager.rs                # CISA policies
consensus/core/src/tx.rs                     # Transaction payload handling

13.4 Code Implementation Examples

CISA Envelope Structure

// crypto/txscript/src/standard/taproot/cisa.rs
use tondi_consensus_core::hashing::sighash_type::SigHashType;
use tondi_consensus_core::tx::{Transaction, VerifiableTransaction};
use tondi_crypto_txscript::TxScriptError;
use tondi_hashes::{Hash, TransactionSigningHash};

#[derive(Debug, Clone)]
pub struct CisaEnvelope {
    pub magic: [u8; 4],           // "CISA"
    pub version: u8,              // 0x01
    pub flags: u16,              // bit0: SIGHASH_ALL only, bit1: Half-Agg enabled
    pub hash_type: u8,           // MUST be 0x01
    pub cohort_bitmap: Vec<u8>,  // ceil(num_inputs/8) bytes
    pub agg_nonce_r: [u8; 32],  // x-only R, even-y required
    pub agg_sig_s: [u8; 32],     // Schnorr scalar s
    // Half-Aggregation fields (when flags bit1=1)
    pub half_agg_r_components: Option<Vec<[u8; 32]>>, // Individual R components
    pub half_agg_s_contributions: Option<Vec<[u8; 32]>>, // Individual s contributions
}

impl CisaEnvelope {
    pub fn parse(data: &[u8]) -> Result<Self, TxScriptError> {
        if data.len() < 4 {
            return Err(TxScriptError::InvalidSignature);
        }
        
        // Check magic bytes "CISA"
        if &data[0..4] != b"CISA" {
            return Err(TxScriptError::InvalidSignature);
        }
        
        // Parse remaining fields...
        // Implementation details for parsing envelope structure
        
        Ok(CisaEnvelope {
            magic: [0x43, 0x49, 0x53, 0x41], // "CISA"
            version: 0x01,
            flags: 0x0001, // SIGHASH_ALL only (bit1=0 for full agg)
            hash_type: 0x01,
            cohort_bitmap: Vec::new(), // Parse from data
            agg_nonce_r: [0u8; 32], // Parse from data
            agg_sig_s: [0u8; 32], // Parse from data
            half_agg_r_components: None, // Parse if flags bit1=1
            half_agg_s_contributions: None, // Parse if flags bit1=1
        })
    }
    
    pub fn validate<T: VerifiableTransaction>(&self, tx: &T) -> Result<(), TxScriptError> {
        // Validate envelope constraints
        if self.version != 1 {
            return Err(TxScriptError::InvalidSignature);
        }
        
        if self.hash_type != 0x01 {
            return Err(TxScriptError::InvalidSignature);
        }
        
        // Check cohort bitmap consistency
        let expected_bitmap_size = (tx.inputs().len() + 7) / 8;
        if self.cohort_bitmap.len() != expected_bitmap_size {
            return Err(TxScriptError::InvalidSignature);
        }
        
        // Validate Half-Aggregation fields if enabled
        let is_half_agg = (self.flags & 0x0002) != 0;
        if is_half_agg {
            if self.half_agg_r_components.is_none() || self.half_agg_s_contributions.is_none() {
                return Err(TxScriptError::InvalidSignature);
            }
            
            let cohort_size = self.cohort_bitmap.iter().map(|b| b.count_ones()).sum::<u32>() as usize;
            if let (Some(r_components), Some(s_contributions)) = (&self.half_agg_r_components, &self.half_agg_s_contributions) {
                if r_components.len() != cohort_size || s_contributions.len() != cohort_size {
                    return Err(TxScriptError::InvalidSignature);
                }
            }
        }
        
        Ok(())
    }
}

CISA Opcodes Implementation

// Add to crypto/txscript/src/opcodes/mod.rs
use tondi_crypto_txscript::{TxScriptEngine, TxScriptError, caches::Cache, SigCacheKey};
use tondi_consensus_core::hashing::sighash::SigHashReusedValues;
use tondi_consensus_core::tx::VerifiableTransaction;
use secp256k1::XOnlyPublicKey;

impl<T: VerifiableTransaction, Reused: SigHashReusedValues> 
    OpCodeExecution<T, Reused> for OpCode<OP_CHECKSIG_CISA> {
    
    fn execute(&self, vm: &mut TxScriptEngine<T, Reused>) -> OpCodeResult {
        // Check if top of stack is TSP-0008 pubkey (0x02||pubkey32)
        let pubkey_data = vm.dstack.pop()?;
        ensure_tsp0008_pubkey(&pubkey_data)?;
        
        // Check if this is an adaptor signature path (non-aggregatable)
        let is_adaptor_path = vm.is_adaptor_signature_path();
        if is_adaptor_path {
            // For adaptor signatures, use regular Schnorr validation
            return vm.execute_regular_schnorr_checksig(&pubkey_data);
        }
        
        // Mark current input as requiring CISA validation
        vm.mark_input_requires_cisa();
        
        // Push true - actual validation happens at transaction level
        vm.dstack.push_bool(true)?;
        Ok(())
    }
}

impl<T: VerifiableTransaction, Reused: SigHashReusedValues> 
    OpCodeExecution<T, Reused> for OpCode<OP_CHECKSIGVERIFY_CISA> {
    
    fn execute(&self, vm: &mut TxScriptEngine<T, Reused>) -> OpCodeResult {
        // Check if top of stack is TSP-0008 pubkey (0x02||pubkey32)
        let pubkey_data = vm.dstack.pop()?;
        ensure_tsp0008_pubkey(&pubkey_data)?;
        
        // Mark current input as requiring CISA validation
        vm.mark_input_requires_cisa();
        
        // Push true and execute VERIFY
        vm.dstack.push_bool(true)?;
        vm.op_verify()?;
        Ok(())
    }
}

fn ensure_tsp0008_pubkey(data: &[u8]) -> Result<XOnlyPublicKey, TxScriptError> {
    if data.len() != 33 || data[0] != 0x02 {
        return Err(TxScriptError::InvalidSignature);
    }
    
    let pubkey_bytes = &data[1..];
    XOnlyPublicKey::from_slice(pubkey_bytes)
        .map_err(|_| TxScriptError::InvalidSignature)
}

CISA Signature Hash Calculation

// consensus/core/src/hashing/cisa_sighash.rs
use tondi_consensus_core::tx::{Transaction, VerifiableTransaction, UtxoEntry};
use tondi_consensus_core::hashing::sighash::{SigHashReusedValues, SigHashReusedValuesUnsync};
use tondi_hashes::{Hash, Hasher, HasherBase, TransactionSigningHash};

#[derive(Debug, Clone)]
pub struct CohortBinding {
    pub amount: u64,
    pub script_pubkey: Vec<u8>,
    pub annex_flag: u8,        // 0=no annex, 1=has annex
    pub annex: Vec<u8>,        // annex data (empty if annex_flag=0)
    pub sequence: u32,         // le32 encoding
    pub codesep_pos: u32,      // le32 encoding (0xFFFFFFFF if no CODESEPARATOR)
    pub tapleaf_hash: [u8; 32], // MUST include leaf_version
}

pub fn calc_cisa_signature_hash<T: VerifiableTransaction>(
    tx: &T,
    cohort_bitmap: &[u8],
    cohort_bindings: &[CohortBinding],
    reused_values: &SigHashReusedValuesUnsync,
) -> Hash {
    // TxBase (same as tapscript SIGHASH_ALL)
    let tx_base = build_txbase_sighash_all(tx, reused_values);
    
    // CohortBindings (per-input binding data)
    let bindings_digest = hash_cohort_bindings(cohort_bindings);
    
    // CohortBitmapDigest (prevents replay attacks)
    let cohort_digest = tag_hash("TSP-0008/Cohort", cohort_bitmap);
    
    // Final message
    tag_hash("TSP-0008/CISASighash", &tx_base, &bindings_digest, &cohort_digest)
}

fn build_txbase_sighash_all<T: VerifiableTransaction>(
    tx: &T, 
    reused_values: &SigHashReusedValuesUnsync
) -> Hash {
    let mut hasher = TransactionSigningHash::new();
    
    // Hash type (0x01 for SIGHASH_ALL) - MUST match BIP-341 exactly
    hasher.write_u8(0x01);
    
    // Transaction version (le32) - MUST match BIP-341 byte order
    hasher.write_u32_le(tx.version());
    
    // Lock time (le32) - MUST match BIP-341 byte order  
    hasher.write_u32_le(tx.lock_time());
    
    // Previous outputs hash - MUST use identical BIP-341 encoding
    let prevouts_hash = reused_values.previous_outputs_hash(|| {
        let mut h = TransactionSigningHash::new();
        for input in tx.inputs() {
            h.update(input.previous_outpoint.transaction_id.as_bytes());
            h.write_u32_le(input.previous_outpoint.index); // le32 encoding
        }
        h.finalize()
    });
    hasher.update(prevouts_hash.as_bytes());
    
    // Sequences hash - MUST use identical BIP-341 encoding
    let sequences_hash = reused_values.sequences_hash(|| {
        let mut h = TransactionSigningHash::new();
        for input in tx.inputs() {
            h.write_u32_le(input.sequence); // le32 encoding
        }
        h.finalize()
    });
    hasher.update(sequences_hash.as_bytes());
    
    // Outputs hash - MUST use identical BIP-341 CompactSize + encoding
    let outputs_hash = reused_values.outputs_hash(|| {
        let mut h = TransactionSigningHash::new();
        for output in tx.outputs() {
            h.write_u64_le(output.value); // le64 encoding
            // CompactSize encoding for script length
            let script_len = output.script_public_key.script.len();
            if script_len < 0xfd {
                h.write_u8(script_len as u8);
            } else if script_len <= 0xffff {
                h.write_u8(0xfd);
                h.write_u16_le(script_len as u16);
            } else {
                h.write_u8(0xfe);
                h.write_u32_le(script_len as u32);
            }
            h.update(&output.script_public_key.script);
        }
        h.finalize()
    });
    hasher.update(outputs_hash.as_bytes());
    
    hasher.finalize()
}

fn hash_cohort_bindings(bindings: &[CohortBinding]) -> Hash {
    let mut hasher = TransactionSigningHash::new();
    for binding in bindings {
        hasher.write_u64_le(binding.amount); // le64 encoding
        // CompactSize encoding for script length
        let script_len = binding.script_pubkey.len();
        if script_len < 0xfd {
            hasher.write_u8(script_len as u8);
        } else if script_len <= 0xffff {
            hasher.write_u8(0xfd);
            hasher.write_u16_le(script_len as u16);
        } else {
            hasher.write_u8(0xfe);
            hasher.write_u32_le(script_len as u32);
        }
        hasher.update(&binding.script_pubkey);
        
        // Annex flag (0=no annex, 1=has annex)
        hasher.write_u8(binding.annex_flag);
        if binding.annex_flag == 1 {
            // MUST match tapscript annex binding exactly
            let annex_len = binding.annex.len();
            if annex_len < 0xfd {
                hasher.write_u8(annex_len as u8);
            } else if annex_len <= 0xffff {
                hasher.write_u8(0xfd);
                hasher.write_u16_le(annex_len as u16);
            } else {
                hasher.write_u8(0xfe);
                hasher.write_u32_le(annex_len as u32);
            }
            hasher.update(&binding.annex);
        }
        
        hasher.write_u32_le(binding.sequence); // le32 encoding
        hasher.write_u32_le(binding.codesep_pos); // le32 encoding (0xFFFFFFFF if none)
        hasher.update(&binding.tapleaf_hash); // 32 bytes
    }
    hasher.finalize()
}

fn compute_tapleaf_hash(script: &[u8], leaf_version: u8) -> [u8; 32] {
    // MUST include leaf_version: H_tag("TapLeaf", leaf_version || CompactSize(script_len) || script)
    let mut hasher = TransactionSigningHash::new();
    
    // TapLeaf tag
    hasher.update(b"TapLeaf");
    
    // Leaf version
    hasher.write_u8(leaf_version);
    
    // CompactSize encoding for script length
    let script_len = script.len();
    if script_len < 0xfd {
        hasher.write_u8(script_len as u8);
    } else if script_len <= 0xffff {
        hasher.write_u8(0xfd);
        hasher.write_u16_le(script_len as u16);
    } else {
        hasher.write_u8(0xfe);
        hasher.write_u32_le(script_len as u32);
    }
    
    // Script content
    hasher.update(script);
    
    hasher.finalize().into()
}

fn tag_hash(tag: &str, data1: &[u8], data2: &[u8], data3: &[u8]) -> Hash {
    let mut hasher = TransactionSigningHash::new();
    hasher.update(tag.as_bytes());
    hasher.update(data1);
    hasher.update(data2);
    hasher.update(data3);
    hasher.finalize()
}

Integration with TxScriptEngine

// Extend crypto/txscript/src/lib.rs
use tondi_crypto_txscript::{TxScriptEngine, TxScriptError, caches::Cache, SigCacheKey};
use tondi_consensus_core::hashing::sighash::SigHashReusedValues;
use tondi_consensus_core::tx::{VerifiableTransaction, UtxoEntry};
use secp256k1::{XOnlyPublicKey, Secp256k1};
use std::collections::HashMap;

// Half-Aggregation cache for mempool optimization
#[derive(Debug, Clone)]
pub struct HalfAggregationCache {
    // Cache s components and R vectors for efficient block-level aggregation
    pub cached_s_components: HashMap<TransactionId, Vec<[u8; 32]>>,
    pub cached_r_vectors: HashMap<TransactionId, Vec<[u8; 32]>>,
    // Track confirmation depth for reorg handling
    pub confirmation_depths: HashMap<TransactionId, u64>,
}

impl<'a, T: VerifiableTransaction, Reused: SigHashReusedValues> 
    TxScriptEngine<'a, T, Reused> {
    
    pub fn validate_cisa_transaction(
        tx: &T,
        utxo_entries: &[UtxoEntry],
        reused_values: &Reused,
        sig_cache: &Cache<SigCacheKey, bool>,
        half_agg_cache: &mut HalfAggregationCache
    ) -> Result<(), TxScriptError> {
        // 1. Parse CISA envelope
        let envelope = Self::extract_cisa_envelope(tx)?;
        
        // 2. Collect pubkeys and bindings for cohort
        let (pubkeys, bindings) = Self::collect_cohort_data(tx, utxo_entries, &envelope)?;
        
        // 3. Compute aggregated pubkey (MuSig2)
        let agg_pubkey = Self::compute_aggregated_pubkey(&pubkeys)?;
        
        // 4. Build signature message
        let message = calc_cisa_signature_hash(
            tx, 
            &envelope.cohort_bitmap, 
            &bindings, 
            reused_values
        );
        
        // 5. Verify aggregated signature (with Half-Agg support)
        Self::verify_aggregated_signature(&envelope, &agg_pubkey, &message, half_agg_cache)?;
        
        Ok(())
    }
    
    fn extract_cisa_envelope<T: VerifiableTransaction>(tx: &T) -> Result<CisaEnvelope, TxScriptError> {
        // Extract CISA envelope from transaction witness data
        // Implementation depends on how envelope is stored in Tondi
        // Could be in payload field or as special witness element
        todo!("Extract CISA envelope from transaction")
    }
    
    fn collect_cohort_data<T: VerifiableTransaction>(
        tx: &T,
        utxo_entries: &[UtxoEntry],
        envelope: &CisaEnvelope
    ) -> Result<(Vec<XOnlyPublicKey>, Vec<CohortBinding>), TxScriptError> {
        let mut pubkeys = Vec::new();
        let mut bindings = Vec::new();
        
        for (idx, byte) in envelope.cohort_bitmap.iter().enumerate() {
            for bit in 0..8 {
                if (byte >> bit) & 1 == 1 {
                    let input_idx = idx * 8 + bit;
                    if input_idx >= tx.inputs().len() {
                        continue;
                    }
                    
                    let (pubkey, binding) = extract_pubkey_and_binding(
                        tx, 
                        input_idx, 
                        &utxo_entries[input_idx]
                    )?;
                    
                    pubkeys.push(pubkey);
                    bindings.push(binding);
                }
            }
        }
        
        Ok((pubkeys, bindings))
    }
    
    fn compute_aggregated_pubkey(pubkeys: &[XOnlyPublicKey]) -> Result<XOnlyPublicKey, TxScriptError> {
        // Implement MuSig2 key aggregation
        // This would integrate with secp256k1-musig2 or implement MuSig2 directly
        todo!("Implement MuSig2 key aggregation")
    }
    
    fn verify_aggregated_signature(
        envelope: &CisaEnvelope,
        agg_pubkey: &XOnlyPublicKey,
        message: &Hash
    ) -> Result<(), TxScriptError> {
        // Implement Schnorr signature verification
        // Using secp256k1 library for verification
        todo!("Implement Schnorr signature verification")
    }
}

13.5 Tondi Client Compatibility Review

โœ… Compatible Components:

  • Transaction Structure: Uses tondi_consensus_core::tx::Transaction with proper field access
  • Script Engine: Integrates with existing TxScriptEngine<T, Reused> architecture
  • Signature Types: Uses secp256k1::XOnlyPublicKey and secp256k1::schnorr::Signature
  • Hash Functions: Leverages tondi_hashes::TransactionSigningHash and existing hashing infrastructure
  • Error Handling: Uses TxScriptError for consistent error propagation
  • Caching: Integrates with existing Cache<SigCacheKey, bool> signature cache
  • UTXO Handling: Works with UtxoEntry and VerifiableTransaction traits
  • Taproot Support: Existing taproot implementation in crypto/txscript/src/standard/taproot/

โš ๏ธ Implementation Considerations:

  • CISA Envelope Storage: Tondi uses signature_script field instead of separate witness structure; CISA envelope should be stored as transaction-level extension in payload field
  • MuSig2 Integration: May need to add secp256k1-musig2 dependency or implement MuSig2 directly
  • OpCode Registration: Need to register new CISA opcodes in Tondi's opcode system (crypto/txscript/src/opcodes/mod.rs)
  • Transaction Structure: Tondi transactions have payload field that could store CISA envelope
  • Script Public Key: Tondi uses ScriptPublicKey with version and script fields
  • Half-Aggregation Cache: Need to integrate with Tondi's mempool system (mining/src/mempool/) for caching s components and R vectors
  • Adaptor Signature Detection: Need to add adaptor signature path detection in script execution
  • Reorg Handling: Need to integrate with Tondi's block processing for confirmation depth tracking

๐Ÿ”ง Required Adaptations:

  1. Transaction Payload: Store CISA envelope in transaction's payload field as witness extension
  2. Script Parsing: Update script parsing to handle TSP-0008 pubkey format (0x02||pubkey32)
  3. Validation Integration: Integrate CISA validation into Tondi's existing transaction validation pipeline
  4. Half-Aggregation Cache: Integrate with mempool system for s/R component caching and reorg handling
  5. Adaptor Signature Support: Add adaptor signature path detection and non-aggregatable flag handling
  6. Testing Framework: Adapt test vectors to Tondi's transaction format and testing infrastructure
  7. OpCode System: Extend Tondi's opcode system to support CISA-specific opcodes via OP_SUCCESSx encoding
  8. Mempool Integration: Add Half-Aggregation caching to mining/src/mempool/ components

13.6 Deployment Timeline

  • Q1 2025: Phase 1 completion, core infrastructure ready
  • Q2 2025: Phase 2 completion, validation engine integration
  • Q3 2025: Phase 3 completion, comprehensive testing and optimization
  • Q4 2025: Testnet deployment and community testing
  • Q1 2026: Mainnet activation preparation

14. Conclusion

TSP-0008 securely implements cross-input Schnorr aggregation as a soft fork within strict tapscript-only, SIGHASH_ALL boundaries:

  • Significantly reduces transaction volume and validation costs;
  • Aligns with Tondi's high-throughput DAG goals;
  • Resists replays and rogue-keys via per-input bindings and MuSig2 coefficients;
  • Advances in parallel with TSP-0007 (v1 bans APO mixing, extensible later).

Implementation Status: The Tondi client has a solid foundation with Schnorr and Taproot support. CISA functionality implementation is estimated to take 12-14 weeks, and it is recommended to proceed through the three phases outlined above.

Tondi-Specific Implementation Notes:

  • Transaction Structure: Tondi uses Transaction with payload field for storing witness extensions
  • Script Engine: Existing TxScriptEngine<T, Reused> architecture supports soft fork opcodes via OP_SUCCESSx
  • Hash Functions: TransactionSigningHash provides consistent hashing across the codebase
  • Caching: Cache<SigCacheKey, bool> provides signature verification caching
  • Taproot Integration: Existing taproot support in crypto/txscript/src/standard/taproot/ can be extended for CISA
  • Wallet Integration: Wallet core architecture supports transaction generation and signing workflows
  • Mempool System: mining/src/mempool/ provides transaction pool management for Half-Aggregation caching
  • Block Processing: Consensus core provides block validation and reorg handling for confirmation depth tracking
  • PSBT Support: Wallet core can be extended with CISA-specific PSBT fields for Half-Aggregation and Adaptor signatures

Appendix A: Size Estimation Comparison (Non-Normative)

A.1 Tondi-Specific Calculations

  • Typical P2TR script-path input: Witness includes 64B signature + various script elements.
  • 8-input transaction:
    • Without CISA: Signature volume โ‰ˆ 8 ร— 64 = 512B (excluding other stack/script);
    • CISA: 64 (s) + 32 (R) + 1 (hash_type) + ceil(8/8)=1 (bitmap) + header โ‰ˆ 120B;
    • Signature-related savings โ‰ˆ ~392B (>75%).

A.2 Blockstream Research Comparison Table

Aggregation Type N=2 N=4 N=8 N=16 N=64 N=256
Half-Agg 15.2% 18.7% 20.6% 21.8% 22.9% 23.4%
Full Agg 19.8% 23.4% 26.1% 27.8% 29.2% 29.8%
Combined 28.1% 31.2% 33.6% 35.1% 36.4% 36.9%
Large Coinjoin 35.2% 38.1% 41.2% 42.8% 44.1% 44.6%

Note: Percentages represent byte savings. Weight unit savings are approximately 1/3 of byte savings.

Appendix B: Common Implementation Pitfalls (Non-Normative)

  • Inconsistent CompactSize and varbytes serialization;
  • Whether annex length prefix enters hash (this proposal explicitly includes it);
  • CODESEPARATOR position evaluation with multi-leaf scripts;
  • MuSig2 coefficient $a_i$ list ordering (must be ascending input index);
  • R normalization (x-only) and BIP-340 challenge domain separation tag consistency.

References

  • BIP-340: Schnorr Signatures for secp256k1
  • MuSig2: Simple Two-Round Schnorr Multi-Signatures
  • TSP-0007: ANYPREVOUT Support for Eltoo-based Payment Channels (Tondi Flash)
  • Kaspa GHOSTDAG/PHANTOM (architectural background, for context only)
  • Blockstream Research: Cross-Input Aggregation Analysis - OP_SUCCESSx risks, Half-Aggregation, Adaptor compatibility, g'root/Entroot deployment paths
  • Blockstream Research: CISA Savings Analysis - Economic benefits comparison across aggregation types

Appendix C: Additional Recommendations (Roadmap/Privacy/Ecosystem)

Multi-Cohort v2

Once introduced, multiple envelopes must include cohort_id in message and isolate key-agg domain separation (e.g., H_tag(".../KeyAggList/c<id>")).

Key-Path CISA

Recommended to introduce in new witness version to avoid entanglement with existing key-path rules.

CISA + APO Joint Specification

Explicitly include APO ignored fields in CohortBindings extension vector; requires separate hash_type negotiation and long-term testnet experimentation.

Wallet UX

In coinjoin mode, enable "fixed-length bitmap policy" + "nonce commitment timeout + blame reorganization" to reduce social engineering space for participant rejection.

Implementation Priority Matrix

  1. Phase 1 (Critical): Consensus-critical fixes, domain separation standardization, basic test vectors
  2. Phase 2 (Security): Rogue-key protection, duplicate key handling, error code standardization
  3. Phase 3 (Ecosystem): PSBT extensions, wallet interoperability, privacy padding options
  4. Phase 4 (Advanced): Multi-cohort support, APO integration, performance optimization