{"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,KAAK;CAC/C,MAAM,kBAAkB,KAAK,KAAK,iBAAiB,EAAE;AAErD,KAAI,aAAa,WAAW,kBAAkB,EAC5C,OAAM,IAAI,mBACR,sEAAsE,kBAAkB,EAAE,iBAAiB,MAC5G;CAIH,MAAM,IAAI,aAAa,MAAM,GAAG,gBAAgB;CAChD,MAAM,IAAI,aAAa,MAAM,gBAAgB;CAG7C,MAAM,SAAS,mBAAmB,EAAE;CACpC,MAAM,SAAS,mBAAmB,EAAE;CAGpC,MAAM,YAAY,IAAI,eAAe;AACrC,WAAU,IAAI,IAAI,WAAW,eAAe,OAAO,CAAC,CAAC;AACrD,WAAU,IAAI,IAAI,WAAW,eAAe,OAAO,CAAC,CAAC;AAGrD,QAAO,IAAI,WAAW,WAAW,UAAU,UAAU,CAAC;;;;;;;;;AAUxD,SAAgB,oBAAoB,cAA0B,KAAwC;CAEpG,MAAM,MAAM,WAAW,MAAM,cAAc,cAAc;CAEzD,MAAM,iBAAiB,mBAAmB,KAAK;CAC/C,MAAM,kBAAkB,KAAK,KAAK,iBAAiB,EAAE;CAGrD,MAAM,UAAU,YAAY,IAAI,WAAW,IAAI,EAAE,EAAE,gBAAgB;CACnE,MAAM,UAAU,YAAY,IAAI,WAAW,IAAI,EAAE,EAAE,gBAAgB;CAGnE,MAAM,eAAe,IAAI,WAAW,kBAAkB,EAAE;AACxD,cAAa,IAAI,SAAS,EAAE;AAC5B,cAAa,IAAI,SAAS,gBAAgB;AAE1C,QAAO;;;;;;;;AAST,SAAS,mBAAmB,MAA8B;CACxD,IAAI,aAAa;AACjB,QAAO,aAAa,KAAK,SAAS,KAAK,KAAK,gBAAgB,EAC1D;AAGF,QAAO,KAAK,MAAM,WAAW;;;;;;;;;AAU/B,SAAS,eAAe,MAA8B;AAEpD,KAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAU,GAAG;EAC7C,MAAM,SAAS,IAAI,WAAW,KAAK,SAAS,EAAE;AAC9C,SAAO,IAAI,MAAM,EAAE;AACnB,SAAO;;AAET,QAAO;;;;;;;;;AAUT,SAAS,YAAY,MAAkB,cAAsB;AAC3D,KAAI,KAAK,WAAW,aAClB,QAAO;AAGT,KAAI,KAAK,SAAS,cAAc;EAE9B,MAAM,mBAAmB,KAAK,SAAS;AACvC,OAAK,IAAI,IAAI,GAAG,IAAI,kBAAkB,IACpC,KAAI,KAAK,OAAO,EACd,OAAM,IAAI,mBAAmB,+CAA+C;AAGhF,SAAO,KAAK,MAAM,iBAAiB;;CAIrC,MAAM,SAAS,IAAI,WAAW,aAAa;AAC3C,QAAO,IAAI,MAAM,eAAe,KAAK,OAAO;AAC5C,QAAO"}