diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | python-multisig-hmac.spec | 582 | ||||
-rw-r--r-- | sources | 1 |
3 files changed, 584 insertions, 0 deletions
@@ -0,0 +1 @@ +/multisig-hmac-0.2.4.tar.gz diff --git a/python-multisig-hmac.spec b/python-multisig-hmac.spec new file mode 100644 index 0000000..339619b --- /dev/null +++ b/python-multisig-hmac.spec @@ -0,0 +1,582 @@ +%global _empty_manifest_terminate_build 0 +Name: python-multisig-hmac +Version: 0.2.4 +Release: 1 +Summary: multisig HMAC +License: ISC License (ISCL) +URL: https://github.com/AmalieDue/multisig-hmac-python-version +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/e3/47/e3364e7b41dd140eeb42977b77dbd60fe33e537b3e0e5f2f796fb28f10c3/multisig-hmac-0.2.4.tar.gz +BuildArch: noarch + + +%description +# multisig-hmac + +> Multisig scheme for HMAC authentication. Python implementation of [multisig-hmac](https://github.com/emilbayes/multisig-hmac). + +## Usage +Key management can happen in either of two modes, either by storing every of the component keys, or by storing a single master seed and using that to derive keys ad hoc. + +The following two examples return `true` when they are executed, for example inside a virtual environment. + +Using stored keys: + +```python +import multisig_hmac +from multisig_hmac.multisig_hmac import MultisigHMAC +import base64 + +m = MultisigHMAC() + +# generate keys which need to be stored securely and need to be shared securely with each party +k0 = m.keygen(0) +k1 = m.keygen(1) +k2 = m.keygen(2) + +# sign by each client +data = b'hello world' + +s0 = m.sign(k0, data) +s2 = m.sign(k2, data) + +# combine the used signatures +out = m.combine([s0, s2]) + +sent = (out[0], base64.urlsafe_b64encode(out[1])) + +# --- network --- + +received = (sent[0], base64.urlsafe_b64decode(sent[1])) + +# verify on the server +threshold = 2 +keys = [k0, k1, k2] +signature = received + +print(m.verify(keys, signature, data, threshold)) + +``` + +Using a derived master key: + +```python +import multisig_hmac +from multisig_hmac.multisig_hmac import MultisigHMAC +import base64 + +m = MultisigHMAC() + +# generate a master seed which needs to be stored securely +# this seed must NOT be shared with any other party +seed = m.seedgen() + +k0 = m.deriveKey(seed, 0) +k1 = m.deriveKey(seed, 1) +k2 = m.deriveKey(seed, 2) + +# sign by each client +data = b'hello world' + +s0 = m.sign(k0, data) +s2 = m.sign(k2, data) + +# combine the used signatures +out = m.combine([s0, s2]) + +sent = (out[0], base64.urlsafe_b64encode(out[1])) + +# --- network --- + +received = (sent[0], base64.urlsafe_b64decode(sent[1])) + +# verify on the server, but now keys are dynamically derived +threshold = 2 +signature = received + +print(m.verifyDerived(seed, signature, data, threshold)) + +``` + +## API +### Constants +* `MultisigHMAC.BYTES` signature length in bytes (default) +* `MultisigHMAC.KEYBYTES` key length in bytes (default) +* `MultisigHMAC.PRIMITIVE` is `sha256` (default) + +So far, the implementation supports the following specific algorithms: +* `MultisigHMAC.SHA256_BYTES` signature length in bytes +* `MultisigHMAC.SHA256_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA256_PRIMITIVE` is `sha256` +* `MultisigHMAC.SHA512_BYTES` signature length in bytes +* `MultisigHMAC.SHA512_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA512_PRIMITIVE` is `sha512` +* `MultisigHMAC.SHA384_BYTES` signature length in bytes +* `MultisigHMAC.SHA384_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA384_PRIMITIVE` is `sha384` + +### `n = MultisigHMAC.popcount(bitfield)` +Returns the number of keys (i.e. high bits) in `bitfield`. `bitfield` must be a 32-bit unsigned integer. Example: +```python +assert MultisigHMAC.popcount(5) == 2 +``` + +### `xs = MultisigHMAC.keyIndexes(bitfield)` +Returns the indexes of the keys (i.e. high bits) in `bitfield` as a list. `bitfield` must be a 32-bit unsigned integer. Example: +```python +assert MultisigHMAC.keyIndexes(5) == [0,2] +``` + +### `m = MultisigHMAC([alg = MultisigHMAC.PRIMITIVE])` +Creates a new instance of `MultisigHMAC` which can be used as a global singleton. Just sets the algorithm to be used for subsequent methods and associated constants. Example: +```python +m = MultisigHMAC() +assert (m.popcount(5) == 2 and m.keyIndexes(5) == [0,2]) +``` + +### `key = MultisigHMAC.keygen(index)` +Generates a new cryptographically random key. The function returns `{ index: 32-bit unsigned integer, key: bytes of length KEYBYTES }`. + +Note: `index` should be counted from 0. + +### `masterSeed = MultisigHMAC.seedgen()` +Generates a new cryptographically random master seed. + +### `key = MultisigHMAC.deriveKey(masterSeed, index)` +Derives a new subkey from a master seed. `index` must be a 32-bit unsigned integer, but in practice you want to keep a much lower number, as the bitfield used with the signature has as many bits as the largest index. The function returns `{ index: 32-bit unsigned integer, key: bytes of length KEYBYTES }`. + +Note: `index` should be counted from 0. + +Keys are derived using a KDF based on HMAC: +``` +b[0...BYTES] = HMAC(Key = masterSeed, data = 'derive' || U32LE(index) || 0x00) +b[BYTES...] = HMAC(Key = masterSeed, b[0...BYTES] || 0x01) +``` + +### `signature = MultisigHMAC.sign(key, data)` +Independently signs `data` with `key`. The function returns `{ bitfield: 32-bit unsigned integer, signature: bytes of length BYTES }`. This object can be passed to the `combine()` function explained below. + +### `signature = MultisigHMAC.combine([signatures...])` +Combines a list of signatures which have all been signed independently. Only include each signature once, otherwise they will cancel out. Signatures can be combined in any order. The function returns `{ bitfield: 32-bit unsigned integer, signature: bytearray of length BYTES }`. + +### `valid = MultisigHMAC.verify(keys, signature, data, threshold)` +Verifies a `signature` of `data` against a list of `keys`, over a given `threshold`. `keys` must be an array of keys. The function returns `True` or `False`. + +### `valid = MultisigHMAC.verifyDerived(masterSeed, signature, data, threshold)` +Verifies a `signature` of `data` against dynamically derived keys from `masterSeed`, over a given `threshold`. `masterSeed` must be bytes of length `KEYBYTES`. The function returns `True` or `False`. + +## Installation +```console +$ pip install multisig-hmac +``` + +## Running tests +```console +$ pip install -U pytest +$ py.test +``` + +## License + +[ISC](LICENSE) + + + + +%package -n python3-multisig-hmac +Summary: multisig HMAC +Provides: python-multisig-hmac +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-multisig-hmac +# multisig-hmac + +> Multisig scheme for HMAC authentication. Python implementation of [multisig-hmac](https://github.com/emilbayes/multisig-hmac). + +## Usage +Key management can happen in either of two modes, either by storing every of the component keys, or by storing a single master seed and using that to derive keys ad hoc. + +The following two examples return `true` when they are executed, for example inside a virtual environment. + +Using stored keys: + +```python +import multisig_hmac +from multisig_hmac.multisig_hmac import MultisigHMAC +import base64 + +m = MultisigHMAC() + +# generate keys which need to be stored securely and need to be shared securely with each party +k0 = m.keygen(0) +k1 = m.keygen(1) +k2 = m.keygen(2) + +# sign by each client +data = b'hello world' + +s0 = m.sign(k0, data) +s2 = m.sign(k2, data) + +# combine the used signatures +out = m.combine([s0, s2]) + +sent = (out[0], base64.urlsafe_b64encode(out[1])) + +# --- network --- + +received = (sent[0], base64.urlsafe_b64decode(sent[1])) + +# verify on the server +threshold = 2 +keys = [k0, k1, k2] +signature = received + +print(m.verify(keys, signature, data, threshold)) + +``` + +Using a derived master key: + +```python +import multisig_hmac +from multisig_hmac.multisig_hmac import MultisigHMAC +import base64 + +m = MultisigHMAC() + +# generate a master seed which needs to be stored securely +# this seed must NOT be shared with any other party +seed = m.seedgen() + +k0 = m.deriveKey(seed, 0) +k1 = m.deriveKey(seed, 1) +k2 = m.deriveKey(seed, 2) + +# sign by each client +data = b'hello world' + +s0 = m.sign(k0, data) +s2 = m.sign(k2, data) + +# combine the used signatures +out = m.combine([s0, s2]) + +sent = (out[0], base64.urlsafe_b64encode(out[1])) + +# --- network --- + +received = (sent[0], base64.urlsafe_b64decode(sent[1])) + +# verify on the server, but now keys are dynamically derived +threshold = 2 +signature = received + +print(m.verifyDerived(seed, signature, data, threshold)) + +``` + +## API +### Constants +* `MultisigHMAC.BYTES` signature length in bytes (default) +* `MultisigHMAC.KEYBYTES` key length in bytes (default) +* `MultisigHMAC.PRIMITIVE` is `sha256` (default) + +So far, the implementation supports the following specific algorithms: +* `MultisigHMAC.SHA256_BYTES` signature length in bytes +* `MultisigHMAC.SHA256_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA256_PRIMITIVE` is `sha256` +* `MultisigHMAC.SHA512_BYTES` signature length in bytes +* `MultisigHMAC.SHA512_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA512_PRIMITIVE` is `sha512` +* `MultisigHMAC.SHA384_BYTES` signature length in bytes +* `MultisigHMAC.SHA384_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA384_PRIMITIVE` is `sha384` + +### `n = MultisigHMAC.popcount(bitfield)` +Returns the number of keys (i.e. high bits) in `bitfield`. `bitfield` must be a 32-bit unsigned integer. Example: +```python +assert MultisigHMAC.popcount(5) == 2 +``` + +### `xs = MultisigHMAC.keyIndexes(bitfield)` +Returns the indexes of the keys (i.e. high bits) in `bitfield` as a list. `bitfield` must be a 32-bit unsigned integer. Example: +```python +assert MultisigHMAC.keyIndexes(5) == [0,2] +``` + +### `m = MultisigHMAC([alg = MultisigHMAC.PRIMITIVE])` +Creates a new instance of `MultisigHMAC` which can be used as a global singleton. Just sets the algorithm to be used for subsequent methods and associated constants. Example: +```python +m = MultisigHMAC() +assert (m.popcount(5) == 2 and m.keyIndexes(5) == [0,2]) +``` + +### `key = MultisigHMAC.keygen(index)` +Generates a new cryptographically random key. The function returns `{ index: 32-bit unsigned integer, key: bytes of length KEYBYTES }`. + +Note: `index` should be counted from 0. + +### `masterSeed = MultisigHMAC.seedgen()` +Generates a new cryptographically random master seed. + +### `key = MultisigHMAC.deriveKey(masterSeed, index)` +Derives a new subkey from a master seed. `index` must be a 32-bit unsigned integer, but in practice you want to keep a much lower number, as the bitfield used with the signature has as many bits as the largest index. The function returns `{ index: 32-bit unsigned integer, key: bytes of length KEYBYTES }`. + +Note: `index` should be counted from 0. + +Keys are derived using a KDF based on HMAC: +``` +b[0...BYTES] = HMAC(Key = masterSeed, data = 'derive' || U32LE(index) || 0x00) +b[BYTES...] = HMAC(Key = masterSeed, b[0...BYTES] || 0x01) +``` + +### `signature = MultisigHMAC.sign(key, data)` +Independently signs `data` with `key`. The function returns `{ bitfield: 32-bit unsigned integer, signature: bytes of length BYTES }`. This object can be passed to the `combine()` function explained below. + +### `signature = MultisigHMAC.combine([signatures...])` +Combines a list of signatures which have all been signed independently. Only include each signature once, otherwise they will cancel out. Signatures can be combined in any order. The function returns `{ bitfield: 32-bit unsigned integer, signature: bytearray of length BYTES }`. + +### `valid = MultisigHMAC.verify(keys, signature, data, threshold)` +Verifies a `signature` of `data` against a list of `keys`, over a given `threshold`. `keys` must be an array of keys. The function returns `True` or `False`. + +### `valid = MultisigHMAC.verifyDerived(masterSeed, signature, data, threshold)` +Verifies a `signature` of `data` against dynamically derived keys from `masterSeed`, over a given `threshold`. `masterSeed` must be bytes of length `KEYBYTES`. The function returns `True` or `False`. + +## Installation +```console +$ pip install multisig-hmac +``` + +## Running tests +```console +$ pip install -U pytest +$ py.test +``` + +## License + +[ISC](LICENSE) + + + + +%package help +Summary: Development documents and examples for multisig-hmac +Provides: python3-multisig-hmac-doc +%description help +# multisig-hmac + +> Multisig scheme for HMAC authentication. Python implementation of [multisig-hmac](https://github.com/emilbayes/multisig-hmac). + +## Usage +Key management can happen in either of two modes, either by storing every of the component keys, or by storing a single master seed and using that to derive keys ad hoc. + +The following two examples return `true` when they are executed, for example inside a virtual environment. + +Using stored keys: + +```python +import multisig_hmac +from multisig_hmac.multisig_hmac import MultisigHMAC +import base64 + +m = MultisigHMAC() + +# generate keys which need to be stored securely and need to be shared securely with each party +k0 = m.keygen(0) +k1 = m.keygen(1) +k2 = m.keygen(2) + +# sign by each client +data = b'hello world' + +s0 = m.sign(k0, data) +s2 = m.sign(k2, data) + +# combine the used signatures +out = m.combine([s0, s2]) + +sent = (out[0], base64.urlsafe_b64encode(out[1])) + +# --- network --- + +received = (sent[0], base64.urlsafe_b64decode(sent[1])) + +# verify on the server +threshold = 2 +keys = [k0, k1, k2] +signature = received + +print(m.verify(keys, signature, data, threshold)) + +``` + +Using a derived master key: + +```python +import multisig_hmac +from multisig_hmac.multisig_hmac import MultisigHMAC +import base64 + +m = MultisigHMAC() + +# generate a master seed which needs to be stored securely +# this seed must NOT be shared with any other party +seed = m.seedgen() + +k0 = m.deriveKey(seed, 0) +k1 = m.deriveKey(seed, 1) +k2 = m.deriveKey(seed, 2) + +# sign by each client +data = b'hello world' + +s0 = m.sign(k0, data) +s2 = m.sign(k2, data) + +# combine the used signatures +out = m.combine([s0, s2]) + +sent = (out[0], base64.urlsafe_b64encode(out[1])) + +# --- network --- + +received = (sent[0], base64.urlsafe_b64decode(sent[1])) + +# verify on the server, but now keys are dynamically derived +threshold = 2 +signature = received + +print(m.verifyDerived(seed, signature, data, threshold)) + +``` + +## API +### Constants +* `MultisigHMAC.BYTES` signature length in bytes (default) +* `MultisigHMAC.KEYBYTES` key length in bytes (default) +* `MultisigHMAC.PRIMITIVE` is `sha256` (default) + +So far, the implementation supports the following specific algorithms: +* `MultisigHMAC.SHA256_BYTES` signature length in bytes +* `MultisigHMAC.SHA256_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA256_PRIMITIVE` is `sha256` +* `MultisigHMAC.SHA512_BYTES` signature length in bytes +* `MultisigHMAC.SHA512_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA512_PRIMITIVE` is `sha512` +* `MultisigHMAC.SHA384_BYTES` signature length in bytes +* `MultisigHMAC.SHA384_KEYBYTES` key length in bytes +* `MultisigHMAC.SHA384_PRIMITIVE` is `sha384` + +### `n = MultisigHMAC.popcount(bitfield)` +Returns the number of keys (i.e. high bits) in `bitfield`. `bitfield` must be a 32-bit unsigned integer. Example: +```python +assert MultisigHMAC.popcount(5) == 2 +``` + +### `xs = MultisigHMAC.keyIndexes(bitfield)` +Returns the indexes of the keys (i.e. high bits) in `bitfield` as a list. `bitfield` must be a 32-bit unsigned integer. Example: +```python +assert MultisigHMAC.keyIndexes(5) == [0,2] +``` + +### `m = MultisigHMAC([alg = MultisigHMAC.PRIMITIVE])` +Creates a new instance of `MultisigHMAC` which can be used as a global singleton. Just sets the algorithm to be used for subsequent methods and associated constants. Example: +```python +m = MultisigHMAC() +assert (m.popcount(5) == 2 and m.keyIndexes(5) == [0,2]) +``` + +### `key = MultisigHMAC.keygen(index)` +Generates a new cryptographically random key. The function returns `{ index: 32-bit unsigned integer, key: bytes of length KEYBYTES }`. + +Note: `index` should be counted from 0. + +### `masterSeed = MultisigHMAC.seedgen()` +Generates a new cryptographically random master seed. + +### `key = MultisigHMAC.deriveKey(masterSeed, index)` +Derives a new subkey from a master seed. `index` must be a 32-bit unsigned integer, but in practice you want to keep a much lower number, as the bitfield used with the signature has as many bits as the largest index. The function returns `{ index: 32-bit unsigned integer, key: bytes of length KEYBYTES }`. + +Note: `index` should be counted from 0. + +Keys are derived using a KDF based on HMAC: +``` +b[0...BYTES] = HMAC(Key = masterSeed, data = 'derive' || U32LE(index) || 0x00) +b[BYTES...] = HMAC(Key = masterSeed, b[0...BYTES] || 0x01) +``` + +### `signature = MultisigHMAC.sign(key, data)` +Independently signs `data` with `key`. The function returns `{ bitfield: 32-bit unsigned integer, signature: bytes of length BYTES }`. This object can be passed to the `combine()` function explained below. + +### `signature = MultisigHMAC.combine([signatures...])` +Combines a list of signatures which have all been signed independently. Only include each signature once, otherwise they will cancel out. Signatures can be combined in any order. The function returns `{ bitfield: 32-bit unsigned integer, signature: bytearray of length BYTES }`. + +### `valid = MultisigHMAC.verify(keys, signature, data, threshold)` +Verifies a `signature` of `data` against a list of `keys`, over a given `threshold`. `keys` must be an array of keys. The function returns `True` or `False`. + +### `valid = MultisigHMAC.verifyDerived(masterSeed, signature, data, threshold)` +Verifies a `signature` of `data` against dynamically derived keys from `masterSeed`, over a given `threshold`. `masterSeed` must be bytes of length `KEYBYTES`. The function returns `True` or `False`. + +## Installation +```console +$ pip install multisig-hmac +``` + +## Running tests +```console +$ pip install -U pytest +$ py.test +``` + +## License + +[ISC](LICENSE) + + + + +%prep +%autosetup -n multisig-hmac-0.2.4 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-multisig-hmac -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Mon May 29 2023 Python_Bot <Python_Bot@openeuler.org> - 0.2.4-1 +- Package Spec generated @@ -0,0 +1 @@ +314662f4754bf0f5eeefaed92bb290fb multisig-hmac-0.2.4.tar.gz |