Title: RIP_7696___generic_Double_Scalar_Multiplication__D
Category: RIPs

Author: rdubois-crypto
Date: 2024-04-25T08:05:54.157Z

This proposal creates two precompiled contracts that perform a double point multiplication (DSM) and sum then over any elliptic curve  given p, a,b curve parameters.
This operation consists in computing the value uP+vQ, u and v being scalars, P and Q being points.
We managed to implement generic DSM in full solidity with a lower cost than previous implementations (FCL, Daimo, p256-verifier-huff). Such genericity will enable curves such as Ed25519 and Babyjujub (with the use of isogeny we will describe later), Palla,Vesta, Starkcurve, etc.
The proposal includes two precompiles, taking curves parameters as calldata.
The first one is very comparable to RIP7212 and EIP6565, only taking those extra p,a,b parameters.
The second them uses extra values (namely 2^128.P and 2^128Q), to provide a GLV comparable speedup, which is 50% asymptotically (less in full solidity, but ZK version will benefit largely from it).
As of now there is a huge traction on P256, being the first FIDO curve implemented in WebAuthn. Ed25519 shall follow, and is superior in all ways (Schnorr based, no hidden seed constant,MPC friendly).
This precompile also solve the ‘hacky’ use of ecrecover (as implemented for Schnorr based Dapps, such as Ambire Wallet, and secure MPC uses relying on Musig2). This cunning use of ecrecover in fact enables DSM.
Implementing DSM at lower levels (for ZKEVM or nodes) only requires to implement Montgomery multiplications to emulate prime fields. (It is how it is done by Lambda for ZKsync right now). This is how are implemented most generic libraries (OpenSSL, libECC, Bolos, etc.).
https://github.com/ethereum/RIPs/pull/18/files#diff-1991105bd164aa9e87619fa8426d5978f420c7033b30393f07a3b7afd09df7f3

Author: jdetychey
Date: 2024-04-25T21:31:20.529Z

insert youtube video “Shia LaBeouf “Just Do It” Motivational Speech”
Thanks for this RIP that will also benefit EVM L2 not sequencing on the Ethereum mainnet.

Author: nlordell
Date: 2024-04-26T06:03:28.876Z

Personally, I would be super happy to see Ed25519 and EdDSA in general over ECDSA. However, AFAIU it uses SHA-512 as the hashing function, for which there is no precompile at the moment, making it not so useful (which is a shame IMO).
Also, as far as I understand, Ed25519 is a twisted Edwards curve, while this precompile implements uP + vQ given scalars u and v and points P and Q for Weierstrass curves with coefficients a and b. Correct me if I’m wrong (this is not my area of expertise), but I think you can map twisted Edwards curves to and from Weierstrass form, allowing this precompile to be used for efficient EdDSA signature verification, but it would be nice to spell out how this is done somewhere (for less cryptographically savvy engineers like myself).

Author: rdubois-crypto
Date: 2024-04-26T07:23:51.690Z

You are totally right, it is very cheap to reuse Weierstrass formulae to implement Ed25519 (only a few multiplication/inversion),  the name of the isogeneous curve is Wei25519, here is the solidity code:
function Edwards2WeierStrass(uint256 x,uint256 y)  view returns (uint256 X, uint256 Y){
//wx = ((1 + ey) * (1 - ey)^-1) + delta
X=addmod(delta, mulmod(addmod(1,y,p),pModInv(addmod(1, p-y,p)),p) ,p);
//  wy = (c * (1 + ey)) * ((1 - ey) * ex)^-1
Y=mulmod(mulmod(c, addmod(1, y, p),p),        pModInv(mulmod(addmod(1, p-y,p), x,p)),p);
}
Concerning SHA512 you are right for L1 where gas is cheap for SHA256 (but that should change as gas cost on L1 shall reflect more the ZK cost in the future). But for a L2, implementing SHA512 circuit is a similar cost to SHA256.
There are also equivalent version of EDdsa, over babyjujub, which uses Poseidon instead (Circom framework), sometimes ZK is not necessary everywhere and using ZK verifier for a simple Eddsa verification is “crushing a fly with a Hammer”.
The concern is also over MPC versions. ECDSA is crippled with vulnerabilities, while Musig2, used for Taproot BTC gives better security proofs. DSM enables MPC signatures.
The thing is also “why choose now ?” option, using 7696 instead of limiting to a single curve through 6565 or 7212 provides maximum degree of freedom.

