CHIP 2025-05 Native Elliptic Curve Arithmetic Operations

In the case of shielded pools that have confidential amounts specifically, it’s worth noting: Pedersen hiding is information-theoretic, so a future QC replaying old chain data can’t open the commitments themselves. The retroactive leak in the Monero case is the ECDH channel, which is the kind of surface that ML-KEM note delivery or a PQ NIKE-based exchange protects against.

What a QC does break is binding, i.e. forging proofs going forward. That’s where the design matters with a transparent-backed pool (BCH locked visibly into a covenant, confidential notes inside, redeem back out), the covenant is consensus-enforced to not release more than was locked. In Monero a binding break means undetectable counterfeit; here the worst case is bounded theft inside one pool, not supply inflation. And there’s no compact PQ drop-in for Pedersen + Bulletproofs today, lattice replacements are still research; the PQ-sound route that exists in principle is hash-based STARKs proving the same range and balance statements, just heavier, tens of KB vs ~700 bytes for a bulletproof.

Notably, that path needs zero new opcodes, it’s hashing plus field arithmetic, all live on CashVM today (SHA256, BigInt, loops, functions), waiting mainly on the TXv5 limit raise (op-cost budget feasibility still to be measured). Even Monero devs own answer to this concern is a migration timeline (Luke Parker from Monero proposed a 5-year PQ plan), so I see no reason to avoid EC. And to be clear on why the EC ops are needed at all: hiding itself costs nothing, a Pedersen commitment is just bytes the chain could carry blindly. The opcodes are for enforcement, the covenant checking that hidden amounts still obey the rules: the balance check (sum of input commitments equals sum of output commitments) is point addition, and the range-proof verify is scalar mult / one big MSM. Without them the chain can’t hold anyone to the commitments. The ops are cheap, reusing libsecp256k1, and as noted upthread ECMUL costs less than a CHECKSIG, which already does one internally. The STARK path is the later for the same layer, not a reason to withhold the now.

2 Likes

Fair concern. However EC ops enable Pedersen commitments and Bulletproofs which are useful now regardless of the long-term quantum picture. The expressive VM argument cuts both ways here: if the VM can express any verifier in script, then when PQ-friendly proof systems mature, you swap the verifier without a consensus fork. EC ops don’t lock you in, they unlock confidential transactions now while the PQ layer catches

1 Like

If im being honest, it wasn’t BCH specifically that attracted me. I wasn’t explicitly poking around on here.
I built a shielded payroll protocol on Solana, had some non technical issues and stumbled on a friends project and joined his telegram. Then I met someone there who was solving the same amount-hiding problem from a completely different direction on BCH. The Nostr coordination layer and the expressive VM philosophy were things I hadn’t seen approached that way before. Plus The overlap in goals with very different constraints was too interesting to ignore. And very good discussions so far. I’m intrigued.
Thank you guys for having me

4 Likes

We want Bitcoin Cash to be the most inclusive currency, the one most widely used. We don’t just want it to address the issue of transaction volume; we want it to provide privacy and smart contracts, and we need strong promotion.

1 Like

imo we should, because basic EC math (add/mul) already exists and is very mature, minimal tech debt is added as long as the implementation is spec’d well. When q-day comes it’ll just be obsolete… along with the biggest usecase of EC of all, CHECKSIG. Meanwhile we get to enjoy all the neat EC stuff as a bet on the quite plausible scenario of “what if quantum threat fails to materialize”.

The only real downside I can see is its existence may hinder momentum in terms of developing and adopting PQC schemes via competition for mindshare. But I haven’t heard any PQC scheme that even approaches the amount of magic EC enables, so the competition is kinda tangential.

3 Likes

We can overload CHECKSIG with multiple signing schemes, conveniently the pubkey stack element encoding already has a prefix byte we can use as switch.

Yes, good argument. And to steel-man it, it’s not like it would be the first time some opcode becomes obsolete, we will carry OP_SHA1 forever :slight_smile:

