Overview

The P256 precompile provides a suite of cryptographic functions for the NIST P-256 elliptic curve. It enables smart contracts to perform essential operations such as signature verification, scalar multiplication, and point addition, which are fundamental for building secure and privacy-preserving applications. Precompile Address: 0x0000000000000000000000000000000000000100 Related Module: Core cryptographic functionality

Methods

verifySignature

Verifies a P-256 ECDSA signature against a hash and public key.

scalarMult

Performs scalar multiplication on the P-256 elliptic curve.

pointAdd

Adds two points on the P-256 elliptic curve.

getGenerator

Returns the generator point of the P-256 curve.

isOnCurve

Validates whether a given point lies on the P-256 curve.

compressPoint

Compresses a P-256 point to its 33-byte representation.

decompressPoint

Decompresses a 33-byte compressed point to its full coordinates.

Example: Verifying a P-256 Signature

import { ethers } from "ethers";

// ABI definition for the verifySignature function
const precompileAbi = [
  "function verifySignature(bytes32 hash, tuple(bytes32 r, bytes32 s) signature, tuple(bytes32 x, bytes32 y) publicKey) pure returns (bool isValid)"
];

// Provider and contract setup
const provider = new ethers.JsonRpcProvider("<RPC_URL>");
const precompileAddress = "0x0000000000000000000000000000000000000100";
const contract = new ethers.Contract(precompileAddress, precompileAbi, provider);

// Example inputs (replace with your actual values)
const hash = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
const signature = {
  r: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
  s: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
};
const publicKey = {
  x: "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  y: "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
};

async function verifySignature() {
  try {
    const isValid = await contract.verifySignature(hash, signature, publicKey);
    console.log("Signature valid:", isValid);
  } catch (error) {
    console.error("Error verifying signature:", error);
  }
}

verifySignature();

Example: Getting the Generator Point

import { ethers } from "ethers";

// ABI definition for the getGenerator function
const precompileAbi = [
  "function getGenerator() pure returns (tuple(bytes32 x, bytes32 y) generator)"
];

// Provider and contract setup
const provider = new ethers.JsonRpcProvider("<RPC_URL>");
const precompileAddress = "0x0000000000000000000000000000000000000100";
const contract = new ethers.Contract(precompileAddress, precompileAbi, provider);

async function getGenerator() {
  try {
    const generator = await contract.getGenerator();
    console.log("Generator Point:", {
      x: generator.x,
      y: generator.y
    });
  } catch (error) {
    console.error("Error getting generator:", error);
  }
}

getGenerator();

Example: Scalar Multiplication

import { ethers } from "ethers";

// ABI definition for the scalarMult function
const precompileAbi = [
  "function scalarMult(bytes32 scalar, tuple(bytes32 x, bytes32 y) point) pure returns (tuple(bytes32 x, bytes32 y) result)"
];

// Provider and contract setup
const provider = new ethers.JsonRpcProvider("<RPC_URL>");
const precompileAddress = "0x0000000000000000000000000000000000000100";
const contract = new ethers.Contract(precompileAddress, precompileAbi, provider);

// Example inputs
const scalar = "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
const point = {
  x: "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
  y: "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
};

async function performScalarMult() {
  try {
    const result = await contract.scalarMult(scalar, point);
    console.log("Scalar Multiplication Result:", {
      x: result.x,
      y: result.y
    });
  } catch (error) {
    console.error("Error performing scalar multiplication:", error);
  }
}

performScalarMult();

Full Solidity Interface & ABI

P256 Solidity Interface
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.18;

/// @dev The P256Point struct contains the x and y coordinates of a point on the P-256 curve
struct P256Point {
    bytes32 x;
    bytes32 y;
}

/// @dev The P256Signature struct contains the r and s values of a P-256 signature
struct P256Signature {
    bytes32 r;
    bytes32 s;
}

