Stellar Atlas
Protocol
CAP-0080

Host functions for efficient ZK BN254 use cases

FinalGitHub

Specification

Preamble

CAP: 0080
Title: Host functions for efficient ZK BN254 use cases
Working Group:
    Owner: Siddharth Suresh <@sisuresh>
    Authors: Jay Geng <@jayz22>, Siddharth Suresh <@sisuresh>
    Consulted: Tomer Weller <@tomerweller>
Status: Final
Created: 2026-01-21
Discussion: https://github.com/orgs/stellar/discussions/1826
Protocol version: 26

Simple Summary

This CAP adds host functions for BN254 MSM, BN254 modular arithmetic, and curve membership checks for BLS12-381 and BN254.

Working Group

As described in the preamble section.

Motivation

Stellar has host support for the BN254 functions available on the EVM (G1 Add, G1 Mul, and Pairing), but there are use cases that require additional functionality.

Contracts need modular arithmetic operations on scalar field elements (Fr) and cannot afford to implement these on the guest side. Adding host functions for add, sub, mul, pow, and inv enables these use cases.

For use cases that require many G1 additions and scalar multiplications, the cost of repeatedly converting points and scalars between their external encoding and the internal representation can be expensive. Each call to bn254_g1_add or bn254_g1_mul requires this conversion. With MSM, the conversion happens only once at the beginning, all intermediate operations occur in internal form, and only the final result is converted back. This significantly reduces the overall cost.

Some ZK applications need to verify that a point lies on the curve to validate user input. Adding is_on_curve functions for BLS12-381 G1, BLS12-381 G2, and BN254 G1 provides a cheaper way to do this.

Goals Alignment

This CAP is aligned with the following Stellar Network Goals:

  • The Stellar Network should run at scale and at low cost to all participants of the network.

Abstract

Nine new host functions are proposed here.

Specification

New host functions

{
    "export": "r",
    "name": "bn254_g1_msm",
    "args": [
        { "name": "vp", "type": "VecObject" },
        { "name": "vs", "type": "VecObject" }
    ],
    "return": "BytesObject",
    "docs": "Performs multi-scalar-multiplication (inner product) on a vector of BN254 G1 points (`Vec<BytesObject>`) by a vector of scalars (`Vec<U256Val>`), and returns the resulting G1 point in 64-byte uncompressed format.",
    "min_supported_protocol": 26
},
{
    "export": "s",
    "name": "bn254_fr_add",
    "args": [
        { "name": "lhs", "type": "U256Val" },
        { "name": "rhs", "type": "U256Val" }
    ],
    "return": "U256Val",
    "docs": "Performs addition `(lhs + rhs) mod r` between two BN254 scalar elements (Fr), where r is the subgroup order",
    "min_supported_protocol": 26
},
{
    "export": "t",
    "name": "bn254_fr_sub",
    "args": [
        { "name": "lhs", "type": "U256Val" },
        { "name": "rhs", "type": "U256Val" }
    ],
    "return": "U256Val",
    "docs": "Performs subtraction `(lhs - rhs) mod r` between two BN254 scalar elements (Fr), where r is the subgroup order",
    "min_supported_protocol": 26
},
{
    "export": "u",
    "name": "bn254_fr_mul",
    "args": [
        { "name": "lhs", "type": "U256Val" },
        { "name": "rhs", "type": "U256Val" }
    ],
    "return": "U256Val",
    "docs": "Performs multiplication `(lhs * rhs) mod r` between two BN254 scalar elements (Fr), where r is the subgroup order",
    "min_supported_protocol": 26
},
{
    "export": "v",
    "name": "bn254_fr_pow",
    "args": [
        { "name": "lhs", "type": "U256Val" },
        { "name": "rhs", "type": "U64Val" }
    ],
    "return": "U256Val",
    "docs": "Performs exponentiation of a BN254 scalar element (Fr) with a u64 exponent i.e. `lhs.exp(rhs) mod r`, where r is the subgroup order",
    "min_supported_protocol": 26
},
{
    "export": "w",
    "name": "bn254_fr_inv",
    "args": [
        { "name": "lhs", "type": "U256Val" }
    ],
    "return": "U256Val",
    "docs": "Performs inversion of a BN254 scalar element (Fr) modulo r (the subgroup order)",
    "min_supported_protocol": 26
},
{
    "export": "x",
    "name": "bls12_381_g1_is_on_curve",
    "args": [
        { "name": "point", "type": "BytesObject" }
    ],
    "return": "Bool",
    "docs": "Checks if a BLS12-381 G1 point is on the curve (does not check subgroup membership). Returns true if the point is on the curve, false otherwise.",
    "min_supported_protocol": 26
},
{
    "export": "y",
    "name": "bls12_381_g2_is_on_curve",
    "args": [
        { "name": "point", "type": "BytesObject" }
    ],
    "return": "Bool",
    "docs": "Checks if a BLS12-381 G2 point is on the curve (does not check subgroup membership). Returns true if the point is on the curve, false otherwise.",
    "min_supported_protocol": 26
},
{
    "export": "z",
    "name": "bn254_g1_is_on_curve",
    "args": [
        { "name": "point", "type": "BytesObject" }
    ],
    "return": "Bool",
    "docs": "Checks if a BN254 G1 point is on the curve. Returns true if the point is on the curve, false otherwise.",
    "min_supported_protocol": 26
},

XDR changes

