Skip to main content

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 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:

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

ISC

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

multisig-hmac-0.2.4.tar.gz (6.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

multisig_hmac-0.2.4-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

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

Hashes for multisig-hmac-0.2.4.tar.gz
Algorithm Hash digest
SHA256 3f2770f845070917dd331d201376f4919229dd1809e4cc98da522bf9eb44d370
MD5 314662f4754bf0f5eeefaed92bb290fb
BLAKE2b-256 e347e3364e7b41dd140eeb42977b77dbd60fe33e537b3e0e5f2f796fb28f10c3

See more details on using hashes here.

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

Hashes for multisig_hmac-0.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 bc1d810022d6d30367a7626dfa42b160e9b1b804ff88242d7323cb4f826dce82
MD5 2fba438d9ff34136d5411c527bb75418
BLAKE2b-256 c7909dfad1435a629874e4d4f5acd6ab7331b55bfbc41455b218ec1e9226e138

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.4 This release

2 files

0.2.2

2 files

0.2.1

2 files

0.2

1 file

0.1

1 file

0.0.4

2 files

0.0.3

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page