Author: nlordell
Date: 2024-04-26T09:06:55.901Z

You are totally right, it is very cheap to reuse Weierstrass formulae to implement Ed25519 (only a few multiplication/inversion), the name of the isogeneous curve is Wei25519, here is the solidity code:

Ok, so if I understand correctly, this code maps Ed25519 curve points to a point on the Wei25519 Weierstrass curve. Given the signature verification equation [s]B = R + [k]A (B is base/generator point, s and R are signature components, A is the public key), you would implement this by mapping B, R, and A to Wei25519 and using ecmulmuladd to verify the equality holds?

An additional point, I noticed that the EIP assumes ECs over prime fields where p fits into 256-bit integers. I wonder if it makes sense to consider a mechanism like the EXPMOD precompile where additional widths for the values in Fp are included in the parameters. This would allow supporting ecmulmuladd for curves over larger prime fields like P-384. To elaborate on this a bit, the input data would look like:

Input data: 64 + 7n + 2l bytes of data including:

32 bytes of the size n in bytes required to represent elements of the prime field over which the elliptic curve is defined
32 bytes of the size l in bytes required to represent the curve order
n bytes of the modulus p modulus of the prime field of the curve
n bytes of the a first coefficient of the curve
n bytes of the b second coefficient of the curve
n bytes of the Px x coordinate of the first point
n bytes of the Py y coordinate of the first point
n bytes of the Qx x coordinate of the first point
n bytes of the Qy y coordinate of the first point
l bytes of the u first scalar to multiply with P
l bytes of the v second scalar to multiply with Q



We can probably conflate n and l use a single “size” for all values, since they tend to have a similar order of magnitude in most cases and max(n, l) will always suffice.

Author: rdubois-crypto
Date: 2024-04-26T12:55:48.882Z

The thing is that the implication to handle 384 bits curve has a lot of implication at ZK level. Handling variable length is more complex in term of code coverage, audits and potential vulnerabilities.
It implies to handle multiprecision integers (EVM is a 256 bit machine). It seems less probable to be accepted any time soon, as MSM which has been proposed for long now. There is a cursor to place between a fully configurable MSM (not limited to double, but any number of points) over any curve, and very specific (limited to one curve) precompile.
MSM is superior, but too complex. Specific curves precompiles are too limited. Optimized DSM is only 100 lines of solidity code. Actually it is very close to the specific one (mainly handling constant into calldata, and more efforts to handle the stack without via IR which crush performances).
Actually the provided code will be used as a temporary solution by some L2s before implementing it at circuit level.

Author: rdubois-crypto
Date: 2024-04-26T14:27:03.754Z

I forgot to answer the Ed25519 part. Yes I did it. I reproduced the RFC8032 vectors for short length, ECC is OK, but I still work on the SHA512 part.

Author: nlordell
Date: 2024-04-30T15:04:50.990Z

rdubois-crypto:

Handling variable length is more complex in term of code coverage, audits and potential vulnerabilities.
It implies to handle multiprecision integers


I agree it is at first glance more complex, however, I just figured that since expmod precompile already requires arbitrary precision integer math, that it would not be a stretch to add it for mulmuladd. I would argue that the implementation difference between implementing this precompile for 256 bit integers vs. arbitrary precision integers is not that crazy, and mostly boil down to figuring out an appropriate gas schedule that is in function of the integer width, like expmod does.



 rdubois-crypto:

It seems less probable to be accepted any time soon, as MSM which has been proposed for long now. There is a cursor to place between a fully configurable MSM (not limited to double, but any number of points) over any curve, and very specific (limited to one curve) precompile.


For sure. I also would generally assume that use cases for curves over prime fields where log2(p) > 256 is not so widespread, and as you mentioned would eliminate the possibility of providing a Solidity fallback.
I do think it might be worth documenting this rationale in the RIP itself.

Author: nlordell
Date: 2024-05-02T08:22:49.155Z

Another significant advantage over 7212 IMO is that this would also allow ECDSA recovery to be implemented efficiently for curves like P-256.

Author: mratsim
Date: 2024-05-10T06:12:31.193Z

nlordell:

I would argue that the implementation difference between implementing this precompile for 256 bit integers vs. arbitrary precision integers is not that crazy, and mostly boil down to figuring out an appropriate gas schedule that is in function of the integer width, like expmod does.


