CHIP 2025-05 Native Elliptic Curve Arithmetic Operations

I’d like to introduce a proposal I put together to bring native elliptic curve arithmetic to the Bitcoin Cash VM. Specifically, I’m proposing the addition of OP_ECADD and OP_ECMUL to support elliptic curve point addition and scalar multiplication directly in script.

With native ECADD/ECMUL, BCH smart contracts would gain the ability to natively validate zero-knowledge proofs, enable signature aggregation, and lay the groundwork for scalable privacy and off-chain protocols like Bulletproofs – all without resorting to trusted setups or external proof systems.

While these operations can be approximated via covenants and loops, doing so comes at a massive cost in complexity, size, and execution cost. Native opcodes would make these systems practical and accessible.

This is the initial draft of the CHIP. Feedback is very welcome as we continue refining the proposal.

Looking forward to your feedbacks, questions and thoughts.

https://github.com/lightswarm124/bch-ec-arithmetic

7 Likes

I like this proposal initially.

What I am interested in, as usual, is what would the CPU cost of these operations?

Elliptic curve cryptography is used everywhere now, including SSH, of what I remember the SSH’s version is actually faster and simpler than many other algos that can be used.

But would that be the case here too?

I think I am optimistic, but I wouldn’t want the nodes to be burdened with too heavy math. Maybe some performance numbers/benchmarks could be determined experimentally during the CHIP process so that we know what kind of impact we are dealing with before we make the final decision?

What I am interested in, as usual, is what would the CPU cost of these operations?

I’m hoping to explore this as well and see what kind of vm limits would be appropriate to set for these operations. I’ll assume the multiplication will be more expensive than addition, but will definitely need to see some benchmarking to get a better sense of what range of operational costs will not over burden nodes while still providing the core functionalities.

Love this as a great area of research!

Is there any consideration to do with incoming quantum tech related to this?

1 Like

Not yet. As far as I can tell from what I looked up, this is just having arithmetic operations on the existing secp256k1 curve. If there are issues with secp256k1 with quantum, then this proposal, along with a whole bunch more cryptography we use in blockchain, will be impacted.

On the flipside, this proposal should just use the existing libsecp256k1 libraries that various blockchain projects are already using, so it would just be a matter of implementing the math behind EC arithmetic.

From what I heard from Hunter Beast, the author of BIP-360, Satoshi’s coins and taproot are vulnerable to quantum computing, and that P2PKH is somewhat safe from QC

3 Likes

Sharing some links I found helpful when I was learning about Chainlink VRF a while back:

Ethereum and ZCash both use alt_bc128 or BN-254 curve for zero knoelwdge proofs, with operations like ECADD, ECMUL and pairing checks. For Ethereum, precompiled contracts for elliptic curve operations are required in order to perform zkSNARK verification within the block gas limit.

4 Likes

EC_MUL is cheaper than OP_CHECKSIG or OP_CHECKDATASIG (because CDS uses EC_MUL internally + it does hashing)

EC_ADD is orders of magnitude cheaper

2 Likes

Just on a side note: [Functional] Quantum Computing does not (yet?) exist.

It’s all vaporware and handwaving so far.

It may never exist. Like energy-efficient fusion.

1 Like

Since these operations are already done by checksig/checkdatasig, they seem like relatively low-cost upgrades, and would be useful for a bunch of things outside of zk (say, doing something like EC Multiset but general purpose ). Is there a comparison to alternatives - exactly how costly would it be to do a multiplication and addition with loops?

1 Like

Since we are touching consensus again, it would generally make most sense to collect up multiple of these math operations together and implement them as a single upgrade.

Dividing mutiple small simple changes between multiple upgrades will create chaos and increase implementation cost across the entire ecosystem.

1 Like

In order to emulate EC math, it seems we’ll need to implement every step in the secp256k1 group arithmetic. Roughly, that would equate to:

1. Finite‑Field Arithmetic Primitives - currently missing modular inverse, which might look something like this if we were to roll out our own implementation in Script

// Pseudocode in CashAssembly‑style

// Inputs: a, p (the prime)
// Outputs: inv = a⁻¹ mod p
// Maintains variables (a, b=p, x0=1, x1=0)

<E> OP_TOALTSTACK      // E = p
<A> OP_TOALTSTACK      // A = a

// x0=1, x1=0 on the stack as immediate constants
<1> <0>

// Loop until a == 1 or a == 0
OP_BEGIN
  // if a == 0, fail (no inverse)
  OP_DUP OP_0 OP_EQUALVERIFY  

  // q = b / a
  OP_FROMALTSTACK OP_SWAP   // bring b,a to top
  OP_DUP OP_HASH256 // not needed—just illustrative
  OP_DIV                   // q = b÷a

  // (b, a) ← (a, b mod a)
  OP_SWAP OP_MOD

  // (x0, x1) ← (x1, x0 − q·x1)
  OP_SWAP            // bring x0,x1
  OP_OVER OP_SWAP    // stack: x0,x1|x1,x0
  OP_OVER OP_MUL     // compute q·x1
  OP_SUB             // x0 − q·x1
  OP_SWAP            // new x1,x0

  // Continue looping while a > 1
  OP_DUP OP_1 OP_GREATERTHAN OP_ENDIF // jump back if a>1
OP_UNTIL
// Now x1 holds the inverse; reduce mod p

2. Point Addition for 2 points (x1, y1), (x2, y2)

  • Compute λ=(y2−y1)×inv(x2−x1)mod p\lambda = (y_2 - y_1)\times \text{inv}(x_2 - x_1)\mod pλ=(y2​−y1​)×inv(x2​−x1​)modp.
  • Compute x3=λ2−x1−x2x_3 = \lambda^2 - x_1 - x_2x3​=λ2−x1​−x2​.
  • Compute y3=λ (x1−x3)−y1y_3 = \lambda,(x_1 - x_3) - y_1y3​=λ(x1​−x3​)−y1​.

