multisig HMAC
Project description
multisig-hmac
Multisig scheme for HMAC authentication. Python implementation of 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:
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:
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
issha256
(default)
So far, the implementation supports the following specific algorithms:
MultisigHMAC.SHA256_BYTES
signature length in bytesMultisigHMAC.SHA256_KEYBYTES
key length in bytesMultisigHMAC.SHA256_PRIMITIVE
issha256
MultisigHMAC.SHA512_BYTES
signature length in bytesMultisigHMAC.SHA512_KEYBYTES
key length in bytesMultisigHMAC.SHA512_PRIMITIVE
issha512
MultisigHMAC.SHA384_BYTES
signature length in bytesMultisigHMAC.SHA384_KEYBYTES
key length in bytesMultisigHMAC.SHA384_PRIMITIVE
issha384
n = MultisigHMAC.popcount(bitfield)
Returns the number of keys (i.e. high bits) in bitfield
. bitfield
must be a 32-bit unsigned integer. Example:
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:
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:
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
$ pip install multisig-hmac
Running tests
$ pip install -U pytest
$ py.test
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file multisig-hmac-0.2.4.tar.gz
.
File metadata
- Download URL: multisig-hmac-0.2.4.tar.gz
- Upload date:
- Size: 6.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.36.1 CPython/3.7.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3f2770f845070917dd331d201376f4919229dd1809e4cc98da522bf9eb44d370 |
|
MD5 | 314662f4754bf0f5eeefaed92bb290fb |
|
BLAKE2b-256 | e347e3364e7b41dd140eeb42977b77dbd60fe33e537b3e0e5f2f796fb28f10c3 |
File details
Details for the file multisig_hmac-0.2.4-py3-none-any.whl
.
File metadata
- Download URL: multisig_hmac-0.2.4-py3-none-any.whl
- Upload date:
- Size: 8.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.36.1 CPython/3.7.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bc1d810022d6d30367a7626dfa42b160e9b1b804ff88242d7323cb4f826dce82 |
|
MD5 | 2fba438d9ff34136d5411c527bb75418 |
|
BLAKE2b-256 | c7909dfad1435a629874e4d4f5acd6ab7331b55bfbc41455b218ec1e9226e138 |