I didn’t check how good modexp gas schedule is, but one artifact is that implementations for odd moduli is wildly different from implementation for even moduli. And below a certain size, moving to Montgomery domain for Montgomery multiplication exposes you to denial-of-service.
That said, it’s “just” a matter of implementing and measuring the gas cost, one can do that in Constantine: EIP-2537 (BLS12 precompile) discussion thread - #77 by mratsim and even get detailed metering on internal calls, for example: constantine/metering/eip2537.md at master · mratsim/constantine · GitHub

Author: rdubois-crypto
Date: 2024-06-04T14:32:46.450Z

Hi, just some news here.
We added ed25519 computation using the 4MSM described in RIP7696.
It is run over all the rfc8032 vectors here:


github.com


get-smooth/crypto-lib/blob/7cef31dd0cb36b9a814866085463d8e758a0d1be/test/libSCL_rip6565.t.sol#L158

      
                 res=SCL_RIP6565.Verify_LE(string(Msg), r, s, extKpub); 
               
                 assertEq(res,true);
             }
          
          
          /*assess all testvectors of  [ED25519-TEST-VECTORS]
                       Bernstein, D., Duif, N., Lange, T., Schwabe, P., and B.
                       Yang, "Ed25519 test vectors", July 2011,
                       <http://ed25519.cr.yp.to/python/sign.input>.*/
          function test_rip6565_allrfc() public view {
              uint256[5] memory extKpub;
              uint256[2] memory signer;
          
                 bool res;
          
                 string memory file = "./test/utils/ed25519tv.json";
                 while (true) {
                    
                     string memory vector = vm.readLine(file);
                     if (bytes(vector).length == 0) {
      
    





If you have some use cases for the Ed25519, please reach us (we are thinking about farcaster, cosmos bridges, Webauthn with eddsa). Last year, many have built upon FCL (Base Smartwallet, Abstract Wallet, many demos). We would like to support the migration to the more efficient and generic SCL to encourage RIP7696.

Author: mratsim
Date: 2024-07-18T09:44:20.399Z

Maybe we can have 2 different precompiles, one for 256 and one for 384 bits so that it’s also easier for zkEVMs / zkVMs to specialize.
For instance, one use-case for Taiko is verifying signatures coming from Amazon Nitro enclaves which use P-384.
Furthermore for zkEVMs, as soon as you deal with fields larger than the curve order, you already need to deal with “carries” beyond your order.
And BN254 which is the sole valid curve until EIP-2537 is delivered, only has a 254-bit order. Meaning when used with Curve25519, it will need to deal with the extra bits the same way it would deal with extra bits with P384.

Author: rdubois-crypto
Date: 2024-07-18T14:24:38.839Z

Going with a bunch of specific RIP decreases the chance of adoption of each IMHO. So we could adapt the RIP to be more generic.
The thing is that I didn’t realize the fact that progressive precompile is the way for Dapps (pushing something anyone can use, then by its adoption push it to RIP then EIP).
But in fact L2s need node implementations in major clients. And major clients won"t integrate anything destined to L1. Seems like the process is in a “chicken or egg” situation here.

Author: mralj
Date: 2024-09-17T08:23:28.167Z

Hello everyone!
Firstly I want to stress that I have never implemented any cryptographic algorithms nor implemented any EIPs/RIPS. But I want to learn 
I came across this RIP and I was wondering what’s the process of actually implementing this in prod.
As I am experimenting with various geth forks I wanted to see how hard would it be to fork geth and implement this. Here is my understanding/what I have so far:

I have created my lib for handling general Weierstrass curves (by handling I mean I’ve implemented code to calculate ecMulmuladd). Note this is not prod-ready - not even close.
I have a fork of geth and I plan to follow eg. op-geth steps adding RIP-7212 to add support for RIP-7696 in my experimental fork.
Write “integration” tests core/vm/contracts_test.go
Q: To test this I should have a node running and execute Solidity code similar to this example to check if the precompile was indeed called?
Q: To benchmark should I use benchmarkPrecompiled from core/vm/contracts_test.go
Q: Is there a way of checking that implementation correlates with suggested gas usage?

Am I missing some steps?
Of course, I understand that this won’t lend in official geth repo, at the moment my journey is for learning purposes.
Questions about implementing prod-ready Weierstrass curve
I have an “mvp” version of the implementation link
I believe the implementation is correct since I’ve used Sage to generate a bunch of tests.
It uses the Montgomery ladder to calculate kP, it is implemented naively - without any performance improvements, and since it has branched in algo execution, I guess that it is not side-channel attack resistant.
In the RIP description it is stated:

The node is free to implement the elliptic computations as it sees fit (choice of inner elliptic point representation, ladder, etc).

Since I already have a naive implementation, and since the description also helpfully includes a couple of techniques for performance improvements, I wondering about benchmarking the improvements.
My questions are:

How to benchmark the implementation against get-smooth by @rdubois-crypto as their code is in Solidity and this will be Go implementation
What’s the best way to make sure implementation is “cryptographically secure” (ie resistant to side-channel attacks)
What’s the best way of making sure (testing) the correctness? Is generating test vectors via Sage the way to go or are there better approaches?

I know I asked a bunch of questions, but any answers would be much appreciated!

Author: rdubois-crypto
Date: 2024-09-17T12:21:00.341Z

Hi,
Thanks for you interest in the RIP. I will first answer for the Weierstrass part:



you can benchmark by selecting various curves from Wycheproof project. We actually run all ed25519 and P256 vectors in the repo. But this is only a start.




Side channel attack are not in the scope of a node because there is no secret to extract. Except if you consider bugs as a channel (as Shamir bug attack). Bugs can lead to critical vuln (such as this one ) and loss of funds, which lead to next point.




The only way is to go through audits, SCL currently went through 2 audits (CryptoExperts and Verdise). This is expensive, but i am very surprised that despite HUGE warnings, people still use my last FCL.

Author: rdubois-crypto
Date: 2024-09-17T12:25:22.743Z

For the node implementation part, i did not go through it, but it is clearly important to push 7696. I think op-geth already have its support of 7212 by Clave team. I will gladly help for 7696 integration thus. Do not hesitate to PM me.

Author: mralj
Date: 2024-09-17T12:45:02.487Z

I think op-geth already have its support of 7212 by Clave team

Yeah they do, since Fjord fork

I will gladly help for 7696 integration thus. Do not hesitate to PM me.

Thanks! I don’t maintain any of the official geth forks, but  if I manage to get this working on node (even with naive algorithm implementation) I’ll let you know so that can be used to kickstart implementing this properly

Author: mralj
Date: 2024-09-17T13:49:50.321Z

@rdubois-crypto  one more small thing, not sure if I’m brain farting, but in the RIP spec it is stated:

ecMulmuladd
The ecMulmuladd precompiled contract is proposed with the following input and outputs, which are big-endian values:

Input data: 224 bytes of data including:

32 bytes of the modulus p modulus of the prime field of the curve
32 bytes of the a first coefficient of the curve
32 bytes of the b second coefficient of the curve
32 bytes of the Px x coordinate of the first point
32 bytes of the Py y coordinate of the first point
32 bytes of the Qx x coordinate of the first point
32 bytes of the Qy y coordinate of the first point
32 bytes of the u first scalar to multiply with P
32 bytes of the v second scalar to multiply with Q




What’s bothering me is the 224 bytes.
I’m counting 9 args * 32 bytes = 288 bytes of data. Is there typo in the spec, or am I wrong?
Note for ecMulmuladd_b4 we have 32 * 13 = 416 as stated in the specs (so that maches)

Author: rdubois-crypto
Date: 2024-09-18T15:11:26.840Z

Your are totally right, gonna push the correction

Author: rdubois-crypto
Date: 2024-09-22T10:36:09.135Z

The Eucleak vulnerability is one from many examples  about why RIP7696 and cryptographic agility seems preferable.
First, there is no true reason to prefer P256 over EDDSA:

Eddsa is compatible with frost, while ecdsa is not. It is more MPC friendly,
ECDSA-MPC suffered several flaws
Yubikey P256 is compromised by Eucleak, and there might be other hardwares, including enclave sensible to it. Eddsa is not vulnerable to euckleak because no nonce inversion is required.
eddsa is deterministic, thus enables to derive secret from the signing algorithm. While a distinct algorithm&key is preferable, leveraging secure enclave is always preferable. Nonce generation is also a strong covert channel,
actually looking at SHA512, its implementation might be faster than SHA256, because emulating 64 bits numbers from 31/32 bits as in babybear/goldylocks/M31 require 3 elements to parse input by 64 bits, while 32 bits elements require 2 element to parse input by 32. Remember that the roadmap is to align hash function cost to ZK proving cost.
eddsa has a “proof of generation”, following the “nothing in my sleeves”, while P256 is still opaque.

Remember that ECDSA was a weaker alternative choice to avoid patents no expired. EDDSA would have been the way to go otherwise.
Not saying that P256 should be banned, but be second choice when Eddsa over Ed25519 is possible. It might happen (but less likely) that a HW will have its Ed rather than ECdsa implementation broken.
My concern about Eucleak is that if it had happenned in a more complex hardware than ubikey, another process spying the enclave could enable remote attack (while Eucleak concern is only about cloning capacity).

Author: Arvolear
Date: 2024-12-24T14:12:24.135Z

Really like this one, especially if higher-order curves can be supported.
We actually used double scalar multiplication (Strauss-Shamir method) with 6 bits of precompute to implement on-chain verification of ECDSA signatures over 384-bit curves. Check out the Solidity code here (fuzz-tested and fully covered).
P.S.
Many national passport issuers use higher-order curves to sign off passports. I see this ZK research area benefiting a lot from a DSM precompile.

Author: rdubois-crypto
Date: 2024-12-24T15:42:57.524Z

RIP7696 was wrote with 256 bits size in mind, but it is feasible to integrate a generic lib such as
GitHub - ANSSI-FR/libecc: Library for elliptic curves cryptography in nodes to handle any curve.
This implementation is already quite optimized, but handling 384 bit size as an overhead far superior to the theoreticall x4 factor (because infact double precision requires to handle 128 bits to enable double word on 256).
Take a look at the second operator of the RIP, enabling 4MSM would decrease the cost by 50% (which still let us with a 5 MB gas cost), 8 MSM by 75% (but requires 24kb of precomputed tables stored as contract).

Author: colinlyguo
Date: 2025-01-26T21:19:03.756Z

Hi, really excited to see this kind of “framework” and “progressive” precompile for general usage.
having a small question when reading the spec, in mentioned the precompile takes 160k gas in RIPs/RIPS/rip-7696.md at 6261b59fed20e792ffe6e122c759944f2a2cc136 · ethereum/RIPs · GitHub.
Does the 160k gas result come from a self-implemented one instead of a precompile (with recommended ECMULMULADD_B4_COST of 2000 gas)?
also, the RIP mentions “Apple’s secure enclave uses ed25519”, while in the latest developer doc of Apple, it mentions secure enclave “works only with NIST P-256 elliptic curve keys”, this info in the RIP might be outdated.
Another question would be in this spec it mentioned “MSM would be superior, but the variable length and complexity of possible tradeoffs seems to reduce the probability of acceptance.” While I think it’s also worth opening the discussion for MSM (e.g. in another RIP), to be hands-on and see the difficulties, brainstorm and collect some usage cases, etc. any considerations about this?

Author: dipkakwani
Date: 2025-02-18T09:22:25.935Z

@mralj and I spent some more time exploring the implementation approach for rollup-geth (GitHub - NethermindEth/rollup-geth: Fork of go-ethereum tailored for L2 Rollups) project. One of the issues we have faced with the implementation is that the majority of Go crypto libraries do not support generic curve implementation (Go std library, Gnark from Consensys, Circl from Cloudfare). For example, the standard Go library has completely deprecated the generic curve API (https://cs.opensource.google/go/go/+/refs/tags/go1.23.6:src/crypto/elliptic/params.go;l=12).
As as per my understanding there are two issues with supporting generic curves: a) Using a non-standard curve which has not been tested could lead to security risks b) Most operations on the standard curves have specific optimized implementations, which have also been well-tested. Thus all the standard crypto libraries in the Go ecosystem focus on providing APIs for specific elliptic curves. Moreover, if we do not use a battle-tested/audited crypto library within any precompile, it could leave potential security loopholes in the L1.
@rdubois-crypto Please let me know what do you think about these challenges, since currently the RIP focuses on generic curve implementation while it might be possible to provide support for specific curves safely.

Author: rdubois-crypto
Date: 2025-02-18T10:04:22.808Z

a) The use of a non standard curve is like misusing ecrecover with a fixed nonce: not a problem of the precompile but of its use.
b) It is possible to use a custom curve in OpenSSL. I saw that some go implementation are instead using some mappings from C to go, would it be an acceptable way to do so ?
OpenSSL is a reference for crypto implementations. There is also libECC from the ANSSI which is a remarkable library that can be used with custom curves.

github.com




GitHub - ANSSI-FR/libecc: Library for elliptic curves cryptography
Library for elliptic curves cryptography