summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--python-multisig-hmac.spec582
-rw-r--r--sources1
3 files changed, 584 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..be4a515 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/sources b/sources
new file mode 100644
index 0000000..04d8e56
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+314662f4754bf0f5eeefaed92bb290fb multisig-hmac-0.2.4.tar.gz