Each step is multiple multiplies, subs, and an extra inverse.

3. Scalar Multiplication

// binary expansion of k
// result = ∞
// for each bit of k (most to least):
//   result = ECADD(result, result)      // point doubling
//   if bit = 1: result = ECADD(result, P)

4. Curve‑Membership Checking

Before ever doing arithmetic, we must verify input points lie on
y2≡x3+7(modp)y^2 ≡ x^3 + 7 \pmod py2≡x3+7(modp): one OP_MUL , one OP_SUB , one OP_MOD , two OP_DIV

5. Looping & Stack‑Management

We’ll need to juggle at least 8–12 “registers” of big‑ints on the stack, managing the OP_SWAP / OP_TOALTSTACK choreography to keep the right values in place

I think with all these operations, we’ll easily hit the vm limit caps, increase unnecessary complexity and open DoS attack vectors with all these computations.

3 Likes

I’m currently looking for interesting problems to apply albaDsl to — especially where OP_EVAL can be utilized. The problem in this thread just became an obvious candidate.

My demo implementation of Elliptic curve multiplication on secp256k1 implemented in Bitcoin Cash script currently looks to be working. Example output from the REPL:

λ> ev (c (g # ecMul # getX)) 0xAA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598
EE3C2613BF99522

23960696573610029253367988531088137163395307586261939660421638862381187549638

This prints the x-coordinate of G multiplied by 0xAA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598.

This above is one of the test vectors from:
[https://crypto.stackexchange.com/questions/784/are-there-any-secp256k1-ecdsa-test-examples-available]

A multiplication takes a few seconds on the non-optimized albaVm on a laptop. The program itself is not optimized at all. With optimizations and running on BCHN I think this can be made orders of magnitude faster.

To make this work I raised the VM stack/cond-stack limits from 1000/100 to 5000/5000. With optimization, stack requirements could drop.

This example illustrates that it likely is possible to solve this kind of problem using BCH script. We just need to explore how performant it can be made.

Links:

4 Likes

Here are some other math operations that we could consider on top of ECADD and ECMUL.

Opcode Description Benefit (vs. emulation) Cost to Emulate in Script Risk/Complexity Notes & Recommendation
Basic Operations
OP_ECADD Point addition: given two secp256k1 points P, Q on the stack, pushes P+Q. ≈ >1000× faster than doing field operations + curve math in script. ~ 4000+ big‑int ops + looping (~200 K “unit” ops) Moderate: must validate inputs lie on curve, constant‑time implementation. Include: core building block for any EC work.
OP_ECMUL Scalar multiplication: given a point P and scalar k, pushes k·P. ≈ >10 000× faster than repeated doubling/add in script. ~ 100× OP_ECADD via double‑and‑add loop (≈ 400 K “unit” ops) Moderate: enforce 0<k<order, constant‑time ladder. Include: required to do any signature‑style verification or covenant logic.
Highly Useful
OP_MODINV Modular inversion: given nonzero a in 𝔽ₚ, returns a⁻¹ mod p. O(1) native vs. O(n²) exponentiation in script (≈ thousands of ops). ~ 5000+ big‑int ops + loops Must be constant‑time; must detect & reject a=0. Recommend: needed for slope computation in ECADD/ECDOUBLE and other field work.
OP_ECMULTGEN Generator mul: like OP_ECMUL(k, G), but 3× faster using precomputed G tables. ≈ 3× faster than generic ECMUL when one operand is known generator G. ≈ same cost as generic ECMUL in script Same checks as ECMUL; uses fixed-window tables. Strongly recommend if you plan any on‑chain Schnorr or MuSig verification.
Optional
OP_ECDOUBLE Point doubling: given a point P, pushes 2·P. ≈ 30–50% speedup in windowed ECMUL or multi‑add loops vs. two ECADD. N/A (would be 2× OP_ECADD) Same as ECADD. Optional: skip if you have ECMUL, but useful to speed up multi‑scalar routines.
OP_ECNEG Point negation: given P=(x,y), pushes –P=(x,−y). Native constant‑time negate vs. a handful of big‑int ops in script. ~ 20 big‑int ops Negligible. Optional: very cheap to emulate; lowest priority.
High‑Risk / Specialized
OP_DECOMPRESS Point decompress: given 33‑byte compressed P, pushes full 65‑byte (x,y). Saves 32 bytes per output + ~10× faster than script‑level sqrt. Emulate via modular sqrt ≈ O(p^¼) exponentiation → millions of ops Needs constant‑time sqrt, parity check, heavy code. Use with care: big chain‑savings but very tricky and DoS‑sensitive.
OP_ECMULTMULTI Multi‑scalar mult: given [kᵢ, Pᵢ] for i=1…n, pushes ∑kᵢ·Pᵢ sub‑linearly in n. Sub‑linear speedup vs. doing n separate ECMULs in script. ≥ n× generic ECMUL (linear) Must cap n, fixed-window, careful memory use. Only for very large batch ops (e.g. MuSig with many keys); otherwise too complex.
OP_PAIRING_CHECK BN‑pairing: verify pairing equation e(P, Q)… for SNARKs/BLS.* On‑chain SNARK/BLS proof with a single op vs. infeasible in script. Impossible in script Massive code size, DoS risk, consensus complexity. Not recommended—far too heavy & risky for BCH today.

For right now, it might be worth considering adding MODINV and ECMULTIGEN as these seem fairly useful without having cheap substitutes while still keeping to relatively safe computation. There are some like the one for on-chain SNARK/BLS proof, but I don’t think they are really needed for the near-term future until the tech gets a bit more mature

2 Likes