-
Notifications
You must be signed in to change notification settings - Fork 516
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2559 from dbluhm/refactor/replace-multiformats
refactor: replace multiformats library
- Loading branch information
Showing
10 changed files
with
264 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Multiformats utility functions.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
"""MultiBase encoding and decoding utilities.""" | ||
|
||
from abc import ABC, abstractmethod | ||
from enum import Enum | ||
from typing import ClassVar, Literal, Union | ||
|
||
|
||
class MultibaseEncoder(ABC): | ||
"""Encoding details.""" | ||
|
||
name: ClassVar[str] | ||
character: ClassVar[str] | ||
|
||
@abstractmethod | ||
def encode(self, value: bytes) -> str: | ||
"""Encode a byte string using this encoding.""" | ||
|
||
@abstractmethod | ||
def decode(self, value: str) -> bytes: | ||
"""Decode a string using this encoding.""" | ||
|
||
|
||
class Base58BtcEncoder(MultibaseEncoder): | ||
"""Base58BTC encoding.""" | ||
|
||
name = "base58btc" | ||
character = "z" | ||
|
||
def encode(self, value: bytes) -> str: | ||
"""Encode a byte string using the base58btc encoding.""" | ||
import base58 | ||
|
||
return base58.b58encode(value).decode() | ||
|
||
def decode(self, value: str) -> bytes: | ||
"""Decode a multibase encoded string.""" | ||
import base58 | ||
|
||
return base58.b58decode(value) | ||
|
||
|
||
class Encoding(Enum): | ||
"""Enum for supported encodings.""" | ||
|
||
base58btc = Base58BtcEncoder() | ||
# Insert additional encodings here | ||
|
||
@classmethod | ||
def from_name(cls, name: str) -> MultibaseEncoder: | ||
"""Get encoding from name.""" | ||
for encoding in cls: | ||
if encoding.value.name == name: | ||
return encoding.value | ||
raise ValueError(f"Unsupported encoding: {name}") | ||
|
||
@classmethod | ||
def from_character(cls, character: str) -> MultibaseEncoder: | ||
"""Get encoding from character.""" | ||
for encoding in cls: | ||
if encoding.value.character == character: | ||
return encoding.value | ||
raise ValueError(f"Unsupported encoding: {character}") | ||
|
||
|
||
EncodingStr = Literal[ | ||
"base58btc", | ||
# Insert additional encoding names here | ||
] | ||
|
||
|
||
def encode(value: bytes, encoding: Union[Encoding, EncodingStr]) -> str: | ||
"""Encode a byte string using the given encoding. | ||
Args: | ||
value: The byte string to encode | ||
encoding: The encoding to use | ||
Returns: | ||
The encoded string | ||
""" | ||
if isinstance(encoding, str): | ||
encoder = Encoding.from_name(encoding) | ||
elif isinstance(encoding, Encoding): | ||
encoder = encoding.value | ||
else: | ||
raise TypeError("encoding must be an Encoding or EncodingStr") | ||
|
||
return encoder.character + encoder.encode(value) | ||
|
||
|
||
def decode(value: str) -> bytes: | ||
"""Decode a multibase encoded string. | ||
Args: | ||
value: The string to decode | ||
Returns: | ||
The decoded byte string | ||
""" | ||
encoding = value[0] | ||
encoded = value[1:] | ||
encoder = Encoding.from_character(encoding) | ||
|
||
return encoder.decode(encoded) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
"""Multicodec wrap and unwrap functions.""" | ||
|
||
from enum import Enum | ||
from typing import Literal, NamedTuple, Optional, Union | ||
|
||
|
||
class Multicodec(NamedTuple): | ||
"""Multicodec base class.""" | ||
|
||
name: str | ||
code: bytes | ||
|
||
|
||
class SupportedCodecs(Enum): | ||
"""Enumeration of supported multicodecs.""" | ||
|
||
ed25519_pub = Multicodec("ed25519-pub", b"\xed\x01") | ||
x25519_pub = Multicodec("x25519-pub", b"\xec\x01") | ||
bls12381g1 = Multicodec("bls12_381-g1-pub", b"\xea\x01") | ||
bls12381g2 = Multicodec("bls12_381-g2-pub", b"\xeb\x01") | ||
bls12381g1g2 = Multicodec("bls12_381-g1g2-pub", b"\xee\x01") | ||
secp256k1_pub = Multicodec("secp256k1-pub", b"\xe7\x01") | ||
|
||
@classmethod | ||
def by_name(cls, name: str) -> Multicodec: | ||
"""Get multicodec by name.""" | ||
for codec in cls: | ||
if codec.value.name == name: | ||
return codec.value | ||
raise ValueError(f"Unsupported multicodec: {name}") | ||
|
||
@classmethod | ||
def for_data(cls, data: bytes) -> Multicodec: | ||
"""Get multicodec by data.""" | ||
for codec in cls: | ||
if data.startswith(codec.value.code): | ||
return codec.value | ||
raise ValueError("Unsupported multicodec") | ||
|
||
|
||
MulticodecStr = Literal[ | ||
"ed25519-pub", | ||
"x25519-pub", | ||
"bls12_381-g1-pub", | ||
"bls12_381-g2-pub", | ||
"bls12_381-g1g2-pub", | ||
"secp256k1-pub", | ||
] | ||
|
||
|
||
def multicodec(name: str) -> Multicodec: | ||
"""Get multicodec by name.""" | ||
return SupportedCodecs.by_name(name) | ||
|
||
|
||
def wrap(multicodec: Union[Multicodec, MulticodecStr], data: bytes) -> bytes: | ||
"""Wrap data with multicodec prefix.""" | ||
if isinstance(multicodec, str): | ||
multicodec = SupportedCodecs.by_name(multicodec) | ||
elif isinstance(multicodec, Multicodec): | ||
pass | ||
else: | ||
raise TypeError("multicodec must be Multicodec or MulticodecStr") | ||
|
||
return multicodec.code + data | ||
|
||
|
||
def unwrap(data: bytes, codec: Optional[Multicodec] = None) -> tuple[Multicodec, bytes]: | ||
"""Unwrap data with multicodec prefix.""" | ||
if not codec: | ||
codec = SupportedCodecs.for_data(data) | ||
return codec, data[len(codec.code) :] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import pytest | ||
from ..multiformats import multibase, multicodec | ||
|
||
|
||
def test_encode_decode(): | ||
value = b"Hello World!" | ||
encoded = multibase.encode(value, "base58btc") | ||
assert encoded == "z2NEpo7TZRRrLZSi2U" | ||
decoded = multibase.decode(encoded) | ||
assert decoded == value | ||
|
||
|
||
def test_encode_decode_by_encoding(): | ||
value = b"Hello World!" | ||
encoded = multibase.encode(value, multibase.Encoding.base58btc) | ||
assert encoded == "z2NEpo7TZRRrLZSi2U" | ||
decoded = multibase.decode(encoded) | ||
assert decoded == value | ||
|
||
|
||
def test_x_unknown_encoding(): | ||
with pytest.raises(ValueError): | ||
multibase.encode(b"Hello World!", "fancy-encoding") | ||
|
||
|
||
def test_x_unknown_character(): | ||
with pytest.raises(ValueError): | ||
multibase.decode("fHello World!") | ||
|
||
|
||
def test_x_invalid_encoding(): | ||
with pytest.raises(TypeError): | ||
multibase.encode(b"Hello World!", 123) | ||
|
||
|
||
def test_wrap_unwrap(): | ||
value = b"Hello World!" | ||
wrapped = multicodec.wrap("ed25519-pub", value) | ||
codec, unwrapped = multicodec.unwrap(wrapped) | ||
assert codec == multicodec.multicodec("ed25519-pub") | ||
assert unwrapped == value | ||
|
||
|
||
def test_wrap_unwrap_custom(): | ||
value = b"Hello World!" | ||
my_codec = multicodec.Multicodec("my-codec", b"\x00\x01") | ||
wrapped = multicodec.wrap(my_codec, value) | ||
codec, unwrapped = multicodec.unwrap(wrapped, my_codec) | ||
assert codec == my_codec | ||
assert unwrapped == value | ||
|
||
|
||
def test_wrap_unwrap_by_codec(): | ||
value = b"Hello World!" | ||
wrapped = multicodec.wrap(multicodec.multicodec("ed25519-pub"), value) | ||
codec, unwrapped = multicodec.unwrap(wrapped, multicodec.multicodec("ed25519-pub")) | ||
assert codec == multicodec.multicodec("ed25519-pub") | ||
assert unwrapped == value | ||
|
||
|
||
def test_x_unknown_multicodec(): | ||
with pytest.raises(ValueError): | ||
multicodec.wrap("fancy-multicodec", b"Hello World!") | ||
|
||
|
||
def test_x_invalid_multicodec(): | ||
with pytest.raises(TypeError): | ||
multicodec.wrap(123, b"Hello World!") | ||
|
||
|
||
def test_x_invalid_multicodec_unwrap(): | ||
with pytest.raises(ValueError): | ||
multicodec.unwrap(b"Hello World!") |
7 changes: 3 additions & 4 deletions
7
aries_cloudagent/vc/ld_proofs/suites/ed25519_signature_2020.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.