We can just have both then. Pat’s CHIP lays out a framework that supports adding multiple schemes later, and SPHINCS+ is the safest bet now, big but reliable, so we can tick the “quantum ready” checkmark, and have a bunker if q-day materializes - and by then other more compact schemes may become available in which case we just add them to CHECKSIG’s registry.

Yeah, the only reliable schemes are hash-based, which are chunky, reliable and boring because they can’t do much but sign/verify. CHECKSIG supports adding multiple, so we might as well just start with the bunker option, and if some magical system later surfaces, add it, too.


For this CHIP, I would prefer it be deployed as a 2-byte opcode, so we can start with a smaller set and expand as needed and avoid taking too much opcode space for something that may have an expiration date.

3 Likes

Here again, nice work on this lightswarm. I build FlowGuard, treasury and payroll streaming live on BCH mainnet, and I want to add a builder’s support for this CHIP. The one wall we keep hitting is that amounts are public, and for payroll that is disqualifying. Nobody wants their salary readable by anyone who knows the contract address.

The design we want is two layers, and they need different things:

  • Hiding who : membership + nullifier proofs over a Merkle set. This already runs on CashVM today (SHA256, BigInt, loops, functions), no new opcodes.

  • Hiding how much : Pedersen commitments plus a Bulletproof range proof. This is the part that needs native EC. ECADD for the balance check (sum of input commitments equals sum of output commitments), ECMUL / one MSM for the range-proof verify. Without those the chain can only carry the commitments blindly, it cannot enforce them.

So from where we sit the minimum that unlocks confidential amounts is OP_ECADD and OP_ECMUL, with OP_MODINV making the bulletproof verifier practical and OP_ECMULTGEN useful for the Schnorr/multisig checks our treasury covenants already do. That lines up with what lightswarm and ABLA laid out above.

On the quantum question raised above: the hiding is information-theoretic, so old commitments do not open retroactively. What a QC threatens is binding, i.e. forging going forward. In a transparent-backed pool (BCH locked visibly into a covenant, confidential notes inside, redeem back out) the covenant is consensus-enforced never to release more than was locked, so a binding break is bounded to theft inside one pool, never supply inflation. And the PQ path is already expressible: swap the Bulletproof verifier for a hash-based STARK proving the same range and balance statements, which needs zero new opcodes. EC ops do not lock us in, they unlock the practical version now.

Concretely: if this activates, FlowGuard will implement confidential payroll amounts on it. Happy to be a test case and to help benchmark the verifier cost against a real covenant.

2 Likes

It just became obvious we need this, thanks for the CHIP!

faster blocks + ECA OP’s in 2027, let’s do it. :slightly_smiling_face:

3 Likes

Strong support for this CHIP from the BCH Cloak (formerly known as confidential transactions) side.

The main lesson from private-note design is that amount privacy is not just hiding values. The hard part is enforcing conservation while values stay hidden.

Pedersen commitments are the natural tool for that: they hide value and support additive balance checks. But for BCH covenants to enforce the balance rule, the VM needs point arithmetic. Otherwise the chain can carry commitments as bytes, but cannot cheaply verify that the hidden amounts obey the rules.

That is why OP_ECADD and OP_ECMUL are important. They are not a hard-coded ZKP system. They are general math primitives. Wallets and dapps can build Bulletproof-style, Sigma-style, STARK-hybrid, or future proof systems in libraries and contracts without asking consensus to ossify one verifier forever.

For BCH Cloak, the direction is:

Pedersen commitments for hidden additive balance
STARK/hash proofs for well-formedness, range, seal binding, and packet binding
BCH UTXO seals for double-spend uniqueness
aggregation for anonymity set

The PQ concern is real, but I do not think it is a reason to avoid EC. The STARK/hash route remains the heavier future/PQ-oriented path. EC ops unlock the practical confidential-amount path now, while still allowing contracts to upgrade proof systems later.

