{"version":3,"file":"concatKdf.mjs","names":["blocks: Uint8Array[]"],"sources":["../../src/jwe/concatKdf.ts"],"sourcesContent":["/**\n * NIST SP 800-56A Concat KDF (used by JWE ECDH-ES per RFC 7518 §4.6.2).\n * Pinned by `tests/unit/jweConcatKdf.test.ts` against the RFC 7518\n * Appendix C reference vector.\n */\n\nimport { sha256 } from '@noble/hashes/sha2'\n\n/**\n * Derive `keyDataLen / 8` bytes from `sharedSecret`. `keyDataLen` is\n * **bits** (RFC 7518 §4.6.2). OtherInfo is the spec layout:\n * AlgorithmID || PartyUInfo || PartyVInfo || SuppPubInfo, each\n * length-prefixed with a 4-byte big-endian count.\n */\nexport function concatKdf({\n  sharedSecret,\n  algorithmId,\n  partyUInfo,\n  partyVInfo,\n  keyDataLen,\n  supplPubInfo,\n}: {\n  sharedSecret: Uint8Array\n  algorithmId: string\n  partyUInfo: Uint8Array\n  partyVInfo: Uint8Array\n  keyDataLen: number\n  supplPubInfo?: Uint8Array\n}): Uint8Array {\n  if (keyDataLen <= 0 || keyDataLen % 8 !== 0) {\n    throw new Error('keyDataLen must be a positive multiple of 8')\n  }\n\n  const algBytes = textEncoder.encode(algorithmId)\n\n  const suppPub = supplPubInfo && supplPubInfo.length > 0 ? supplPubInfo : be32(keyDataLen)\n\n  const otherInfo = concat(\n    lengthPrefixed(algBytes),\n    lengthPrefixed(partyUInfo),\n    lengthPrefixed(partyVInfo),\n    suppPub\n  )\n\n  const targetBytes = keyDataLen / 8\n  const blocks: Uint8Array[] = []\n  let outLen = 0\n  let counter = 1\n  while (outLen < targetBytes) {\n    const block = sha256(concat(be32(counter), sharedSecret, otherInfo))\n    blocks.push(block)\n    outLen += block.length\n    counter += 1\n  }\n  return concat(...blocks).subarray(0, targetBytes)\n}\n\n// ─────────────────────────── helpers ─────────────────────────────────\n\nconst textEncoder = new TextEncoder()\n\nfunction be32(n: number): Uint8Array {\n  if (!Number.isInteger(n) || n < 0 || n > 0xffffffff) {\n    throw new Error(`be32 expects a u32, got ${n}`)\n  }\n  const buf = new Uint8Array(4)\n  buf[0] = (n >>> 24) & 0xff\n  buf[1] = (n >>> 16) & 0xff\n  buf[2] = (n >>> 8) & 0xff\n  buf[3] = n & 0xff\n  return buf\n}\n\nfunction lengthPrefixed(b: Uint8Array): Uint8Array {\n  return concat(be32(b.length), b)\n}\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n  let total = 0\n  for (const p of parts) total += p.length\n  const out = new Uint8Array(total)\n  let off = 0\n  for (const p of parts) {\n    out.set(p, off)\n    off += p.length\n  }\n  return out\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAgB,UAAU,EACxB,cACA,aACA,YACA,YACA,YACA,gBAQa;AACb,KAAI,cAAc,KAAK,aAAa,MAAM,EACxC,OAAM,IAAI,MAAM,8CAA8C;CAGhE,MAAM,WAAW,YAAY,OAAO,YAAY;CAEhD,MAAM,UAAU,gBAAgB,aAAa,SAAS,IAAI,eAAe,KAAK,WAAW;CAEzF,MAAM,YAAY,OAChB,eAAe,SAAS,EACxB,eAAe,WAAW,EAC1B,eAAe,WAAW,EAC1B,QACD;CAED,MAAM,cAAc,aAAa;CACjC,MAAMA,SAAuB,EAAE;CAC/B,IAAI,SAAS;CACb,IAAI,UAAU;AACd,QAAO,SAAS,aAAa;EAC3B,MAAM,QAAQ,OAAO,OAAO,KAAK,QAAQ,EAAE,cAAc,UAAU,CAAC;AACpE,SAAO,KAAK,MAAM;AAClB,YAAU,MAAM;AAChB,aAAW;;AAEb,QAAO,OAAO,GAAG,OAAO,CAAC,SAAS,GAAG,YAAY;;AAKnD,MAAM,cAAc,IAAI,aAAa;AAErC,SAAS,KAAK,GAAuB;AACnC,KAAI,CAAC,OAAO,UAAU,EAAE,IAAI,IAAI,KAAK,IAAI,WACvC,OAAM,IAAI,MAAM,2BAA2B,IAAI;CAEjD,MAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,KAAI,KAAM,MAAM,KAAM;AACtB,KAAI,KAAM,MAAM,KAAM;AACtB,KAAI,KAAM,MAAM,IAAK;AACrB,KAAI,KAAK,IAAI;AACb,QAAO;;AAGT,SAAS,eAAe,GAA2B;AACjD,QAAO,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;;AAGlC,SAAS,OAAO,GAAG,OAAiC;CAClD,IAAI,QAAQ;AACZ,MAAK,MAAM,KAAK,MAAO,UAAS,EAAE;CAClC,MAAM,MAAM,IAAI,WAAW,MAAM;CACjC,IAAI,MAAM;AACV,MAAK,MAAM,KAAK,OAAO;AACrB,MAAI,IAAI,GAAG,IAAI;AACf,SAAO,EAAE;;AAEX,QAAO"}