{"version":3,"file":"ecSignature.mjs","names":[],"sources":["../../../../../../src/modules/kms/jwk/kty/ec/ecSignature.ts"],"sourcesContent":["import { ECDSASigValue } from '@peculiar/asn1-ecc'\nimport { AsnConvert } from '@peculiar/asn1-schema'\nimport { KeyManagementError } from '../../../error/KeyManagementError'\nimport type { KmsJwkPublicEc } from './ecJwk'\nimport { ecCrvToCurveParams } from './ecPublicKey'\n\n/**\n * Converts a RAW EC signature to DER format\n *\n * @param rawSignature - Raw signature as r || s concatenated values\n * @param crv - The EC crv of the key used for the signature\n * @returns DER encoded signature\n */\nexport function rawEcSignatureToDer(rawSignature: Uint8Array, crv: KmsJwkPublicEc['crv']): Uint8Array {\n  const pointBitLength = ecCrvToCurveParams[crv].pointBitLength\n  const pointByteLength = Math.ceil(pointBitLength / 8)\n\n  if (rawSignature.length !== pointByteLength * 2) {\n    throw new KeyManagementError(\n      `Invalid raw signature length for EC signature conversion. Expected ${pointByteLength * 2} bytes for crv ${crv}`\n    )\n  }\n\n  // Extract r and s values from the raw signature\n  const r = rawSignature.slice(0, pointByteLength)\n  const s = rawSignature.slice(pointByteLength)\n\n  // Remove leading zeros that aren't necessary for ASN.1 encoding\n  const rValue = removeLeadingZeros(r)\n  const sValue = removeLeadingZeros(s)\n\n  // Create the EcDsaSignature object\n  const signature = new ECDSASigValue()\n  signature.r = new Uint8Array(ensurePositive(rValue)).buffer\n  signature.s = new Uint8Array(ensurePositive(sValue)).buffer\n\n  // Convert to DER\n  return new Uint8Array(AsnConvert.serialize(signature))\n}\n\n/**\n * Converts a DER encoded EC signature to RAW format\n *\n * @param derSignature - DER encoded signature\n * @param crv - The EC crv of the key used for the signature\n * @returns Raw signature as r || s concatenated values\n */\nexport function derEcSignatureToRaw(derSignature: Uint8Array, crv: KmsJwkPublicEc['crv']): Uint8Array {\n  // Parse DER signature\n  const asn = AsnConvert.parse(derSignature, ECDSASigValue)\n\n  const pointBitLength = ecCrvToCurveParams[crv].pointBitLength\n  const pointByteLength = Math.ceil(pointBitLength / 8)\n\n  // Ensure r and s are padded to the correct point size\n  const rPadded = padToLength(new Uint8Array(asn.r), pointByteLength)\n  const sPadded = padToLength(new Uint8Array(asn.s), pointByteLength)\n\n  // Concatenate to form raw signature\n  const rawSignature = new Uint8Array(pointByteLength * 2)\n  rawSignature.set(rPadded, 0)\n  rawSignature.set(sPadded, pointByteLength)\n\n  return rawSignature\n}\n\n/**\n * Helper function to remove unnecessary leading zeros from an integer representation\n *\n * @param data - The integer bytes\n * @returns - Data with leading zeros removed\n */\nfunction removeLeadingZeros(data: Uint8Array): Uint8Array {\n  let startIndex = 0\n  while (startIndex < data.length - 1 && data[startIndex] === 0) {\n    startIndex++\n  }\n\n  return data.slice(startIndex)\n}\n\n/**\n * Ensures an integer value is represented as positive in ASN.1 by\n * adding a leading zero if the high bit is set\n *\n * @param data - The integer bytes\n * @returns Data ensuring positive integer representation\n */\nfunction ensurePositive(data: Uint8Array): Uint8Array {\n  // If high bit is set, prepend a zero byte to ensure it's treated as positive\n  if (data.length > 0 && (data[0] & 0x80) !== 0) {\n    const result = new Uint8Array(data.length + 1)\n    result.set(data, 1)\n    return result\n  }\n  return data\n}\n\n/**\n * Pads an integer value to the specified length\n *\n * @param data - The integer bytes\n * @param targetLength - The desired length\n * @returns Padded data\n */\nfunction padToLength(data: Uint8Array, targetLength: number) {\n  if (data.length === targetLength) {\n    return data\n  }\n\n  if (data.length > targetLength) {\n    // If the value is larger, ensure we're not losing significant bytes\n    const significantStart = data.length - targetLength\n    for (let i = 0; i < significantStart; i++) {\n      if (data[i] !== 0) {\n        throw new KeyManagementError('Value too large for the specified point size')\n      }\n    }\n    return data.slice(significantStart)\n  }\n\n  // Pad with leading zeros\n  const result = new Uint8Array(targetLength)\n  result.set(data, targetLength - data.length)\n  return result\n}\n"],"mappings":";;;;;;;;;;;;AAaA,SAAgB,oBAAoB,cAA0B,KAAwC;CACpG,MAAM,iBAAiB,mBAAmB,IAAI,CAAC;CAC/C,MAAM,kBAAkB,KAAK,KAAK,iBAAiB,CAAC;CAEpD,IAAI,aAAa,WAAW,kBAAkB,GAC5C,MAAM,IAAI,mBACR,sEAAsE,kBAAkB,EAAE,iBAAiB,KAC7G;CAIF,MAAM,IAAI,aAAa,MAAM,GAAG,eAAe;CAC/C,MAAM,IAAI,aAAa,MAAM,eAAe;CAG5C,MAAM,SAAS,mBAAmB,CAAC;CACnC,MAAM,SAAS,mBAAmB,CAAC;CAGnC,MAAM,YAAY,IAAI,cAAc;CACpC,UAAU,IAAI,IAAI,WAAW,eAAe,MAAM,CAAC,CAAC,CAAC;CACrD,UAAU,IAAI,IAAI,WAAW,eAAe,MAAM,CAAC,CAAC,CAAC;CAGrD,OAAO,IAAI,WAAW,WAAW,UAAU,SAAS,CAAC;AACvD;;;;;;;;AASA,SAAgB,oBAAoB,cAA0B,KAAwC;CAEpG,MAAM,MAAM,WAAW,MAAM,cAAc,aAAa;CAExD,MAAM,iBAAiB,mBAAmB,IAAI,CAAC;CAC/C,MAAM,kBAAkB,KAAK,KAAK,iBAAiB,CAAC;CAGpD,MAAM,UAAU,YAAY,IAAI,WAAW,IAAI,CAAC,GAAG,eAAe;CAClE,MAAM,UAAU,YAAY,IAAI,WAAW,IAAI,CAAC,GAAG,eAAe;CAGlE,MAAM,eAAe,IAAI,WAAW,kBAAkB,CAAC;CACvD,aAAa,IAAI,SAAS,CAAC;CAC3B,aAAa,IAAI,SAAS,eAAe;CAEzC,OAAO;AACT;;;;;;;AAQA,SAAS,mBAAmB,MAA8B;CACxD,IAAI,aAAa;CACjB,OAAO,aAAa,KAAK,SAAS,KAAK,KAAK,gBAAgB,GAC1D;CAGF,OAAO,KAAK,MAAM,UAAU;AAC9B;;;;;;;;AASA,SAAS,eAAe,MAA8B;CAEpD,IAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAU,GAAG;EAC7C,MAAM,SAAS,IAAI,WAAW,KAAK,SAAS,CAAC;EAC7C,OAAO,IAAI,MAAM,CAAC;EAClB,OAAO;CACT;CACA,OAAO;AACT;;;;;;;;AASA,SAAS,YAAY,MAAkB,cAAsB;CAC3D,IAAI,KAAK,WAAW,cAClB,OAAO;CAGT,IAAI,KAAK,SAAS,cAAc;EAE9B,MAAM,mBAAmB,KAAK,SAAS;EACvC,KAAK,IAAI,IAAI,GAAG,IAAI,kBAAkB,KACpC,IAAI,KAAK,OAAO,GACd,MAAM,IAAI,mBAAmB,8CAA8C;EAG/E,OAAO,KAAK,MAAM,gBAAgB;CACpC;CAGA,MAAM,SAAS,IAAI,WAAW,YAAY;CAC1C,OAAO,IAAI,MAAM,eAAe,KAAK,MAAM;CAC3C,OAAO;AACT"}