Skip to content

Commit

Permalink
Added ecMul coverage.
Browse files Browse the repository at this point in the history
Signed-off-by: ebadiere <[email protected]>
  • Loading branch information
ebadiere committed Oct 25, 2023
1 parent 59cf330 commit 77f4718
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 22 deletions.
35 changes: 35 additions & 0 deletions contracts/evm/Precompiles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,39 @@ contract Precompiles {
}
}
}

function ecMul(uint256[2] memory point, uint256 k, uint256 prime) public returns (uint256[2] memory result) {
// Ensure the input point is on the curve
require(isOnCurve(point, prime), "Point is not on the curve");

// Use the precompiled contract for the ecMul operation
// The precompiled contract for ecMul is at address 0x07
assembly {
// Free memory pointer
let p := mload(0x40)

// Store input data in memory
mstore(p, mload(point))
mstore(add(p, 0x20), mload(add(point, 0x20)))
mstore(add(p, 0x40), k)

// Call the precompiled contract
// Input: 0x60 bytes (point x, point y, scalar k)
// Output: 0x40 bytes (resulting point x', y')
if iszero(call(not(0), 0x07, 0, p, 0x60, p, 0x40)) {
revert(0, 0)
}

// Load the result from memory
result := p
}
}

function isOnCurve(uint256[2] memory point, uint256 prime) public pure returns (bool) {
uint256 x = point[0];
uint256 y = point[1];
uint256 lhs = mulmod(y, y, prime);
uint256 rhs = addmod(mulmod(mulmod(x, x, prime), x, prime), 3, prime);
return lhs == rhs;
}
}
78 changes: 56 additions & 22 deletions test/evm/Precompiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ const BN = require('bn.js');

describe("@solidityevmequiv1 Precompiles Support", function () {
let precompilesContract;
const prime = '21888242871839275222246405745257275088696311157297823662689037894645226208583';

const alt_bn128 = new elliptic.curve.short({
p: new BN(prime),
a: '0',
b: '3',
g: [
new BN('1'),
new BN('2')
],
n: new BN('21888242871839275222246405745257275088548364400416034343698204186575808495617'),
h: '1'
});

before(async () => {
const Precompiles = await ethers.getContractFactory("Precompiles");
Expand Down Expand Up @@ -91,44 +104,65 @@ describe("@solidityevmequiv1 Precompiles Support", function () {
expect(result).to.equal(expectedOutput);
});

it("should add two elliptic curve points", async function () {

// build an elliptic curve
const alt_bn128 = new elliptic.curve.short({
p: new BN('21888242871839275222246405745257275088696311157297823662689037894645226208583'),
a: '0',
b: '3',
g: [
new BN('1'),
new BN('2')
],
n: new BN('21888242871839275222246405745257275088548364400416034343698204186575808495617'),
h: '1'
});

it("should add two elliptic curve points", async function () {
// Get the base point (generator) of the curve
const basePoint = alt_bn128.g;
// check that all is well
expect(alt_bn128.validate(basePoint)).to.be.true;

// Get another point on the curve by multiplying the base point by 2
const anotherPoint = basePoint.mul(new BN('2'));
expect(alt_bn128.validate(anotherPoint)).to.be.true;
const secondPoint = basePoint.mul(new BN('2'));
// check that all is well
expect(alt_bn128.validate(secondPoint)).to.be.true;

const resPoint = basePoint.add(anotherPoint);
const resPoint = basePoint.add(secondPoint);

const base = [
ethers.BigNumber.from(basePoint.getX().toString()),
ethers.BigNumber.from(basePoint.getY().toString())
];

const another = [
ethers.BigNumber.from(anotherPoint.getX().toString()),
ethers.BigNumber.from(anotherPoint.getY().toString())
const second = [
ethers.BigNumber.from(secondPoint.getX().toString()),
ethers.BigNumber.from(secondPoint.getY().toString())
];

// check in contract that the second point is on the curve
expect(await precompilesContract.isOnCurve(second, prime)).to.be.true;

const result = await precompilesContract.ecAdd(base, another);
const result = await precompilesContract.ecAdd(base, second);

expect(result[0]).to.equal(resPoint.getX());
expect(result[1]).to.equal(resPoint.getY());
});

it("should correctly multiply a point on the curve by a scalar", async () => {
// Define a point on the curve (for example, the generator/base point)
const basePoint = alt_bn128.g; // This is the generator point of the curve

// Get another point on the curve by multiplying the base point by 2
const secondPoint = basePoint.mul(new BN('2'));
// check that all is well
expect(alt_bn128.validate(secondPoint)).to.be.true

// Define a scalar for multiplication
const scalar = new BN('7');

// Multiply the point by the scalar
const resultPoint = secondPoint.mul(scalar);

const result = await precompilesContract.callStatic.ecMul(
[
ethers.BigNumber.from(secondPoint.getX().toString()),
ethers.BigNumber.from(secondPoint.getY().toString())
],
ethers.BigNumber.from(scalar.toString()),
ethers.BigNumber.from(prime.toString())
);

expect(result[0]).to.equal(resultPoint.getX());
expect(result[1]).to.equal(resultPoint.getY());

});

});

0 comments on commit 77f4718

Please sign in to comment.