/// @author The Berachain Polaris Team
/// @title P256 Precompile Contract
/// @dev The interface through which solidity contracts will interact with the P256 precompile
interface IP256 {
    /// @dev Verifies a P-256 ECDSA signature
    /// @param hash The hash that was signed
    /// @param signature The signature to verify
    /// @param publicKey The public key to verify the signature with
    /// @return isValid True if the signature is valid
    function verifySignature(bytes32 hash, P256Signature memory signature, P256Point memory publicKey) external pure returns (bool isValid);

    /// @dev Performs scalar multiplication on the P-256 curve
    /// @param scalar The scalar to multiply by
    /// @param point The point to multiply
    /// @return result The result of the scalar multiplication
    function scalarMult(bytes32 scalar, P256Point memory point) external pure returns (P256Point memory result);

    /// @dev Adds two points on the P-256 curve
    /// @param point1 The first point to add
    /// @param point2 The second point to add
    /// @return result The result of the point addition
    function pointAdd(P256Point memory point1, P256Point memory point2) external pure returns (P256Point memory result);

    /// @dev Returns the generator point of the P-256 curve
    /// @return generator The generator point
    function getGenerator() external pure returns (P256Point memory generator);

    /// @dev Checks if a point is on the P-256 curve
    /// @param point The point to check
    /// @return onCurve True if the point is on the curve
    function isOnCurve(P256Point memory point) external pure returns (bool onCurve);

    /// @dev Compresses a point on the P-256 curve
    /// @param point The point to compress
    /// @return compressed The compressed point
    function compressPoint(P256Point memory point) external pure returns (bytes memory compressed);

    /// @dev Decompresses a point on the P-256 curve
    /// @param compressed The compressed point
    /// @return point The decompressed point
    function decompressPoint(bytes memory compressed) external pure returns (P256Point memory point);
}
P256 ABI
[
  { "inputs": [ { "internalType": "bytes32", "name": "hash", "type": "bytes32" }, { "components": [ { "internalType": "bytes32", "name": "r", "type": "bytes32" }, { "internalType": "bytes32", "name": "s", "type": "bytes32" } ], "internalType": "struct P256Signature", "name": "signature", "type": "tuple" }, { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "publicKey", "type": "tuple" } ], "name": "verifySignature", "outputs": [ { "internalType": "bool", "name": "isValid", "type": "bool" } ], "stateMutability": "view", "type": "function" },
  { "inputs": [ { "internalType": "bytes32", "name": "scalar", "type": "bytes32" }, { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "point", "type": "tuple" } ], "name": "scalarMult", "outputs": [ { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "result", "type": "tuple" } ], "stateMutability": "view", "type": "function" },
  { "inputs": [ { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "point1", "type": "tuple" }, { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "point2", "type": "tuple" } ], "name": "pointAdd", "outputs": [ { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "result", "type": "tuple" } ], "stateMutability": "view", "type": "function" },
  { "inputs": [], "name": "getGenerator", "outputs": [ { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "generator", "type": "tuple" } ], "stateMutability": "view", "type": "function" },
  { "inputs": [ { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "point", "type": "tuple" } ], "name": "isOnCurve", "outputs": [ { "internalType": "bool", "name": "onCurve", "type": "bool" } ], "stateMutability": "view", "type": "function" },
  { "inputs": [ { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "point", "type": "tuple" } ], "name": "compressPoint", "outputs": [ { "internalType": "bytes", "name": "compressed", "type": "bytes" } ], "stateMutability": "view", "type": "function" },
  { "inputs": [ { "internalType": "bytes", "name": "compressed", "type": "bytes" } ], "name": "decompressPoint", "outputs": [ { "components": [ { "internalType": "bytes32", "name": "x", "type": "bytes32" }, { "internalType": "bytes32", "name": "y", "type": "bytes32" } ], "internalType": "struct P256Point", "name": "point", "type": "tuple" } ], "stateMutability": "view", "type": "function" }
]