Skip to content

Instantly share code, notes, and snippets.

@Turupawn
Created May 22, 2025 15:45

Revisions

  1. Turupawn created this gist May 22, 2025.
    41 changes: 41 additions & 0 deletions P256Verifier.sol
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,41 @@
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;

    contract P256Verifier {
    address constant P256_PRECOMPILE = address(0x0100);

    /// @notice Verifies a secp256r1 signature using the EIP-7212 precompile.
    /// @param hash The 32-byte message hash that was signed.
    /// @param r The 32-byte r component of the signature.
    /// @param s The 32-byte s component of the signature.
    /// @param x The 32-byte x coordinate of the public key.
    /// @param y The 32-byte y coordinate of the public key.
    /// @return isValid True if the signature is valid, false otherwise.
    function verifySignature(
    bytes32 hash,
    bytes32 r,
    bytes32 s,
    bytes32 x,
    bytes32 y
    ) external view returns (bool isValid) {
    bytes memory input = abi.encodePacked(hash, r, s, x, y);
    bytes memory output = new bytes(32);

    assembly {
    // Call the precompiled contract
    let success := staticcall(
    gas(),
    0x0100,
    add(input, 32),
    160,
    add(output, 32),
    32
    )
    // Check if the call was successful and the output is 1
    isValid := and(
    success,
    eq(mload(add(output, 32)), 1)
    )
    }
    }
    }
    15 changes: 15 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    {
    "name": "p256-signature",
    "version": "1.0.0",
    "main": "index.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "dependencies": {
    "secp256r1": "^0.0.3"
    }
    }
    34 changes: 34 additions & 0 deletions sign.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    // sign.js
    const crypto = require('crypto');
    const secp256r1 = require('secp256r1');

    // Generate a random 32-byte message
    const message = crypto.randomBytes(32);

    // Generate a valid private key
    let privateKey;
    do {
    privateKey = crypto.randomBytes(32);
    } while (!secp256r1.privateKeyVerify(privateKey));

    // Derive the public key (uncompressed)
    const publicKey = secp256r1.publicKeyCreate(privateKey, false); // 65 bytes: 0x04 || X || Y

    // Sign the message
    const signatureObj = secp256r1.sign(message, privateKey);
    const { signature } = signatureObj;

    // Extract r and s from the signature
    const r = signature.slice(0, 32);
    const s = signature.slice(32, 64);

    // Extract x and y from the public key
    const x = publicKey.slice(1, 33);
    const y = publicKey.slice(33, 65);

    // Output the components in hexadecimal format
    console.log('Message Hash:', message.toString('hex'));
    console.log('r:', r.toString('hex'));
    console.log('s:', s.toString('hex'));
    console.log('x:', x.toString('hex'));
    console.log('y:', y.toString('hex'));