BCH Cloak can help benchmark the real costs: balance checks, range-proof verification, partial STARK checks, TXv5 verifier layouts, and what should stay client-side vs. consensus-enforced.

5 Likes

For bulletproof, the op that matters besides OP_ECADD/OP_ECMUL is the multi-exponentiation or EC MSM

As far as I understand, that “only for very large batch ops, otherwise too complex” note is the bulletproof case. A bulletproof verify is one big multiexp over hundreds of points (~2n + 2log₂n terms for n bits). Do it as ~2n + 2log₂n separate OP_ECMUL calls, which i think would blow the per-input budget. Native OP_ECMULTMULTI is what makes it fit comfortably.

Also, the only spot I can think OP_MODINV applies in bulletproof is the inverses, which are just the ~log₂n challenge inverses. Either hint each and check x·x⁻¹ ≡ 1 mod n (one OP_MUL + OP_MOD, soundness intact, and no scripted inversion), or batch invert with Montgomery (which inverts n values using a single inversion plus 3(n-1) muls, by multiplying them all into one product, inverting that once, then unwinding to recover each).

Either route is one real inversion for the whole proof plus a handful of OP_MUL. The s-vector inverses are free (reversed s), and mod n scalar math is already native bigint (OP_MUL + OP_MOD) since May 2025 upgrade. So OP_MODINV would only save that one inversion, ~5000 ops down to O(1), sitting next to a multiexp of hundreds of OP_ECMUL calls. Not the main bottleneck. However, OP_MODINV may still be worth having, just for other stuff: slope in script-level OP_ECADD/OP_ECDOUBLE, ECDSA s⁻¹ mod n, and Jacobian to affine.

2 Likes

Yep, that distinction is helpful. ECADD/ECMUL are the minimum layer that unlocks the direction, but if the range/proof layer is Bulletproof-style and BCH-enforced, then MSM support is probably what makes it practical. ECMULTMULTI matters because Bulletproof verification checks one large linear combination of many curve points; doing that as many separate ECMUL calls can blow the budget, while native MSM can make the same check efficient.

Just a reminder since this seems to be gaining momentum: It’s now June, so for an 2027 activation a fully specc’d out thing should be published soon, maybe with additional opcodes aside from ecadd/mul, maybe not. There’s also very limited capacity at bchn to code up and test things so perhaps some triage needs to be made between this and other unrelated chips, especially if more opcodes are added that have concerning notes in their risk column.

5 Likes

Happy to work on the code to include the opcode

7 Likes

Code comes later, fully specced CHIP is paramount.

We must first agree what to code. Since we expect scope creep to more than just add/mul I suggest to now introduce a framework for the whole group, behind 1 code-point, e.g.:

  • 0xbc - EC arithmetics prefix, operation byte will follow

so:

  • 0xbc01 = OP_ECADD
  • 0xbc02 = OP_ECMUL
  • 0xbc… = future CHIP may add more as needed, even on other curves
4 Likes

Additionally to the good point from imaginary, any new opcode should have actual real usage.

Which means that not only should the opcode be written into BCHN, there should be some actual scripts using it available that demonstrate the real use-case that you want to sell to the audience.
So to be clear, not a simple example script. It would be the actual zero knowledge script you are aiming to enable with this opcode so the goal of the new opcode is demonstrated in a way that we don’t invest in an upgrade that may never end up being used.

This is the demonstration tom’s asking for in #32; not a toy, the real confidential-payroll verifier. FlowGuard can be the test case: transparent-backed pool, payroll amounts as Pedersen commitments, covenant enforcing sum of input commitments == sum of outputs via OP_ECADD. That balance check is the tractable first piece.

