├── docs ├── authors.rst ├── history.rst ├── contributing.rst ├── .gitignore ├── usage.rst ├── index.rst ├── api_reference.rst ├── installation.rst ├── Makefile ├── make.bat └── conf.py ├── tests ├── __init__.py ├── test_multicodec.py ├── test_code.py └── test_serialization.py ├── codecov.yaml ├── AUTHORS.rst ├── newsfragments ├── 23.feature.rst ├── 25.feature.rst ├── 21.internal.rst ├── README.md └── validate_files.py ├── HISTORY.rst ├── MANIFEST.in ├── .github ├── workflows │ ├── stale.yml │ ├── generated-pr.yml │ └── tox.yml └── ISSUE_TEMPLATE.md ├── .editorconfig ├── tox.ini ├── .readthedocs.yaml ├── ruff.toml ├── .pre-commit-config.yaml ├── multicodec ├── exceptions.py ├── __init__.py ├── multicodec.py ├── serialization.py ├── code.py ├── constants.py └── code_table.py ├── .gitignore ├── LICENSE ├── Makefile ├── tools ├── update-table.py └── gen_code_table.py ├── README.rst ├── CONTRIBUTING.rst └── pyproject.toml /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/history.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../HISTORY.rst 2 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Unit test package for multicodec.""" 2 | -------------------------------------------------------------------------------- /codecov.yaml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: header, changes, diff, uncovered 3 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /multicodec.rst 2 | /multicodec.*.rst 3 | /modules.rst 4 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | Contributors 2 | ============ 3 | 4 | - Dhruv Baldawa (@dhruvbaldawa) 5 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Usage 3 | ===== 4 | 5 | To use py-multicodec in a project:: 6 | 7 | import multicodec 8 | -------------------------------------------------------------------------------- /newsfragments/23.feature.rst: -------------------------------------------------------------------------------- 1 | Added Codec constants, List all codecs function and Reserved range support for Codec management. 2 | -------------------------------------------------------------------------------- /newsfragments/25.feature.rst: -------------------------------------------------------------------------------- 1 | Added serialization with JSON/raw codecs, custom codec interface, encode/decode functions, and a dynamic codec registry. 2 | -------------------------------------------------------------------------------- /newsfragments/21.internal.rst: -------------------------------------------------------------------------------- 1 | Modernized repository infrastructure to use pyproject.toml, GitHub Actions CI/CD, Python 3.10+ support, ruff for linting/formatting, and pre-commit hooks. 2 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | History 3 | ======= 4 | 5 | 0.1.3 (2018-10-20) 6 | ------------------ 7 | 8 | * Handle exception when the varint is invalid 9 | 10 | 0.1.0 (2017-09-03) 11 | ------------------ 12 | 13 | * First release on PyPI. 14 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.rst 6 | 7 | recursive-include tests * 8 | recursive-exclude * __pycache__ 9 | recursive-exclude * *.py[co] 10 | 11 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif 12 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close Stale Issues 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1 15 | -------------------------------------------------------------------------------- /.github/workflows/generated-pr.yml: -------------------------------------------------------------------------------- 1 | name: Close Generated PRs 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.bat] 14 | indent_style = tab 15 | end_of_line = crlf 16 | 17 | [LICENSE] 18 | insert_final_newline = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | 3 | 4 | Table of contents 5 | ================= 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | 10 | installation 11 | usage 12 | api_reference 13 | modules 14 | contributing 15 | authors 16 | history 17 | 18 | Indices and tables 19 | ================== 20 | 21 | * :ref:`genindex` 22 | * :ref:`modindex` 23 | * :ref:`search` 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * python-multicodec version: 2 | * Python version: 3 | * Operating System: 4 | 5 | ### Description 6 | 7 | Describe what you were trying to get done. 8 | Tell us what happened, what went wrong, and what you expected to happen. 9 | 10 | ### What I Did 11 | 12 | ``` 13 | Paste the command(s) you ran and the output. 14 | If there was a crash, please include the traceback here. 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/api_reference.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ------------- 3 | 4 | .. py:currentmodule:: multicodec 5 | 6 | .. autofunction:: add_prefix 7 | :no-index: 8 | 9 | .. autofunction:: remove_prefix 10 | :no-index: 11 | 12 | .. autofunction:: get_codec 13 | :no-index: 14 | 15 | .. autofunction:: get_prefix 16 | :no-index: 17 | 18 | .. autofunction:: is_codec 19 | :no-index: 20 | 21 | .. autofunction:: extract_prefix 22 | :no-index: 23 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist= 3 | py{310,311,312,313,314}-core 4 | py{310,311,312,313,314}-lint 5 | docs 6 | 7 | [testenv] 8 | extras= 9 | dev 10 | commands= 11 | core: pytest {posargs:tests} 12 | 13 | [testenv:py{310,311,312,313,314}-lint] 14 | deps=pre-commit 15 | commands= 16 | ; pre-commit install 17 | pre-commit run --all-files --show-diff-on-failure 18 | 19 | [testenv:docs] 20 | commands = 21 | make docs-ci 22 | allowlist_externals= 23 | make 24 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | version: 2 5 | 6 | build: 7 | os: ubuntu-24.04 8 | tools: 9 | python: "3.10" 10 | 11 | sphinx: 12 | configuration: docs/conf.py 13 | fail_on_warning: true 14 | 15 | python: 16 | install: 17 | - method: pip 18 | path: . 19 | extra_requirements: 20 | - dev 21 | 22 | formats: 23 | - epub 24 | - htmlzip 25 | -------------------------------------------------------------------------------- /ruff.toml: -------------------------------------------------------------------------------- 1 | line-length = 120 2 | indent-width = 4 3 | exclude = [ 4 | ".eggs", 5 | ".git", 6 | ".ruff_cache", 7 | ".tox", 8 | ".venv", 9 | "venv", 10 | "build", 11 | "dist", 12 | "docs", 13 | "*.egg", 14 | ] 15 | 16 | [lint] 17 | select = ["E", "F", "W", "I", "RUF"] 18 | dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" 19 | 20 | [format] 21 | quote-style = "double" 22 | indent-style = "space" 23 | skip-magic-trailing-comma = false 24 | line-ending = "lf" 25 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: '.project-template|docs/conf.py|.*pb2\..*' 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v5.0.0 5 | hooks: 6 | - id: check-yaml 7 | - id: check-toml 8 | - id: end-of-file-fixer 9 | - id: trailing-whitespace 10 | - repo: https://github.com/asottile/pyupgrade 11 | rev: v3.15.0 12 | hooks: 13 | - id: pyupgrade 14 | args: [--py310-plus] 15 | - repo: https://github.com/astral-sh/ruff-pre-commit 16 | rev: v0.11.10 17 | hooks: 18 | - id: ruff 19 | args: [--fix, --exit-non-zero-on-fix] 20 | - id: ruff-format 21 | - repo: local 22 | hooks: 23 | - id: mypy-local 24 | name: run mypy with all dev dependencies present 25 | entry: mypy -p multicodec 26 | language: system 27 | always_run: true 28 | pass_filenames: false 29 | require_serial: false 30 | -------------------------------------------------------------------------------- /multicodec/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Exception classes for multicodec. 3 | 4 | This module defines the exception hierarchy for multicodec operations, 5 | providing specific error types for different failure modes. 6 | """ 7 | 8 | 9 | class MulticodecError(Exception): 10 | """Base exception for all multicodec-related errors.""" 11 | 12 | pass 13 | 14 | 15 | class CodecError(MulticodecError): 16 | """Base exception for codec-related errors.""" 17 | 18 | pass 19 | 20 | 21 | class EncodeError(CodecError): 22 | """Raised when encoding fails.""" 23 | 24 | pass 25 | 26 | 27 | class DecodeError(CodecError): 28 | """Raised when decoding fails.""" 29 | 30 | pass 31 | 32 | 33 | class UnknownCodecError(CodecError): 34 | """Raised when an unknown codec is requested.""" 35 | 36 | pass 37 | 38 | 39 | __all__ = [ 40 | "CodecError", 41 | "DecodeError", 42 | "EncodeError", 43 | "MulticodecError", 44 | "UnknownCodecError", 45 | ] 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | venv/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | # pyenv python configuration file 63 | .python-version 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2017, Dhruv Baldawa 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /newsfragments/README.md: -------------------------------------------------------------------------------- 1 | This directory collects "newsfragments": short files that each contain 2 | a snippet of ReST-formatted text that will be added to the next 3 | release notes. This should be a description of aspects of the change 4 | (if any) that are relevant to users. (This contrasts with the 5 | commit message and PR description, which are a description of the change as 6 | relevant to people working on the code itself.) 7 | 8 | Each file should be named like `..rst`, where 9 | `` is an issue number, and `` is one of: 10 | 11 | - `breaking` 12 | - `bugfix` 13 | - `deprecation` 14 | - `docs` 15 | - `feature` 16 | - `internal` 17 | - `misc` 18 | - `performance` 19 | - `removal` 20 | 21 | So for example: `123.feature.rst`, `456.bugfix.rst` 22 | 23 | Files should be placed directly in this `newsfragments/` directory (not in subdirectories). 24 | 25 | If the PR fixes an issue, use that number here. If there is no issue, 26 | then open up the PR first and use the PR number for the newsfragment. 27 | 28 | Note that the `towncrier` tool will automatically 29 | reflow your text, so don't try to do any fancy formatting. Run 30 | `towncrier build --draft` to get a preview of what the release notes entry 31 | will look like in the final release notes. 32 | -------------------------------------------------------------------------------- /newsfragments/validate_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Towncrier silently ignores files that do not match the expected ending. 4 | # We use this script to ensure we catch these as errors in CI. 5 | 6 | import pathlib 7 | import sys 8 | 9 | ALLOWED_EXTENSIONS = { 10 | ".breaking.rst", 11 | ".bugfix.rst", 12 | ".deprecation.rst", 13 | ".docs.rst", 14 | ".feature.rst", 15 | ".internal.rst", 16 | ".misc.rst", 17 | ".performance.rst", 18 | ".removal.rst", 19 | } 20 | 21 | ALLOWED_FILES = { 22 | "validate_files.py", 23 | "README.md", 24 | } 25 | 26 | THIS_DIR = pathlib.Path(__file__).parent 27 | 28 | num_args = len(sys.argv) - 1 29 | assert num_args in {0, 1} 30 | if num_args == 1: 31 | assert sys.argv[1] in ("is-empty",) 32 | 33 | for fragment_file in THIS_DIR.iterdir(): 34 | if fragment_file.name in ALLOWED_FILES: 35 | continue 36 | elif num_args == 0: 37 | full_extension = "".join(fragment_file.suffixes) 38 | if full_extension not in ALLOWED_EXTENSIONS: 39 | raise Exception(f"Unexpected file: {fragment_file}") 40 | elif sys.argv[1] == "is-empty": 41 | raise Exception(f"Unexpected file: {fragment_file}") 42 | else: 43 | raise RuntimeError(f"Strange: arguments {sys.argv} were validated, but not found") 44 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Installation 5 | ============ 6 | 7 | 8 | Stable release 9 | -------------- 10 | 11 | To install py-multicodec, run this command in your terminal: 12 | 13 | .. code-block:: console 14 | 15 | $ pip install py-multicodec 16 | 17 | This is the preferred method to install py-multicodec, as it will always install the most recent stable release. 18 | 19 | If you don't have `pip`_ installed, this `Python installation guide`_ can guide 20 | you through the process. 21 | 22 | .. _pip: https://pip.pypa.io 23 | .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ 24 | 25 | 26 | From sources 27 | ------------ 28 | 29 | The sources for py-multicodec can be downloaded from the `Github repo`_. 30 | 31 | You can either clone the public repository: 32 | 33 | .. code-block:: console 34 | 35 | $ git clone git://github.com/multiformats/py-multicodec 36 | 37 | Or download the `tarball`_: 38 | 39 | .. code-block:: console 40 | 41 | $ curl -OL https://github.com/multiformats/py-multicodec/tarball/master 42 | 43 | Once you have a copy of the source, you can install it with: 44 | 45 | .. code-block:: console 46 | 47 | $ pip install -e . 48 | 49 | For development, install with dev dependencies: 50 | 51 | .. code-block:: console 52 | 53 | $ pip install -e ".[dev]" 54 | 55 | 56 | .. _Github repo: https://github.com/multiformats/py-multicodec 57 | .. _tarball: https://github.com/multiformats/py-multicodec/tarball/master 58 | -------------------------------------------------------------------------------- /tests/test_multicodec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Tests for `multicodec` package.""" 3 | 4 | import pytest 5 | import varint 6 | 7 | from multicodec import add_prefix, extract_prefix, get_codec, get_prefix, is_codec, remove_prefix 8 | from multicodec.constants import CODECS 9 | 10 | INVALID_CODECS = ( 11 | ("abc", 0x101), 12 | ("def", 0xFFFFF), 13 | ("deadbeef", 0xDEADBEEF), 14 | ) 15 | 16 | 17 | @pytest.mark.parametrize("multicodec,prefix", CODECS.items()) 18 | def test_verify_prefix_complete(multicodec, prefix): 19 | data = b"testbytesbuffer" 20 | prefix_int = prefix["prefix"] 21 | prefixed_data = add_prefix(multicodec, data) 22 | 23 | assert is_codec(multicodec) 24 | assert get_codec(prefixed_data) == multicodec 25 | assert remove_prefix(prefixed_data) == data 26 | assert extract_prefix(prefixed_data) == prefix_int 27 | 28 | 29 | @pytest.mark.parametrize("multicodec,_", INVALID_CODECS) 30 | def test_get_prefix_invalid_prefix(multicodec, _): 31 | with pytest.raises(ValueError) as excinfo: 32 | get_prefix(multicodec) 33 | assert "multicodec is not supported" in str(excinfo.value) 34 | 35 | 36 | @pytest.mark.parametrize("_,prefix", INVALID_CODECS) 37 | def test_get_codec_invalid_prefix(_, prefix): 38 | prefix_bytes = varint.encode(prefix) 39 | with pytest.raises(ValueError) as excinfo: 40 | get_codec(prefix_bytes) 41 | assert "not present in the lookup table" in str(excinfo.value) 42 | 43 | 44 | @pytest.mark.parametrize("multicodec,_", INVALID_CODECS) 45 | def test_is_codec_invalid_prefix(multicodec, _): 46 | assert not is_codec(multicodec) 47 | 48 | 49 | def test_extract_prefix_invalid_varint(): 50 | with pytest.raises(ValueError) as excinfo: 51 | extract_prefix(b"\xff") 52 | assert "incorrect varint provided" in str(excinfo.value) 53 | -------------------------------------------------------------------------------- /multicodec/__init__.py: -------------------------------------------------------------------------------- 1 | """Top-level package for py-multicodec.""" 2 | 3 | __author__ = """Dhruv Baldawa""" 4 | __email__ = "dhruv@dhruvb.com" 5 | __version__ = "0.2.1" 6 | 7 | # Core Code type 8 | from .code import ( 9 | RESERVED_END, 10 | RESERVED_START, 11 | Code, 12 | is_reserved, 13 | known_codes, 14 | ) 15 | 16 | # Exceptions 17 | from .exceptions import ( 18 | CodecError, 19 | DecodeError, 20 | EncodeError, 21 | MulticodecError, 22 | UnknownCodecError, 23 | ) 24 | 25 | # Original multicodec functions 26 | from .multicodec import add_prefix, extract_prefix, get_codec, get_prefix, is_codec, remove_prefix 27 | 28 | # Serialization support 29 | from .serialization import ( 30 | Codec, 31 | JSONCodec, 32 | RawCodec, 33 | decode, 34 | encode, 35 | get_registered_codec, 36 | is_codec_registered, 37 | json_codec, 38 | list_registered_codecs, 39 | raw_codec, 40 | register_codec, 41 | unregister_codec, 42 | ) 43 | 44 | __all__ = [ 45 | # Constants 46 | "RESERVED_END", 47 | "RESERVED_START", 48 | # Code type 49 | "Code", 50 | # Serialization base classes 51 | "Codec", 52 | "CodecError", 53 | "DecodeError", 54 | "EncodeError", 55 | # Built-in codecs 56 | "JSONCodec", 57 | # Exceptions 58 | "MulticodecError", 59 | "RawCodec", 60 | "UnknownCodecError", 61 | # Original functions 62 | "add_prefix", 63 | "decode", 64 | # Serialization functions 65 | "encode", 66 | "extract_prefix", 67 | "get_codec", 68 | "get_prefix", 69 | "get_registered_codec", 70 | "is_codec", 71 | "is_codec_registered", 72 | "is_reserved", 73 | "json_codec", 74 | "known_codes", 75 | "list_registered_codecs", 76 | "raw_codec", 77 | "register_codec", 78 | "remove_prefix", 79 | "unregister_codec", 80 | ] 81 | -------------------------------------------------------------------------------- /.github/workflows/tox.yml: -------------------------------------------------------------------------------- 1 | name: Run tox 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | defaults: 10 | run: 11 | shell: bash 12 | 13 | jobs: 14 | tox: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] 19 | toxenv: [core, lint] 20 | include: 21 | - python-version: "3.10" 22 | toxenv: docs 23 | fail-fast: false 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: actions/setup-python@v5 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | - name: Set TOXENV 30 | run: | 31 | if [[ "${{ matrix.toxenv }}" == "docs" ]]; then 32 | echo "TOXENV=docs" >> "$GITHUB_ENV" 33 | else 34 | python_version="${{ matrix.python-version }}" 35 | echo "TOXENV=py${python_version//./}-${{ matrix.toxenv }}" >> "$GITHUB_ENV" 36 | fi 37 | - run: | 38 | python -m pip install --upgrade pip 39 | python -m pip install "tox>=4.10" 40 | - run: | 41 | python -m tox run -e "$TOXENV" -r 42 | 43 | windows: 44 | runs-on: windows-latest 45 | strategy: 46 | matrix: 47 | python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] 48 | toxenv: [core, lint] 49 | fail-fast: false 50 | steps: 51 | - uses: actions/checkout@v4 52 | - name: Set up Python ${{ matrix.python-version }} 53 | uses: actions/setup-python@v5 54 | with: 55 | python-version: ${{ matrix.python-version }} 56 | - name: Set TOXENV 57 | shell: bash 58 | run: | 59 | python_version="${{ matrix.python-version }}" 60 | echo "TOXENV=py${python_version//./}-${{ matrix.toxenv }}" >> "$GITHUB_ENV" 61 | - name: Install dependencies 62 | run: | 63 | python -m pip install --upgrade pip 64 | python -m pip install "tox>=4.10" 65 | - name: Test with tox 66 | shell: bash 67 | run: | 68 | python -m tox run -e "$TOXENV" -r 69 | -------------------------------------------------------------------------------- /multicodec/multicodec.py: -------------------------------------------------------------------------------- 1 | import varint 2 | 3 | from .constants import CODE_TABLE, NAME_TABLE 4 | 5 | 6 | def extract_prefix(bytes_: bytes) -> int: 7 | """ 8 | Extracts the prefix from multicodec prefixed data 9 | 10 | :param bytes bytes_: multicodec prefixed data 11 | :return: prefix for the prefixed data 12 | :rtype: int 13 | :raises ValueError: when incorrect varint is provided 14 | """ 15 | try: 16 | return varint.decode_bytes(bytes_) 17 | except TypeError as err: 18 | raise ValueError("incorrect varint provided") from err 19 | 20 | 21 | def get_prefix(multicodec: str) -> bytes: 22 | """ 23 | Returns prefix for a given multicodec 24 | 25 | :param str multicodec: multicodec codec name 26 | :return: the prefix for the given multicodec 27 | :rtype: bytes 28 | :raises ValueError: if an invalid multicodec name is provided 29 | """ 30 | try: 31 | prefix = varint.encode(NAME_TABLE[multicodec]) 32 | except KeyError as err: 33 | raise ValueError(f"{multicodec} multicodec is not supported.") from err 34 | return prefix 35 | 36 | 37 | def add_prefix(multicodec: str, bytes_: bytes) -> bytes: 38 | """ 39 | Adds multicodec prefix to the given bytes input 40 | 41 | :param str multicodec: multicodec to use for prefixing 42 | :param bytes bytes_: data to prefix 43 | :return: prefixed byte data 44 | :rtype: bytes 45 | """ 46 | prefix = get_prefix(multicodec) 47 | return b"".join([prefix, bytes_]) 48 | 49 | 50 | def remove_prefix(bytes_: bytes) -> bytes: 51 | """ 52 | Removes prefix from a prefixed data 53 | 54 | :param bytes bytes_: multicodec prefixed data bytes 55 | :return: prefix removed data bytes 56 | :rtype: bytes 57 | """ 58 | prefix_int = extract_prefix(bytes_) 59 | prefix = varint.encode(prefix_int) 60 | return bytes_[len(prefix) :] 61 | 62 | 63 | def get_codec(bytes_: bytes) -> str: 64 | """ 65 | Gets the codec used for prefix the multicodec prefixed data 66 | 67 | :param bytes bytes_: multicodec prefixed data bytes 68 | :return: name of the multicodec used to prefix 69 | :rtype: str 70 | """ 71 | prefix = extract_prefix(bytes_) 72 | try: 73 | return CODE_TABLE[prefix] 74 | except KeyError as err: 75 | raise ValueError(f"Prefix {prefix} not present in the lookup table") from err 76 | 77 | 78 | def is_codec(name: str) -> bool: 79 | """ 80 | Check if the codec is a valid codec or not 81 | 82 | :param str name: name of the codec 83 | :return: if the codec is valid or not 84 | :rtype: bool 85 | """ 86 | return name in NAME_TABLE 87 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc clean-build docs clean help pr 2 | define BROWSER_PYSCRIPT 3 | import os, webbrowser, sys 4 | try: 5 | from urllib import pathname2url 6 | except: 7 | from urllib.request import pathname2url 8 | 9 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 10 | endef 11 | export BROWSER_PYSCRIPT 12 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 13 | 14 | help: 15 | @echo "Available commands:" 16 | @echo "clean-build - remove build artifacts" 17 | @echo "clean-pyc - remove Python file artifacts" 18 | @echo "clean-test - remove test artifacts" 19 | @echo "clean - run clean-build, clean-pyc, and clean-test" 20 | @echo "setup - install development requirements" 21 | @echo "fix - fix formatting & linting issues with ruff" 22 | @echo "lint - run pre-commit hooks on all files" 23 | @echo "typecheck - run mypy type checking" 24 | @echo "test - run tests quickly with the default Python" 25 | @echo "coverage - run tests with coverage report" 26 | @echo "docs-ci - generate docs for CI" 27 | @echo "docs - generate docs and open in browser" 28 | @echo "servedocs - serve docs with live reload" 29 | @echo "dist - build package and show contents" 30 | @echo "pr - run clean, lint, and test (everything needed before creating a PR)" 31 | 32 | clean: clean-build clean-pyc clean-test 33 | 34 | clean-build: 35 | rm -fr build/ 36 | rm -fr dist/ 37 | rm -fr .eggs/ 38 | find . -name '*.egg-info' -exec rm -fr {} + 39 | find . -name '*.egg' -exec rm -rf {} + 40 | 41 | clean-pyc: 42 | find . -name '*.pyc' -exec rm -f {} + 43 | find . -name '*.pyo' -exec rm -f {} + 44 | find . -name '*~' -exec rm -f {} + 45 | find . -name '__pycache__' -exec rm -fr {} + 46 | 47 | clean-test: 48 | rm -fr .tox/ 49 | rm -fr .mypy_cache 50 | rm -fr .ruff_cache 51 | rm -f .coverage 52 | rm -fr htmlcov/ 53 | 54 | setup: 55 | pip install -e ".[dev]" 56 | 57 | lint: 58 | pre-commit run --all-files 59 | 60 | fix: 61 | python -m ruff check --fix 62 | 63 | typecheck: 64 | pre-commit run mypy-local --all-files 65 | 66 | test: 67 | python -m pytest tests 68 | 69 | coverage: 70 | coverage run --source multicodec -m pytest tests 71 | coverage report -m 72 | coverage html 73 | $(BROWSER) htmlcov/index.html 74 | 75 | docs-ci: 76 | rm -f docs/multicodec.rst 77 | rm -f docs/modules.rst 78 | sphinx-apidoc -o docs/ multicodec 79 | $(MAKE) -C docs clean 80 | mkdir -p docs/_static 81 | $(MAKE) -C docs html SPHINXOPTS="-W" 82 | 83 | docs: docs-ci 84 | $(BROWSER) docs/_build/html/index.html 85 | 86 | servedocs: docs 87 | watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . 88 | 89 | dist: clean 90 | python -m build 91 | ls -l dist 92 | 93 | pr: clean fix lint typecheck test 94 | @echo "PR preparation complete! All checks passed." 95 | -------------------------------------------------------------------------------- /tools/update-table.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import csv 4 | import os 5 | import sys 6 | from collections import OrderedDict 7 | 8 | # This is relative to where this script resides 9 | # Though you can also define an absolute path 10 | DEFAULT_OUTPUT_DIR = "../multicodec" 11 | 12 | # The header of the generated files 13 | HEADER = """\ 14 | # THIS FILE IS GENERATED, DO NO EDIT MANUALLY 15 | # For more information see the README.md 16 | 17 | """ 18 | 19 | FOOTER = """\ 20 | 21 | NAME_TABLE = {name: value['prefix'] for name, value in CODECS.items()} 22 | CODE_TABLE = {value['prefix']: name for name, value in CODECS.items()} 23 | """ 24 | 25 | 26 | def padded_hex(hexstring): 27 | """Creates a padded (starting with a 0 if odd) hex string""" 28 | number = int(row["code"], 16) 29 | hexbytes = f"{number:x}" 30 | if len(hexbytes) % 2: 31 | prefix = "0x0" 32 | else: 33 | prefix = "0x" 34 | return prefix + hexbytes 35 | 36 | 37 | def unique_code(codecs): 38 | """Returns a list where every code exists only one. 39 | 40 | The first item in the list is taken 41 | """ 42 | seen = [] 43 | unique = [] 44 | for codec in codecs: 45 | if "code" in codec: 46 | if codec["code"] in seen: 47 | continue 48 | else: 49 | seen.append(codec["code"]) 50 | unique.append(codec) 51 | return unique 52 | 53 | 54 | # Preserve the order from earlier versions. New tags are appended 55 | parsed = OrderedDict( 56 | [ 57 | ("serialization", []), 58 | ("multiformat", []), 59 | ("multihash", []), 60 | ("multiaddr", []), 61 | ("ipld", []), 62 | ("namespace", []), 63 | ("key", []), 64 | ("holochain", []), 65 | ] 66 | ) 67 | 68 | maxlen = 0 69 | 70 | multicodec_reader = csv.DictReader(sys.stdin, skipinitialspace=True) 71 | for row in multicodec_reader: 72 | code = padded_hex(row["code"]) 73 | name_const = row["name"].upper().replace("-", "_") 74 | name_human = row["name"] 75 | tag = row["tag"] 76 | value = {"const": name_const, "human": name_human, "code": code} 77 | if tag not in parsed: 78 | parsed[tag] = [] 79 | 80 | parsed[tag].append(value) 81 | 82 | if maxlen < len(name_human): 83 | maxlen = len(name_human) 84 | 85 | tools_dir = os.path.dirname(os.path.abspath(__file__)) 86 | output_dir = os.path.join(tools_dir, DEFAULT_OUTPUT_DIR) 87 | 88 | print_file = os.path.join(output_dir, "constants.py") 89 | with open(print_file, "w") as ff: 90 | ff.write(HEADER) 91 | ff.write("CODECS = {") 92 | for _tagindex, (tag, codecs) in enumerate(parsed.items()): 93 | ff.write(f"\n # {tag}\n") 94 | unique = unique_code(codecs) 95 | for _codecindex, codec in enumerate(unique): 96 | name = "'{human}':".format(human=codec["human"]).ljust(maxlen + 4) 97 | value = "{{'prefix': {code}, }},\n".format(code=codec["code"]) 98 | ff.write(" " + name + value) 99 | ff.write("}\n") 100 | ff.write(FOOTER) 101 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | py-multicodec 2 | ------------- 3 | 4 | .. image:: https://img.shields.io/pypi/v/py-multicodec.svg 5 | :target: https://pypi.python.org/pypi/py-multicodec 6 | 7 | .. image:: https://github.com/multiformats/py-multicodec/actions/workflows/tox.yml/badge.svg?branch=master 8 | :target: https://github.com/multiformats/py-multicodec/actions/workflows/tox.yml 9 | 10 | .. image:: https://codecov.io/gh/multiformats/py-multicodec/branch/master/graph/badge.svg 11 | :target: https://codecov.io/gh/multiformats/py-multicodec 12 | 13 | .. image:: https://readthedocs.org/projects/py-multicodec/badge/?version=stable 14 | :target: https://py-multicodec.readthedocs.io/en/stable/?badge=stable 15 | :alt: Documentation Status 16 | 17 | 18 | `Multicodec `_ implementation in Python 19 | 20 | ``multicodec`` *is a self-describing multiformat*, it wraps other formats with a tiny bit of self-description. 21 | 22 | A multicodec identifier is both a varint and the code identifying the following data, this means that the most 23 | significant bit of every multicodec code is reserved to signal the continuation. 24 | 25 | You can check `the table here `_ for the list of supported codecs by ``py-multicodec``. 26 | 27 | * Free software: MIT license 28 | * Documentation: https://py-multicodec.readthedocs.io. 29 | * Python versions: 3.10, 3.11, 3.12, 3.13, 3.14 30 | 31 | 32 | Installation 33 | ============ 34 | 35 | .. code-block:: shell 36 | 37 | $ pip install py-multicodec 38 | 39 | 40 | Sample Usage 41 | ============ 42 | 43 | .. code-block:: python 44 | 45 | >>> from multicodec import add_prefix, remove_prefix, get_codec 46 | >>> # adding a prefix to existing data 47 | >>> add_prefix('sha2-256', b'EiC5TSe5k00') 48 | b'\x12EiC5TSe5k00' 49 | >>> # removing prefix from prefixed data 50 | >>> remove_prefix(b'\x12EiC5TSe5k00') 51 | EiC5TSe5k00 52 | >>> # get codec used to prefix the prefixed data 53 | >>> get_codec(b'\x12EiC5TSe5k00') 54 | 'sha2-256' 55 | 56 | Code Management 57 | =============== 58 | 59 | In addition to the basic prefix operations, py-multicodec provides type-safe codec 60 | management functionality: 61 | 62 | .. code-block:: python 63 | 64 | >>> from multicodec import Code, known_codes 65 | >>> from multicodec.code_table import SHA2_256, DAG_CBOR 66 | 67 | >>> # Use named constants for type-safe codec handling 68 | >>> code = SHA2_256 69 | >>> str(code) 70 | 'sha2-256' 71 | >>> int(code) 72 | 18 73 | 74 | >>> # Create Code from string (name or hex) 75 | >>> code = Code.from_string("sha2-256") 76 | >>> code = Code.from_string("0x12") # hex also works 77 | 78 | >>> # List all known codecs 79 | >>> all_codes = known_codes() 80 | >>> len(all_codes) 81 | 460 82 | 83 | Updating the lookup table 84 | ========================== 85 | 86 | Updating the lookup table is done with a script. The source of truth is the 87 | `multicodec default table `_. 88 | Update the table with running: 89 | 90 | .. code-block:: shell 91 | 92 | $ curl -X GET https://raw.githubusercontent.com/multiformats/multicodec/master/table.csv | ./tools/update-table.py 93 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Contributing 5 | ============ 6 | 7 | Contributions are welcome, and they are greatly appreciated! Every 8 | little bit helps, and credit will always be given. 9 | 10 | You can contribute in many ways: 11 | 12 | Types of Contributions 13 | ---------------------- 14 | 15 | Report Bugs 16 | ~~~~~~~~~~~ 17 | 18 | Report bugs at https://github.com/multiformats/py-multicodec/issues. 19 | 20 | If you are reporting a bug, please include: 21 | 22 | * Your operating system name and version. 23 | * Any details about your local setup that might be helpful in troubleshooting. 24 | * Detailed steps to reproduce the bug. 25 | 26 | Fix Bugs 27 | ~~~~~~~~ 28 | 29 | Look through the GitHub issues for bugs. Anything tagged with "bug" 30 | and "help wanted" is open to whoever wants to implement it. 31 | 32 | Implement Features 33 | ~~~~~~~~~~~~~~~~~~ 34 | 35 | Look through the GitHub issues for features. Anything tagged with "enhancement" 36 | and "help wanted" is open to whoever wants to implement it. 37 | 38 | Write Documentation 39 | ~~~~~~~~~~~~~~~~~~~ 40 | 41 | py-multicodec could always use more documentation, whether as part of the 42 | official py-multicodec docs, in docstrings, or even on the web in blog posts, 43 | articles, and such. 44 | 45 | Submit Feedback 46 | ~~~~~~~~~~~~~~~ 47 | 48 | The best way to send feedback is to file an issue at https://github.com/multiformats/py-multicodec/issues. 49 | 50 | If you are proposing a feature: 51 | 52 | * Explain in detail how it would work. 53 | * Keep the scope as narrow as possible, to make it easier to implement. 54 | * Remember that this is a volunteer-driven project, and that contributions 55 | are welcome :) 56 | 57 | Get Started! 58 | ------------ 59 | 60 | Ready to contribute? Here's how to set up `multicodec` for local development. 61 | 62 | 1. Fork the `py-multicodec` repo on GitHub. 63 | 2. Clone your fork locally:: 64 | 65 | $ git clone git@github.com:your_name_here/py-multicodec.git 66 | 67 | 3. Install your local copy into a virtualenv. Create and activate a virtual environment:: 68 | 69 | $ python -m venv venv 70 | $ source venv/bin/activate # On Windows: venv\Scripts\activate 71 | $ pip install -e ".[dev]" 72 | 73 | 4. Install pre-commit hooks (optional but recommended):: 74 | 75 | $ pre-commit install 76 | 77 | This will set up git hooks to automatically run linting and formatting checks 78 | before each commit. 79 | 80 | 5. Create a branch for local development:: 81 | 82 | $ git checkout -b name-of-your-bugfix-or-feature 83 | 84 | Now you can make your changes locally. 85 | 86 | 6. When you're done making changes, check that your changes pass linting and the 87 | tests, including testing other Python versions with tox:: 88 | 89 | $ make lint 90 | $ make test 91 | $ tox 92 | 93 | Or run pre-commit manually on all files:: 94 | 95 | $ pre-commit run --all-files 96 | 97 | If you installed pre-commit hooks (step 4), they will run automatically on commit. 98 | 99 | Development Workflow Commands 100 | ------------------------------- 101 | 102 | The project provides several ``make`` targets to help with development: 103 | 104 | * ``make fix`` - Automatically fix formatting and linting issues using ruff. 105 | Use this when you want to auto-fix code style issues. 106 | 107 | * ``make lint`` - Run all pre-commit hooks on all files to check for code quality 108 | issues. This includes YAML/TOML validation, trailing whitespace checks, pyupgrade, 109 | ruff linting and formatting, and mypy type checking. 110 | 111 | * ``make typecheck`` - Run mypy type checking only. Use this when you want to 112 | quickly check for type errors without running all other checks. 113 | 114 | * ``make test`` - Run the test suite with pytest using the default Python version. 115 | For testing across multiple Python versions, use ``tox`` instead. 116 | 117 | * ``make pr`` - Run a complete pre-PR check: clean build artifacts, fix formatting, 118 | run linting, type checking, and tests. This is the recommended command to run 119 | before submitting a pull request. 120 | 121 | * ``make coverage`` - Run tests with coverage reporting and open the HTML report 122 | in your browser. 123 | 124 | For a full list of available commands, run ``make help``. 125 | 126 | 7. Commit your changes and push your branch to GitHub:: 127 | 128 | $ git add . 129 | $ git commit -m "Your detailed description of your changes." 130 | $ git push -u origin name-of-your-bugfix-or-feature 131 | 132 | 8. Submit a pull request through the GitHub website. 133 | 134 | Pull Request Guidelines 135 | ----------------------- 136 | 137 | Before you submit a pull request, check that it meets these guidelines: 138 | 139 | 1. The pull request should include tests. 140 | 2. If the pull request adds functionality, the docs should be updated. Put 141 | your new functionality into a function with a docstring, and add the 142 | feature to the list in README.rst. 143 | 3. The pull request should work for Python 3.10, 3.11, 3.12, 3.13, and 3.14. Check 144 | https://github.com/multiformats/py-multicodec/actions 145 | and make sure that the tests pass for all supported Python versions. 146 | 147 | Tips 148 | ---- 149 | 150 | To run a subset of tests:: 151 | 152 | $ pytest tests/test_multicodec.py 153 | 154 | To run tests with coverage:: 155 | 156 | $ make coverage 157 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "py-multicodec" 7 | version = "0.2.1" 8 | description = "Multicodec implementation in Python" 9 | readme = "README.rst" 10 | authors = [{ name = "Dhruv Baldawa", email = "dhruv@dhruvb.com" }] 11 | license = { text = "MIT" } 12 | keywords = ["multicodec", "multiformats", "CID", "IPFS", "IPLD"] 13 | classifiers = [ 14 | "Development Status :: 4 - Beta", 15 | "Intended Audience :: Developers", 16 | "License :: OSI Approved :: MIT License", 17 | "Natural Language :: English", 18 | "Programming Language :: Python :: 3", 19 | "Programming Language :: Python :: 3.10", 20 | "Programming Language :: Python :: 3.11", 21 | "Programming Language :: Python :: 3.12", 22 | "Programming Language :: Python :: 3.13", 23 | "Programming Language :: Python :: 3.14", 24 | ] 25 | requires-python = ">=3.10, <4.0" 26 | dependencies = [ 27 | "varint>=1.0.2,<2.0.0", 28 | ] 29 | 30 | [project.urls] 31 | Homepage = "https://github.com/multiformats/py-multicodec" 32 | Download = "https://github.com/multiformats/py-multicodec/tarball/0.2.1" 33 | 34 | [project.optional-dependencies] 35 | dev = [ 36 | "Sphinx>=5.0.0", 37 | "build>=0.9.0", 38 | "bump-my-version>=1.2.0", 39 | "codecov", 40 | "coverage>=6.5.0", 41 | "mypy", 42 | "pre-commit", 43 | "pytest", 44 | "pytest-cov", 45 | "pytest-runner", 46 | "ruff", 47 | "towncrier>=24,<25", 48 | "tox>=4.10.0", 49 | "twine", 50 | "watchdog>=3.0.0", 51 | "wheel>=0.31.0", 52 | ] 53 | 54 | [tool.setuptools] 55 | include-package-data = true 56 | zip-safe = false 57 | 58 | [tool.setuptools.packages.find] 59 | where = ["."] 60 | include = ["multicodec*"] 61 | 62 | [tool.pytest.ini_options] 63 | testpaths = ["tests"] 64 | python_classes = "*TestCase" 65 | 66 | [tool.coverage.run] 67 | source = ["multicodec"] 68 | 69 | [tool.coverage.report] 70 | exclude_lines = [ 71 | "pragma: no cover", 72 | "def __repr__", 73 | "if self.debug:", 74 | "if settings.DEBUG", 75 | "raise AssertionError", 76 | "raise NotImplementedError", 77 | "if 0:", 78 | "if __name__ == .__main__.:", 79 | ] 80 | 81 | [tool.towncrier] 82 | # Read https://github.com/multiformats/py-multicodec/blob/master/newsfragments/README.md for instructions 83 | directory = "newsfragments" 84 | filename = "HISTORY.rst" 85 | issue_format = "`#{issue} `__" 86 | package = "multicodec" 87 | title_format = "py-multicodec v{version} ({project_date})" 88 | underlines = ["-", "~", "^"] 89 | ignore = ["validate_files.py", "README.md"] 90 | 91 | [[tool.towncrier.type]] 92 | directory = "breaking" 93 | name = "Breaking Changes" 94 | showcontent = true 95 | 96 | [[tool.towncrier.type]] 97 | directory = "bugfix" 98 | name = "Bugfixes" 99 | showcontent = true 100 | 101 | [[tool.towncrier.type]] 102 | directory = "deprecation" 103 | name = "Deprecations" 104 | showcontent = true 105 | 106 | [[tool.towncrier.type]] 107 | directory = "docs" 108 | name = "Improved Documentation" 109 | showcontent = true 110 | 111 | [[tool.towncrier.type]] 112 | directory = "feature" 113 | name = "Features" 114 | showcontent = true 115 | 116 | [[tool.towncrier.type]] 117 | directory = "internal" 118 | name = "Internal Changes - for py-multicodec Contributors" 119 | showcontent = true 120 | 121 | [[tool.towncrier.type]] 122 | directory = "misc" 123 | name = "Miscellaneous Changes" 124 | showcontent = false 125 | 126 | [[tool.towncrier.type]] 127 | directory = "performance" 128 | name = "Performance Improvements" 129 | showcontent = true 130 | 131 | [[tool.towncrier.type]] 132 | directory = "removal" 133 | name = "Removals" 134 | showcontent = true 135 | 136 | [tool.bumpversion] 137 | current_version = "0.2.1" 138 | parse = """ 139 | (?P\\d+) 140 | \\.(?P\\d+) 141 | \\.(?P\\d+) 142 | """ 143 | serialize = [ 144 | "{major}.{minor}.{patch}", 145 | ] 146 | search = "{current_version}" 147 | replace = "{new_version}" 148 | regex = false 149 | ignore_missing_version = false 150 | tag = true 151 | sign_tags = true 152 | tag_name = "v{new_version}" 153 | tag_message = "Bump version: {current_version} → {new_version}" 154 | allow_dirty = false 155 | commit = true 156 | message = "Bump version: {current_version} → {new_version}" 157 | 158 | [[tool.bumpversion.files]] 159 | filename = "pyproject.toml" 160 | search = "version = \"{current_version}\"" 161 | replace = "version = \"{new_version}\"" 162 | 163 | [[tool.bumpversion.files]] 164 | filename = "multicodec/__init__.py" 165 | search = "__version__ = '{current_version}'" 166 | replace = "__version__ = '{new_version}'" 167 | 168 | [[tool.bumpversion.files]] 169 | filename = "pyproject.toml" 170 | search = "Download = \"https://github.com/multiformats/py-multicodec/tarball/{current_version}\"" 171 | replace = "Download = \"https://github.com/multiformats/py-multicodec/tarball/{new_version}\"" 172 | 173 | [tool.mypy] 174 | python_version = "3.10" 175 | check_untyped_defs = false 176 | disallow_any_generics = false 177 | disallow_incomplete_defs = false 178 | disallow_subclassing_any = false 179 | disallow_untyped_calls = false 180 | disallow_untyped_decorators = false 181 | disallow_untyped_defs = false 182 | ignore_missing_imports = true 183 | incremental = false 184 | strict_equality = false 185 | strict_optional = false 186 | warn_redundant_casts = false 187 | warn_return_any = false 188 | warn_unused_configs = true 189 | warn_unused_ignores = false 190 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/multicodec.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/multicodec.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/multicodec" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/multicodec" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\multicodec.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\multicodec.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /tools/gen_code_table.py: -------------------------------------------------------------------------------- 1 | """ 2 | Generate code_table.py with named Code constants. 3 | 4 | This script generates code_table.py. 5 | Run this script to regenerate code_table.py from constants.py. 6 | 7 | Usage: 8 | python tools/gen_code_table.py 9 | """ 10 | 11 | import ast 12 | from pathlib import Path 13 | 14 | 15 | def load_codecs_from_file() -> dict[str, dict[str, int]]: 16 | """Load CODECS dict from constants.py without importing.""" 17 | constants_path = Path(__file__).parent.parent / "multicodec" / "constants.py" 18 | content = constants_path.read_text() 19 | 20 | # Find and extract the CODECS dictionary 21 | tree = ast.parse(content) 22 | for node in ast.walk(tree): 23 | if isinstance(node, ast.Assign): 24 | for target in node.targets: 25 | if isinstance(target, ast.Name) and target.id == "CODECS": 26 | # Evaluate the dictionary 27 | codecs_source = ast.get_source_segment(content, node.value) 28 | return eval(codecs_source) 29 | raise ValueError("CODECS not found in constants.py") 30 | 31 | 32 | def name_to_const(name: str) -> str: 33 | """Convert codec name to Python constant name. 34 | 35 | Examples: 36 | sha2-256 -> SHA2_256 37 | dag-cbor -> DAG_CBOR 38 | bls12_381-g1-pub -> BLS12_381_G1_PUB 39 | """ 40 | # Replace hyphens and dots with underscores, then uppercase 41 | const = name.upper().replace("-", "_").replace(".", "_") 42 | # Ensure it starts with a letter or underscore (valid Python identifier) 43 | if const[0].isdigit(): 44 | const = "_" + const 45 | return const 46 | 47 | 48 | def generate_code_table(CODECS: dict) -> str: 49 | """Generate the code_table.py content.""" 50 | lines = [ 51 | "# Code generated from constants.py; DO NOT EDIT MANUALLY.", 52 | "#", 53 | "# To regenerate, run: python tools/gen_code_table.py", 54 | "#", 55 | "# These constants provide type-safe Code values for all known multicodecs,", 56 | "# allowing usage like:", 57 | "# from multicodec import SHA2_256", 58 | "# code = SHA2_256 # Code object for sha2-256", 59 | "#", 60 | "# Instead of:", 61 | "# from multicodec import Code", 62 | "# code = Code(0x12)", 63 | "", 64 | "from __future__ import annotations", 65 | "", 66 | "from .code import Code", 67 | "", 68 | ] 69 | 70 | # Group codecs by category based on their names 71 | categories = { 72 | "multihash": [], 73 | "multiaddr": [], 74 | "ipld": [], 75 | "serialization": [], 76 | "multiformat": [], 77 | "key": [], 78 | "namespace": [], 79 | "other": [], 80 | } 81 | 82 | # Pattern lists for categorization 83 | multihash_patterns = [ 84 | "sha", 85 | "keccak", 86 | "blake", 87 | "md4", 88 | "md5", 89 | "ripemd", 90 | "murmur", 91 | "identity", 92 | "x11", 93 | "kangaroo", 94 | "sm3", 95 | "skein", 96 | "poseidon", 97 | "bmt", 98 | "dbl-sha", 99 | ] 100 | multiaddr_patterns = [ 101 | "ip4", 102 | "ip6", 103 | "tcp", 104 | "udp", 105 | "dns", 106 | "sctp", 107 | "dccp", 108 | "quic", 109 | "ws", 110 | "http", 111 | "p2p", 112 | "onion", 113 | "garlic", 114 | "tls", 115 | "unix", 116 | "thread", 117 | "udt", 118 | "utp", 119 | "sni", 120 | "noise", 121 | "shs", 122 | "certhash", 123 | "webrtc", 124 | "memory", 125 | "scion", 126 | "plaintextv2", 127 | ] 128 | ipld_patterns = [ 129 | "cid", 130 | "raw", 131 | "dag-", 132 | "libp2p-key", 133 | "git-raw", 134 | "torrent", 135 | "leofcoin", 136 | "eth-", 137 | "bitcoin", 138 | "zcash", 139 | "stellar", 140 | "decred", 141 | "dash", 142 | "swarm-manifest", 143 | "swarm-feed", 144 | "beeson", 145 | "swhid", 146 | ] 147 | serialization_patterns = [ 148 | "protobuf", 149 | "cbor", 150 | "rlp", 151 | "bencode", 152 | "json", 153 | "messagepack", 154 | "car", 155 | "ipns-record", 156 | "x509", 157 | "ssz", 158 | ] 159 | key_patterns = [ 160 | "-pub", 161 | "-priv", 162 | "secp256k1", 163 | "bls12_381", 164 | "x25519", 165 | "ed25519", 166 | "p256", 167 | "p384", 168 | "p521", 169 | "ed448", 170 | "x448", 171 | "sr25519", 172 | "rsa", 173 | "sm2", 174 | "mlkem", 175 | "jwk", 176 | ] 177 | namespace_patterns = [ 178 | "path", 179 | "ns", 180 | "lbry", 181 | "streamid", 182 | "zeronet", 183 | "dnslink", 184 | "skynet", 185 | "arweave", 186 | "subspace", 187 | "kumandra", 188 | "docid", 189 | ] 190 | 191 | for name, info in sorted(CODECS.items(), key=lambda x: x[1]["prefix"]): 192 | const_name = name_to_const(name) 193 | prefix = info["prefix"] 194 | 195 | # Categorize based on name patterns 196 | if any(h in name for h in multihash_patterns): 197 | categories["multihash"].append((const_name, prefix, name)) 198 | elif any(a in name for a in multiaddr_patterns): 199 | categories["multiaddr"].append((const_name, prefix, name)) 200 | elif any(c in name for c in ipld_patterns): 201 | categories["ipld"].append((const_name, prefix, name)) 202 | elif any(s in name for s in serialization_patterns): 203 | categories["serialization"].append((const_name, prefix, name)) 204 | elif name in ["multicodec", "multihash", "multiaddr", "multibase", "varsig"]: 205 | categories["multiformat"].append((const_name, prefix, name)) 206 | elif any(k in name for k in key_patterns): 207 | categories["key"].append((const_name, prefix, name)) 208 | elif any(n in name for n in namespace_patterns): 209 | categories["namespace"].append((const_name, prefix, name)) 210 | else: 211 | categories["other"].append((const_name, prefix, name)) 212 | 213 | # Generate constants for each category 214 | all_names = [] 215 | 216 | for category, items in categories.items(): 217 | if not items: 218 | continue 219 | lines.append(f"# {category.title()}") 220 | for const_name, prefix, name in items: 221 | lines.append(f"{const_name}: Code = Code(0x{prefix:02x}) # {name}") 222 | all_names.append(const_name) 223 | lines.append("") 224 | 225 | # Generate __all__ 226 | lines.append("__all__ = [") 227 | for name in sorted(all_names): 228 | lines.append(f' "{name}",') 229 | lines.append("]") 230 | 231 | return "\n".join(lines) 232 | 233 | 234 | def main(): 235 | CODECS = load_codecs_from_file() 236 | output_path = Path(__file__).parent.parent / "multicodec" / "code_table.py" 237 | content = generate_code_table(CODECS) 238 | output_path.write_text(content) 239 | print(f"Generated {output_path}") 240 | print(f"Total constants: {len(CODECS)}") 241 | 242 | 243 | if __name__ == "__main__": 244 | main() 245 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # multicodec documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Jul 9 22:26:36 2013. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import os 16 | import sys 17 | 18 | # If extensions (or modules to document with autodoc) are in another 19 | # directory, add these directories to sys.path here. If the directory is 20 | # relative to the documentation root, use os.path.abspath to make it 21 | # absolute, like shown here. 22 | # sys.path.insert(0, os.path.abspath('.')) 23 | 24 | # Get the project root dir, which is the parent dir of this 25 | cwd = os.getcwd() 26 | project_root = os.path.dirname(cwd) 27 | 28 | # Insert the project root dir as the first element in the PYTHONPATH. 29 | # This lets us ensure that the source package is imported, and that its 30 | # version is used. 31 | sys.path.insert(0, project_root) 32 | 33 | import multicodec 34 | 35 | # -- General configuration --------------------------------------------- 36 | 37 | # If your documentation needs a minimal Sphinx version, state it here. 38 | # needs_sphinx = '1.0' 39 | 40 | # Add any Sphinx extension module names here, as strings. They can be 41 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 42 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] 43 | 44 | # Add any paths that contain templates here, relative to this directory. 45 | templates_path = ['_templates'] 46 | 47 | # The suffix of source filenames. 48 | source_suffix = '.rst' 49 | 50 | # The encoding of source files. 51 | # source_encoding = 'utf-8-sig' 52 | 53 | # The master toctree document. 54 | master_doc = 'index' 55 | 56 | # General information about the project. 57 | project = 'py-multicodec' 58 | copyright = '2017, Dhruv Baldawa' 59 | 60 | # The version info for the project you're documenting, acts as replacement 61 | # for |version| and |release|, also used in various other places throughout 62 | # the built documents. 63 | # 64 | # The short X.Y version. 65 | version = multicodec.__version__ 66 | # The full version, including alpha/beta/rc tags. 67 | release = multicodec.__version__ 68 | 69 | # The language for content autogenerated by Sphinx. Refer to documentation 70 | # for a list of supported languages. 71 | # language = None 72 | 73 | # There are two options for replacing |today|: either, you set today to 74 | # some non-false value, then it is used: 75 | # today = '' 76 | # Else, today_fmt is used as the format for a strftime call. 77 | # today_fmt = '%B %d, %Y' 78 | 79 | # List of patterns, relative to source directory, that match files and 80 | # directories to ignore when looking for source files. 81 | exclude_patterns = ['_build'] 82 | 83 | # The reST default role (used for this markup: `text`) to use for all 84 | # documents. 85 | # default_role = None 86 | 87 | # If true, '()' will be appended to :func: etc. cross-reference text. 88 | # add_function_parentheses = True 89 | 90 | # If true, the current module name will be prepended to all description 91 | # unit titles (such as .. function::). 92 | # add_module_names = True 93 | 94 | # If true, sectionauthor and moduleauthor directives will be shown in the 95 | # output. They are ignored by default. 96 | # show_authors = False 97 | 98 | # The name of the Pygments (syntax highlighting) style to use. 99 | pygments_style = 'sphinx' 100 | 101 | # A list of ignored prefixes for module index sorting. 102 | # modindex_common_prefix = [] 103 | 104 | # If true, keep warnings as "system message" paragraphs in the built 105 | # documents. 106 | # keep_warnings = False 107 | 108 | 109 | # -- Options for HTML output ------------------------------------------- 110 | 111 | # The theme to use for HTML and HTML Help pages. See the documentation for 112 | # a list of builtin themes. 113 | html_theme = 'alabaster' 114 | 115 | # Theme options are theme-specific and customize the look and feel of a 116 | # theme further. For a list of options available for each theme, see the 117 | # documentation. 118 | # html_theme_options = {} 119 | 120 | # Add any paths that contain custom themes here, relative to this directory. 121 | # html_theme_path = [] 122 | 123 | # The name for this set of Sphinx documents. If None, it defaults to 124 | # " v documentation". 125 | # html_title = None 126 | 127 | # A shorter title for the navigation bar. Default is the same as 128 | # html_title. 129 | # html_short_title = None 130 | 131 | # The name of an image file (relative to this directory) to place at the 132 | # top of the sidebar. 133 | # html_logo = None 134 | 135 | # The name of an image file (within the static path) to use as favicon 136 | # of the docs. This file should be a Windows icon file (.ico) being 137 | # 16x16 or 32x32 pixels large. 138 | # html_favicon = None 139 | 140 | # Add any paths that contain custom static files (such as style sheets) 141 | # here, relative to this directory. They are copied after the builtin 142 | # static files, so a file named "default.css" will overwrite the builtin 143 | # "default.css". 144 | html_static_path = ['_static'] 145 | 146 | # If not '', a 'Last updated on:' timestamp is inserted at every page 147 | # bottom, using the given strftime format. 148 | # html_last_updated_fmt = '%b %d, %Y' 149 | 150 | # If true, SmartyPants will be used to convert quotes and dashes to 151 | # typographically correct entities. 152 | # html_use_smartypants = True 153 | 154 | # Custom sidebar templates, maps document names to template names. 155 | # html_sidebars = {} 156 | 157 | # Additional templates that should be rendered to pages, maps page names 158 | # to template names. 159 | # html_additional_pages = {} 160 | 161 | # If false, no module index is generated. 162 | # html_domain_indices = True 163 | 164 | # If false, no index is generated. 165 | # html_use_index = True 166 | 167 | # If true, the index is split into individual pages for each letter. 168 | # html_split_index = False 169 | 170 | # If true, links to the reST sources are added to the pages. 171 | # html_show_sourcelink = True 172 | 173 | # If true, "Created using Sphinx" is shown in the HTML footer. 174 | # Default is True. 175 | # html_show_sphinx = True 176 | 177 | # If true, "(C) Copyright ..." is shown in the HTML footer. 178 | # Default is True. 179 | # html_show_copyright = True 180 | 181 | # If true, an OpenSearch description file will be output, and all pages 182 | # will contain a tag referring to it. The value of this option 183 | # must be the base URL from which the finished HTML is served. 184 | # html_use_opensearch = '' 185 | 186 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 187 | # html_file_suffix = None 188 | 189 | # Output file base name for HTML help builder. 190 | htmlhelp_basename = 'multicodecdoc' 191 | 192 | html_sidebars = { 193 | '**': [ 194 | 'about.html', 195 | 'navigation.html', 196 | 'relations.html', 197 | 'searchbox.html', 198 | ], 199 | } 200 | 201 | html_theme_options = { 202 | 'github_user': 'multiformats', 203 | 'github_repo': 'py-multicodec', 204 | 'github_button': True, 205 | 'github_banner': True, 206 | 'code_font_size': '0.8em', 207 | } 208 | 209 | 210 | # -- Options for LaTeX output ------------------------------------------ 211 | 212 | latex_elements = { 213 | # The paper size ('letterpaper' or 'a4paper'). 214 | #'papersize': 'letterpaper', 215 | # The font size ('10pt', '11pt' or '12pt'). 216 | #'pointsize': '10pt', 217 | # Additional stuff for the LaTeX preamble. 218 | #'preamble': '', 219 | } 220 | 221 | # Grouping the document tree into LaTeX files. List of tuples 222 | # (source start file, target name, title, author, documentclass 223 | # [howto/manual]). 224 | latex_documents = [ 225 | ('index', 'multicodec.tex', 'py-multicodec Documentation', 'Dhruv Baldawa', 'manual'), 226 | ] 227 | 228 | # The name of an image file (relative to this directory) to place at 229 | # the top of the title page. 230 | # latex_logo = None 231 | 232 | # For "manual" documents, if this is true, then toplevel headings 233 | # are parts, not chapters. 234 | # latex_use_parts = False 235 | 236 | # If true, show page references after internal links. 237 | # latex_show_pagerefs = False 238 | 239 | # If true, show URL addresses after external links. 240 | # latex_show_urls = False 241 | 242 | # Documents to append as an appendix to all manuals. 243 | # latex_appendices = [] 244 | 245 | # If false, no module index is generated. 246 | # latex_domain_indices = True 247 | 248 | 249 | # -- Options for manual page output ------------------------------------ 250 | 251 | # One entry per manual page. List of tuples 252 | # (source start file, name, description, authors, manual section). 253 | man_pages = [('index', 'multicodec', 'py-multicodec Documentation', ['Dhruv Baldawa'], 1)] 254 | 255 | # If true, show URL addresses after external links. 256 | # man_show_urls = False 257 | 258 | 259 | # -- Options for Texinfo output ---------------------------------------- 260 | 261 | # Grouping the document tree into Texinfo files. List of tuples 262 | # (source start file, target name, title, author, 263 | # dir menu entry, description, category) 264 | texinfo_documents = [ 265 | ( 266 | 'index', 267 | 'multicodec', 268 | 'py-multicodec Documentation', 269 | 'Dhruv Baldawa', 270 | 'multicodec', 271 | 'One line description of project.', 272 | 'Miscellaneous', 273 | ), 274 | ] 275 | 276 | # Documents to append as an appendix to all manuals. 277 | # texinfo_appendices = [] 278 | 279 | # If false, no module index is generated. 280 | # texinfo_domain_indices = True 281 | 282 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 283 | # texinfo_show_urls = 'footnote' 284 | 285 | # If true, do not generate a @detailmenu in the "Top" node's menu. 286 | # texinfo_no_detailmenu = False 287 | -------------------------------------------------------------------------------- /tests/test_code.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Tests for Code type.""" 3 | 4 | import pytest 5 | 6 | from multicodec import RESERVED_END, RESERVED_START, Code, is_reserved, known_codes 7 | 8 | 9 | class CodeTestCase: 10 | """Tests for Code type.""" 11 | 12 | def test_code_from_int(self): 13 | """Test creating Code from integer.""" 14 | code = Code(0x12) 15 | assert int(code) == 0x12 16 | assert str(code) == "sha2-256" 17 | 18 | def test_code_from_string_name(self): 19 | """Test Code.from_string with codec name.""" 20 | code = Code.from_string("sha2-256") 21 | assert int(code) == 0x12 22 | 23 | def test_code_from_string_hex(self): 24 | """Test Code.from_string with hex number.""" 25 | code = Code.from_string("0x12") 26 | assert int(code) == 0x12 27 | assert str(code) == "sha2-256" 28 | 29 | def test_code_from_string_decimal(self): 30 | """Test Code.from_string with decimal number.""" 31 | code = Code.from_string("18") 32 | assert int(code) == 0x12 33 | 34 | def test_code_from_string_reserved(self): 35 | """Test Code.from_string with reserved range number.""" 36 | code = Code.from_string("0x300001") 37 | assert int(code) == 0x300001 38 | 39 | def test_code_from_string_invalid(self): 40 | """Test Code.from_string with invalid input.""" 41 | with pytest.raises(ValueError) as excinfo: 42 | Code.from_string("nonexistent-codec") 43 | assert "unknown multicodec" in str(excinfo.value) 44 | 45 | def test_code_set(self): 46 | """Test Code.set method.""" 47 | code = Code(0) 48 | code.set("sha2-256") 49 | assert int(code) == 0x12 50 | 51 | def test_code_string_known(self): 52 | """Test str(Code) for known codec.""" 53 | code = Code(0x12) 54 | assert str(code) == "sha2-256" 55 | 56 | def test_code_string_unknown(self): 57 | """Test str(Code) for unknown codec.""" 58 | code = Code(0xDEADBEEF) 59 | assert "0xdeadbeef" in str(code).lower() 60 | 61 | def test_code_repr(self): 62 | """Test repr(Code).""" 63 | code = Code(0x12) 64 | assert "sha2-256" in repr(code) 65 | assert "0x12" in repr(code) 66 | 67 | def test_code_equality(self): 68 | """Test Code equality.""" 69 | code1 = Code(0x12) 70 | code2 = Code(0x12) 71 | code3 = Code(0x13) 72 | assert code1 == code2 73 | assert code1 != code3 74 | assert code1 == 0x12 75 | assert code1 != 0x13 76 | 77 | def test_code_comparison(self): 78 | """Test Code comparison operators.""" 79 | code1 = Code(0x12) 80 | code2 = Code(0x13) 81 | assert code1 < code2 82 | assert code1 <= code2 83 | assert code2 > code1 84 | assert code2 >= code1 85 | assert code1 < 0x13 86 | assert code1 <= 0x12 87 | 88 | def test_code_hash(self): 89 | """Test Code is hashable.""" 90 | code = Code(0x12) 91 | code_set = {code} 92 | assert Code(0x12) in code_set 93 | 94 | def test_code_name_property(self): 95 | """Test Code.name property.""" 96 | code = Code(0x12) 97 | assert code.name == "sha2-256" 98 | 99 | unknown = Code(0xDEADBEEF) 100 | assert unknown.name == "" 101 | 102 | def test_code_tag(self): 103 | """Test Code.tag() method.""" 104 | # Multihash 105 | code = Code(0x12) # sha2-256 106 | assert code.tag() == "multihash" 107 | 108 | # Multiaddr 109 | code = Code(0x04) # ip4 110 | assert code.tag() == "multiaddr" 111 | 112 | # CID 113 | code = Code(0x01) # cidv1 114 | assert code.tag() == "cid" 115 | 116 | # IPLD 117 | code = Code(0x55) # raw 118 | assert code.tag() == "ipld" 119 | 120 | 121 | class ReservedRangeTestCase: 122 | """Tests for reserved range constants and functions.""" 123 | 124 | def test_reserved_constants(self): 125 | """Test RESERVED_START and RESERVED_END constants.""" 126 | assert RESERVED_START == 0x300000 127 | assert RESERVED_END == 0x3FFFFF 128 | 129 | def test_is_reserved_in_range(self): 130 | """Test is_reserved returns True for codes in range.""" 131 | assert is_reserved(RESERVED_START) 132 | assert is_reserved(RESERVED_END) 133 | assert is_reserved(0x300001) 134 | assert is_reserved(0x350000) 135 | 136 | def test_is_reserved_out_of_range(self): 137 | """Test is_reserved returns False for codes outside range.""" 138 | assert not is_reserved(0x12) 139 | assert not is_reserved(0x00) 140 | assert not is_reserved(RESERVED_START - 1) 141 | assert not is_reserved(RESERVED_END + 1) 142 | 143 | def test_is_reserved_with_code_object(self): 144 | """Test is_reserved with Code object.""" 145 | assert is_reserved(Code(RESERVED_START)) 146 | assert not is_reserved(Code(0x12)) 147 | 148 | 149 | class KnownCodesTestCase: 150 | """Tests for known_codes function.""" 151 | 152 | def test_known_codes_returns_list(self): 153 | """Test known_codes returns a list.""" 154 | codes = known_codes() 155 | assert isinstance(codes, list) 156 | assert len(codes) > 0 157 | 158 | def test_known_codes_contains_code_objects(self): 159 | """Test known_codes contains Code objects.""" 160 | codes = known_codes() 161 | assert all(isinstance(c, Code) for c in codes) 162 | 163 | def test_known_codes_contains_common_codecs(self): 164 | """Test known_codes contains common codecs.""" 165 | codes = known_codes() 166 | code_values = [int(c) for c in codes] 167 | assert 0x12 in code_values # sha2-256 168 | assert 0x00 in code_values # identity 169 | assert 0x55 in code_values # raw 170 | 171 | def test_known_codes_is_sorted(self): 172 | """Test known_codes returns sorted list.""" 173 | codes = known_codes() 174 | code_values = [int(c) for c in codes] 175 | assert code_values == sorted(code_values) 176 | 177 | def test_known_codes_same_instance(self): 178 | """Test known_codes returns cached list.""" 179 | codes1 = known_codes() 180 | codes2 = known_codes() 181 | assert codes1 is codes2 182 | 183 | 184 | class CodeTableConstantsTestCase: 185 | """Tests for code_table named constants.""" 186 | 187 | def test_named_constants_exist(self): 188 | """Test that named constants are importable.""" 189 | from multicodec.code_table import ( 190 | IDENTITY, 191 | SHA2_256, 192 | ) 193 | 194 | assert SHA2_256 is not None 195 | assert IDENTITY is not None 196 | 197 | def test_named_constants_are_code_objects(self): 198 | """Test that named constants are Code instances.""" 199 | from multicodec.code_table import DAG_CBOR, IDENTITY, SHA2_256 200 | 201 | assert isinstance(SHA2_256, Code) 202 | assert isinstance(IDENTITY, Code) 203 | assert isinstance(DAG_CBOR, Code) 204 | 205 | def test_named_constants_values(self): 206 | """Test that named constants have correct values.""" 207 | from multicodec.code_table import ( 208 | DAG_CBOR, 209 | DAG_PB, 210 | DNS, 211 | IDENTITY, 212 | IP4, 213 | RAW, 214 | SHA2_256, 215 | TCP, 216 | ) 217 | 218 | assert int(IDENTITY) == 0x00 219 | assert int(SHA2_256) == 0x12 220 | assert int(IP4) == 0x04 221 | assert int(TCP) == 0x06 222 | assert int(DNS) == 0x35 223 | assert int(RAW) == 0x55 224 | assert int(DAG_PB) == 0x70 225 | assert int(DAG_CBOR) == 0x71 226 | 227 | def test_named_constants_string_representation(self): 228 | """Test that named constants have correct string names.""" 229 | from multicodec.code_table import DAG_CBOR, IDENTITY, SHA2_256 230 | 231 | assert str(IDENTITY) == "identity" 232 | assert str(SHA2_256) == "sha2-256" 233 | assert str(DAG_CBOR) == "dag-cbor" 234 | 235 | def test_named_constants_can_be_used_in_comparisons(self): 236 | """Test that named constants work in comparisons.""" 237 | from multicodec.code_table import SHA2_256 238 | 239 | code = Code(0x12) 240 | assert code == SHA2_256 241 | assert SHA2_256 == code 242 | assert SHA2_256 == 0x12 243 | 244 | def test_named_constants_can_be_used_in_sets(self): 245 | """Test that named constants can be used in sets.""" 246 | from multicodec.code_table import DAG_CBOR, SHA2_256 247 | 248 | code_set = {SHA2_256, DAG_CBOR} 249 | assert Code(0x12) in code_set 250 | assert Code(0x71) in code_set 251 | assert Code(0x99) not in code_set 252 | 253 | def test_blake_variants_exist(self): 254 | """Test that BLAKE2 variants are defined.""" 255 | from multicodec.code_table import BLAKE2B_256, BLAKE2S_256, BLAKE3 256 | 257 | assert int(BLAKE3) == 0x1E 258 | assert int(BLAKE2B_256) == 0xB220 259 | assert int(BLAKE2S_256) == 0xB260 260 | 261 | def test_multiaddr_constants(self): 262 | """Test multiaddr constants.""" 263 | from multicodec.code_table import ( 264 | DNS, 265 | DNS4, 266 | DNS6, 267 | DNSADDR, 268 | HTTP, 269 | HTTPS, 270 | IP4, 271 | IP6, 272 | QUIC, 273 | TCP, 274 | UDP, 275 | WS, 276 | WSS, 277 | ) 278 | 279 | assert int(IP4) == 0x04 280 | assert int(IP6) == 0x29 281 | assert int(TCP) == 0x06 282 | assert int(UDP) == 0x0111 283 | assert int(DNS) == 0x35 284 | assert int(DNS4) == 0x36 285 | assert int(DNS6) == 0x37 286 | assert int(DNSADDR) == 0x38 287 | assert int(QUIC) == 0x01CC 288 | assert int(WS) == 0x01DD 289 | assert int(WSS) == 0x01DE 290 | assert int(HTTP) == 0x01E0 291 | assert int(HTTPS) == 0x01BB 292 | 293 | def test_key_constants(self): 294 | """Test key constants.""" 295 | from multicodec.code_table import ( 296 | ED25519_PRIV, 297 | ED25519_PUB, 298 | SECP256K1_PUB, 299 | X25519_PUB, 300 | ) 301 | 302 | assert int(SECP256K1_PUB) == 0xE7 303 | assert int(X25519_PUB) == 0xEC 304 | assert int(ED25519_PUB) == 0xED 305 | assert int(ED25519_PRIV) == 0x1300 306 | -------------------------------------------------------------------------------- /multicodec/serialization.py: -------------------------------------------------------------------------------- 1 | """ 2 | Serialization module for multicodec. 3 | 4 | This module provides a codec interface for serializing and deserializing data 5 | with multicodec prefixes. It includes built-in codecs for common formats: 6 | - JSON: Structured data serialization 7 | - Raw: Pass-through codec for binary data 8 | 9 | The design follows a similar pattern to js-multiformats and rust-multicodec, 10 | providing a clean interface for encoding/decoding operations. 11 | 12 | Example usage: 13 | >>> from multicodec.serialization import json_codec, raw_codec, encode, decode 14 | >>> # Using JSON codec 15 | >>> data = {"hello": "world"} 16 | >>> encoded = json_codec.encode(data) 17 | >>> decoded = json_codec.decode(encoded) 18 | >>> assert decoded == data 19 | >>> 20 | >>> # Using the generic encode/decode with codec name 21 | >>> encoded = encode("json", {"key": "value"}) 22 | >>> decoded = decode(encoded) 23 | """ 24 | 25 | from __future__ import annotations 26 | 27 | import json 28 | from abc import ABC, abstractmethod 29 | from typing import Any, Generic, TypeVar 30 | 31 | import varint 32 | 33 | from .constants import CODE_TABLE 34 | from .exceptions import CodecError, DecodeError, EncodeError, UnknownCodecError 35 | 36 | # Type variable for codec data types 37 | T = TypeVar("T") 38 | 39 | 40 | class Codec(ABC, Generic[T]): 41 | """ 42 | Abstract base class for multicodec serialization codecs. 43 | 44 | A codec provides methods to encode data to bytes and decode bytes back 45 | to data. Each codec is identified by its multicodec name and code. 46 | 47 | Subclasses must implement: 48 | - name: The multicodec name (e.g., 'json', 'raw') 49 | - code: The multicodec code (e.g., 0x0200 for json) 50 | - _encode: Transform data to bytes (without prefix) 51 | - _decode: Transform bytes to data (without prefix) 52 | """ 53 | 54 | @property 55 | @abstractmethod 56 | def name(self) -> str: 57 | """Return the multicodec name for this codec.""" 58 | ... 59 | 60 | @property 61 | @abstractmethod 62 | def code(self) -> int: 63 | """Return the multicodec code for this codec.""" 64 | ... 65 | 66 | @abstractmethod 67 | def _encode(self, data: T) -> bytes: 68 | """ 69 | Encode data to bytes without the multicodec prefix. 70 | 71 | :param data: Data to encode 72 | :return: Encoded bytes without prefix 73 | :raises EncodeError: If encoding fails 74 | """ 75 | ... 76 | 77 | @abstractmethod 78 | def _decode(self, data: bytes) -> T: 79 | """ 80 | Decode bytes to data, assuming no multicodec prefix. 81 | 82 | :param data: Bytes to decode (without prefix) 83 | :return: Decoded data 84 | :raises DecodeError: If decoding fails 85 | """ 86 | ... 87 | 88 | def encode(self, data: T) -> bytes: 89 | """ 90 | Encode data to bytes with multicodec prefix. 91 | 92 | :param data: Data to encode 93 | :return: Multicodec-prefixed encoded bytes 94 | :raises EncodeError: If encoding fails 95 | """ 96 | try: 97 | encoded = self._encode(data) 98 | prefix = varint.encode(self.code) 99 | return prefix + encoded 100 | except EncodeError: 101 | raise 102 | except Exception as e: 103 | raise EncodeError(f"Failed to encode with {self.name}: {e}") from e 104 | 105 | def decode(self, data: bytes) -> T: 106 | """ 107 | Decode multicodec-prefixed bytes to data. 108 | 109 | :param data: Multicodec-prefixed bytes to decode 110 | :return: Decoded data 111 | :raises DecodeError: If decoding fails or codec mismatch 112 | """ 113 | try: 114 | # Extract and verify the prefix 115 | prefix_int = varint.decode_bytes(data) 116 | if prefix_int != self.code: 117 | expected_name = CODE_TABLE.get(prefix_int, f"0x{prefix_int:x}") 118 | raise DecodeError( 119 | f"Codec mismatch: expected {self.name} (0x{self.code:x}), got {expected_name} (0x{prefix_int:x})" 120 | ) 121 | 122 | # Remove prefix and decode 123 | prefix_bytes = varint.encode(prefix_int) 124 | payload = data[len(prefix_bytes) :] 125 | return self._decode(payload) 126 | except DecodeError: 127 | raise 128 | except Exception as e: 129 | raise DecodeError(f"Failed to decode with {self.name}: {e}") from e 130 | 131 | def decode_raw(self, data: bytes) -> T: 132 | """ 133 | Decode bytes without expecting a multicodec prefix. 134 | 135 | :param data: Raw bytes to decode (no prefix) 136 | :return: Decoded data 137 | :raises DecodeError: If decoding fails 138 | """ 139 | try: 140 | return self._decode(data) 141 | except DecodeError: 142 | raise 143 | except Exception as e: 144 | raise DecodeError(f"Failed to decode raw data with {self.name}: {e}") from e 145 | 146 | def __repr__(self) -> str: 147 | return f"<{self.__class__.__name__}(name={self.name!r}, code=0x{self.code:x})>" 148 | 149 | 150 | class JSONCodec(Codec[Any]): 151 | """ 152 | JSON codec for encoding/decoding JSON-serializable data. 153 | 154 | Uses the standard library json module with UTF-8 encoding. 155 | The multicodec code for JSON is 0x0200. 156 | 157 | Example: 158 | >>> codec = JSONCodec() 159 | >>> encoded = codec.encode({"hello": "world"}) 160 | >>> decoded = codec.decode(encoded) 161 | >>> assert decoded == {"hello": "world"} 162 | """ 163 | 164 | @property 165 | def name(self) -> str: 166 | return "json" 167 | 168 | @property 169 | def code(self) -> int: 170 | return 0x0200 # json multicodec code 171 | 172 | def _encode(self, data: Any) -> bytes: 173 | """Encode data as JSON bytes.""" 174 | try: 175 | return json.dumps(data, separators=(",", ":"), ensure_ascii=False).encode("utf-8") 176 | except (TypeError, ValueError) as e: 177 | raise EncodeError(f"Data is not JSON serializable: {e}") from e 178 | 179 | def _decode(self, data: bytes) -> Any: 180 | """Decode JSON bytes to Python object.""" 181 | try: 182 | return json.loads(data.decode("utf-8")) 183 | except (json.JSONDecodeError, UnicodeDecodeError) as e: 184 | raise DecodeError(f"Invalid JSON data: {e}") from e 185 | 186 | 187 | class RawCodec(Codec[bytes]): 188 | """ 189 | Raw codec for pass-through binary data. 190 | 191 | This codec performs no transformation on the data, useful for 192 | binary data that should be stored as-is with a multicodec prefix. 193 | The multicodec code for raw is 0x55. 194 | 195 | Example: 196 | >>> codec = RawCodec() 197 | >>> data = b"binary data" 198 | >>> encoded = codec.encode(data) 199 | >>> decoded = codec.decode(encoded) 200 | >>> assert decoded == data 201 | """ 202 | 203 | @property 204 | def name(self) -> str: 205 | return "raw" 206 | 207 | @property 208 | def code(self) -> int: 209 | return 0x55 # raw multicodec code 210 | 211 | def _encode(self, data: bytes) -> bytes: 212 | """Pass through bytes unchanged.""" 213 | if not isinstance(data, bytes): 214 | raise EncodeError(f"RawCodec expects bytes, got {type(data).__name__}") 215 | return data 216 | 217 | def _decode(self, data: bytes) -> bytes: 218 | """Pass through bytes unchanged.""" 219 | return data 220 | 221 | 222 | # Singleton codec instances for convenience 223 | json_codec = JSONCodec() 224 | raw_codec = RawCodec() 225 | 226 | 227 | # Codec registry for dynamic codec lookup 228 | _codec_registry: dict[str, Codec[Any]] = { 229 | "json": json_codec, 230 | "raw": raw_codec, 231 | } 232 | 233 | 234 | def register_codec(codec: Codec[Any]) -> None: 235 | """ 236 | Register a custom codec in the global registry. 237 | 238 | :param codec: The codec instance to register 239 | :raises ValueError: If codec name is already registered 240 | """ 241 | if codec.name in _codec_registry: 242 | raise ValueError(f"Codec '{codec.name}' is already registered") 243 | _codec_registry[codec.name] = codec 244 | 245 | 246 | def unregister_codec(name: str) -> None: 247 | """ 248 | Unregister a codec from the global registry. 249 | 250 | :param name: The codec name to unregister 251 | :raises KeyError: If codec is not registered 252 | """ 253 | if name not in _codec_registry: 254 | raise KeyError(f"Codec '{name}' is not registered") 255 | del _codec_registry[name] 256 | 257 | 258 | def get_registered_codec(name: str) -> Codec[Any]: 259 | """ 260 | Get a registered codec by name. 261 | 262 | :param name: The codec name 263 | :return: The codec instance 264 | :raises UnknownCodecError: If codec is not registered 265 | """ 266 | try: 267 | return _codec_registry[name] 268 | except KeyError: 269 | raise UnknownCodecError(f"Codec '{name}' is not registered") from None 270 | 271 | 272 | def list_registered_codecs() -> list[str]: 273 | """ 274 | List all registered codec names. 275 | 276 | :return: List of registered codec names 277 | """ 278 | return list(_codec_registry.keys()) 279 | 280 | 281 | def encode(codec_name: str, data: Any) -> bytes: 282 | """ 283 | Encode data using a registered codec by name. 284 | 285 | :param codec_name: Name of the codec to use (e.g., 'json', 'raw') 286 | :param data: Data to encode 287 | :return: Multicodec-prefixed encoded bytes 288 | :raises UnknownCodecError: If codec is not registered 289 | :raises EncodeError: If encoding fails 290 | """ 291 | codec = get_registered_codec(codec_name) 292 | return codec.encode(data) 293 | 294 | 295 | def decode(data: bytes, codec_name: str | None = None) -> Any: 296 | """ 297 | Decode multicodec-prefixed data. 298 | 299 | If codec_name is provided, uses that specific codec (and verifies prefix matches). 300 | If codec_name is None, auto-detects codec from the prefix. 301 | 302 | :param data: Multicodec-prefixed bytes to decode 303 | :param codec_name: Optional codec name to use for decoding 304 | :return: Decoded data 305 | :raises UnknownCodecError: If codec is not registered 306 | :raises DecodeError: If decoding fails or codec mismatch 307 | """ 308 | if codec_name is not None: 309 | codec = get_registered_codec(codec_name) 310 | return codec.decode(data) 311 | 312 | # Auto-detect codec from prefix 313 | try: 314 | prefix_int = varint.decode_bytes(data) 315 | except TypeError as e: 316 | raise DecodeError(f"Invalid varint prefix: {e}") from e 317 | 318 | codec_name_detected = CODE_TABLE.get(prefix_int) 319 | if codec_name_detected is None: 320 | raise DecodeError(f"Unknown codec prefix: 0x{prefix_int:x}") 321 | 322 | if codec_name_detected not in _codec_registry: 323 | raise UnknownCodecError( 324 | f"Codec '{codec_name_detected}' (0x{prefix_int:x}) is not registered. " 325 | f"Available codecs: {list_registered_codecs()}" 326 | ) 327 | 328 | return _codec_registry[codec_name_detected].decode(data) 329 | 330 | 331 | def is_codec_registered(name: str) -> bool: 332 | """ 333 | Check if a codec is registered. 334 | 335 | :param name: The codec name to check 336 | :return: True if codec is registered, False otherwise 337 | """ 338 | return name in _codec_registry 339 | 340 | 341 | __all__ = [ 342 | # Base classes 343 | "Codec", 344 | # Exceptions 345 | "CodecError", 346 | "DecodeError", 347 | "EncodeError", 348 | "JSONCodec", 349 | # Built-in codecs 350 | "RawCodec", 351 | "UnknownCodecError", 352 | # Generic functions 353 | "decode", 354 | "encode", 355 | "get_registered_codec", 356 | "is_codec_registered", 357 | # Codec instances 358 | "json_codec", 359 | "list_registered_codecs", 360 | "raw_codec", 361 | # Registry functions 362 | "register_codec", 363 | "unregister_codec", 364 | ] 365 | -------------------------------------------------------------------------------- /multicodec/code.py: -------------------------------------------------------------------------------- 1 | """ 2 | Multicodec Code type and core functionality. 3 | 4 | This module provides: 5 | - Code class for type-safe codec handling 6 | - ReservedStart and ReservedEnd constants 7 | - KnownCodes() function to list all registered codes 8 | """ 9 | 10 | from __future__ import annotations 11 | 12 | from .constants import CODE_TABLE, NAME_TABLE 13 | 14 | # ReservedStart is the (inclusive) start of the reserved range of codes that 15 | # are safe to use for internal purposes. 16 | RESERVED_START: int = 0x300000 17 | 18 | # ReservedEnd is the (inclusive) end of the reserved range of codes that are 19 | # safe to use for internal purposes. 20 | RESERVED_END: int = 0x3FFFFF 21 | 22 | 23 | class Code: 24 | """ 25 | Code describes an integer reserved in the multicodec table. 26 | 27 | This class provides: 28 | - Type-safe codec handling 29 | - String conversion (name lookup) 30 | - Set from string (name or hex number) 31 | - Tag lookup 32 | 33 | Example: 34 | >>> code = Code(0x12) 35 | >>> str(code) 36 | 'sha2-256' 37 | >>> code = Code.from_string("sha2-256") 38 | >>> int(code) 39 | 18 40 | """ 41 | 42 | __slots__ = ("_value",) 43 | 44 | def __init__(self, value: int) -> None: 45 | """Initialize a Code with an integer value.""" 46 | if not isinstance(value, int): 47 | raise TypeError(f"Code value must be an integer, got {type(value).__name__}") 48 | if value < 0: 49 | raise ValueError("Code value must be non-negative") 50 | self._value = value 51 | 52 | @classmethod 53 | def from_string(cls, text: str) -> Code: 54 | """ 55 | Create a Code from a string, interpreting it as a multicodec name or number. 56 | 57 | The input string can be the name or number for a known code. A number can be 58 | in decimal or hexadecimal format (with 0x prefix). 59 | 60 | Numbers in the reserved range 0x300000-0x3FFFFF are also accepted. 61 | 62 | :param str text: The codec name or number 63 | :return: A Code instance 64 | :rtype: Code 65 | :raises ValueError: If the text is not a valid codec 66 | """ 67 | # Try parsing as a number first (cheap operation) 68 | try: 69 | n = int(text, 0) # base 0 allows decimal, hex (0x), octal (0o), binary (0b) 70 | code = cls(n) 71 | # Accept if in reserved range 72 | if RESERVED_START <= n <= RESERVED_END: 73 | return code 74 | # Accept if known code 75 | if n in CODE_TABLE: 76 | return code 77 | except ValueError: 78 | pass 79 | 80 | # Try matching by name 81 | if text in NAME_TABLE: 82 | return cls(NAME_TABLE[text]) 83 | 84 | raise ValueError(f'unknown multicodec: "{text}"') 85 | 86 | def set(self, text: str) -> None: 87 | """ 88 | Set the code from a string. 89 | 90 | :param str text: The codec name or number 91 | :raises ValueError: If the text is not a valid codec 92 | """ 93 | new_code = Code.from_string(text) 94 | self._value = new_code._value 95 | 96 | def __int__(self) -> int: 97 | """Return the integer value of the code.""" 98 | return self._value 99 | 100 | def __index__(self) -> int: 101 | """Support using Code in contexts that require an integer index.""" 102 | return self._value 103 | 104 | def __str__(self) -> str: 105 | """ 106 | Return the string name of the code. 107 | 108 | Returns the codec name if known, otherwise returns the hex representation. 109 | """ 110 | if self._value in CODE_TABLE: 111 | return CODE_TABLE[self._value] 112 | return f"Code(0x{self._value:x})" 113 | 114 | def __repr__(self) -> str: 115 | """Return a detailed representation of the code.""" 116 | if self._value in CODE_TABLE: 117 | return f"Code({CODE_TABLE[self._value]!r}, 0x{self._value:x})" 118 | return f"Code(0x{self._value:x})" 119 | 120 | def __eq__(self, other: object) -> bool: 121 | """Check equality with another Code or integer.""" 122 | if isinstance(other, Code): 123 | return self._value == other._value 124 | if isinstance(other, int): 125 | return self._value == other 126 | return NotImplemented 127 | 128 | def __hash__(self) -> int: 129 | """Return hash of the code value.""" 130 | return hash(self._value) 131 | 132 | def __lt__(self, other: Code | int) -> bool: 133 | """Compare less than.""" 134 | if isinstance(other, Code): 135 | return self._value < other._value 136 | if isinstance(other, int): 137 | return self._value < other 138 | return NotImplemented 139 | 140 | def __le__(self, other: Code | int) -> bool: 141 | """Compare less than or equal.""" 142 | if isinstance(other, Code): 143 | return self._value <= other._value 144 | if isinstance(other, int): 145 | return self._value <= other 146 | return NotImplemented 147 | 148 | def __gt__(self, other: Code | int) -> bool: 149 | """Compare greater than.""" 150 | if isinstance(other, Code): 151 | return self._value > other._value 152 | if isinstance(other, int): 153 | return self._value > other 154 | return NotImplemented 155 | 156 | def __ge__(self, other: Code | int) -> bool: 157 | """Compare greater than or equal.""" 158 | if isinstance(other, Code): 159 | return self._value >= other._value 160 | if isinstance(other, int): 161 | return self._value >= other 162 | return NotImplemented 163 | 164 | @property 165 | def name(self) -> str: 166 | """Return the codec name, or '' if not found.""" 167 | return CODE_TABLE.get(self._value, "") 168 | 169 | def tag(self) -> str: 170 | """ 171 | Return the tag for this codec. 172 | 173 | Tags categorize codecs (e.g., "multihash", "multiaddr", "ipld", etc.) 174 | """ 175 | return _get_tag(self._value) 176 | 177 | 178 | def _get_tag(code: int) -> str: 179 | """Get the tag for a codec code (mirrors go-multicodec's Tag() method).""" 180 | name = CODE_TABLE.get(code, "") 181 | 182 | # CID 183 | if name in ("cidv1", "cidv2", "cidv3"): 184 | return "cid" 185 | 186 | # Encryption 187 | if name in ("aes-gcm-256",): 188 | return "encryption" 189 | 190 | # Filecoin 191 | if name in ("fil-commitment-unsealed", "fil-commitment-sealed"): 192 | return "filecoin" 193 | 194 | # Hash (non-multihash) 195 | if name in ( 196 | "murmur3-x64-64", 197 | "murmur3-32", 198 | "murmur3-128", 199 | "crc32", 200 | "crc64-ecma", 201 | "crc64-nvme", 202 | "murmur3-x64-128", 203 | "sha256a", 204 | "xxh-32", 205 | "xxh-64", 206 | "xxh3-64", 207 | "xxh3-128", 208 | ): 209 | return "hash" 210 | 211 | # Holochain 212 | if "holochain" in name: 213 | return "holochain" 214 | 215 | # IPLD 216 | if name in ( 217 | "cbor", 218 | "raw", 219 | "dag-pb", 220 | "dag-cbor", 221 | "libp2p-key", 222 | "git-raw", 223 | "torrent-info", 224 | "torrent-file", 225 | "blake3-hashseq", 226 | "leofcoin-block", 227 | "leofcoin-tx", 228 | "leofcoin-pr", 229 | "dag-jose", 230 | "dag-cose", 231 | "eth-block", 232 | "eth-block-list", 233 | "eth-tx-trie", 234 | "eth-tx", 235 | "eth-tx-receipt-trie", 236 | "eth-tx-receipt", 237 | "eth-state-trie", 238 | "eth-account-snapshot", 239 | "eth-storage-trie", 240 | "eth-receipt-log-trie", 241 | "eth-receipt-log", 242 | "bitcoin-block", 243 | "bitcoin-tx", 244 | "bitcoin-witness-commitment", 245 | "zcash-block", 246 | "zcash-tx", 247 | "stellar-block", 248 | "stellar-tx", 249 | "decred-block", 250 | "decred-tx", 251 | "dash-block", 252 | "dash-tx", 253 | "swarm-manifest", 254 | "swarm-feed", 255 | "beeson", 256 | "dag-json", 257 | "swhid-1-snp", 258 | "json", 259 | "rdfc-1", 260 | "json-jcs", 261 | ): 262 | return "ipld" 263 | 264 | # Key 265 | if any( 266 | k in name 267 | for k in ( 268 | "-pub", 269 | "-priv", 270 | "secp256k1", 271 | "bls12_381", 272 | "x25519", 273 | "ed25519", 274 | "p256", 275 | "p384", 276 | "p521", 277 | "ed448", 278 | "x448", 279 | "sr25519", 280 | "rsa", 281 | "sm2", 282 | "mlkem", 283 | "jwk", 284 | ) 285 | ): 286 | return "key" 287 | 288 | # Libp2p 289 | if name in ("libp2p-peer-record", "libp2p-relay-rsvp"): 290 | return "libp2p" 291 | 292 | # Multiaddr 293 | if name in ( 294 | "ip4", 295 | "tcp", 296 | "dccp", 297 | "ip6", 298 | "ip6zone", 299 | "ipcidr", 300 | "dns", 301 | "dns4", 302 | "dns6", 303 | "dnsaddr", 304 | "sctp", 305 | "udp", 306 | "p2p-webrtc-star", 307 | "p2p-webrtc-direct", 308 | "p2p-stardust", 309 | "p2p-circuit", 310 | "udt", 311 | "utp", 312 | "unix", 313 | "thread", 314 | "p2p", 315 | "https", 316 | "onion", 317 | "onion3", 318 | "garlic64", 319 | "garlic32", 320 | "tls", 321 | "sni", 322 | "noise", 323 | "shs", 324 | "quic", 325 | "quic-v1", 326 | "webtransport", 327 | "certhash", 328 | "ws", 329 | "wss", 330 | "p2p-websocket-star", 331 | "http", 332 | "http-path", 333 | "webrtc-direct", 334 | "webrtc", 335 | "plaintextv2", 336 | "scion", 337 | "memory", 338 | ): 339 | return "multiaddr" 340 | 341 | # Multiformat 342 | if name in ("multicodec", "multihash", "multiaddr", "multibase", "varsig"): 343 | return "multiformat" 344 | 345 | # Multihash 346 | if any( 347 | h in name 348 | for h in ( 349 | "identity", 350 | "sha1", 351 | "sha2-", 352 | "sha3-", 353 | "shake-", 354 | "keccak-", 355 | "blake2b-", 356 | "blake2s-", 357 | "blake3", 358 | "dbl-sha2-", 359 | "md4", 360 | "md5", 361 | "bmt", 362 | "ripemd-", 363 | "x11", 364 | "kangarootwelve", 365 | "sm3-", 366 | "poseidon-", 367 | "skein", 368 | ) 369 | ): 370 | return "multihash" 371 | 372 | # Namespace 373 | if name in ( 374 | "path", 375 | "lbry", 376 | "streamid", 377 | "ipld-ns", 378 | "ipfs-ns", 379 | "swarm-ns", 380 | "ipns-ns", 381 | "zeronet", 382 | "dnslink", 383 | "skynet-ns", 384 | "arweave-ns", 385 | "subspace-ns", 386 | "kumandra-ns", 387 | ): 388 | return "namespace" 389 | 390 | # Serialization 391 | if name in ( 392 | "protobuf", 393 | "rlp", 394 | "bencode", 395 | "messagepack", 396 | "car", 397 | "car-index-sorted", 398 | "car-multihash-index-sorted", 399 | "ipns-record", 400 | "x509-certificate", 401 | "ssz", 402 | ): 403 | return "serialization" 404 | 405 | # Transport 406 | if name in ( 407 | "transport-bitswap", 408 | "transport-graphsync-filecoinv1", 409 | "transport-ipfs-gateway-http", 410 | ): 411 | return "transport" 412 | 413 | # Varsig 414 | if name in ( 415 | "nonstandard-sig", 416 | "es256k", 417 | "bls12_381-g1-sig", 418 | "bls12_381-g2-sig", 419 | "eddsa", 420 | "eip-191", 421 | "es256", 422 | "es384", 423 | "es512", 424 | "rs256", 425 | ): 426 | return "varsig" 427 | 428 | # Zeroxcert 429 | if name in ("zeroxcert-imprint-256",): 430 | return "zeroxcert" 431 | 432 | return "" 433 | 434 | 435 | # Cache for known codes list 436 | _known_codes: list[Code] | None = None 437 | 438 | 439 | def known_codes() -> list[Code]: 440 | """ 441 | Return a list of all codes registered in the multicodec table. 442 | 443 | The returned list should be treated as read-only. 444 | 445 | :return: List of all known Code objects 446 | :rtype: list[Code] 447 | """ 448 | global _known_codes 449 | if _known_codes is None: 450 | _known_codes = [Code(code) for code in sorted(CODE_TABLE.keys())] 451 | return _known_codes 452 | 453 | 454 | def is_reserved(code: int | Code) -> bool: 455 | """ 456 | Check if a code falls within the reserved range. 457 | 458 | The reserved range (0x300000-0x3FFFFF) is designated for internal 459 | and experimental use. 460 | 461 | :param code: The codec code to check 462 | :return: True if the code is in the reserved range 463 | :rtype: bool 464 | """ 465 | if isinstance(code, Code): 466 | code = int(code) 467 | return RESERVED_START <= code <= RESERVED_END 468 | -------------------------------------------------------------------------------- /tests/test_serialization.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Tests for serialization module.""" 3 | 4 | import pytest 5 | 6 | from multicodec import ( 7 | Codec, 8 | CodecError, 9 | DecodeError, 10 | EncodeError, 11 | JSONCodec, 12 | MulticodecError, 13 | RawCodec, 14 | UnknownCodecError, 15 | decode, 16 | encode, 17 | get_registered_codec, 18 | is_codec_registered, 19 | json_codec, 20 | list_registered_codecs, 21 | raw_codec, 22 | register_codec, 23 | unregister_codec, 24 | ) 25 | 26 | 27 | class JSONCodecTestCase: 28 | """Tests for the JSONCodec class.""" 29 | 30 | def test_codec_properties(self): 31 | """Test codec name and code properties.""" 32 | codec = JSONCodec() 33 | assert codec.name == "json" 34 | assert codec.code == 0x0200 35 | 36 | def test_encode_simple_dict(self): 37 | """Test encoding a simple dictionary.""" 38 | codec = JSONCodec() 39 | data = {"hello": "world"} 40 | encoded = codec.encode(data) 41 | # Should have prefix (0x0200 as varint) + JSON bytes 42 | assert encoded.startswith(b"\x80\x04") # varint for 0x0200 43 | assert b"hello" in encoded 44 | assert b"world" in encoded 45 | 46 | def test_encode_decode_roundtrip(self): 47 | """Test encoding and decoding preserves data.""" 48 | codec = JSONCodec() 49 | test_cases = [ 50 | {"hello": "world"}, 51 | [1, 2, 3, 4, 5], 52 | {"nested": {"key": "value"}, "list": [1, 2, 3]}, 53 | "simple string", 54 | 123, 55 | 123.456, 56 | True, 57 | False, 58 | None, 59 | ] 60 | for data in test_cases: 61 | encoded = codec.encode(data) 62 | decoded = codec.decode(encoded) 63 | assert decoded == data, f"Failed for {data}" 64 | 65 | def test_encode_unicode(self): 66 | """Test encoding Unicode data.""" 67 | codec = JSONCodec() 68 | data = {"emoji": "🎉", "chinese": "你好", "arabic": "مرحبا"} 69 | encoded = codec.encode(data) 70 | decoded = codec.decode(encoded) 71 | assert decoded == data 72 | 73 | def test_encode_non_serializable_raises(self): 74 | """Test encoding non-JSON-serializable data raises EncodeError.""" 75 | codec = JSONCodec() 76 | with pytest.raises(EncodeError) as excinfo: 77 | codec.encode({"func": lambda x: x}) 78 | assert "not JSON serializable" in str(excinfo.value) 79 | 80 | def test_decode_invalid_json_raises(self): 81 | """Test decoding invalid JSON raises DecodeError.""" 82 | codec = JSONCodec() 83 | # Create a properly prefixed but invalid JSON payload 84 | prefix = b"\x80\x04" # varint for 0x0200 85 | invalid_json = prefix + b"not valid json" 86 | with pytest.raises(DecodeError) as excinfo: 87 | codec.decode(invalid_json) 88 | assert "Invalid JSON data" in str(excinfo.value) 89 | 90 | def test_decode_wrong_codec_raises(self): 91 | """Test decoding with wrong codec prefix raises DecodeError.""" 92 | codec = JSONCodec() 93 | # Use raw codec prefix (0x55) 94 | raw_prefixed = b"\x55" + b'{"hello": "world"}' 95 | with pytest.raises(DecodeError) as excinfo: 96 | codec.decode(raw_prefixed) 97 | assert "Codec mismatch" in str(excinfo.value) 98 | 99 | def test_decode_raw(self): 100 | """Test decoding without prefix using decode_raw.""" 101 | codec = JSONCodec() 102 | raw_json = b'{"hello": "world"}' 103 | decoded = codec.decode_raw(raw_json) 104 | assert decoded == {"hello": "world"} 105 | 106 | def test_repr(self): 107 | """Test codec string representation.""" 108 | codec = JSONCodec() 109 | repr_str = repr(codec) 110 | assert "JSONCodec" in repr_str 111 | assert "json" in repr_str 112 | assert "0x200" in repr_str 113 | 114 | 115 | class RawCodecTestCase: 116 | """Tests for the RawCodec class.""" 117 | 118 | def test_codec_properties(self): 119 | """Test codec name and code properties.""" 120 | codec = RawCodec() 121 | assert codec.name == "raw" 122 | assert codec.code == 0x55 123 | 124 | def test_encode_bytes(self): 125 | """Test encoding bytes.""" 126 | codec = RawCodec() 127 | data = b"binary data" 128 | encoded = codec.encode(data) 129 | # Should have prefix (0x55 as varint) + raw bytes 130 | assert encoded.startswith(b"\x55") 131 | assert encoded[1:] == data 132 | 133 | def test_encode_decode_roundtrip(self): 134 | """Test encoding and decoding preserves data.""" 135 | codec = RawCodec() 136 | test_cases = [ 137 | b"hello world", 138 | b"\x00\x01\x02\x03", 139 | b"", 140 | bytes(range(256)), 141 | ] 142 | for data in test_cases: 143 | encoded = codec.encode(data) 144 | decoded = codec.decode(encoded) 145 | assert decoded == data, f"Failed for {data!r}" 146 | 147 | def test_encode_non_bytes_raises(self): 148 | """Test encoding non-bytes data raises EncodeError.""" 149 | codec = RawCodec() 150 | with pytest.raises(EncodeError) as excinfo: 151 | codec.encode("not bytes") # type: ignore 152 | assert "expects bytes" in str(excinfo.value) 153 | 154 | def test_decode_wrong_codec_raises(self): 155 | """Test decoding with wrong codec prefix raises DecodeError.""" 156 | codec = RawCodec() 157 | # Use JSON codec prefix (0x0200) 158 | json_prefixed = b"\x80\x04" + b"some data" 159 | with pytest.raises(DecodeError) as excinfo: 160 | codec.decode(json_prefixed) 161 | assert "Codec mismatch" in str(excinfo.value) 162 | 163 | def test_repr(self): 164 | """Test codec string representation.""" 165 | codec = RawCodec() 166 | repr_str = repr(codec) 167 | assert "RawCodec" in repr_str 168 | assert "raw" in repr_str 169 | assert "0x55" in repr_str 170 | 171 | 172 | class SingletonCodecsTestCase: 173 | """Tests for singleton codec instances.""" 174 | 175 | def test_json_codec_instance(self): 176 | """Test json_codec is a JSONCodec instance.""" 177 | assert isinstance(json_codec, JSONCodec) 178 | assert json_codec.name == "json" 179 | 180 | def test_raw_codec_instance(self): 181 | """Test raw_codec is a RawCodec instance.""" 182 | assert isinstance(raw_codec, RawCodec) 183 | assert raw_codec.name == "raw" 184 | 185 | 186 | class CodecRegistryTestCase: 187 | """Tests for codec registry functions.""" 188 | 189 | def test_list_registered_codecs(self): 190 | """Test listing registered codecs.""" 191 | codecs = list_registered_codecs() 192 | assert "json" in codecs 193 | assert "raw" in codecs 194 | 195 | def test_is_codec_registered(self): 196 | """Test checking if codec is registered.""" 197 | assert is_codec_registered("json") 198 | assert is_codec_registered("raw") 199 | assert not is_codec_registered("nonexistent") 200 | 201 | def test_get_registered_codec(self): 202 | """Test getting registered codec.""" 203 | codec = get_registered_codec("json") 204 | assert isinstance(codec, JSONCodec) 205 | 206 | def test_get_unregistered_codec_raises(self): 207 | """Test getting unregistered codec raises UnknownCodecError.""" 208 | with pytest.raises(UnknownCodecError) as excinfo: 209 | get_registered_codec("nonexistent") 210 | assert "not registered" in str(excinfo.value) 211 | 212 | def test_register_custom_codec(self): 213 | """Test registering a custom codec.""" 214 | 215 | class CustomCodec(Codec[str]): 216 | @property 217 | def name(self) -> str: 218 | return "custom" 219 | 220 | @property 221 | def code(self) -> int: 222 | return 0x9999 223 | 224 | def _encode(self, data: str) -> bytes: 225 | return data.encode("utf-8") 226 | 227 | def _decode(self, data: bytes) -> str: 228 | return data.decode("utf-8") 229 | 230 | codec = CustomCodec() 231 | try: 232 | register_codec(codec) 233 | assert is_codec_registered("custom") 234 | assert get_registered_codec("custom") is codec 235 | finally: 236 | # Clean up 237 | unregister_codec("custom") 238 | 239 | def test_register_duplicate_raises(self): 240 | """Test registering duplicate codec raises ValueError.""" 241 | with pytest.raises(ValueError) as excinfo: 242 | register_codec(json_codec) 243 | assert "already registered" in str(excinfo.value) 244 | 245 | def test_unregister_codec(self): 246 | """Test unregistering a codec.""" 247 | 248 | class TempCodec(Codec[str]): 249 | @property 250 | def name(self) -> str: 251 | return "temp" 252 | 253 | @property 254 | def code(self) -> int: 255 | return 0x8888 256 | 257 | def _encode(self, data: str) -> bytes: 258 | return data.encode() 259 | 260 | def _decode(self, data: bytes) -> str: 261 | return data.decode() 262 | 263 | codec = TempCodec() 264 | register_codec(codec) 265 | assert is_codec_registered("temp") 266 | unregister_codec("temp") 267 | assert not is_codec_registered("temp") 268 | 269 | def test_unregister_nonexistent_raises(self): 270 | """Test unregistering nonexistent codec raises KeyError.""" 271 | with pytest.raises(KeyError) as excinfo: 272 | unregister_codec("nonexistent") 273 | assert "not registered" in str(excinfo.value) 274 | 275 | 276 | class GenericEncodeDecodeTestCase: 277 | """Tests for generic encode/decode functions.""" 278 | 279 | def test_encode_with_json(self): 280 | """Test generic encode with JSON codec.""" 281 | data = {"key": "value"} 282 | encoded = encode("json", data) 283 | assert encoded.startswith(b"\x80\x04") 284 | 285 | def test_encode_with_raw(self): 286 | """Test generic encode with raw codec.""" 287 | data = b"binary data" 288 | encoded = encode("raw", data) 289 | assert encoded.startswith(b"\x55") 290 | 291 | def test_encode_unknown_codec_raises(self): 292 | """Test encoding with unknown codec raises UnknownCodecError.""" 293 | with pytest.raises(UnknownCodecError): 294 | encode("nonexistent", {"data": "value"}) 295 | 296 | def test_decode_with_codec_name(self): 297 | """Test decode with explicit codec name.""" 298 | encoded = encode("json", {"hello": "world"}) 299 | decoded = decode(encoded, "json") 300 | assert decoded == {"hello": "world"} 301 | 302 | def test_decode_auto_detect(self): 303 | """Test decode with auto-detection.""" 304 | # JSON 305 | json_encoded = encode("json", {"hello": "world"}) 306 | json_decoded = decode(json_encoded) 307 | assert json_decoded == {"hello": "world"} 308 | 309 | # Raw 310 | raw_encoded = encode("raw", b"binary data") 311 | raw_decoded = decode(raw_encoded) 312 | assert raw_decoded == b"binary data" 313 | 314 | def test_decode_unknown_prefix_raises(self): 315 | """Test decoding unknown prefix raises DecodeError.""" 316 | # Use an unknown prefix 317 | unknown_data = b"\xff\xff\xff\x07" + b"some data" # Large unknown prefix 318 | with pytest.raises(DecodeError) as excinfo: 319 | decode(unknown_data) 320 | assert "Unknown codec prefix" in str(excinfo.value) 321 | 322 | def test_decode_unregistered_codec_raises(self): 323 | """Test decoding with unregistered codec raises UnknownCodecError.""" 324 | # Use a valid multicodec prefix that's not registered (e.g., cbor = 0x51) 325 | import varint as varint_lib 326 | 327 | cbor_prefix = varint_lib.encode(0x51) # cbor codec 328 | data = cbor_prefix + b"\xa1\x65hello\x65world" # some CBOR-ish data 329 | with pytest.raises(UnknownCodecError) as excinfo: 330 | decode(data) 331 | assert "not registered" in str(excinfo.value) 332 | 333 | def test_decode_invalid_varint_raises(self): 334 | """Test decoding invalid varint raises DecodeError.""" 335 | with pytest.raises(DecodeError) as excinfo: 336 | decode(b"\xff") # Invalid varint 337 | assert "Invalid varint prefix" in str(excinfo.value) 338 | 339 | 340 | class ExceptionsTestCase: 341 | """Tests for exception hierarchy.""" 342 | 343 | def test_exception_hierarchy(self): 344 | """Test exception inheritance.""" 345 | assert issubclass(CodecError, MulticodecError) 346 | assert issubclass(EncodeError, CodecError) 347 | assert issubclass(DecodeError, CodecError) 348 | assert issubclass(UnknownCodecError, CodecError) 349 | assert issubclass(MulticodecError, Exception) 350 | 351 | def test_encode_error_message(self): 352 | """Test EncodeError message.""" 353 | err = EncodeError("test error") 354 | assert str(err) == "test error" 355 | 356 | def test_decode_error_message(self): 357 | """Test DecodeError message.""" 358 | err = DecodeError("test error") 359 | assert str(err) == "test error" 360 | 361 | def test_unknown_codec_error_message(self): 362 | """Test UnknownCodecError message.""" 363 | err = UnknownCodecError("test error") 364 | assert str(err) == "test error" 365 | 366 | 367 | class EdgeCasesTestCase: 368 | """Tests for edge cases.""" 369 | 370 | def test_empty_json_object(self): 371 | """Test encoding/decoding empty JSON object.""" 372 | codec = JSONCodec() 373 | encoded = codec.encode({}) 374 | decoded = codec.decode(encoded) 375 | assert decoded == {} 376 | 377 | def test_empty_json_array(self): 378 | """Test encoding/decoding empty JSON array.""" 379 | codec = JSONCodec() 380 | encoded = codec.encode([]) 381 | decoded = codec.decode(encoded) 382 | assert decoded == [] 383 | 384 | def test_empty_raw_bytes(self): 385 | """Test encoding/decoding empty bytes.""" 386 | codec = RawCodec() 387 | encoded = codec.encode(b"") 388 | decoded = codec.decode(encoded) 389 | assert decoded == b"" 390 | 391 | def test_large_json_data(self): 392 | """Test encoding/decoding large JSON data.""" 393 | codec = JSONCodec() 394 | data = {"items": list(range(10000))} 395 | encoded = codec.encode(data) 396 | decoded = codec.decode(encoded) 397 | assert decoded == data 398 | 399 | def test_large_raw_data(self): 400 | """Test encoding/decoding large raw data.""" 401 | codec = RawCodec() 402 | data = bytes(range(256)) * 1000 403 | encoded = codec.encode(data) 404 | decoded = codec.decode(encoded) 405 | assert decoded == data 406 | 407 | def test_deeply_nested_json(self): 408 | """Test encoding/decoding deeply nested JSON.""" 409 | codec = JSONCodec() 410 | # Create deeply nested structure 411 | data: dict = {"level": 0} 412 | current = data 413 | for i in range(1, 50): 414 | current["nested"] = {"level": i} 415 | current = current["nested"] 416 | encoded = codec.encode(data) 417 | decoded = codec.decode(encoded) 418 | assert decoded == data 419 | -------------------------------------------------------------------------------- /multicodec/constants.py: -------------------------------------------------------------------------------- 1 | # THIS FILE IS GENERATED, DO NO EDIT MANUALLY 2 | # For more information see the README.md 3 | 4 | CODECS = { 5 | # serialization 6 | "protobuf": { 7 | "prefix": 0x50, 8 | }, 9 | "cbor": { 10 | "prefix": 0x51, 11 | }, 12 | "rlp": { 13 | "prefix": 0x60, 14 | }, 15 | "bencode": { 16 | "prefix": 0x63, 17 | }, 18 | "json": { 19 | "prefix": 0x0200, 20 | }, 21 | "messagepack": { 22 | "prefix": 0x0201, 23 | }, 24 | # multiformat 25 | "multicodec": { 26 | "prefix": 0x30, 27 | }, 28 | "multihash": { 29 | "prefix": 0x31, 30 | }, 31 | "multiaddr": { 32 | "prefix": 0x32, 33 | }, 34 | "multibase": { 35 | "prefix": 0x33, 36 | }, 37 | # multihash 38 | "identity": { 39 | "prefix": 0x00, 40 | }, 41 | "sha1": { 42 | "prefix": 0x11, 43 | }, 44 | "sha2-256": { 45 | "prefix": 0x12, 46 | }, 47 | "sha2-512": { 48 | "prefix": 0x13, 49 | }, 50 | "sha3-512": { 51 | "prefix": 0x14, 52 | }, 53 | "sha3-384": { 54 | "prefix": 0x15, 55 | }, 56 | "sha3-256": { 57 | "prefix": 0x16, 58 | }, 59 | "sha3-224": { 60 | "prefix": 0x17, 61 | }, 62 | "shake-128": { 63 | "prefix": 0x18, 64 | }, 65 | "shake-256": { 66 | "prefix": 0x19, 67 | }, 68 | "keccak-224": { 69 | "prefix": 0x1A, 70 | }, 71 | "keccak-256": { 72 | "prefix": 0x1B, 73 | }, 74 | "keccak-384": { 75 | "prefix": 0x1C, 76 | }, 77 | "keccak-512": { 78 | "prefix": 0x1D, 79 | }, 80 | "blake3": { 81 | "prefix": 0x1E, 82 | }, 83 | "murmur3-128": { 84 | "prefix": 0x22, 85 | }, 86 | "murmur3-32": { 87 | "prefix": 0x23, 88 | }, 89 | "dbl-sha2-256": { 90 | "prefix": 0x56, 91 | }, 92 | "md4": { 93 | "prefix": 0xD4, 94 | }, 95 | "md5": { 96 | "prefix": 0xD5, 97 | }, 98 | "bmt": { 99 | "prefix": 0xD6, 100 | }, 101 | "sha2-256-trunc254-padded": { 102 | "prefix": 0x1012, 103 | }, 104 | "ripemd-128": { 105 | "prefix": 0x1052, 106 | }, 107 | "ripemd-160": { 108 | "prefix": 0x1053, 109 | }, 110 | "ripemd-256": { 111 | "prefix": 0x1054, 112 | }, 113 | "ripemd-320": { 114 | "prefix": 0x1055, 115 | }, 116 | "x11": { 117 | "prefix": 0x1100, 118 | }, 119 | "kangarootwelve": { 120 | "prefix": 0x1D01, 121 | }, 122 | "sm3-256": { 123 | "prefix": 0x534D, 124 | }, 125 | "blake2b-8": { 126 | "prefix": 0xB201, 127 | }, 128 | "blake2b-16": { 129 | "prefix": 0xB202, 130 | }, 131 | "blake2b-24": { 132 | "prefix": 0xB203, 133 | }, 134 | "blake2b-32": { 135 | "prefix": 0xB204, 136 | }, 137 | "blake2b-40": { 138 | "prefix": 0xB205, 139 | }, 140 | "blake2b-48": { 141 | "prefix": 0xB206, 142 | }, 143 | "blake2b-56": { 144 | "prefix": 0xB207, 145 | }, 146 | "blake2b-64": { 147 | "prefix": 0xB208, 148 | }, 149 | "blake2b-72": { 150 | "prefix": 0xB209, 151 | }, 152 | "blake2b-80": { 153 | "prefix": 0xB20A, 154 | }, 155 | "blake2b-88": { 156 | "prefix": 0xB20B, 157 | }, 158 | "blake2b-96": { 159 | "prefix": 0xB20C, 160 | }, 161 | "blake2b-104": { 162 | "prefix": 0xB20D, 163 | }, 164 | "blake2b-112": { 165 | "prefix": 0xB20E, 166 | }, 167 | "blake2b-120": { 168 | "prefix": 0xB20F, 169 | }, 170 | "blake2b-128": { 171 | "prefix": 0xB210, 172 | }, 173 | "blake2b-136": { 174 | "prefix": 0xB211, 175 | }, 176 | "blake2b-144": { 177 | "prefix": 0xB212, 178 | }, 179 | "blake2b-152": { 180 | "prefix": 0xB213, 181 | }, 182 | "blake2b-160": { 183 | "prefix": 0xB214, 184 | }, 185 | "blake2b-168": { 186 | "prefix": 0xB215, 187 | }, 188 | "blake2b-176": { 189 | "prefix": 0xB216, 190 | }, 191 | "blake2b-184": { 192 | "prefix": 0xB217, 193 | }, 194 | "blake2b-192": { 195 | "prefix": 0xB218, 196 | }, 197 | "blake2b-200": { 198 | "prefix": 0xB219, 199 | }, 200 | "blake2b-208": { 201 | "prefix": 0xB21A, 202 | }, 203 | "blake2b-216": { 204 | "prefix": 0xB21B, 205 | }, 206 | "blake2b-224": { 207 | "prefix": 0xB21C, 208 | }, 209 | "blake2b-232": { 210 | "prefix": 0xB21D, 211 | }, 212 | "blake2b-240": { 213 | "prefix": 0xB21E, 214 | }, 215 | "blake2b-248": { 216 | "prefix": 0xB21F, 217 | }, 218 | "blake2b-256": { 219 | "prefix": 0xB220, 220 | }, 221 | "blake2b-264": { 222 | "prefix": 0xB221, 223 | }, 224 | "blake2b-272": { 225 | "prefix": 0xB222, 226 | }, 227 | "blake2b-280": { 228 | "prefix": 0xB223, 229 | }, 230 | "blake2b-288": { 231 | "prefix": 0xB224, 232 | }, 233 | "blake2b-296": { 234 | "prefix": 0xB225, 235 | }, 236 | "blake2b-304": { 237 | "prefix": 0xB226, 238 | }, 239 | "blake2b-312": { 240 | "prefix": 0xB227, 241 | }, 242 | "blake2b-320": { 243 | "prefix": 0xB228, 244 | }, 245 | "blake2b-328": { 246 | "prefix": 0xB229, 247 | }, 248 | "blake2b-336": { 249 | "prefix": 0xB22A, 250 | }, 251 | "blake2b-344": { 252 | "prefix": 0xB22B, 253 | }, 254 | "blake2b-352": { 255 | "prefix": 0xB22C, 256 | }, 257 | "blake2b-360": { 258 | "prefix": 0xB22D, 259 | }, 260 | "blake2b-368": { 261 | "prefix": 0xB22E, 262 | }, 263 | "blake2b-376": { 264 | "prefix": 0xB22F, 265 | }, 266 | "blake2b-384": { 267 | "prefix": 0xB230, 268 | }, 269 | "blake2b-392": { 270 | "prefix": 0xB231, 271 | }, 272 | "blake2b-400": { 273 | "prefix": 0xB232, 274 | }, 275 | "blake2b-408": { 276 | "prefix": 0xB233, 277 | }, 278 | "blake2b-416": { 279 | "prefix": 0xB234, 280 | }, 281 | "blake2b-424": { 282 | "prefix": 0xB235, 283 | }, 284 | "blake2b-432": { 285 | "prefix": 0xB236, 286 | }, 287 | "blake2b-440": { 288 | "prefix": 0xB237, 289 | }, 290 | "blake2b-448": { 291 | "prefix": 0xB238, 292 | }, 293 | "blake2b-456": { 294 | "prefix": 0xB239, 295 | }, 296 | "blake2b-464": { 297 | "prefix": 0xB23A, 298 | }, 299 | "blake2b-472": { 300 | "prefix": 0xB23B, 301 | }, 302 | "blake2b-480": { 303 | "prefix": 0xB23C, 304 | }, 305 | "blake2b-488": { 306 | "prefix": 0xB23D, 307 | }, 308 | "blake2b-496": { 309 | "prefix": 0xB23E, 310 | }, 311 | "blake2b-504": { 312 | "prefix": 0xB23F, 313 | }, 314 | "blake2b-512": { 315 | "prefix": 0xB240, 316 | }, 317 | "blake2s-8": { 318 | "prefix": 0xB241, 319 | }, 320 | "blake2s-16": { 321 | "prefix": 0xB242, 322 | }, 323 | "blake2s-24": { 324 | "prefix": 0xB243, 325 | }, 326 | "blake2s-32": { 327 | "prefix": 0xB244, 328 | }, 329 | "blake2s-40": { 330 | "prefix": 0xB245, 331 | }, 332 | "blake2s-48": { 333 | "prefix": 0xB246, 334 | }, 335 | "blake2s-56": { 336 | "prefix": 0xB247, 337 | }, 338 | "blake2s-64": { 339 | "prefix": 0xB248, 340 | }, 341 | "blake2s-72": { 342 | "prefix": 0xB249, 343 | }, 344 | "blake2s-80": { 345 | "prefix": 0xB24A, 346 | }, 347 | "blake2s-88": { 348 | "prefix": 0xB24B, 349 | }, 350 | "blake2s-96": { 351 | "prefix": 0xB24C, 352 | }, 353 | "blake2s-104": { 354 | "prefix": 0xB24D, 355 | }, 356 | "blake2s-112": { 357 | "prefix": 0xB24E, 358 | }, 359 | "blake2s-120": { 360 | "prefix": 0xB24F, 361 | }, 362 | "blake2s-128": { 363 | "prefix": 0xB250, 364 | }, 365 | "blake2s-136": { 366 | "prefix": 0xB251, 367 | }, 368 | "blake2s-144": { 369 | "prefix": 0xB252, 370 | }, 371 | "blake2s-152": { 372 | "prefix": 0xB253, 373 | }, 374 | "blake2s-160": { 375 | "prefix": 0xB254, 376 | }, 377 | "blake2s-168": { 378 | "prefix": 0xB255, 379 | }, 380 | "blake2s-176": { 381 | "prefix": 0xB256, 382 | }, 383 | "blake2s-184": { 384 | "prefix": 0xB257, 385 | }, 386 | "blake2s-192": { 387 | "prefix": 0xB258, 388 | }, 389 | "blake2s-200": { 390 | "prefix": 0xB259, 391 | }, 392 | "blake2s-208": { 393 | "prefix": 0xB25A, 394 | }, 395 | "blake2s-216": { 396 | "prefix": 0xB25B, 397 | }, 398 | "blake2s-224": { 399 | "prefix": 0xB25C, 400 | }, 401 | "blake2s-232": { 402 | "prefix": 0xB25D, 403 | }, 404 | "blake2s-240": { 405 | "prefix": 0xB25E, 406 | }, 407 | "blake2s-248": { 408 | "prefix": 0xB25F, 409 | }, 410 | "blake2s-256": { 411 | "prefix": 0xB260, 412 | }, 413 | "skein256-8": { 414 | "prefix": 0xB301, 415 | }, 416 | "skein256-16": { 417 | "prefix": 0xB302, 418 | }, 419 | "skein256-24": { 420 | "prefix": 0xB303, 421 | }, 422 | "skein256-32": { 423 | "prefix": 0xB304, 424 | }, 425 | "skein256-40": { 426 | "prefix": 0xB305, 427 | }, 428 | "skein256-48": { 429 | "prefix": 0xB306, 430 | }, 431 | "skein256-56": { 432 | "prefix": 0xB307, 433 | }, 434 | "skein256-64": { 435 | "prefix": 0xB308, 436 | }, 437 | "skein256-72": { 438 | "prefix": 0xB309, 439 | }, 440 | "skein256-80": { 441 | "prefix": 0xB30A, 442 | }, 443 | "skein256-88": { 444 | "prefix": 0xB30B, 445 | }, 446 | "skein256-96": { 447 | "prefix": 0xB30C, 448 | }, 449 | "skein256-104": { 450 | "prefix": 0xB30D, 451 | }, 452 | "skein256-112": { 453 | "prefix": 0xB30E, 454 | }, 455 | "skein256-120": { 456 | "prefix": 0xB30F, 457 | }, 458 | "skein256-128": { 459 | "prefix": 0xB310, 460 | }, 461 | "skein256-136": { 462 | "prefix": 0xB311, 463 | }, 464 | "skein256-144": { 465 | "prefix": 0xB312, 466 | }, 467 | "skein256-152": { 468 | "prefix": 0xB313, 469 | }, 470 | "skein256-160": { 471 | "prefix": 0xB314, 472 | }, 473 | "skein256-168": { 474 | "prefix": 0xB315, 475 | }, 476 | "skein256-176": { 477 | "prefix": 0xB316, 478 | }, 479 | "skein256-184": { 480 | "prefix": 0xB317, 481 | }, 482 | "skein256-192": { 483 | "prefix": 0xB318, 484 | }, 485 | "skein256-200": { 486 | "prefix": 0xB319, 487 | }, 488 | "skein256-208": { 489 | "prefix": 0xB31A, 490 | }, 491 | "skein256-216": { 492 | "prefix": 0xB31B, 493 | }, 494 | "skein256-224": { 495 | "prefix": 0xB31C, 496 | }, 497 | "skein256-232": { 498 | "prefix": 0xB31D, 499 | }, 500 | "skein256-240": { 501 | "prefix": 0xB31E, 502 | }, 503 | "skein256-248": { 504 | "prefix": 0xB31F, 505 | }, 506 | "skein256-256": { 507 | "prefix": 0xB320, 508 | }, 509 | "skein512-8": { 510 | "prefix": 0xB321, 511 | }, 512 | "skein512-16": { 513 | "prefix": 0xB322, 514 | }, 515 | "skein512-24": { 516 | "prefix": 0xB323, 517 | }, 518 | "skein512-32": { 519 | "prefix": 0xB324, 520 | }, 521 | "skein512-40": { 522 | "prefix": 0xB325, 523 | }, 524 | "skein512-48": { 525 | "prefix": 0xB326, 526 | }, 527 | "skein512-56": { 528 | "prefix": 0xB327, 529 | }, 530 | "skein512-64": { 531 | "prefix": 0xB328, 532 | }, 533 | "skein512-72": { 534 | "prefix": 0xB329, 535 | }, 536 | "skein512-80": { 537 | "prefix": 0xB32A, 538 | }, 539 | "skein512-88": { 540 | "prefix": 0xB32B, 541 | }, 542 | "skein512-96": { 543 | "prefix": 0xB32C, 544 | }, 545 | "skein512-104": { 546 | "prefix": 0xB32D, 547 | }, 548 | "skein512-112": { 549 | "prefix": 0xB32E, 550 | }, 551 | "skein512-120": { 552 | "prefix": 0xB32F, 553 | }, 554 | "skein512-128": { 555 | "prefix": 0xB330, 556 | }, 557 | "skein512-136": { 558 | "prefix": 0xB331, 559 | }, 560 | "skein512-144": { 561 | "prefix": 0xB332, 562 | }, 563 | "skein512-152": { 564 | "prefix": 0xB333, 565 | }, 566 | "skein512-160": { 567 | "prefix": 0xB334, 568 | }, 569 | "skein512-168": { 570 | "prefix": 0xB335, 571 | }, 572 | "skein512-176": { 573 | "prefix": 0xB336, 574 | }, 575 | "skein512-184": { 576 | "prefix": 0xB337, 577 | }, 578 | "skein512-192": { 579 | "prefix": 0xB338, 580 | }, 581 | "skein512-200": { 582 | "prefix": 0xB339, 583 | }, 584 | "skein512-208": { 585 | "prefix": 0xB33A, 586 | }, 587 | "skein512-216": { 588 | "prefix": 0xB33B, 589 | }, 590 | "skein512-224": { 591 | "prefix": 0xB33C, 592 | }, 593 | "skein512-232": { 594 | "prefix": 0xB33D, 595 | }, 596 | "skein512-240": { 597 | "prefix": 0xB33E, 598 | }, 599 | "skein512-248": { 600 | "prefix": 0xB33F, 601 | }, 602 | "skein512-256": { 603 | "prefix": 0xB340, 604 | }, 605 | "skein512-264": { 606 | "prefix": 0xB341, 607 | }, 608 | "skein512-272": { 609 | "prefix": 0xB342, 610 | }, 611 | "skein512-280": { 612 | "prefix": 0xB343, 613 | }, 614 | "skein512-288": { 615 | "prefix": 0xB344, 616 | }, 617 | "skein512-296": { 618 | "prefix": 0xB345, 619 | }, 620 | "skein512-304": { 621 | "prefix": 0xB346, 622 | }, 623 | "skein512-312": { 624 | "prefix": 0xB347, 625 | }, 626 | "skein512-320": { 627 | "prefix": 0xB348, 628 | }, 629 | "skein512-328": { 630 | "prefix": 0xB349, 631 | }, 632 | "skein512-336": { 633 | "prefix": 0xB34A, 634 | }, 635 | "skein512-344": { 636 | "prefix": 0xB34B, 637 | }, 638 | "skein512-352": { 639 | "prefix": 0xB34C, 640 | }, 641 | "skein512-360": { 642 | "prefix": 0xB34D, 643 | }, 644 | "skein512-368": { 645 | "prefix": 0xB34E, 646 | }, 647 | "skein512-376": { 648 | "prefix": 0xB34F, 649 | }, 650 | "skein512-384": { 651 | "prefix": 0xB350, 652 | }, 653 | "skein512-392": { 654 | "prefix": 0xB351, 655 | }, 656 | "skein512-400": { 657 | "prefix": 0xB352, 658 | }, 659 | "skein512-408": { 660 | "prefix": 0xB353, 661 | }, 662 | "skein512-416": { 663 | "prefix": 0xB354, 664 | }, 665 | "skein512-424": { 666 | "prefix": 0xB355, 667 | }, 668 | "skein512-432": { 669 | "prefix": 0xB356, 670 | }, 671 | "skein512-440": { 672 | "prefix": 0xB357, 673 | }, 674 | "skein512-448": { 675 | "prefix": 0xB358, 676 | }, 677 | "skein512-456": { 678 | "prefix": 0xB359, 679 | }, 680 | "skein512-464": { 681 | "prefix": 0xB35A, 682 | }, 683 | "skein512-472": { 684 | "prefix": 0xB35B, 685 | }, 686 | "skein512-480": { 687 | "prefix": 0xB35C, 688 | }, 689 | "skein512-488": { 690 | "prefix": 0xB35D, 691 | }, 692 | "skein512-496": { 693 | "prefix": 0xB35E, 694 | }, 695 | "skein512-504": { 696 | "prefix": 0xB35F, 697 | }, 698 | "skein512-512": { 699 | "prefix": 0xB360, 700 | }, 701 | "skein1024-8": { 702 | "prefix": 0xB361, 703 | }, 704 | "skein1024-16": { 705 | "prefix": 0xB362, 706 | }, 707 | "skein1024-24": { 708 | "prefix": 0xB363, 709 | }, 710 | "skein1024-32": { 711 | "prefix": 0xB364, 712 | }, 713 | "skein1024-40": { 714 | "prefix": 0xB365, 715 | }, 716 | "skein1024-48": { 717 | "prefix": 0xB366, 718 | }, 719 | "skein1024-56": { 720 | "prefix": 0xB367, 721 | }, 722 | "skein1024-64": { 723 | "prefix": 0xB368, 724 | }, 725 | "skein1024-72": { 726 | "prefix": 0xB369, 727 | }, 728 | "skein1024-80": { 729 | "prefix": 0xB36A, 730 | }, 731 | "skein1024-88": { 732 | "prefix": 0xB36B, 733 | }, 734 | "skein1024-96": { 735 | "prefix": 0xB36C, 736 | }, 737 | "skein1024-104": { 738 | "prefix": 0xB36D, 739 | }, 740 | "skein1024-112": { 741 | "prefix": 0xB36E, 742 | }, 743 | "skein1024-120": { 744 | "prefix": 0xB36F, 745 | }, 746 | "skein1024-128": { 747 | "prefix": 0xB370, 748 | }, 749 | "skein1024-136": { 750 | "prefix": 0xB371, 751 | }, 752 | "skein1024-144": { 753 | "prefix": 0xB372, 754 | }, 755 | "skein1024-152": { 756 | "prefix": 0xB373, 757 | }, 758 | "skein1024-160": { 759 | "prefix": 0xB374, 760 | }, 761 | "skein1024-168": { 762 | "prefix": 0xB375, 763 | }, 764 | "skein1024-176": { 765 | "prefix": 0xB376, 766 | }, 767 | "skein1024-184": { 768 | "prefix": 0xB377, 769 | }, 770 | "skein1024-192": { 771 | "prefix": 0xB378, 772 | }, 773 | "skein1024-200": { 774 | "prefix": 0xB379, 775 | }, 776 | "skein1024-208": { 777 | "prefix": 0xB37A, 778 | }, 779 | "skein1024-216": { 780 | "prefix": 0xB37B, 781 | }, 782 | "skein1024-224": { 783 | "prefix": 0xB37C, 784 | }, 785 | "skein1024-232": { 786 | "prefix": 0xB37D, 787 | }, 788 | "skein1024-240": { 789 | "prefix": 0xB37E, 790 | }, 791 | "skein1024-248": { 792 | "prefix": 0xB37F, 793 | }, 794 | "skein1024-256": { 795 | "prefix": 0xB380, 796 | }, 797 | "skein1024-264": { 798 | "prefix": 0xB381, 799 | }, 800 | "skein1024-272": { 801 | "prefix": 0xB382, 802 | }, 803 | "skein1024-280": { 804 | "prefix": 0xB383, 805 | }, 806 | "skein1024-288": { 807 | "prefix": 0xB384, 808 | }, 809 | "skein1024-296": { 810 | "prefix": 0xB385, 811 | }, 812 | "skein1024-304": { 813 | "prefix": 0xB386, 814 | }, 815 | "skein1024-312": { 816 | "prefix": 0xB387, 817 | }, 818 | "skein1024-320": { 819 | "prefix": 0xB388, 820 | }, 821 | "skein1024-328": { 822 | "prefix": 0xB389, 823 | }, 824 | "skein1024-336": { 825 | "prefix": 0xB38A, 826 | }, 827 | "skein1024-344": { 828 | "prefix": 0xB38B, 829 | }, 830 | "skein1024-352": { 831 | "prefix": 0xB38C, 832 | }, 833 | "skein1024-360": { 834 | "prefix": 0xB38D, 835 | }, 836 | "skein1024-368": { 837 | "prefix": 0xB38E, 838 | }, 839 | "skein1024-376": { 840 | "prefix": 0xB38F, 841 | }, 842 | "skein1024-384": { 843 | "prefix": 0xB390, 844 | }, 845 | "skein1024-392": { 846 | "prefix": 0xB391, 847 | }, 848 | "skein1024-400": { 849 | "prefix": 0xB392, 850 | }, 851 | "skein1024-408": { 852 | "prefix": 0xB393, 853 | }, 854 | "skein1024-416": { 855 | "prefix": 0xB394, 856 | }, 857 | "skein1024-424": { 858 | "prefix": 0xB395, 859 | }, 860 | "skein1024-432": { 861 | "prefix": 0xB396, 862 | }, 863 | "skein1024-440": { 864 | "prefix": 0xB397, 865 | }, 866 | "skein1024-448": { 867 | "prefix": 0xB398, 868 | }, 869 | "skein1024-456": { 870 | "prefix": 0xB399, 871 | }, 872 | "skein1024-464": { 873 | "prefix": 0xB39A, 874 | }, 875 | "skein1024-472": { 876 | "prefix": 0xB39B, 877 | }, 878 | "skein1024-480": { 879 | "prefix": 0xB39C, 880 | }, 881 | "skein1024-488": { 882 | "prefix": 0xB39D, 883 | }, 884 | "skein1024-496": { 885 | "prefix": 0xB39E, 886 | }, 887 | "skein1024-504": { 888 | "prefix": 0xB39F, 889 | }, 890 | "skein1024-512": { 891 | "prefix": 0xB3A0, 892 | }, 893 | "skein1024-520": { 894 | "prefix": 0xB3A1, 895 | }, 896 | "skein1024-528": { 897 | "prefix": 0xB3A2, 898 | }, 899 | "skein1024-536": { 900 | "prefix": 0xB3A3, 901 | }, 902 | "skein1024-544": { 903 | "prefix": 0xB3A4, 904 | }, 905 | "skein1024-552": { 906 | "prefix": 0xB3A5, 907 | }, 908 | "skein1024-560": { 909 | "prefix": 0xB3A6, 910 | }, 911 | "skein1024-568": { 912 | "prefix": 0xB3A7, 913 | }, 914 | "skein1024-576": { 915 | "prefix": 0xB3A8, 916 | }, 917 | "skein1024-584": { 918 | "prefix": 0xB3A9, 919 | }, 920 | "skein1024-592": { 921 | "prefix": 0xB3AA, 922 | }, 923 | "skein1024-600": { 924 | "prefix": 0xB3AB, 925 | }, 926 | "skein1024-608": { 927 | "prefix": 0xB3AC, 928 | }, 929 | "skein1024-616": { 930 | "prefix": 0xB3AD, 931 | }, 932 | "skein1024-624": { 933 | "prefix": 0xB3AE, 934 | }, 935 | "skein1024-632": { 936 | "prefix": 0xB3AF, 937 | }, 938 | "skein1024-640": { 939 | "prefix": 0xB3B0, 940 | }, 941 | "skein1024-648": { 942 | "prefix": 0xB3B1, 943 | }, 944 | "skein1024-656": { 945 | "prefix": 0xB3B2, 946 | }, 947 | "skein1024-664": { 948 | "prefix": 0xB3B3, 949 | }, 950 | "skein1024-672": { 951 | "prefix": 0xB3B4, 952 | }, 953 | "skein1024-680": { 954 | "prefix": 0xB3B5, 955 | }, 956 | "skein1024-688": { 957 | "prefix": 0xB3B6, 958 | }, 959 | "skein1024-696": { 960 | "prefix": 0xB3B7, 961 | }, 962 | "skein1024-704": { 963 | "prefix": 0xB3B8, 964 | }, 965 | "skein1024-712": { 966 | "prefix": 0xB3B9, 967 | }, 968 | "skein1024-720": { 969 | "prefix": 0xB3BA, 970 | }, 971 | "skein1024-728": { 972 | "prefix": 0xB3BB, 973 | }, 974 | "skein1024-736": { 975 | "prefix": 0xB3BC, 976 | }, 977 | "skein1024-744": { 978 | "prefix": 0xB3BD, 979 | }, 980 | "skein1024-752": { 981 | "prefix": 0xB3BE, 982 | }, 983 | "skein1024-760": { 984 | "prefix": 0xB3BF, 985 | }, 986 | "skein1024-768": { 987 | "prefix": 0xB3C0, 988 | }, 989 | "skein1024-776": { 990 | "prefix": 0xB3C1, 991 | }, 992 | "skein1024-784": { 993 | "prefix": 0xB3C2, 994 | }, 995 | "skein1024-792": { 996 | "prefix": 0xB3C3, 997 | }, 998 | "skein1024-800": { 999 | "prefix": 0xB3C4, 1000 | }, 1001 | "skein1024-808": { 1002 | "prefix": 0xB3C5, 1003 | }, 1004 | "skein1024-816": { 1005 | "prefix": 0xB3C6, 1006 | }, 1007 | "skein1024-824": { 1008 | "prefix": 0xB3C7, 1009 | }, 1010 | "skein1024-832": { 1011 | "prefix": 0xB3C8, 1012 | }, 1013 | "skein1024-840": { 1014 | "prefix": 0xB3C9, 1015 | }, 1016 | "skein1024-848": { 1017 | "prefix": 0xB3CA, 1018 | }, 1019 | "skein1024-856": { 1020 | "prefix": 0xB3CB, 1021 | }, 1022 | "skein1024-864": { 1023 | "prefix": 0xB3CC, 1024 | }, 1025 | "skein1024-872": { 1026 | "prefix": 0xB3CD, 1027 | }, 1028 | "skein1024-880": { 1029 | "prefix": 0xB3CE, 1030 | }, 1031 | "skein1024-888": { 1032 | "prefix": 0xB3CF, 1033 | }, 1034 | "skein1024-896": { 1035 | "prefix": 0xB3D0, 1036 | }, 1037 | "skein1024-904": { 1038 | "prefix": 0xB3D1, 1039 | }, 1040 | "skein1024-912": { 1041 | "prefix": 0xB3D2, 1042 | }, 1043 | "skein1024-920": { 1044 | "prefix": 0xB3D3, 1045 | }, 1046 | "skein1024-928": { 1047 | "prefix": 0xB3D4, 1048 | }, 1049 | "skein1024-936": { 1050 | "prefix": 0xB3D5, 1051 | }, 1052 | "skein1024-944": { 1053 | "prefix": 0xB3D6, 1054 | }, 1055 | "skein1024-952": { 1056 | "prefix": 0xB3D7, 1057 | }, 1058 | "skein1024-960": { 1059 | "prefix": 0xB3D8, 1060 | }, 1061 | "skein1024-968": { 1062 | "prefix": 0xB3D9, 1063 | }, 1064 | "skein1024-976": { 1065 | "prefix": 0xB3DA, 1066 | }, 1067 | "skein1024-984": { 1068 | "prefix": 0xB3DB, 1069 | }, 1070 | "skein1024-992": { 1071 | "prefix": 0xB3DC, 1072 | }, 1073 | "skein1024-1000": { 1074 | "prefix": 0xB3DD, 1075 | }, 1076 | "skein1024-1008": { 1077 | "prefix": 0xB3DE, 1078 | }, 1079 | "skein1024-1016": { 1080 | "prefix": 0xB3DF, 1081 | }, 1082 | "skein1024-1024": { 1083 | "prefix": 0xB3E0, 1084 | }, 1085 | "poseidon-bls12_381-a2-fc1": { 1086 | "prefix": 0xB401, 1087 | }, 1088 | "poseidon-bls12_381-a2-fc1-sc": { 1089 | "prefix": 0xB402, 1090 | }, 1091 | # multiaddr 1092 | "ip4": { 1093 | "prefix": 0x04, 1094 | }, 1095 | "tcp": { 1096 | "prefix": 0x06, 1097 | }, 1098 | "dccp": { 1099 | "prefix": 0x21, 1100 | }, 1101 | "ip6": { 1102 | "prefix": 0x29, 1103 | }, 1104 | "ip6zone": { 1105 | "prefix": 0x2A, 1106 | }, 1107 | "dns": { 1108 | "prefix": 0x35, 1109 | }, 1110 | "dns4": { 1111 | "prefix": 0x36, 1112 | }, 1113 | "dns6": { 1114 | "prefix": 0x37, 1115 | }, 1116 | "dnsaddr": { 1117 | "prefix": 0x38, 1118 | }, 1119 | "sctp": { 1120 | "prefix": 0x84, 1121 | }, 1122 | "udp": { 1123 | "prefix": 0x0111, 1124 | }, 1125 | "p2p-webrtc-star": { 1126 | "prefix": 0x0113, 1127 | }, 1128 | "p2p-webrtc-direct": { 1129 | "prefix": 0x0114, 1130 | }, 1131 | "p2p-stardust": { 1132 | "prefix": 0x0115, 1133 | }, 1134 | "p2p-circuit": { 1135 | "prefix": 0x0122, 1136 | }, 1137 | "udt": { 1138 | "prefix": 0x012D, 1139 | }, 1140 | "utp": { 1141 | "prefix": 0x012E, 1142 | }, 1143 | "unix": { 1144 | "prefix": 0x0190, 1145 | }, 1146 | "thread": { 1147 | "prefix": 0x0196, 1148 | }, 1149 | "p2p": { 1150 | "prefix": 0x01A5, 1151 | }, 1152 | "https": { 1153 | "prefix": 0x01BB, 1154 | }, 1155 | "onion": { 1156 | "prefix": 0x01BC, 1157 | }, 1158 | "onion3": { 1159 | "prefix": 0x01BD, 1160 | }, 1161 | "garlic64": { 1162 | "prefix": 0x01BE, 1163 | }, 1164 | "garlic32": { 1165 | "prefix": 0x01BF, 1166 | }, 1167 | "tls": { 1168 | "prefix": 0x01C0, 1169 | }, 1170 | "quic": { 1171 | "prefix": 0x01CC, 1172 | }, 1173 | "ws": { 1174 | "prefix": 0x01DD, 1175 | }, 1176 | "wss": { 1177 | "prefix": 0x01DE, 1178 | }, 1179 | "p2p-websocket-star": { 1180 | "prefix": 0x01DF, 1181 | }, 1182 | "http": { 1183 | "prefix": 0x01E0, 1184 | }, 1185 | # ipld 1186 | "cidv1": { 1187 | "prefix": 0x01, 1188 | }, 1189 | "cidv2": { 1190 | "prefix": 0x02, 1191 | }, 1192 | "cidv3": { 1193 | "prefix": 0x03, 1194 | }, 1195 | "raw": { 1196 | "prefix": 0x55, 1197 | }, 1198 | "dag-pb": { 1199 | "prefix": 0x70, 1200 | }, 1201 | "dag-cbor": { 1202 | "prefix": 0x71, 1203 | }, 1204 | "libp2p-key": { 1205 | "prefix": 0x72, 1206 | }, 1207 | "git-raw": { 1208 | "prefix": 0x78, 1209 | }, 1210 | "torrent-info": { 1211 | "prefix": 0x7B, 1212 | }, 1213 | "torrent-file": { 1214 | "prefix": 0x7C, 1215 | }, 1216 | "leofcoin-block": { 1217 | "prefix": 0x81, 1218 | }, 1219 | "leofcoin-tx": { 1220 | "prefix": 0x82, 1221 | }, 1222 | "leofcoin-pr": { 1223 | "prefix": 0x83, 1224 | }, 1225 | "dag-jose": { 1226 | "prefix": 0x85, 1227 | }, 1228 | "dag-cose": { 1229 | "prefix": 0x86, 1230 | }, 1231 | "eth-block": { 1232 | "prefix": 0x90, 1233 | }, 1234 | "eth-block-list": { 1235 | "prefix": 0x91, 1236 | }, 1237 | "eth-tx-trie": { 1238 | "prefix": 0x92, 1239 | }, 1240 | "eth-tx": { 1241 | "prefix": 0x93, 1242 | }, 1243 | "eth-tx-receipt-trie": { 1244 | "prefix": 0x94, 1245 | }, 1246 | "eth-tx-receipt": { 1247 | "prefix": 0x95, 1248 | }, 1249 | "eth-state-trie": { 1250 | "prefix": 0x96, 1251 | }, 1252 | "eth-account-snapshot": { 1253 | "prefix": 0x97, 1254 | }, 1255 | "eth-storage-trie": { 1256 | "prefix": 0x98, 1257 | }, 1258 | "bitcoin-block": { 1259 | "prefix": 0xB0, 1260 | }, 1261 | "bitcoin-tx": { 1262 | "prefix": 0xB1, 1263 | }, 1264 | "bitcoin-witness-commitment": { 1265 | "prefix": 0xB2, 1266 | }, 1267 | "zcash-block": { 1268 | "prefix": 0xC0, 1269 | }, 1270 | "zcash-tx": { 1271 | "prefix": 0xC1, 1272 | }, 1273 | "stellar-block": { 1274 | "prefix": 0xD0, 1275 | }, 1276 | "stellar-tx": { 1277 | "prefix": 0xD1, 1278 | }, 1279 | "decred-block": { 1280 | "prefix": 0xE0, 1281 | }, 1282 | "decred-tx": { 1283 | "prefix": 0xE1, 1284 | }, 1285 | "dash-block": { 1286 | "prefix": 0xF0, 1287 | }, 1288 | "dash-tx": { 1289 | "prefix": 0xF1, 1290 | }, 1291 | "swarm-manifest": { 1292 | "prefix": 0xFA, 1293 | }, 1294 | "swarm-feed": { 1295 | "prefix": 0xFB, 1296 | }, 1297 | "dag-json": { 1298 | "prefix": 0x0129, 1299 | }, 1300 | # namespace 1301 | "path": { 1302 | "prefix": 0x2F, 1303 | }, 1304 | "docid": { 1305 | "prefix": 0xCE, 1306 | }, 1307 | "ipld-ns": { 1308 | "prefix": 0xE2, 1309 | }, 1310 | "ipfs-ns": { 1311 | "prefix": 0xE3, 1312 | }, 1313 | "swarm-ns": { 1314 | "prefix": 0xE4, 1315 | }, 1316 | "ipns-ns": { 1317 | "prefix": 0xE5, 1318 | }, 1319 | "zeronet": { 1320 | "prefix": 0xE6, 1321 | }, 1322 | "skynet-ns": { 1323 | "prefix": 0xB19910, 1324 | }, 1325 | # key 1326 | "secp256k1-pub": { 1327 | "prefix": 0xE7, 1328 | }, 1329 | "bls12_381-g1-pub": { 1330 | "prefix": 0xEA, 1331 | }, 1332 | "bls12_381-g2-pub": { 1333 | "prefix": 0xEB, 1334 | }, 1335 | "x25519-pub": { 1336 | "prefix": 0xEC, 1337 | }, 1338 | "ed25519-pub": { 1339 | "prefix": 0xED, 1340 | }, 1341 | "bls12_381-g1g2-pub": { 1342 | "prefix": 0xEE, 1343 | }, 1344 | "p256-pub": { 1345 | "prefix": 0x1200, 1346 | }, 1347 | "p384-pub": { 1348 | "prefix": 0x1201, 1349 | }, 1350 | "p521-pub": { 1351 | "prefix": 0x1202, 1352 | }, 1353 | "ed448-pub": { 1354 | "prefix": 0x1203, 1355 | }, 1356 | "x448-pub": { 1357 | "prefix": 0x1204, 1358 | }, 1359 | "ed25519-priv": { 1360 | "prefix": 0x1300, 1361 | }, 1362 | # holochain 1363 | "holochain-adr-v0": { 1364 | "prefix": 0x807124, 1365 | }, 1366 | "holochain-adr-v1": { 1367 | "prefix": 0x817124, 1368 | }, 1369 | "holochain-key-v0": { 1370 | "prefix": 0x947124, 1371 | }, 1372 | "holochain-key-v1": { 1373 | "prefix": 0x957124, 1374 | }, 1375 | "holochain-sig-v0": { 1376 | "prefix": 0xA27124, 1377 | }, 1378 | "holochain-sig-v1": { 1379 | "prefix": 0xA37124, 1380 | }, 1381 | # libp2p 1382 | "libp2p-peer-record": { 1383 | "prefix": 0x0301, 1384 | }, 1385 | # zeroxcert 1386 | "zeroxcert-imprint-256": { 1387 | "prefix": 0xCE11, 1388 | }, 1389 | # filecoin 1390 | "fil-commitment-unsealed": { 1391 | "prefix": 0xF101, 1392 | }, 1393 | "fil-commitment-sealed": { 1394 | "prefix": 0xF102, 1395 | }, 1396 | } 1397 | 1398 | NAME_TABLE = {name: value["prefix"] for name, value in CODECS.items()} 1399 | CODE_TABLE = {value["prefix"]: name for name, value in CODECS.items()} 1400 | -------------------------------------------------------------------------------- /multicodec/code_table.py: -------------------------------------------------------------------------------- 1 | # Code generated from constants.py; DO NOT EDIT MANUALLY. 2 | # 3 | # To regenerate, run: python tools/gen_code_table.py 4 | # 5 | # These constants provide type-safe Code values for all known multicodecs, 6 | # allowing usage like: 7 | # from multicodec import SHA2_256 8 | # code = SHA2_256 # Code object for sha2-256 9 | # 10 | # Instead of: 11 | # from multicodec import Code 12 | # code = Code(0x12) 13 | 14 | from __future__ import annotations 15 | 16 | from .code import Code 17 | 18 | # Multihash 19 | IDENTITY: Code = Code(0x00) # identity 20 | SHA1: Code = Code(0x11) # sha1 21 | SHA2_256: Code = Code(0x12) # sha2-256 22 | SHA2_512: Code = Code(0x13) # sha2-512 23 | SHA3_512: Code = Code(0x14) # sha3-512 24 | SHA3_384: Code = Code(0x15) # sha3-384 25 | SHA3_256: Code = Code(0x16) # sha3-256 26 | SHA3_224: Code = Code(0x17) # sha3-224 27 | SHAKE_128: Code = Code(0x18) # shake-128 28 | SHAKE_256: Code = Code(0x19) # shake-256 29 | KECCAK_224: Code = Code(0x1A) # keccak-224 30 | KECCAK_256: Code = Code(0x1B) # keccak-256 31 | KECCAK_384: Code = Code(0x1C) # keccak-384 32 | KECCAK_512: Code = Code(0x1D) # keccak-512 33 | BLAKE3: Code = Code(0x1E) # blake3 34 | MURMUR3_128: Code = Code(0x22) # murmur3-128 35 | MURMUR3_32: Code = Code(0x23) # murmur3-32 36 | DBL_SHA2_256: Code = Code(0x56) # dbl-sha2-256 37 | MD4: Code = Code(0xD4) # md4 38 | MD5: Code = Code(0xD5) # md5 39 | BMT: Code = Code(0xD6) # bmt 40 | SHA2_256_TRUNC254_PADDED: Code = Code(0x1012) # sha2-256-trunc254-padded 41 | RIPEMD_128: Code = Code(0x1052) # ripemd-128 42 | RIPEMD_160: Code = Code(0x1053) # ripemd-160 43 | RIPEMD_256: Code = Code(0x1054) # ripemd-256 44 | RIPEMD_320: Code = Code(0x1055) # ripemd-320 45 | X11: Code = Code(0x1100) # x11 46 | KANGAROOTWELVE: Code = Code(0x1D01) # kangarootwelve 47 | SM3_256: Code = Code(0x534D) # sm3-256 48 | BLAKE2B_8: Code = Code(0xB201) # blake2b-8 49 | BLAKE2B_16: Code = Code(0xB202) # blake2b-16 50 | BLAKE2B_24: Code = Code(0xB203) # blake2b-24 51 | BLAKE2B_32: Code = Code(0xB204) # blake2b-32 52 | BLAKE2B_40: Code = Code(0xB205) # blake2b-40 53 | BLAKE2B_48: Code = Code(0xB206) # blake2b-48 54 | BLAKE2B_56: Code = Code(0xB207) # blake2b-56 55 | BLAKE2B_64: Code = Code(0xB208) # blake2b-64 56 | BLAKE2B_72: Code = Code(0xB209) # blake2b-72 57 | BLAKE2B_80: Code = Code(0xB20A) # blake2b-80 58 | BLAKE2B_88: Code = Code(0xB20B) # blake2b-88 59 | BLAKE2B_96: Code = Code(0xB20C) # blake2b-96 60 | BLAKE2B_104: Code = Code(0xB20D) # blake2b-104 61 | BLAKE2B_112: Code = Code(0xB20E) # blake2b-112 62 | BLAKE2B_120: Code = Code(0xB20F) # blake2b-120 63 | BLAKE2B_128: Code = Code(0xB210) # blake2b-128 64 | BLAKE2B_136: Code = Code(0xB211) # blake2b-136 65 | BLAKE2B_144: Code = Code(0xB212) # blake2b-144 66 | BLAKE2B_152: Code = Code(0xB213) # blake2b-152 67 | BLAKE2B_160: Code = Code(0xB214) # blake2b-160 68 | BLAKE2B_168: Code = Code(0xB215) # blake2b-168 69 | BLAKE2B_176: Code = Code(0xB216) # blake2b-176 70 | BLAKE2B_184: Code = Code(0xB217) # blake2b-184 71 | BLAKE2B_192: Code = Code(0xB218) # blake2b-192 72 | BLAKE2B_200: Code = Code(0xB219) # blake2b-200 73 | BLAKE2B_208: Code = Code(0xB21A) # blake2b-208 74 | BLAKE2B_216: Code = Code(0xB21B) # blake2b-216 75 | BLAKE2B_224: Code = Code(0xB21C) # blake2b-224 76 | BLAKE2B_232: Code = Code(0xB21D) # blake2b-232 77 | BLAKE2B_240: Code = Code(0xB21E) # blake2b-240 78 | BLAKE2B_248: Code = Code(0xB21F) # blake2b-248 79 | BLAKE2B_256: Code = Code(0xB220) # blake2b-256 80 | BLAKE2B_264: Code = Code(0xB221) # blake2b-264 81 | BLAKE2B_272: Code = Code(0xB222) # blake2b-272 82 | BLAKE2B_280: Code = Code(0xB223) # blake2b-280 83 | BLAKE2B_288: Code = Code(0xB224) # blake2b-288 84 | BLAKE2B_296: Code = Code(0xB225) # blake2b-296 85 | BLAKE2B_304: Code = Code(0xB226) # blake2b-304 86 | BLAKE2B_312: Code = Code(0xB227) # blake2b-312 87 | BLAKE2B_320: Code = Code(0xB228) # blake2b-320 88 | BLAKE2B_328: Code = Code(0xB229) # blake2b-328 89 | BLAKE2B_336: Code = Code(0xB22A) # blake2b-336 90 | BLAKE2B_344: Code = Code(0xB22B) # blake2b-344 91 | BLAKE2B_352: Code = Code(0xB22C) # blake2b-352 92 | BLAKE2B_360: Code = Code(0xB22D) # blake2b-360 93 | BLAKE2B_368: Code = Code(0xB22E) # blake2b-368 94 | BLAKE2B_376: Code = Code(0xB22F) # blake2b-376 95 | BLAKE2B_384: Code = Code(0xB230) # blake2b-384 96 | BLAKE2B_392: Code = Code(0xB231) # blake2b-392 97 | BLAKE2B_400: Code = Code(0xB232) # blake2b-400 98 | BLAKE2B_408: Code = Code(0xB233) # blake2b-408 99 | BLAKE2B_416: Code = Code(0xB234) # blake2b-416 100 | BLAKE2B_424: Code = Code(0xB235) # blake2b-424 101 | BLAKE2B_432: Code = Code(0xB236) # blake2b-432 102 | BLAKE2B_440: Code = Code(0xB237) # blake2b-440 103 | BLAKE2B_448: Code = Code(0xB238) # blake2b-448 104 | BLAKE2B_456: Code = Code(0xB239) # blake2b-456 105 | BLAKE2B_464: Code = Code(0xB23A) # blake2b-464 106 | BLAKE2B_472: Code = Code(0xB23B) # blake2b-472 107 | BLAKE2B_480: Code = Code(0xB23C) # blake2b-480 108 | BLAKE2B_488: Code = Code(0xB23D) # blake2b-488 109 | BLAKE2B_496: Code = Code(0xB23E) # blake2b-496 110 | BLAKE2B_504: Code = Code(0xB23F) # blake2b-504 111 | BLAKE2B_512: Code = Code(0xB240) # blake2b-512 112 | BLAKE2S_8: Code = Code(0xB241) # blake2s-8 113 | BLAKE2S_16: Code = Code(0xB242) # blake2s-16 114 | BLAKE2S_24: Code = Code(0xB243) # blake2s-24 115 | BLAKE2S_32: Code = Code(0xB244) # blake2s-32 116 | BLAKE2S_40: Code = Code(0xB245) # blake2s-40 117 | BLAKE2S_48: Code = Code(0xB246) # blake2s-48 118 | BLAKE2S_56: Code = Code(0xB247) # blake2s-56 119 | BLAKE2S_64: Code = Code(0xB248) # blake2s-64 120 | BLAKE2S_72: Code = Code(0xB249) # blake2s-72 121 | BLAKE2S_80: Code = Code(0xB24A) # blake2s-80 122 | BLAKE2S_88: Code = Code(0xB24B) # blake2s-88 123 | BLAKE2S_96: Code = Code(0xB24C) # blake2s-96 124 | BLAKE2S_104: Code = Code(0xB24D) # blake2s-104 125 | BLAKE2S_112: Code = Code(0xB24E) # blake2s-112 126 | BLAKE2S_120: Code = Code(0xB24F) # blake2s-120 127 | BLAKE2S_128: Code = Code(0xB250) # blake2s-128 128 | BLAKE2S_136: Code = Code(0xB251) # blake2s-136 129 | BLAKE2S_144: Code = Code(0xB252) # blake2s-144 130 | BLAKE2S_152: Code = Code(0xB253) # blake2s-152 131 | BLAKE2S_160: Code = Code(0xB254) # blake2s-160 132 | BLAKE2S_168: Code = Code(0xB255) # blake2s-168 133 | BLAKE2S_176: Code = Code(0xB256) # blake2s-176 134 | BLAKE2S_184: Code = Code(0xB257) # blake2s-184 135 | BLAKE2S_192: Code = Code(0xB258) # blake2s-192 136 | BLAKE2S_200: Code = Code(0xB259) # blake2s-200 137 | BLAKE2S_208: Code = Code(0xB25A) # blake2s-208 138 | BLAKE2S_216: Code = Code(0xB25B) # blake2s-216 139 | BLAKE2S_224: Code = Code(0xB25C) # blake2s-224 140 | BLAKE2S_232: Code = Code(0xB25D) # blake2s-232 141 | BLAKE2S_240: Code = Code(0xB25E) # blake2s-240 142 | BLAKE2S_248: Code = Code(0xB25F) # blake2s-248 143 | BLAKE2S_256: Code = Code(0xB260) # blake2s-256 144 | SKEIN256_8: Code = Code(0xB301) # skein256-8 145 | SKEIN256_16: Code = Code(0xB302) # skein256-16 146 | SKEIN256_24: Code = Code(0xB303) # skein256-24 147 | SKEIN256_32: Code = Code(0xB304) # skein256-32 148 | SKEIN256_40: Code = Code(0xB305) # skein256-40 149 | SKEIN256_48: Code = Code(0xB306) # skein256-48 150 | SKEIN256_56: Code = Code(0xB307) # skein256-56 151 | SKEIN256_64: Code = Code(0xB308) # skein256-64 152 | SKEIN256_72: Code = Code(0xB309) # skein256-72 153 | SKEIN256_80: Code = Code(0xB30A) # skein256-80 154 | SKEIN256_88: Code = Code(0xB30B) # skein256-88 155 | SKEIN256_96: Code = Code(0xB30C) # skein256-96 156 | SKEIN256_104: Code = Code(0xB30D) # skein256-104 157 | SKEIN256_112: Code = Code(0xB30E) # skein256-112 158 | SKEIN256_120: Code = Code(0xB30F) # skein256-120 159 | SKEIN256_128: Code = Code(0xB310) # skein256-128 160 | SKEIN256_136: Code = Code(0xB311) # skein256-136 161 | SKEIN256_144: Code = Code(0xB312) # skein256-144 162 | SKEIN256_152: Code = Code(0xB313) # skein256-152 163 | SKEIN256_160: Code = Code(0xB314) # skein256-160 164 | SKEIN256_168: Code = Code(0xB315) # skein256-168 165 | SKEIN256_176: Code = Code(0xB316) # skein256-176 166 | SKEIN256_184: Code = Code(0xB317) # skein256-184 167 | SKEIN256_192: Code = Code(0xB318) # skein256-192 168 | SKEIN256_200: Code = Code(0xB319) # skein256-200 169 | SKEIN256_208: Code = Code(0xB31A) # skein256-208 170 | SKEIN256_216: Code = Code(0xB31B) # skein256-216 171 | SKEIN256_224: Code = Code(0xB31C) # skein256-224 172 | SKEIN256_232: Code = Code(0xB31D) # skein256-232 173 | SKEIN256_240: Code = Code(0xB31E) # skein256-240 174 | SKEIN256_248: Code = Code(0xB31F) # skein256-248 175 | SKEIN256_256: Code = Code(0xB320) # skein256-256 176 | SKEIN512_8: Code = Code(0xB321) # skein512-8 177 | SKEIN512_16: Code = Code(0xB322) # skein512-16 178 | SKEIN512_24: Code = Code(0xB323) # skein512-24 179 | SKEIN512_32: Code = Code(0xB324) # skein512-32 180 | SKEIN512_40: Code = Code(0xB325) # skein512-40 181 | SKEIN512_48: Code = Code(0xB326) # skein512-48 182 | SKEIN512_56: Code = Code(0xB327) # skein512-56 183 | SKEIN512_64: Code = Code(0xB328) # skein512-64 184 | SKEIN512_72: Code = Code(0xB329) # skein512-72 185 | SKEIN512_80: Code = Code(0xB32A) # skein512-80 186 | SKEIN512_88: Code = Code(0xB32B) # skein512-88 187 | SKEIN512_96: Code = Code(0xB32C) # skein512-96 188 | SKEIN512_104: Code = Code(0xB32D) # skein512-104 189 | SKEIN512_112: Code = Code(0xB32E) # skein512-112 190 | SKEIN512_120: Code = Code(0xB32F) # skein512-120 191 | SKEIN512_128: Code = Code(0xB330) # skein512-128 192 | SKEIN512_136: Code = Code(0xB331) # skein512-136 193 | SKEIN512_144: Code = Code(0xB332) # skein512-144 194 | SKEIN512_152: Code = Code(0xB333) # skein512-152 195 | SKEIN512_160: Code = Code(0xB334) # skein512-160 196 | SKEIN512_168: Code = Code(0xB335) # skein512-168 197 | SKEIN512_176: Code = Code(0xB336) # skein512-176 198 | SKEIN512_184: Code = Code(0xB337) # skein512-184 199 | SKEIN512_192: Code = Code(0xB338) # skein512-192 200 | SKEIN512_200: Code = Code(0xB339) # skein512-200 201 | SKEIN512_208: Code = Code(0xB33A) # skein512-208 202 | SKEIN512_216: Code = Code(0xB33B) # skein512-216 203 | SKEIN512_224: Code = Code(0xB33C) # skein512-224 204 | SKEIN512_232: Code = Code(0xB33D) # skein512-232 205 | SKEIN512_240: Code = Code(0xB33E) # skein512-240 206 | SKEIN512_248: Code = Code(0xB33F) # skein512-248 207 | SKEIN512_256: Code = Code(0xB340) # skein512-256 208 | SKEIN512_264: Code = Code(0xB341) # skein512-264 209 | SKEIN512_272: Code = Code(0xB342) # skein512-272 210 | SKEIN512_280: Code = Code(0xB343) # skein512-280 211 | SKEIN512_288: Code = Code(0xB344) # skein512-288 212 | SKEIN512_296: Code = Code(0xB345) # skein512-296 213 | SKEIN512_304: Code = Code(0xB346) # skein512-304 214 | SKEIN512_312: Code = Code(0xB347) # skein512-312 215 | SKEIN512_320: Code = Code(0xB348) # skein512-320 216 | SKEIN512_328: Code = Code(0xB349) # skein512-328 217 | SKEIN512_336: Code = Code(0xB34A) # skein512-336 218 | SKEIN512_344: Code = Code(0xB34B) # skein512-344 219 | SKEIN512_352: Code = Code(0xB34C) # skein512-352 220 | SKEIN512_360: Code = Code(0xB34D) # skein512-360 221 | SKEIN512_368: Code = Code(0xB34E) # skein512-368 222 | SKEIN512_376: Code = Code(0xB34F) # skein512-376 223 | SKEIN512_384: Code = Code(0xB350) # skein512-384 224 | SKEIN512_392: Code = Code(0xB351) # skein512-392 225 | SKEIN512_400: Code = Code(0xB352) # skein512-400 226 | SKEIN512_408: Code = Code(0xB353) # skein512-408 227 | SKEIN512_416: Code = Code(0xB354) # skein512-416 228 | SKEIN512_424: Code = Code(0xB355) # skein512-424 229 | SKEIN512_432: Code = Code(0xB356) # skein512-432 230 | SKEIN512_440: Code = Code(0xB357) # skein512-440 231 | SKEIN512_448: Code = Code(0xB358) # skein512-448 232 | SKEIN512_456: Code = Code(0xB359) # skein512-456 233 | SKEIN512_464: Code = Code(0xB35A) # skein512-464 234 | SKEIN512_472: Code = Code(0xB35B) # skein512-472 235 | SKEIN512_480: Code = Code(0xB35C) # skein512-480 236 | SKEIN512_488: Code = Code(0xB35D) # skein512-488 237 | SKEIN512_496: Code = Code(0xB35E) # skein512-496 238 | SKEIN512_504: Code = Code(0xB35F) # skein512-504 239 | SKEIN512_512: Code = Code(0xB360) # skein512-512 240 | SKEIN1024_8: Code = Code(0xB361) # skein1024-8 241 | SKEIN1024_16: Code = Code(0xB362) # skein1024-16 242 | SKEIN1024_24: Code = Code(0xB363) # skein1024-24 243 | SKEIN1024_32: Code = Code(0xB364) # skein1024-32 244 | SKEIN1024_40: Code = Code(0xB365) # skein1024-40 245 | SKEIN1024_48: Code = Code(0xB366) # skein1024-48 246 | SKEIN1024_56: Code = Code(0xB367) # skein1024-56 247 | SKEIN1024_64: Code = Code(0xB368) # skein1024-64 248 | SKEIN1024_72: Code = Code(0xB369) # skein1024-72 249 | SKEIN1024_80: Code = Code(0xB36A) # skein1024-80 250 | SKEIN1024_88: Code = Code(0xB36B) # skein1024-88 251 | SKEIN1024_96: Code = Code(0xB36C) # skein1024-96 252 | SKEIN1024_104: Code = Code(0xB36D) # skein1024-104 253 | SKEIN1024_112: Code = Code(0xB36E) # skein1024-112 254 | SKEIN1024_120: Code = Code(0xB36F) # skein1024-120 255 | SKEIN1024_128: Code = Code(0xB370) # skein1024-128 256 | SKEIN1024_136: Code = Code(0xB371) # skein1024-136 257 | SKEIN1024_144: Code = Code(0xB372) # skein1024-144 258 | SKEIN1024_152: Code = Code(0xB373) # skein1024-152 259 | SKEIN1024_160: Code = Code(0xB374) # skein1024-160 260 | SKEIN1024_168: Code = Code(0xB375) # skein1024-168 261 | SKEIN1024_176: Code = Code(0xB376) # skein1024-176 262 | SKEIN1024_184: Code = Code(0xB377) # skein1024-184 263 | SKEIN1024_192: Code = Code(0xB378) # skein1024-192 264 | SKEIN1024_200: Code = Code(0xB379) # skein1024-200 265 | SKEIN1024_208: Code = Code(0xB37A) # skein1024-208 266 | SKEIN1024_216: Code = Code(0xB37B) # skein1024-216 267 | SKEIN1024_224: Code = Code(0xB37C) # skein1024-224 268 | SKEIN1024_232: Code = Code(0xB37D) # skein1024-232 269 | SKEIN1024_240: Code = Code(0xB37E) # skein1024-240 270 | SKEIN1024_248: Code = Code(0xB37F) # skein1024-248 271 | SKEIN1024_256: Code = Code(0xB380) # skein1024-256 272 | SKEIN1024_264: Code = Code(0xB381) # skein1024-264 273 | SKEIN1024_272: Code = Code(0xB382) # skein1024-272 274 | SKEIN1024_280: Code = Code(0xB383) # skein1024-280 275 | SKEIN1024_288: Code = Code(0xB384) # skein1024-288 276 | SKEIN1024_296: Code = Code(0xB385) # skein1024-296 277 | SKEIN1024_304: Code = Code(0xB386) # skein1024-304 278 | SKEIN1024_312: Code = Code(0xB387) # skein1024-312 279 | SKEIN1024_320: Code = Code(0xB388) # skein1024-320 280 | SKEIN1024_328: Code = Code(0xB389) # skein1024-328 281 | SKEIN1024_336: Code = Code(0xB38A) # skein1024-336 282 | SKEIN1024_344: Code = Code(0xB38B) # skein1024-344 283 | SKEIN1024_352: Code = Code(0xB38C) # skein1024-352 284 | SKEIN1024_360: Code = Code(0xB38D) # skein1024-360 285 | SKEIN1024_368: Code = Code(0xB38E) # skein1024-368 286 | SKEIN1024_376: Code = Code(0xB38F) # skein1024-376 287 | SKEIN1024_384: Code = Code(0xB390) # skein1024-384 288 | SKEIN1024_392: Code = Code(0xB391) # skein1024-392 289 | SKEIN1024_400: Code = Code(0xB392) # skein1024-400 290 | SKEIN1024_408: Code = Code(0xB393) # skein1024-408 291 | SKEIN1024_416: Code = Code(0xB394) # skein1024-416 292 | SKEIN1024_424: Code = Code(0xB395) # skein1024-424 293 | SKEIN1024_432: Code = Code(0xB396) # skein1024-432 294 | SKEIN1024_440: Code = Code(0xB397) # skein1024-440 295 | SKEIN1024_448: Code = Code(0xB398) # skein1024-448 296 | SKEIN1024_456: Code = Code(0xB399) # skein1024-456 297 | SKEIN1024_464: Code = Code(0xB39A) # skein1024-464 298 | SKEIN1024_472: Code = Code(0xB39B) # skein1024-472 299 | SKEIN1024_480: Code = Code(0xB39C) # skein1024-480 300 | SKEIN1024_488: Code = Code(0xB39D) # skein1024-488 301 | SKEIN1024_496: Code = Code(0xB39E) # skein1024-496 302 | SKEIN1024_504: Code = Code(0xB39F) # skein1024-504 303 | SKEIN1024_512: Code = Code(0xB3A0) # skein1024-512 304 | SKEIN1024_520: Code = Code(0xB3A1) # skein1024-520 305 | SKEIN1024_528: Code = Code(0xB3A2) # skein1024-528 306 | SKEIN1024_536: Code = Code(0xB3A3) # skein1024-536 307 | SKEIN1024_544: Code = Code(0xB3A4) # skein1024-544 308 | SKEIN1024_552: Code = Code(0xB3A5) # skein1024-552 309 | SKEIN1024_560: Code = Code(0xB3A6) # skein1024-560 310 | SKEIN1024_568: Code = Code(0xB3A7) # skein1024-568 311 | SKEIN1024_576: Code = Code(0xB3A8) # skein1024-576 312 | SKEIN1024_584: Code = Code(0xB3A9) # skein1024-584 313 | SKEIN1024_592: Code = Code(0xB3AA) # skein1024-592 314 | SKEIN1024_600: Code = Code(0xB3AB) # skein1024-600 315 | SKEIN1024_608: Code = Code(0xB3AC) # skein1024-608 316 | SKEIN1024_616: Code = Code(0xB3AD) # skein1024-616 317 | SKEIN1024_624: Code = Code(0xB3AE) # skein1024-624 318 | SKEIN1024_632: Code = Code(0xB3AF) # skein1024-632 319 | SKEIN1024_640: Code = Code(0xB3B0) # skein1024-640 320 | SKEIN1024_648: Code = Code(0xB3B1) # skein1024-648 321 | SKEIN1024_656: Code = Code(0xB3B2) # skein1024-656 322 | SKEIN1024_664: Code = Code(0xB3B3) # skein1024-664 323 | SKEIN1024_672: Code = Code(0xB3B4) # skein1024-672 324 | SKEIN1024_680: Code = Code(0xB3B5) # skein1024-680 325 | SKEIN1024_688: Code = Code(0xB3B6) # skein1024-688 326 | SKEIN1024_696: Code = Code(0xB3B7) # skein1024-696 327 | SKEIN1024_704: Code = Code(0xB3B8) # skein1024-704 328 | SKEIN1024_712: Code = Code(0xB3B9) # skein1024-712 329 | SKEIN1024_720: Code = Code(0xB3BA) # skein1024-720 330 | SKEIN1024_728: Code = Code(0xB3BB) # skein1024-728 331 | SKEIN1024_736: Code = Code(0xB3BC) # skein1024-736 332 | SKEIN1024_744: Code = Code(0xB3BD) # skein1024-744 333 | SKEIN1024_752: Code = Code(0xB3BE) # skein1024-752 334 | SKEIN1024_760: Code = Code(0xB3BF) # skein1024-760 335 | SKEIN1024_768: Code = Code(0xB3C0) # skein1024-768 336 | SKEIN1024_776: Code = Code(0xB3C1) # skein1024-776 337 | SKEIN1024_784: Code = Code(0xB3C2) # skein1024-784 338 | SKEIN1024_792: Code = Code(0xB3C3) # skein1024-792 339 | SKEIN1024_800: Code = Code(0xB3C4) # skein1024-800 340 | SKEIN1024_808: Code = Code(0xB3C5) # skein1024-808 341 | SKEIN1024_816: Code = Code(0xB3C6) # skein1024-816 342 | SKEIN1024_824: Code = Code(0xB3C7) # skein1024-824 343 | SKEIN1024_832: Code = Code(0xB3C8) # skein1024-832 344 | SKEIN1024_840: Code = Code(0xB3C9) # skein1024-840 345 | SKEIN1024_848: Code = Code(0xB3CA) # skein1024-848 346 | SKEIN1024_856: Code = Code(0xB3CB) # skein1024-856 347 | SKEIN1024_864: Code = Code(0xB3CC) # skein1024-864 348 | SKEIN1024_872: Code = Code(0xB3CD) # skein1024-872 349 | SKEIN1024_880: Code = Code(0xB3CE) # skein1024-880 350 | SKEIN1024_888: Code = Code(0xB3CF) # skein1024-888 351 | SKEIN1024_896: Code = Code(0xB3D0) # skein1024-896 352 | SKEIN1024_904: Code = Code(0xB3D1) # skein1024-904 353 | SKEIN1024_912: Code = Code(0xB3D2) # skein1024-912 354 | SKEIN1024_920: Code = Code(0xB3D3) # skein1024-920 355 | SKEIN1024_928: Code = Code(0xB3D4) # skein1024-928 356 | SKEIN1024_936: Code = Code(0xB3D5) # skein1024-936 357 | SKEIN1024_944: Code = Code(0xB3D6) # skein1024-944 358 | SKEIN1024_952: Code = Code(0xB3D7) # skein1024-952 359 | SKEIN1024_960: Code = Code(0xB3D8) # skein1024-960 360 | SKEIN1024_968: Code = Code(0xB3D9) # skein1024-968 361 | SKEIN1024_976: Code = Code(0xB3DA) # skein1024-976 362 | SKEIN1024_984: Code = Code(0xB3DB) # skein1024-984 363 | SKEIN1024_992: Code = Code(0xB3DC) # skein1024-992 364 | SKEIN1024_1000: Code = Code(0xB3DD) # skein1024-1000 365 | SKEIN1024_1008: Code = Code(0xB3DE) # skein1024-1008 366 | SKEIN1024_1016: Code = Code(0xB3DF) # skein1024-1016 367 | SKEIN1024_1024: Code = Code(0xB3E0) # skein1024-1024 368 | POSEIDON_BLS12_381_A2_FC1: Code = Code(0xB401) # poseidon-bls12_381-a2-fc1 369 | POSEIDON_BLS12_381_A2_FC1_SC: Code = Code(0xB402) # poseidon-bls12_381-a2-fc1-sc 370 | 371 | # Multiaddr 372 | IP4: Code = Code(0x04) # ip4 373 | TCP: Code = Code(0x06) # tcp 374 | DCCP: Code = Code(0x21) # dccp 375 | IP6: Code = Code(0x29) # ip6 376 | IP6ZONE: Code = Code(0x2A) # ip6zone 377 | DNS: Code = Code(0x35) # dns 378 | DNS4: Code = Code(0x36) # dns4 379 | DNS6: Code = Code(0x37) # dns6 380 | DNSADDR: Code = Code(0x38) # dnsaddr 381 | LIBP2P_KEY: Code = Code(0x72) # libp2p-key 382 | SCTP: Code = Code(0x84) # sctp 383 | UDP: Code = Code(0x111) # udp 384 | P2P_WEBRTC_STAR: Code = Code(0x113) # p2p-webrtc-star 385 | P2P_WEBRTC_DIRECT: Code = Code(0x114) # p2p-webrtc-direct 386 | P2P_STARDUST: Code = Code(0x115) # p2p-stardust 387 | P2P_CIRCUIT: Code = Code(0x122) # p2p-circuit 388 | UDT: Code = Code(0x12D) # udt 389 | UTP: Code = Code(0x12E) # utp 390 | UNIX: Code = Code(0x190) # unix 391 | THREAD: Code = Code(0x196) # thread 392 | P2P: Code = Code(0x1A5) # p2p 393 | HTTPS: Code = Code(0x1BB) # https 394 | ONION: Code = Code(0x1BC) # onion 395 | ONION3: Code = Code(0x1BD) # onion3 396 | GARLIC64: Code = Code(0x1BE) # garlic64 397 | GARLIC32: Code = Code(0x1BF) # garlic32 398 | TLS: Code = Code(0x1C0) # tls 399 | QUIC: Code = Code(0x1CC) # quic 400 | WS: Code = Code(0x1DD) # ws 401 | WSS: Code = Code(0x1DE) # wss 402 | P2P_WEBSOCKET_STAR: Code = Code(0x1DF) # p2p-websocket-star 403 | HTTP: Code = Code(0x1E0) # http 404 | LIBP2P_PEER_RECORD: Code = Code(0x301) # libp2p-peer-record 405 | 406 | # Ipld 407 | CIDV1: Code = Code(0x01) # cidv1 408 | CIDV2: Code = Code(0x02) # cidv2 409 | CIDV3: Code = Code(0x03) # cidv3 410 | RAW: Code = Code(0x55) # raw 411 | DAG_PB: Code = Code(0x70) # dag-pb 412 | DAG_CBOR: Code = Code(0x71) # dag-cbor 413 | GIT_RAW: Code = Code(0x78) # git-raw 414 | TORRENT_INFO: Code = Code(0x7B) # torrent-info 415 | TORRENT_FILE: Code = Code(0x7C) # torrent-file 416 | LEOFCOIN_BLOCK: Code = Code(0x81) # leofcoin-block 417 | LEOFCOIN_TX: Code = Code(0x82) # leofcoin-tx 418 | LEOFCOIN_PR: Code = Code(0x83) # leofcoin-pr 419 | DAG_JOSE: Code = Code(0x85) # dag-jose 420 | DAG_COSE: Code = Code(0x86) # dag-cose 421 | ETH_BLOCK: Code = Code(0x90) # eth-block 422 | ETH_BLOCK_LIST: Code = Code(0x91) # eth-block-list 423 | ETH_TX_TRIE: Code = Code(0x92) # eth-tx-trie 424 | ETH_TX: Code = Code(0x93) # eth-tx 425 | ETH_TX_RECEIPT_TRIE: Code = Code(0x94) # eth-tx-receipt-trie 426 | ETH_TX_RECEIPT: Code = Code(0x95) # eth-tx-receipt 427 | ETH_STATE_TRIE: Code = Code(0x96) # eth-state-trie 428 | ETH_ACCOUNT_SNAPSHOT: Code = Code(0x97) # eth-account-snapshot 429 | ETH_STORAGE_TRIE: Code = Code(0x98) # eth-storage-trie 430 | BITCOIN_BLOCK: Code = Code(0xB0) # bitcoin-block 431 | BITCOIN_TX: Code = Code(0xB1) # bitcoin-tx 432 | BITCOIN_WITNESS_COMMITMENT: Code = Code(0xB2) # bitcoin-witness-commitment 433 | ZCASH_BLOCK: Code = Code(0xC0) # zcash-block 434 | ZCASH_TX: Code = Code(0xC1) # zcash-tx 435 | DOCID: Code = Code(0xCE) # docid 436 | STELLAR_BLOCK: Code = Code(0xD0) # stellar-block 437 | STELLAR_TX: Code = Code(0xD1) # stellar-tx 438 | DECRED_BLOCK: Code = Code(0xE0) # decred-block 439 | DECRED_TX: Code = Code(0xE1) # decred-tx 440 | DASH_BLOCK: Code = Code(0xF0) # dash-block 441 | DASH_TX: Code = Code(0xF1) # dash-tx 442 | SWARM_MANIFEST: Code = Code(0xFA) # swarm-manifest 443 | SWARM_FEED: Code = Code(0xFB) # swarm-feed 444 | DAG_JSON: Code = Code(0x129) # dag-json 445 | 446 | # Serialization 447 | PROTOBUF: Code = Code(0x50) # protobuf 448 | CBOR: Code = Code(0x51) # cbor 449 | RLP: Code = Code(0x60) # rlp 450 | BENCODE: Code = Code(0x63) # bencode 451 | JSON: Code = Code(0x200) # json 452 | MESSAGEPACK: Code = Code(0x201) # messagepack 453 | 454 | # Multiformat 455 | MULTICODEC: Code = Code(0x30) # multicodec 456 | MULTIHASH: Code = Code(0x31) # multihash 457 | MULTIADDR: Code = Code(0x32) # multiaddr 458 | MULTIBASE: Code = Code(0x33) # multibase 459 | 460 | # Key 461 | SECP256K1_PUB: Code = Code(0xE7) # secp256k1-pub 462 | BLS12_381_G1_PUB: Code = Code(0xEA) # bls12_381-g1-pub 463 | BLS12_381_G2_PUB: Code = Code(0xEB) # bls12_381-g2-pub 464 | X25519_PUB: Code = Code(0xEC) # x25519-pub 465 | ED25519_PUB: Code = Code(0xED) # ed25519-pub 466 | BLS12_381_G1G2_PUB: Code = Code(0xEE) # bls12_381-g1g2-pub 467 | P256_PUB: Code = Code(0x1200) # p256-pub 468 | P384_PUB: Code = Code(0x1201) # p384-pub 469 | P521_PUB: Code = Code(0x1202) # p521-pub 470 | ED448_PUB: Code = Code(0x1203) # ed448-pub 471 | X448_PUB: Code = Code(0x1204) # x448-pub 472 | ED25519_PRIV: Code = Code(0x1300) # ed25519-priv 473 | 474 | # Namespace 475 | PATH: Code = Code(0x2F) # path 476 | IPLD_NS: Code = Code(0xE2) # ipld-ns 477 | IPFS_NS: Code = Code(0xE3) # ipfs-ns 478 | SWARM_NS: Code = Code(0xE4) # swarm-ns 479 | IPNS_NS: Code = Code(0xE5) # ipns-ns 480 | ZERONET: Code = Code(0xE6) # zeronet 481 | FIL_COMMITMENT_UNSEALED: Code = Code(0xF101) # fil-commitment-unsealed 482 | SKYNET_NS: Code = Code(0xB19910) # skynet-ns 483 | 484 | # Other 485 | ZEROXCERT_IMPRINT_256: Code = Code(0xCE11) # zeroxcert-imprint-256 486 | FIL_COMMITMENT_SEALED: Code = Code(0xF102) # fil-commitment-sealed 487 | HOLOCHAIN_ADR_V0: Code = Code(0x807124) # holochain-adr-v0 488 | HOLOCHAIN_ADR_V1: Code = Code(0x817124) # holochain-adr-v1 489 | HOLOCHAIN_KEY_V0: Code = Code(0x947124) # holochain-key-v0 490 | HOLOCHAIN_KEY_V1: Code = Code(0x957124) # holochain-key-v1 491 | HOLOCHAIN_SIG_V0: Code = Code(0xA27124) # holochain-sig-v0 492 | HOLOCHAIN_SIG_V1: Code = Code(0xA37124) # holochain-sig-v1 493 | 494 | __all__ = [ 495 | "BENCODE", 496 | "BITCOIN_BLOCK", 497 | "BITCOIN_TX", 498 | "BITCOIN_WITNESS_COMMITMENT", 499 | "BLAKE2B_8", 500 | "BLAKE2B_16", 501 | "BLAKE2B_24", 502 | "BLAKE2B_32", 503 | "BLAKE2B_40", 504 | "BLAKE2B_48", 505 | "BLAKE2B_56", 506 | "BLAKE2B_64", 507 | "BLAKE2B_72", 508 | "BLAKE2B_80", 509 | "BLAKE2B_88", 510 | "BLAKE2B_96", 511 | "BLAKE2B_104", 512 | "BLAKE2B_112", 513 | "BLAKE2B_120", 514 | "BLAKE2B_128", 515 | "BLAKE2B_136", 516 | "BLAKE2B_144", 517 | "BLAKE2B_152", 518 | "BLAKE2B_160", 519 | "BLAKE2B_168", 520 | "BLAKE2B_176", 521 | "BLAKE2B_184", 522 | "BLAKE2B_192", 523 | "BLAKE2B_200", 524 | "BLAKE2B_208", 525 | "BLAKE2B_216", 526 | "BLAKE2B_224", 527 | "BLAKE2B_232", 528 | "BLAKE2B_240", 529 | "BLAKE2B_248", 530 | "BLAKE2B_256", 531 | "BLAKE2B_264", 532 | "BLAKE2B_272", 533 | "BLAKE2B_280", 534 | "BLAKE2B_288", 535 | "BLAKE2B_296", 536 | "BLAKE2B_304", 537 | "BLAKE2B_312", 538 | "BLAKE2B_320", 539 | "BLAKE2B_328", 540 | "BLAKE2B_336", 541 | "BLAKE2B_344", 542 | "BLAKE2B_352", 543 | "BLAKE2B_360", 544 | "BLAKE2B_368", 545 | "BLAKE2B_376", 546 | "BLAKE2B_384", 547 | "BLAKE2B_392", 548 | "BLAKE2B_400", 549 | "BLAKE2B_408", 550 | "BLAKE2B_416", 551 | "BLAKE2B_424", 552 | "BLAKE2B_432", 553 | "BLAKE2B_440", 554 | "BLAKE2B_448", 555 | "BLAKE2B_456", 556 | "BLAKE2B_464", 557 | "BLAKE2B_472", 558 | "BLAKE2B_480", 559 | "BLAKE2B_488", 560 | "BLAKE2B_496", 561 | "BLAKE2B_504", 562 | "BLAKE2B_512", 563 | "BLAKE2S_8", 564 | "BLAKE2S_16", 565 | "BLAKE2S_24", 566 | "BLAKE2S_32", 567 | "BLAKE2S_40", 568 | "BLAKE2S_48", 569 | "BLAKE2S_56", 570 | "BLAKE2S_64", 571 | "BLAKE2S_72", 572 | "BLAKE2S_80", 573 | "BLAKE2S_88", 574 | "BLAKE2S_96", 575 | "BLAKE2S_104", 576 | "BLAKE2S_112", 577 | "BLAKE2S_120", 578 | "BLAKE2S_128", 579 | "BLAKE2S_136", 580 | "BLAKE2S_144", 581 | "BLAKE2S_152", 582 | "BLAKE2S_160", 583 | "BLAKE2S_168", 584 | "BLAKE2S_176", 585 | "BLAKE2S_184", 586 | "BLAKE2S_192", 587 | "BLAKE2S_200", 588 | "BLAKE2S_208", 589 | "BLAKE2S_216", 590 | "BLAKE2S_224", 591 | "BLAKE2S_232", 592 | "BLAKE2S_240", 593 | "BLAKE2S_248", 594 | "BLAKE2S_256", 595 | "BLAKE3", 596 | "BLS12_381_G1G2_PUB", 597 | "BLS12_381_G1_PUB", 598 | "BLS12_381_G2_PUB", 599 | "BMT", 600 | "CBOR", 601 | "CIDV1", 602 | "CIDV2", 603 | "CIDV3", 604 | "DAG_CBOR", 605 | "DAG_COSE", 606 | "DAG_JOSE", 607 | "DAG_JSON", 608 | "DAG_PB", 609 | "DASH_BLOCK", 610 | "DASH_TX", 611 | "DBL_SHA2_256", 612 | "DCCP", 613 | "DECRED_BLOCK", 614 | "DECRED_TX", 615 | "DNS", 616 | "DNS4", 617 | "DNS6", 618 | "DNSADDR", 619 | "DOCID", 620 | "ED448_PUB", 621 | "ED25519_PRIV", 622 | "ED25519_PUB", 623 | "ETH_ACCOUNT_SNAPSHOT", 624 | "ETH_BLOCK", 625 | "ETH_BLOCK_LIST", 626 | "ETH_STATE_TRIE", 627 | "ETH_STORAGE_TRIE", 628 | "ETH_TX", 629 | "ETH_TX_RECEIPT", 630 | "ETH_TX_RECEIPT_TRIE", 631 | "ETH_TX_TRIE", 632 | "FIL_COMMITMENT_SEALED", 633 | "FIL_COMMITMENT_UNSEALED", 634 | "GARLIC32", 635 | "GARLIC64", 636 | "GIT_RAW", 637 | "HOLOCHAIN_ADR_V0", 638 | "HOLOCHAIN_ADR_V1", 639 | "HOLOCHAIN_KEY_V0", 640 | "HOLOCHAIN_KEY_V1", 641 | "HOLOCHAIN_SIG_V0", 642 | "HOLOCHAIN_SIG_V1", 643 | "HTTP", 644 | "HTTPS", 645 | "IDENTITY", 646 | "IP4", 647 | "IP6", 648 | "IP6ZONE", 649 | "IPFS_NS", 650 | "IPLD_NS", 651 | "IPNS_NS", 652 | "JSON", 653 | "KANGAROOTWELVE", 654 | "KECCAK_224", 655 | "KECCAK_256", 656 | "KECCAK_384", 657 | "KECCAK_512", 658 | "LEOFCOIN_BLOCK", 659 | "LEOFCOIN_PR", 660 | "LEOFCOIN_TX", 661 | "LIBP2P_KEY", 662 | "LIBP2P_PEER_RECORD", 663 | "MD4", 664 | "MD5", 665 | "MESSAGEPACK", 666 | "MULTIADDR", 667 | "MULTIBASE", 668 | "MULTICODEC", 669 | "MULTIHASH", 670 | "MURMUR3_32", 671 | "MURMUR3_128", 672 | "ONION", 673 | "ONION3", 674 | "P2P", 675 | "P2P_CIRCUIT", 676 | "P2P_STARDUST", 677 | "P2P_WEBRTC_DIRECT", 678 | "P2P_WEBRTC_STAR", 679 | "P2P_WEBSOCKET_STAR", 680 | "P256_PUB", 681 | "P384_PUB", 682 | "P521_PUB", 683 | "PATH", 684 | "POSEIDON_BLS12_381_A2_FC1", 685 | "POSEIDON_BLS12_381_A2_FC1_SC", 686 | "PROTOBUF", 687 | "QUIC", 688 | "RAW", 689 | "RIPEMD_128", 690 | "RIPEMD_160", 691 | "RIPEMD_256", 692 | "RIPEMD_320", 693 | "RLP", 694 | "SCTP", 695 | "SECP256K1_PUB", 696 | "SHA1", 697 | "SHA2_256", 698 | "SHA2_256_TRUNC254_PADDED", 699 | "SHA2_512", 700 | "SHA3_224", 701 | "SHA3_256", 702 | "SHA3_384", 703 | "SHA3_512", 704 | "SHAKE_128", 705 | "SHAKE_256", 706 | "SKEIN256_8", 707 | "SKEIN256_16", 708 | "SKEIN256_24", 709 | "SKEIN256_32", 710 | "SKEIN256_40", 711 | "SKEIN256_48", 712 | "SKEIN256_56", 713 | "SKEIN256_64", 714 | "SKEIN256_72", 715 | "SKEIN256_80", 716 | "SKEIN256_88", 717 | "SKEIN256_96", 718 | "SKEIN256_104", 719 | "SKEIN256_112", 720 | "SKEIN256_120", 721 | "SKEIN256_128", 722 | "SKEIN256_136", 723 | "SKEIN256_144", 724 | "SKEIN256_152", 725 | "SKEIN256_160", 726 | "SKEIN256_168", 727 | "SKEIN256_176", 728 | "SKEIN256_184", 729 | "SKEIN256_192", 730 | "SKEIN256_200", 731 | "SKEIN256_208", 732 | "SKEIN256_216", 733 | "SKEIN256_224", 734 | "SKEIN256_232", 735 | "SKEIN256_240", 736 | "SKEIN256_248", 737 | "SKEIN256_256", 738 | "SKEIN512_8", 739 | "SKEIN512_16", 740 | "SKEIN512_24", 741 | "SKEIN512_32", 742 | "SKEIN512_40", 743 | "SKEIN512_48", 744 | "SKEIN512_56", 745 | "SKEIN512_64", 746 | "SKEIN512_72", 747 | "SKEIN512_80", 748 | "SKEIN512_88", 749 | "SKEIN512_96", 750 | "SKEIN512_104", 751 | "SKEIN512_112", 752 | "SKEIN512_120", 753 | "SKEIN512_128", 754 | "SKEIN512_136", 755 | "SKEIN512_144", 756 | "SKEIN512_152", 757 | "SKEIN512_160", 758 | "SKEIN512_168", 759 | "SKEIN512_176", 760 | "SKEIN512_184", 761 | "SKEIN512_192", 762 | "SKEIN512_200", 763 | "SKEIN512_208", 764 | "SKEIN512_216", 765 | "SKEIN512_224", 766 | "SKEIN512_232", 767 | "SKEIN512_240", 768 | "SKEIN512_248", 769 | "SKEIN512_256", 770 | "SKEIN512_264", 771 | "SKEIN512_272", 772 | "SKEIN512_280", 773 | "SKEIN512_288", 774 | "SKEIN512_296", 775 | "SKEIN512_304", 776 | "SKEIN512_312", 777 | "SKEIN512_320", 778 | "SKEIN512_328", 779 | "SKEIN512_336", 780 | "SKEIN512_344", 781 | "SKEIN512_352", 782 | "SKEIN512_360", 783 | "SKEIN512_368", 784 | "SKEIN512_376", 785 | "SKEIN512_384", 786 | "SKEIN512_392", 787 | "SKEIN512_400", 788 | "SKEIN512_408", 789 | "SKEIN512_416", 790 | "SKEIN512_424", 791 | "SKEIN512_432", 792 | "SKEIN512_440", 793 | "SKEIN512_448", 794 | "SKEIN512_456", 795 | "SKEIN512_464", 796 | "SKEIN512_472", 797 | "SKEIN512_480", 798 | "SKEIN512_488", 799 | "SKEIN512_496", 800 | "SKEIN512_504", 801 | "SKEIN512_512", 802 | "SKEIN1024_8", 803 | "SKEIN1024_16", 804 | "SKEIN1024_24", 805 | "SKEIN1024_32", 806 | "SKEIN1024_40", 807 | "SKEIN1024_48", 808 | "SKEIN1024_56", 809 | "SKEIN1024_64", 810 | "SKEIN1024_72", 811 | "SKEIN1024_80", 812 | "SKEIN1024_88", 813 | "SKEIN1024_96", 814 | "SKEIN1024_104", 815 | "SKEIN1024_112", 816 | "SKEIN1024_120", 817 | "SKEIN1024_128", 818 | "SKEIN1024_136", 819 | "SKEIN1024_144", 820 | "SKEIN1024_152", 821 | "SKEIN1024_160", 822 | "SKEIN1024_168", 823 | "SKEIN1024_176", 824 | "SKEIN1024_184", 825 | "SKEIN1024_192", 826 | "SKEIN1024_200", 827 | "SKEIN1024_208", 828 | "SKEIN1024_216", 829 | "SKEIN1024_224", 830 | "SKEIN1024_232", 831 | "SKEIN1024_240", 832 | "SKEIN1024_248", 833 | "SKEIN1024_256", 834 | "SKEIN1024_264", 835 | "SKEIN1024_272", 836 | "SKEIN1024_280", 837 | "SKEIN1024_288", 838 | "SKEIN1024_296", 839 | "SKEIN1024_304", 840 | "SKEIN1024_312", 841 | "SKEIN1024_320", 842 | "SKEIN1024_328", 843 | "SKEIN1024_336", 844 | "SKEIN1024_344", 845 | "SKEIN1024_352", 846 | "SKEIN1024_360", 847 | "SKEIN1024_368", 848 | "SKEIN1024_376", 849 | "SKEIN1024_384", 850 | "SKEIN1024_392", 851 | "SKEIN1024_400", 852 | "SKEIN1024_408", 853 | "SKEIN1024_416", 854 | "SKEIN1024_424", 855 | "SKEIN1024_432", 856 | "SKEIN1024_440", 857 | "SKEIN1024_448", 858 | "SKEIN1024_456", 859 | "SKEIN1024_464", 860 | "SKEIN1024_472", 861 | "SKEIN1024_480", 862 | "SKEIN1024_488", 863 | "SKEIN1024_496", 864 | "SKEIN1024_504", 865 | "SKEIN1024_512", 866 | "SKEIN1024_520", 867 | "SKEIN1024_528", 868 | "SKEIN1024_536", 869 | "SKEIN1024_544", 870 | "SKEIN1024_552", 871 | "SKEIN1024_560", 872 | "SKEIN1024_568", 873 | "SKEIN1024_576", 874 | "SKEIN1024_584", 875 | "SKEIN1024_592", 876 | "SKEIN1024_600", 877 | "SKEIN1024_608", 878 | "SKEIN1024_616", 879 | "SKEIN1024_624", 880 | "SKEIN1024_632", 881 | "SKEIN1024_640", 882 | "SKEIN1024_648", 883 | "SKEIN1024_656", 884 | "SKEIN1024_664", 885 | "SKEIN1024_672", 886 | "SKEIN1024_680", 887 | "SKEIN1024_688", 888 | "SKEIN1024_696", 889 | "SKEIN1024_704", 890 | "SKEIN1024_712", 891 | "SKEIN1024_720", 892 | "SKEIN1024_728", 893 | "SKEIN1024_736", 894 | "SKEIN1024_744", 895 | "SKEIN1024_752", 896 | "SKEIN1024_760", 897 | "SKEIN1024_768", 898 | "SKEIN1024_776", 899 | "SKEIN1024_784", 900 | "SKEIN1024_792", 901 | "SKEIN1024_800", 902 | "SKEIN1024_808", 903 | "SKEIN1024_816", 904 | "SKEIN1024_824", 905 | "SKEIN1024_832", 906 | "SKEIN1024_840", 907 | "SKEIN1024_848", 908 | "SKEIN1024_856", 909 | "SKEIN1024_864", 910 | "SKEIN1024_872", 911 | "SKEIN1024_880", 912 | "SKEIN1024_888", 913 | "SKEIN1024_896", 914 | "SKEIN1024_904", 915 | "SKEIN1024_912", 916 | "SKEIN1024_920", 917 | "SKEIN1024_928", 918 | "SKEIN1024_936", 919 | "SKEIN1024_944", 920 | "SKEIN1024_952", 921 | "SKEIN1024_960", 922 | "SKEIN1024_968", 923 | "SKEIN1024_976", 924 | "SKEIN1024_984", 925 | "SKEIN1024_992", 926 | "SKEIN1024_1000", 927 | "SKEIN1024_1008", 928 | "SKEIN1024_1016", 929 | "SKEIN1024_1024", 930 | "SKYNET_NS", 931 | "SM3_256", 932 | "STELLAR_BLOCK", 933 | "STELLAR_TX", 934 | "SWARM_FEED", 935 | "SWARM_MANIFEST", 936 | "SWARM_NS", 937 | "TCP", 938 | "THREAD", 939 | "TLS", 940 | "TORRENT_FILE", 941 | "TORRENT_INFO", 942 | "UDP", 943 | "UDT", 944 | "UNIX", 945 | "UTP", 946 | "WS", 947 | "WSS", 948 | "X11", 949 | "X448_PUB", 950 | "X25519_PUB", 951 | "ZCASH_BLOCK", 952 | "ZCASH_TX", 953 | "ZERONET", 954 | "ZEROXCERT_IMPRINT_256", 955 | ] 956 | --------------------------------------------------------------------------------