Appendix C: Cost Table

PRE-ALPHA WARNING: This is a pre-alpha version of The Sigma Book. Content may be incomplete, inaccurate, or subject to change. Do not use as a source of truth. For authoritative information, consult the official repositories:

Complete reference for operation costs in the JIT cost model12.

Cost Model Architecture

Cost Model Structure
══════════════════════════════════════════════════════════════════

┌────────────────────────────────────────────────────────────────┐
│                       CostKind                                  │
├─────────────┬─────────────┬─────────────┬─────────────────────┤
│  FixedCost  │PerItemCost  │TypeBasedCost│   DynamicCost       │
│             │             │             │                      │
│  cost: u32  │ base: u32   │ costFunc()  │ sum of sub-costs    │
│             │ per_chunk   │ per type    │                      │
│             │ chunk_size  │             │                      │
└─────────────┴─────────────┴─────────────┴─────────────────────┘

Cost Calculation Flow:
─────────────────────────────────────────────────────────────────
                 ┌─────────────┐
                 │  Operation  │
                 └──────┬──────┘
                        │
         ┌──────────────┼──────────────┐
         ▼              ▼              ▼
    ┌─────────┐   ┌──────────┐   ┌─────────┐
    │ FixedOp │   │PerItemOp │   │TypedOp  │
    │ cost=26 │   │base=20   │   │depends  │
    └────┬────┘   │chunk=10  │   │on type  │
         │        └────┬─────┘   └────┬────┘
         │             │              │
         └─────────────┼──────────────┘
                       ▼
              ┌────────────────┐
              │CostAccumulator │
              │ accum += cost  │
              │ check < limit  │
              └────────────────┘

Zig Cost Types

const JitCost = struct {
    value: u32,

    pub fn add(self: JitCost, other: JitCost) !JitCost {
        return .{ .value = try std.math.add(u32, self.value, other.value) };
    }
};

const CostKind = union(enum) {
    fixed: FixedCost,
    per_item: PerItemCost,
    type_based: TypeBasedCost,
    dynamic,

    pub fn compute(self: CostKind, ctx: CostContext) JitCost {
        return switch (self) {
            .fixed => |f| f.cost,
            .per_item => |p| p.compute(ctx.n_items),
            .type_based => |t| t.costFunc(ctx.tpe),
            .dynamic => ctx.computed_cost,
        };
    }
};

/// Fixed cost regardless of input
const FixedCost = struct {
    cost: JitCost,
};

/// Cost proportional to collection size
const PerItemCost = struct {
    base: JitCost,
    per_chunk: JitCost,
    chunk_size: usize,

    /// totalCost = base + per_chunk * ceil(n_items / chunk_size)
    pub fn compute(self: PerItemCost, n_items: usize) JitCost {
        const chunks = (n_items + self.chunk_size - 1) / self.chunk_size;
        return .{
            .value = self.base.value + @as(u32, @intCast(chunks)) * self.per_chunk.value,
        };
    }
};

/// Cost depends on type
const TypeBasedCost = struct {
    primitive_cost: JitCost,
    bigint_cost: JitCost,
    collection_cost: ?PerItemCost,

    pub fn costFunc(self: TypeBasedCost, tpe: SType) JitCost {
        return switch (tpe) {
            .byte, .short, .int, .long => self.primitive_cost,
            .big_int, .unsigned_big_int => self.bigint_cost,
            .coll => |elem| if (self.collection_cost) |c|
                c.compute(elem.len)
            else
                self.primitive_cost,
            else => self.primitive_cost,
        };
    }
};

Cost Accumulator

const CostAccumulator = struct {
    accum: u64,
    limit: u64,

    pub fn init(limit: u64) CostAccumulator {
        return .{ .accum = 0, .limit = limit };
    }

    pub fn add(self: *CostAccumulator, cost: JitCost) !void {
        self.accum += cost.value;
        if (self.accum > self.limit) {
            return error.CostLimitExceeded;
        }
    }

    pub fn addSeq(
        self: *CostAccumulator,
        cost: PerItemCost,
        n_items: usize,
    ) !void {
        try self.add(cost.compute(n_items));
    }

    pub fn totalCost(self: *const CostAccumulator) JitCost {
        return .{ .value = @intCast(self.accum) };
    }
};

Fixed Cost Operations

OperationCostDescription
ConstantPlaceholder1Reference segregated constant
Height1Current block height
Inputs1Transaction inputs
Outputs1Transaction outputs
LastBlockUtxoRootHash1UTXO root hash
Self1Self box
MinerPubkey1Miner public key
ValUse5Use defined value
TaggedVariable5Context variable
SomeValue5Option Some
NoneValue5Option None
SelectField8Select tuple field
CreateProveDlog10Create DLog
OptionGetOrElse10Option.getOrElse
OptionIsDefined10Option.isDefined
OptionGet10Option.get
ExtractAmount10Box value
ExtractScriptBytes10Proposition bytes
ExtractId10Box ID
Tuple10Create tuple
Select1-512Select tuple element
ByIndex14Collection access
BoolToSigmaProp15Bool → SigmaProp
DeserializeContext15Deserialize context
DeserializeRegister15Deserialize register
ByteArrayToLong16Bytes → Long
LongToByteArray17Long → bytes
CreateProveDHTuple20Create DHT
If20Conditional
LogicalNot20Boolean NOT
Negation20Numeric negation
ArithOp26Plus, Minus, etc.
ByteArrayToBigInt30Bytes → BigInt
SubstConstants30Substitute constants
SizeOf30Collection size
MultiplyGroup40EC point multiply
ExtractRegisterAs50Register access
Exponentiate300BigInt exponent
DecodePoint900Decode EC point