I can build it against a real covenant as soon as there’s a testnet build of the ops. The range proof is the bigger lift: a bulletproof verify is one large multiexp over a few hundred points, so OP_ECMULTMULTI is what keeps it inside the per-input budget instead of hundreds of separate ECMULs (as ABLA and lightswarm worked through in #27). My plan would be to ship it in two stages, balance-check covenant first to prove the enforcement model, then the full bulletproof verifier on top.

Happy to co-build the script side with anyone already deep in the bulletproof internals.

5 Likes

Updated the CHIP to provide more specs details as well as 3 additional opcodes worthy of consideration as an addendum CHIP accompanying this one (ModInv, ECMultMulti and ECMultGen).

4 Likes

I’m unsure if this was discussed yet, so apologies if it was.

Bulletproofs (assuming a standard 64-bit one) require a set of NUMS points. If an unlocking script were to require feeding the public parameters into OP_ECMULTMULTI, it could likely bloat txs by 4kb or more. A viable option would be implementing standardised generator parameters like from libsecp256k1-zkp. (Thereby allowing for an easy fetch of such). Would such be acceptable?

EDIT:

I received some context from an acquaintance about this.

Instead of a hardcoded library (which would definitively restrict expressiveness), what if OP_MULTMULTI accepted byte-arrays?

I mean as in data being passed via three independent flat byte-arrays–the scalar byte-array (permitting the VM to slice 32 bytes repeatedly during the calculations), the unique-point byte-array (contains only unique curve points required by the given ZKP such as public keys and generators), and the dictionary byte-array (maps the scalar byte-array to the unique-point byte-array).

In this sense, there is no reliance on a single STARK family. It would, hopefully, be expressive in this sense.

Sorry if this was typed incoherently, I just had this idea and was worried I’d forget it.

3 Likes

Question about the encodings specified – all specified as fixed-width 32-byte big-endian encodings ← is this standard way to encode scalars and points?

I am asking because I just want to make sure we make the right choice here.

Also this differs from how we store normal script numbers (which are little endian).

I realize these values aren’t normal script numbers, but it just might be surprising to people and/or hopefully won’t make interop with script numbers cumbersome (is such interop ever needed??).

Just asking…

4 Likes

Good question. We’re not treating these as Script numbers at all, so the fact that normal BCH Script integers are little-endian signed-magnitude does not really drive the design here.

For EC operands, the main goal is to have one canonical encoding per value. Fixed-width 32-byte big-endian gives us that directly: length check first, then range check, then curve math. That avoids Script-number edge cases like sign bits, negative zero, alternate minimal encodings, and variable-length parsing. From a consensus-safety point of view, that reduction in ambiguity is a big win.

Big-endian here is mostly a serialization choice for cryptographic operands. It is a very common convention for secp256k1 field elements and coordinates, and it makes the values easier to compare in hex across implementations and test vectors. We’re not saying big-endian is magically better than little-endian in the abstract, just that it gives us a cleaner canonical byte representation for this use case.

If we want to match BCH’s existing numeric conventions, little-endian is a reasonable argument. It would feel more familiar to people who think in Script-number terms, since BCH Script already uses little-endian signed-magnitude integers.

The important caveat is that these EC operands still should not be Script numbers. If we go little-endian, they should still be treated as fixed-width 32-byte unsigned values with canonical encoding, not as variable-length Script integers

For points specifically, we’re also leaning toward explicit affine (x, y) coordinates rather than compressed points. Compressed points would save space, but they would also pull point decompression into consensus, which adds more parsing logic and more failure modes. Keeping the point representation explicit makes the opcode behavior simpler to reason about and easier to audit.

Interop with Script numbers probably should not be needed inside the opcode itself. If some higher-level script or tool wants to derive EC operands from Script-number values, that conversion can happen outside the opcode boundary. For consensus, it seems safer to keep the EC opcodes on a single byte-oriented representation rather than making them understand multiple numeric encodings.

So the choice here is less “big-endian because it’s the standard” and more “fixed-width canonical bytes because that is the safest consensus surface.”

3 Likes