{"id":22267891,"url":"https://github.com/transmute-industries/cose","last_synced_at":"2025-10-17T17:25:30.560Z","repository":{"id":170441560,"uuid":"646489929","full_name":"transmute-industries/cose","owner":"transmute-industries","description":"A COSE SDK for TypeScript","archived":false,"fork":false,"pushed_at":"2024-03-02T22:48:40.000Z","size":2245,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-05-21T11:44:07.218Z","etag":null,"topics":["cbor","cose","cwt","merkle-proof","merkle-tree","scitt","x509"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/transmute-industries.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-28T15:09:04.000Z","updated_at":"2024-08-10T14:29:25.146Z","dependencies_parsed_at":null,"dependency_job_id":"747a5dda-87cf-44a2-a981-ad0e382df9b5","html_url":"https://github.com/transmute-industries/cose","commit_stats":null,"previous_names":["transmute-industries/cose"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transmute-industries%2Fcose","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transmute-industries%2Fcose/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transmute-industries%2Fcose/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transmute-industries%2Fcose/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/transmute-industries","download_url":"https://codeload.github.com/transmute-industries/cose/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245485690,"owners_count":20623237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cbor","cose","cwt","merkle-proof","merkle-tree","scitt","x509"],"created_at":"2024-12-03T11:09:27.655Z","updated_at":"2025-10-17T17:25:30.548Z","avatar_url":"https://github.com/transmute-industries.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cose\n\n[![CI](https://github.com/transmute-industries/cose/actions/workflows/ci.yml/badge.svg)](https://github.com/transmute-industries/cose/actions/workflows/ci.yml)\n\n## Usage\n\n🔥 This package is not stable or suitable for production use 🚧\n\n```bash\nnpm install '@transmute/cose'\n```\n\n```js\nconst cose = require(\"@transmute/cose\");\n```\n\n```ts\nimport * as cose from \"@transmute/cose\";\n```\n\n## Examples\n\n### COSE Receipts \u0026 Signature Transparency\n\n```ts\nimport crypto from \"crypto\";\nimport sqlite from \"better-sqlite3\";\nimport * as cose from \"@transmute/cose\";\n\nconst create_software_producer = async ({\n  website,\n  product,\n}: {\n  website: string;\n  product: string;\n}) =\u003e {\n  const privateKeyJwk = await cose.crypto.key.generate\u003c\n    \"ES256\",\n    \"application/jwk+json\"\n  \u003e({\n    type: \"application/jwk+json\",\n    algorithm: \"ES256\",\n  });\n  const publicKeyJwk = cose.public_from_private({\n    key: privateKeyJwk,\n    type: \"application/jwk+json\",\n  });\n  const signer = cose.hash.signer({\n    remote: cose.crypto.signer({\n      privateKeyJwk,\n    }),\n  });\n  const verifier = cose.detached.verifier({\n    resolver: {\n      resolve: async () =\u003e {\n        return publicKeyJwk;\n      },\n    },\n  });\n\n  return { website, product, signer, verifier, public_key: publicKeyJwk };\n};\n\nconst create_sqlite_log = (database: string) =\u003e {\n  const db = new sqlite(database);\n\n  db.prepare(\n    `\n  CREATE TABLE IF NOT EXISTS tiles \n  (id TEXT PRIMARY KEY, data BLOB);\n  \n  `\n  ).run();\n\n  db.prepare(\n    `\n  CREATE TABLE IF NOT EXISTS kv \n  (key text unique, value text);\n  `\n  ).run();\n\n  const hash_size = 32;\n  const tile_height = 2;\n\n  const log = new cose.TileLog({\n    tile_height,\n    hash_size,\n    read_tree_size: () =\u003e {\n      const rows = db\n        .prepare(\n          `\n        SELECT * FROM kv\n        WHERE key = 'tree_size'\n                `\n        )\n        .all();\n      const [row] = rows as { key: string; value: string }[];\n      try {\n        return parseInt(row.value, 10);\n      } catch (e) {\n        // console.error(e)\n        return 0;\n      }\n    },\n    update_tree_size: (new_tree_size: number) =\u003e {\n      try {\n        db.prepare(\n          `\n      INSERT OR REPLACE INTO kv (key, value)\n      VALUES( 'tree_size',\t'${new_tree_size}');\n              `\n        ).run();\n      } catch (e) {\n        // console.error(e)\n        // ignore errors\n      }\n    },\n\n    read_tree_root: function () {\n      const rows = db\n        .prepare(\n          `\n        SELECT * FROM kv\n        WHERE key = 'tree_root'\n                `\n        )\n        .all();\n      const [row] = rows as { key: string; value: string }[];\n      try {\n        return new Uint8Array(Buffer.from(row.value, \"hex\"));\n      } catch (e) {\n        return null;\n      }\n    },\n    update_tree_root: (new_tree_root: Uint8Array): void =\u003e {\n      try {\n        db.prepare(\n          `\n      INSERT OR REPLACE INTO kv (key, value)\n      VALUES( 'tree_root',\t'${Buffer.from(new_tree_root).toString(\"hex\")}');\n              `\n        ).run();\n      } catch (e) {\n        // ignore errors\n      }\n    },\n\n    read_tile: (tile: string): Uint8Array =\u003e {\n      const [base_tile] = tile.split(\".\");\n      // look for completed tiles first\n      for (let i = 4; i \u003e 0; i--) {\n        const tile_path = base_tile + \".\" + i;\n        const rows = db\n          .prepare(\n            `\n            SELECT * FROM tiles\n            WHERE id = '${tile_path}'\n                    `\n          )\n          .all();\n        if (rows.length) {\n          const [row] = rows as { id: string; data: Uint8Array }[];\n          return row.data;\n        }\n      }\n      return new Uint8Array(32);\n    },\n    update_tiles: function (\n      tile_path: string,\n      start: number,\n      end: number,\n      stored_hash: Uint8Array\n    ) {\n      if (end - start !== 32) {\n        // this hash was an intermediate of the tile\n        // so it will never be persisted\n        return null;\n      }\n      let tile_data = this.read_tile(tile_path);\n      if (tile_data.length \u003c end) {\n        const expanded_tile_data = new Uint8Array(tile_data.length + 32);\n        expanded_tile_data.set(tile_data);\n        tile_data = expanded_tile_data;\n      }\n      tile_data.set(stored_hash, start);\n      try {\n        db.prepare(\n          `\n      INSERT INTO tiles (id, data)\n      VALUES( '${tile_path}',\tx'${Buffer.from(tile_data).toString(\"hex\")}');\n              `\n        ).run();\n      } catch (e) {\n        // ignore errors\n      }\n      return tile_data;\n    },\n    hash_function: (data: Uint8Array) =\u003e {\n      return new Uint8Array(crypto.createHash(\"sha256\").update(data).digest());\n    },\n  });\n\n  return { db, log };\n};\n\nconst create_transparency_service = async ({\n  website,\n  database,\n}: {\n  website: string;\n  database: string;\n}) =\u003e {\n  const privateKeyJwk = await cose.crypto.key.generate\u003c\n    \"ES256\",\n    \"application/jwk+json\"\n  \u003e({\n    type: \"application/jwk+json\",\n    algorithm: \"ES256\",\n  });\n  const publicKeyJwk = cose.public_from_private({\n    key: privateKeyJwk,\n    type: \"application/jwk+json\",\n  });\n  const signer = cose.detached.signer({\n    remote: cose.crypto.signer({\n      privateKeyJwk,\n    }),\n  });\n  const verifier = cose.detached.verifier({\n    resolver: {\n      resolve: async () =\u003e {\n        return publicKeyJwk;\n      },\n    },\n  });\n  const { log, db } = create_sqlite_log(database);\n  const register_signed_statement = async (signed_statement: Uint8Array) =\u003e {\n    // registration policy goes here...\n    // for this test, we accept everything\n    const record = await cose.prepare_for_inclusion(signed_statement);\n    log.write_record(record);\n    const root = log.root();\n    const index = log.size();\n    const decoded = cose.cbor.decode(signed_statement);\n    const signed_statement_header = cose.cbor.decode(decoded.value[0]);\n    const signed_statement_claims = signed_statement_header.get(\n      cose.header.cwt_claims\n    );\n    const inclusion_proof = log.inclusion_proof(index, index - 1);\n    return signer.sign({\n      protectedHeader: cose.ProtectedHeader([\n        [cose.header.kid, publicKeyJwk.kid],\n        [cose.header.alg, cose.algorithm.es256],\n        [\n          cose.draft_headers.verifiable_data_structure,\n          cose.verifiable_data_structures.rfc9162_sha256,\n        ],\n        [\n          cose.header.cwt_claims,\n          cose.CWTClaims([\n            [cose.cwt_claims.iss, website], // issuer notary\n            // receipt subject is statement subject.\n            // ... could be receipts have different subject id\n            [\n              cose.cwt_claims.sub,\n              signed_statement_claims.get(cose.cwt_claims.sub),\n            ],\n          ]),\n        ],\n      ]),\n      unprotectedHeader: cose.UnprotectedHeader([\n        [\n          cose.draft_headers.verifiable_data_proofs,\n          cose.VerifiableDataStructureProofs([\n            [cose.rfc9162_sha256_proof_types.inclusion, [inclusion_proof]],\n          ]),\n        ],\n      ]),\n      payload: root,\n    });\n  };\n  return {\n    website,\n    db,\n    signer,\n    verifier,\n    log,\n    register_signed_statement,\n    public_key: publicKeyJwk,\n  };\n};\n\nconst software_producer = await create_software_producer({\n  website: \"https://green.example\",\n  product: \"https://green.example/cli@v1.2.3\",\n});\n\nconst blue_notary = await create_transparency_service({\n  website: \"https://blue.example\",\n  database: \"./tests/draft-ietf-scitt-architecture/blue.transparency.db\",\n});\n\nconst orange_notary = await create_transparency_service({\n  website: \"https://orange.example\",\n  database: \"./tests/draft-ietf-scitt-architecture/orange.transparency.db\",\n});\n\nconst statement = Buffer.from(\"large file that never moves over a network\");\n\nconst signed_statement = await software_producer.signer.sign({\n  protectedHeader: cose.ProtectedHeader([\n    [cose.header.kid, software_producer.public_key.kid],\n    [cose.header.alg, cose.algorithm.es256],\n    [cose.draft_headers.payload_hash_algorithm, cose.algorithm.sha_256],\n    [cose.draft_headers.payload_preimage_content_type, \"application/spdx+json\"],\n    [cose.draft_headers.payload_location, \"https://cloud.example/sbom/42\"],\n    [\n      cose.header.cwt_claims,\n      cose.CWTClaims([\n        [cose.cwt_claims.iss, software_producer.website],\n        [cose.cwt_claims.sub, software_producer.product],\n      ]),\n    ],\n  ]),\n  payload: statement,\n});\n\nconst blue_receipt = await blue_notary.register_signed_statement(\n  signed_statement\n);\nconst transparent_statement = await cose.add_receipt(\n  signed_statement,\n  blue_receipt\n);\nconst orange_receipt = await orange_notary.register_signed_statement(\n  transparent_statement\n);\nconst signed_statement_with_multiple_receipts = await cose.add_receipt(\n  transparent_statement,\n  orange_receipt\n);\nconst statement_hash = new Uint8Array(\n  await (await cose.crypto.subtle()).digest(\"SHA-256\", statement)\n);\nconst verification = await verify_transparent_statement(\n  statement_hash,\n  signed_statement_with_multiple_receipts,\n  {\n    tree_hasher: blue_notary.log.tree_hasher, // both logs use same tree algorithm\n    resolver: {\n      resolve: async (token: Buffer) =\u003e {\n        const decoded = cose.cbor.decode(token);\n        const header = cose.cbor.decode(decoded.value[0]);\n        const kid = header.get(cose.header.kid);\n        switch (kid) {\n          case software_producer.public_key.kid: {\n            return software_producer.public_key;\n          }\n          case blue_notary.public_key.kid: {\n            return blue_notary.public_key;\n          }\n          case orange_notary.public_key.kid: {\n            return orange_notary.public_key;\n          }\n          default: {\n            throw new Error(\"Unknown key: \" + kid);\n          }\n        }\n      },\n    },\n  }\n);\n```\n\n### COSE Receipts with CCF Profile\n\nThe library also supports the [COSE Receipts with CCF Profile](https://www.ietf.org/archive/id/draft-birkholz-cose-receipts-ccf-profile-04.txt) draft, which provides stronger tamper-evidence guarantees for transaction ledgers produced via Trusted Execution Environments (TEEs).\n\n```ts\nimport crypto from 'crypto'\nimport * as cose from '@transmute/cose'\n\n// Create a CCF leaf structure\nconst ccfLeaf: cose.CCFLeaf = {\n  internal_transaction_hash: new Uint8Array(32).fill(1),\n  internal_evidence: 'ccf-commit-evidence-12345',\n  data_hash: new Uint8Array(32).fill(2)\n}\n\n// Validate the leaf\nif (!cose.validateCCFLeaf(ccfLeaf)) {\n  throw new Error('Invalid CCF leaf')\n}\n\n// Create hash function\nconst hashFunction = (data: Uint8Array) =\u003e {\n  return new Uint8Array(crypto.createHash('sha256').update(data).digest())\n}\n\n// Create CCF inclusion proof\nconst ccfProof: cose.CCFInclusionProof = {\n  leaf: ccfLeaf,\n  path: [\n    { left: true, hash: new Uint8Array(32).fill(3) }\n  ]\n}\n\n// Compute Merkle root\nconst root = cose.computeCCFRoot(ccfProof, hashFunction)\n\n// Extract index from proof\nconst index = cose.extractIndexFromCCFProof(ccfProof)\n\n// CBOR encoding/decoding\nconst encodedLeaf = cose.encodeCCFLeaf(ccfLeaf)\nconst decodedLeaf = cose.decodeCCFLeaf(encodedLeaf)\n\nconst encodedProof = cose.encodeCCFInclusionProof(ccfProof)\nconst decodedProof = cose.decodeCCFInclusionProof(encodedProof)\n```\n\nSee `examples/ccf-profile-example.ts` for a complete working example.\n\nExample of a transparent signed statement with multiple receipts in extended diagnostic notation:\n\n#### Transparent Statement\n\n```edn\n/ cose-sign1 / 18([\n  / protected   / \u003c\u003c{\n    / key / 4 : \"vCl7UcS0ZZY99VpRthDc-0iUjLdfLtnmFqLJ2-Tt8N4\",\n    / algorithm / 1 : -7,  # ES256\n    / hash  / -6800 : -16, # SHA-256\n    / content  / -6802 : \"application/spdx+json\",\n    / location / -6801 : \"https://cloud.example/sbom/42\",\n    / claims / 15 : {\n      / issuer  / 1 : \"https://green.example\",\n      / subject / 2 : \"https://green.example/cli@v1.2.3\",\n    },\n  }\u003e\u003e,\n  / unprotected / {\n    / receipts / 394 : {\n      \u003c\u003c/ cose-sign1 / 18([\n        / protected   / \u003c\u003c{\n          / key / 4 : \"mxA4KiOkQFZ-dkLebSo3mLOEPR7rN8XtxkJe45xuyJk\",\n          / algorithm / 1 : -7,  # ES256\n          / notary    / 395 : 1, # RFC9162 SHA-256\n          / claims / 15 : {\n            / issuer  / 1 : \"https://blue.example\",\n            / subject / 2 : \"https://green.example/cli@v1.2.3\",\n          },\n        }\u003e\u003e,\n        / unprotected / {\n          / proofs / 396 : {\n            / inclusion / -1 : [\n              \u003c\u003c[\n                / size / 9, / leaf / 8,\n                / inclusion path /\n                h'7558a95f...e02e35d6'\n              ]\u003e\u003e\n            ],\n          },\n        },\n        / payload     / null,\n        / signature   / h'02d227ed...ccd3774f'\n      ])\u003e\u003e,\n      \u003c\u003c/ cose-sign1 / 18([\n        / protected   / \u003c\u003c{\n          / key / 4 : \"ajOkeBTJou_wPrlExLMw7L9OTCD5ZIOBYc-O6LESe9c\",\n          / algorithm / 1 : -7,  # ES256\n          / notary    / 395 : 1, # RFC9162 SHA-256\n          / claims / 15 : {\n            / issuer  / 1 : \"https://orange.example\",\n            / subject / 2 : \"https://green.example/cli@v1.2.3\",\n          },\n        }\u003e\u003e,\n        / unprotected / {\n          / proofs / 396 : {\n            / inclusion / -1 : [\n              \u003c\u003c[\n                / size / 6, / leaf / 5,\n                / inclusion path /\n                h'9352f974...4ffa7ce0',\n                h'54806f32...f007ea06'\n              ]\u003e\u003e\n            ],\n          },\n        },\n        / payload     / null,\n        / signature   / h'36581f38...a5581960'\n      ])\u003e\u003e\n    },\n  },\n  / payload     / h'0167c57c...deeed6d4',\n  / signature   / h'2544f2ed...5840893b'\n])\n\n```\n\n### COSE RFCs\n\n- [RFC9360 - Header Parameters for Carrying and Referencing X.509 Certificates](https://datatracker.ietf.org/doc/rfc9360/)\n- [RFC9052 - Structures and Process](https://datatracker.ietf.org/doc/html/rfc9052)\n- [RFC9053 - Initial Algorithms](https://datatracker.ietf.org/doc/html/rfc9053)\n\n### COSE Drafts\n\n- [COSE Receipts](https://datatracker.ietf.org/doc/draft-ietf-cose-merkle-tree-proofs/)\n- [COSE Hash Envelope](https://datatracker.ietf.org/doc/draft-ietf-cose-hash-envelope/)\n- [COSE HPKE](https://datatracker.ietf.org/doc/draft-ietf-cose-hpke/)\n\n### SCITT Drafts\n\n- [SCITT Architecture](https://datatracker.ietf.org/doc/draft-ietf-scitt-architecture/)\n\n## Develop\n\n```bash\nnpm i\nnpm t\nnpm run lint\nnpm run build\n```\n\n\u003cimg src=\"./transmute-banner.png\" /\u003e\n\n#### [Questions? Contact Transmute](https://transmute.typeform.com/to/RshfIw?typeform-source=cose)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransmute-industries%2Fcose","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftransmute-industries%2Fcose","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransmute-industries%2Fcose/lists"}