* Sign an EIP-712 typed data hash with a secp256k1 private key. * Returns the signature in compact format (r + s + v).
( domainSeparator: Buffer, structHash: Buffer, privateKeyHex: string, )
| 239 | * Returns the signature in compact format (r + s + v). |
| 240 | */ |
| 241 | function signEIP712( |
| 242 | domainSeparator: Buffer, |
| 243 | structHash: Buffer, |
| 244 | privateKeyHex: string, |
| 245 | ): string { |
| 246 | const { sign } = require('crypto') as typeof import('crypto') |
| 247 | |
| 248 | // EIP-712 signing hash: keccak256("\x19\x01" + domainSeparator + structHash) |
| 249 | const prefix = Buffer.from('1901', 'hex') |
| 250 | const message = createHash('sha3-256') |
| 251 | .update(Buffer.concat([prefix, domainSeparator, structHash])) |
| 252 | .digest() |
| 253 | |
| 254 | const keyHex = privateKeyHex.startsWith('0x') |
| 255 | ? privateKeyHex.slice(2) |
| 256 | : privateKeyHex |
| 257 | const keyBuf = Buffer.from(keyHex, 'hex') |
| 258 | |
| 259 | // Use secp256k1 ECDSA signing |
| 260 | // Node.js crypto sign with EC key |
| 261 | const { createPrivateKey } = require('crypto') as typeof import('crypto') |
| 262 | |
| 263 | // DER prefix for secp256k1 private key |
| 264 | const derPrefix = Buffer.from('30740201010420', 'hex') |
| 265 | const derMiddle = Buffer.from('a00706052b8104000aa144034200', 'hex') |
| 266 | |
| 267 | const ecPrivateKey = createPrivateKey({ |
| 268 | key: Buffer.concat([derPrefix, keyBuf, derMiddle]), |
| 269 | format: 'der', |
| 270 | type: 'sec1', |
| 271 | }) |
| 272 | |
| 273 | const signature = sign(null, message, { |
| 274 | key: ecPrivateKey, |
| 275 | dsaEncoding: 'ieee-p1363', |
| 276 | }) |
| 277 | |
| 278 | // Extract r and s (each 32 bytes for secp256k1) |
| 279 | const r = signature.subarray(0, 32) |
| 280 | const s = signature.subarray(32, 64) |
| 281 | |
| 282 | // Recovery ID (v) — for Ethereum it's 27 or 28 |
| 283 | // We try v=27 first; the facilitator will handle recovery |
| 284 | const v = 27 |
| 285 | |
| 286 | return ( |
| 287 | '0x' + r.toString('hex') + s.toString('hex') + v.toString(16) |
| 288 | ) |
| 289 | } |
| 290 | |
| 291 | /** |
| 292 | * Create a signed x402 payment payload for a given requirement. |
no test coverage detected