diff --git a/Stellar-contract-config-setting.x b/Stellar-contract-config-setting.x
index 9a95937da..f1b8a3a78 100644
--- a/Stellar-contract-config-setting.x
+++ b/Stellar-contract-config-setting.x
@@ -291,7 +291,9 @@ enum ContractCostType {
     // Cost of performing BN254 scalar element exponentiation
     Bn254FrPow = 83,
      // Cost of performing BN254 scalar element inversion
-    Bn254FrInv = 84
+    Bn254FrInv = 84,
+    // Cost of performing BN254 G1 multi-scalar multiplication (MSM)
+    Bn254G1Msm = 85
 };
 
 struct ContractCostParamEntry {

Semantics

Field and groups

See CAP-0074 for definitions of the BN254 fields and groups. See CAP-0059 for definitions of the BLS12-381 fields and groups.

New host functions introduced

bls12_381_g1_is_on_curve

Description: checks if a BLS12-381 G1 point is on the curve (does not check subgroup membership).

Cost: includes decoding of the G1 point (Bls12381DecodeFp) and the on curve check (Bls12381G1CheckPointOnCurve).

Error condition: if the input BytesObject does not decode into a valid point:

  • Bytes length is not equal to 96
  • The compression flag (the most significant bit) is set.
  • The infinity flag (the second most significant bit) is set, but the remaining bits are not all zero.
  • The sort flag (the third most significant bit) is set.

Return value: returns true if the point is on the curve, false otherwise.

bls12_381_g2_is_on_curve

Description: checks if a BLS12-381 G2 point is on the curve (does not check subgroup membership).

Cost: includes decoding of the G2 point (Bls12381DecodeFp) and the on curve check (Bls12381G2CheckPointOnCurve).

Error condition: if the input BytesObject does not decode into a valid point:

  • Bytes length is not equal to 192
  • The compression flag (the most significant bit) is set.
  • The infinity flag (the second most significant bit) is set, but the remaining bits are not all zero.
  • The sort flag (the third most significant bit) is set.

Return value: returns true if the point is on the curve, false otherwise.

bn254_g1_is_on_curve

Description: checks if a BN254 G1 point is on the curve.

Cost: includes decoding of the G1 point (Bn254DecodeFp) and the on curve check (Bn254G1CheckPointOnCurve).

Error condition: if the input BytesObject does not decode into a valid point:

  • Bytes length is not equal to 64
  • The point is compressed

Return value: returns true if the point is on the curve, false otherwise.

bn254_g1_msm

Description: perform multi-scalar-multiplication (MSM) in G1.

Cost: includes decoding of the G1 vector (Bn254DecodeFp), converting fr from U256 (Bn254FrFromU256), the MSM operation Bn254G1Msm, converting the point from projective to affine (Bn254G1ProjectiveToAffine), and encoding of the resulting G1 point (Bn254EncodeFp).

Error condition:

  1. if the two vectors have different lengths
  2. if the length of either vector is zero
  3. if any point in the G1 points vector does not decode into a valid G1 point or does not conform to the specified encoding standard:
  • Bytes length is not equal to 64
  • The point is compressed
  • The input point does not belong on the G1 curve
bn254_fr_add

Description: performs addition (lhs + rhs) mod r between two BN254 scalar elements (Fr).

Cost: conversion of fr from U256 (Bn254FrFromU256), scalar addition Bn254FrAddSub, and conversion back to U256 (Bn254FrToU256).

Error condition: None

bn254_fr_sub

Description: performs subtraction (lhs - rhs) mod r between two BN254 scalar elements (Fr).

Cost: conversion of fr from U256 (Bn254FrFromU256), scalar subtraction Bn254FrAddSub, and conversion back to U256 (Bn254FrToU256).

Error condition: None

bn254_fr_mul

Description: performs multiplication (lhs * rhs) mod r between two BN254 scalar elements (Fr).

Cost: conversion of fr from U256 (Bn254FrFromU256), scalar multiplication Bn254FrMul, and conversion back to U256 (Bn254FrToU256).

Error condition: None

bn254_fr_pow

Description: performs exponentiation lhs.exp(rhs) mod r between a BN254 scalar element (Fr) and a u64 exponent.

Cost: conversion of fr from U256 (Bn254FrFromU256), scalar exponentiation Bn254FrPow, and conversion back to U256 (Bn254FrToU256).

Error condition: None

bn254_fr_inv

Description: performs inversion of a BN254 scalar element (Fr).

Cost: conversion of fr from U256 (Bn254FrFromU256), scalar inversion Bn254FrInv, and conversion back to U256 (Bn254FrToU256).

Error condition: if the provided input fr is zero.

New metering CostType introduced

  • Bn254G1Msm - Cost of performing BN254 G1 multi-scalar multiplication (MSM). Type: linear w.r.t the length of the input vectors.

Design Rationale

Adding BN254 specific host functions instead of more general ones.

The BN254 specific modular arithmetic functions (add, sub, mul, pow, inv) were chosen because they map directly to operations provided by the Arkworks library, which is used in the host implementation. This direct mapping simplifies metering since each host function corresponds to a well-defined Arkworks operation with predictable performance characteristics.

The alternative would be to add host functions that take the modulus as an input, but the metering and implementation would be more complex. We also already have BLS12-381 specific arithmetic functions, so the BN254 ones bring the two closer to feature parity.

If we think the general functions will be helpful in the future, we can add those in later.

Protocol Upgrade Transition

The proposed host functions will become available in protocol 26.

Backwards Incompatibilities

This CAP does not introduce any backward incompatibilities.

Resource Utilization

The only new cost type is for BN254 G1 MSM, which we will calibrate. The is_on_curve functions reuse existing cost types.

Security Concerns

  • Proper metering to avoid a Denial of Service.

Test Cases

TODO

Implementation

TODO

Preamble

Status
Final
Protocol version
26
Authors
Siddharth Suresh
Created
2026-01-21

Discussion

0 linked threads