Per-Item Cost Operations

OperationBasePer ChunkChunk Size
CalcBlake2b256207128
CalcSha25620864
MapCollection20110
Exists20510
ForAll20510
Fold20110
Filter20510
FlatMap20510
Slice102100
Append202100
SigmaAnd1021
SigmaOr1021
AND (logical)10532
OR (logical)10532
XorOf20532
AtLeast2031
Xor (bytes)102128

Type-Based Costs

Numeric Casting

Target TypeCost
Byte, Short, Int, Long10
BigInt30
UnsignedBigInt30

Comparison Operations

TypeCost
Primitives10-20
BigInt30
CollectionsPerItemCost
TuplesSum of components

Interpreter Overhead

Cost TypeValueDescription
interpreterInitCost10,000Interpreter init
inputCost2,000Per input
dataInputCost100Per data input
outputCost100Per output
tokenAccessCost100Per token

Cost Limits

ParameterValueDescription
maxBlockCost1,000,000Max per block
scriptCostLimit~8,000,000Single script

Zig Cost Constants

const OperationCosts = struct {
    // Context access (very cheap)
    pub const HEIGHT: FixedCost = .{ .cost = .{ .value = 1 } };
    pub const INPUTS: FixedCost = .{ .cost = .{ .value = 1 } };
    pub const OUTPUTS: FixedCost = .{ .cost = .{ .value = 1 } };
    pub const SELF: FixedCost = .{ .cost = .{ .value = 1 } };

    // Variable access
    pub const VAL_USE: FixedCost = .{ .cost = .{ .value = 5 } };
    pub const CONSTANT_PLACEHOLDER: FixedCost = .{ .cost = .{ .value = 1 } };

    // Arithmetic
    pub const ARITH_OP: FixedCost = .{ .cost = .{ .value = 26 } };
    pub const COMPARISON: FixedCost = .{ .cost = .{ .value = 20 } };

    // Box extraction
    pub const EXTRACT_AMOUNT: FixedCost = .{ .cost = .{ .value = 10 } };
    pub const EXTRACT_REGISTER: FixedCost = .{ .cost = .{ .value = 50 } };

    // Cryptographic
    pub const PROVE_DLOG: FixedCost = .{ .cost = .{ .value = 10 } };
    pub const PROVE_DHT: FixedCost = .{ .cost = .{ .value = 20 } };
    pub const DECODE_POINT: FixedCost = .{ .cost = .{ .value = 900 } };
    pub const MULTIPLY_GROUP: FixedCost = .{ .cost = .{ .value = 40 } };
    pub const EXPONENTIATE: FixedCost = .{ .cost = .{ .value = 300 } };

    // Hashing
    pub const BLAKE2B256: PerItemCost = .{
        .base = .{ .value = 20 },
        .per_chunk = .{ .value = 7 },
        .chunk_size = 128,
    };
    pub const SHA256: PerItemCost = .{
        .base = .{ .value = 20 },
        .per_chunk = .{ .value = 8 },
        .chunk_size = 64,
    };

    // Collection operations
    pub const MAP: PerItemCost = .{
        .base = .{ .value = 20 },
        .per_chunk = .{ .value = 1 },
        .chunk_size = 10,
    };
    pub const FILTER: PerItemCost = .{
        .base = .{ .value = 20 },
        .per_chunk = .{ .value = 5 },
        .chunk_size = 10,
    };
    pub const FOLD: PerItemCost = .{
        .base = .{ .value = 20 },
        .per_chunk = .{ .value = 1 },
        .chunk_size = 10,
    };

    // Sigma operations
    pub const SIGMA_AND: PerItemCost = .{
        .base = .{ .value = 10 },
        .per_chunk = .{ .value = 2 },
        .chunk_size = 1,
    };
    pub const SIGMA_OR: PerItemCost = .{
        .base = .{ .value = 10 },
        .per_chunk = .{ .value = 2 },
        .chunk_size = 1,
    };
};

const InterpreterCosts = struct {
    pub const INIT: u32 = 10_000;
    pub const PER_INPUT: u32 = 2_000;
    pub const PER_DATA_INPUT: u32 = 100;
    pub const PER_OUTPUT: u32 = 100;
    pub const PER_TOKEN: u32 = 100;
};

const CostLimits = struct {
    pub const MAX_BLOCK_COST: u64 = 1_000_000;
    pub const MAX_SCRIPT_COST: u64 = 8_000_000;
};

Cost Calculation Example

/// Calculate total cost for transaction verification
fn calculateTxCost(
    n_inputs: usize,
    n_data_inputs: usize,
    n_outputs: usize,
    script_costs: []const JitCost,
) u64 {
    var total: u64 = InterpreterCosts.INIT;

    total += @as(u64, n_inputs) * InterpreterCosts.PER_INPUT;
    total += @as(u64, n_data_inputs) * InterpreterCosts.PER_DATA_INPUT;
    total += @as(u64, n_outputs) * InterpreterCosts.PER_OUTPUT;

    for (script_costs) |cost| {
        total += cost.value;
    }

    return total;
}

// Example: 2 inputs, 1 data input, 3 outputs
// Base: 10,000 + 4,000 + 100 + 300 = 14,400
// Plus script costs per input

Previous: Appendix B | Next: Appendix D

1

Scala: CostKind.scala