Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5 key and static key parameter gen for alg macs #8

Merged
merged 11 commits into from
Jan 19, 2023
Merged
4 changes: 4 additions & 0 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up python
uses: actions/setup-python@v3
with:
Expand All @@ -29,6 +31,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up python
uses: actions/setup-python@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tool.pylint.main]
disable=missing-module-docstring,missing-function-docstring,invalid-name
disable=missing-module-docstring,missing-function-docstring,invalid-name,import-error,no-name-in-module


[tool.pylint.basic]
Expand Down
4 changes: 4 additions & 0 deletions kvac/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
__version__ = "0.0.1"

from .issuer_key_pair import IssuerPublicKey, IssuerKeyPair
from .system_params import SystemParams
from .ristretto_sho import RistrettoSho
61 changes: 61 additions & 0 deletions kvac/issuer_key_pair.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from typing import List, NamedTuple
from curve25519_dalek.ristretto import RistrettoPoint
from curve25519_dalek.scalar import Scalar

from .ristretto_sho import RistrettoSho
from .system_params import SystemParams


class IssuerPublicKey(NamedTuple):
"""
Represents the public key of an issuer.
"""
C_w: RistrettoPoint
I: RistrettoPoint


class IssuerKeyPair(NamedTuple):
"""
Represents a Server's key pair, including private and public values.
"""

# private
w: Scalar
wprime: Scalar
W: RistrettoPoint

x0: Scalar
x1: Scalar

ys: List[Scalar]

# public
C_w: RistrettoPoint
I: RistrettoPoint

@classmethod
def generate(
cls,
system: SystemParams,
sho: RistrettoSho
) -> 'IssuerKeyPair':

# private
w = sho.get_scalar()
wprime = sho.get_scalar()
W = system.G_w * w
x0 = sho.get_scalar()
x1 = sho.get_scalar()

ys = [sho.get_scalar() for _ in range(system.max_messages)]

# public
C_w = W + (system.G_wprime * wprime)
I = system.G_V - (system.G_x0 * x0) - (system.G_x1 * x1)
for G_y, y in zip(system.G_ys, ys):
I -= G_y * y

return cls(w, wprime, W, x0, x1, ys, C_w, I)

def get_public_key(self) -> IssuerPublicKey:
return IssuerPublicKey(self.C_w, self.I)
30 changes: 30 additions & 0 deletions kvac/ristretto_sho.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from curve25519_dalek.ristretto import RistrettoPoint
from curve25519_dalek.scalar import Scalar

from poksho.poksho import SHO


class RistrettoSho:
leonschmidt99 marked this conversation as resolved.
Show resolved Hide resolved
"""
Encapsulates SHO functions to provide convenient generation of Ristretto points and scalars.
Reference: https://github.com/signalapp/libsignal/blob/main/rust/zkgroup/src/common/sho.rs
"""

def __init__(self, customization_label: bytes, data: bytes):
self._sho = SHO(customization_label, use_hmac=True)
self._sho.absorb_and_ratchet(data)

def squeeze(self, out_length: int) -> bytes:
return self._sho.squeeze_and_ratchet(out_length)

def get_point(self) -> RistrettoPoint:
point_bytes = self.squeeze(64)
return RistrettoPoint.from_uniform_bytes(point_bytes)

def get_point_single_elligator(self) -> RistrettoPoint:
point_bytes = self.squeeze(32)
return RistrettoPoint.from_uniform_bytes_single_elligator(point_bytes)

def get_scalar(self) -> Scalar:
scalar_bytes = self.squeeze(64)
return Scalar.from_bytes_mod_order_wide(scalar_bytes)
65 changes: 65 additions & 0 deletions kvac/system_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from typing import List, NamedTuple
from curve25519_dalek.ristretto import RistrettoPoint

from .ristretto_sho import RistrettoSho


class SystemParams(NamedTuple):
"""
Encapsulates all public parameters of the system.
"""

# documented in Signal's paper
G_w: RistrettoPoint
G_wprime: RistrettoPoint

G_x0: RistrettoPoint
G_x1: RistrettoPoint

G_ys: List[RistrettoPoint]
G_ms: List[RistrettoPoint]

G_V: RistrettoPoint

# not mentioned in the paper, but used in the reference implementation
G_z: RistrettoPoint # used to prove a commitment on z

@classmethod
def generate(
cls,
max_messages: int,
sho: RistrettoSho
) -> 'SystemParams':

G_w, G_wprime, G_x0, G_x1, G_V, G_z = [sho.get_point() for _ in range(6)]
G_ys = [sho.get_point() for _ in range(max_messages)]
G_ms = [sho.get_point() for _ in range(max_messages)]

return cls(G_w, G_wprime, G_x0, G_x1, G_ys, G_ms, G_V, G_z)

@classmethod
def generate_signal_parameters(cls) -> 'SystemParams':
sho = RistrettoSho(
b'Signal_ZKGroup_20200424_Constant_Credentials_SystemParams_Generate',
b''
)
G_w = sho.get_point()
G_wprime = sho.get_point()

G_x0 = sho.get_point()
G_x1 = sho.get_point()

G_ys = [sho.get_point() for _ in range(4)]
G_ms = [sho.get_point() for _ in range(4)]

G_V = sho.get_point()
G_z = sho.get_point()

G_ys.extend([sho.get_point() for _ in range(2)])
G_ms.append(sho.get_point())

return cls(G_w, G_wprime, G_x0, G_x1, G_ys, G_ms, G_V, G_z)

@property
def max_messages(self) -> int:
return len(self.G_ys)
31 changes: 31 additions & 0 deletions tests/test_ristretto_sho.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from curve25519_dalek.ristretto import CompressedRistretto
from curve25519_dalek.scalar import Scalar

from kvac import RistrettoSho


def test_ristretto_sho_get_point():
sho = RistrettoSho(b"test", b"")
assert sho.get_point() == CompressedRistretto(bytes([
0x6c, 0x46, 0x32, 0xe5, 0x57, 0xc6, 0x22, 0xc2, 0x8f, 0xf4, 0x3e,
0x67, 0xcf, 0xb5, 0x66, 0x9b, 0x3a, 0x24, 0xec, 0xff, 0x85, 0x56,
0xa6, 0xfe, 0xed, 0xef, 0x85, 0x26, 0xcf, 0xc0, 0xd3, 0x17
])).decompress()


def test_ristretto_sho_get_point_single_elligator():
sho = RistrettoSho(b"test", b"")
assert sho.get_point_single_elligator() == CompressedRistretto(bytes([
0x78, 0xe2, 0xe6, 0xb3, 0xa9, 0x8c, 0x82, 0xda, 0x9e, 0x70, 0x4c,
0x7c, 0x15, 0xaa, 0xc4, 0xf9, 0xea, 0xd7, 0x6f, 0xcc, 0x90, 0x30,
0x35, 0xb6, 0x48, 0x3d, 0xfe, 0xa0, 0x31, 0xe2, 0x19, 0x67
])).decompress()


def test_ristretto_sho_get_scalar():
sho = RistrettoSho(b"test", b"")
assert sho.get_scalar() == Scalar.from_bytes_mod_order(bytes([
0x3f, 0x23, 0xf7, 0x10, 0x9c, 0x26, 0xeb, 0x6f, 0x6e, 0x17, 0xe4,
0x92, 0x1b, 0x47, 0x41, 0xcf, 0x0f, 0xcd, 0xb7, 0x08, 0x58, 0xd2,
0x76, 0xac, 0x6b, 0x19, 0xa3, 0xe1, 0x76, 0xac, 0xc7, 0x0d
]))
65 changes: 65 additions & 0 deletions tests/test_system_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from curve25519_dalek.ristretto import RistrettoPoint, CompressedRistretto

import kvac

SIGNAL_SYSTEM_HARDCODED = [
0x9a, 0xe7, 0xc8, 0xe5, 0xed, 0x77, 0x9b, 0x11, 0x4a, 0xe7, 0x70, 0x8a, 0xa2, 0xf7, 0x94,
0x67, 0xa, 0xdd, 0xa3, 0x24, 0x98, 0x7b, 0x65, 0x99, 0x13, 0x12, 0x2c, 0x35, 0x50, 0x5b,
0x10, 0x5e, 0x6c, 0xa3, 0x10, 0x25, 0xd2, 0xd7, 0x6b, 0xe7, 0xfd, 0x34, 0x94, 0x4f, 0x98,
0xf7, 0xfa, 0xe, 0x37, 0xba, 0xbb, 0x2c, 0x8b, 0x98, 0xbb, 0xbd, 0xbd, 0x3d, 0xd1, 0xbf,
0x13, 0xc, 0xca, 0x2c, 0x8a, 0x9a, 0x3b, 0xdf, 0xaa, 0xa2, 0xb6, 0xb3, 0x22, 0xd4, 0x6b,
0x93, 0xec, 0xa7, 0xb0, 0xd5, 0x1c, 0x86, 0xa3, 0xc8, 0x39, 0xe1, 0x14, 0x66, 0x35, 0x82,
0x58, 0xa6, 0xc1, 0xc, 0x57, 0x7f, 0xc2, 0xbf, 0xfd, 0x34, 0xcd, 0x99, 0x16, 0x4c, 0x9a,
0x6c, 0xd2, 0x9f, 0xab, 0x55, 0xd9, 0x1f, 0xf9, 0x26, 0x93, 0x22, 0xec, 0x34, 0x58, 0x60,
0x3c, 0xc9, 0x6a, 0xd, 0x47, 0xf7, 0x4, 0x5, 0x82, 0x88, 0xf6, 0x2e, 0xe0, 0xac, 0xed,
0xb8, 0xaa, 0x23, 0x24, 0x21, 0x21, 0xd9, 0x89, 0x65, 0xa9, 0xbb, 0x29, 0x91, 0x25, 0xc,
0x11, 0x75, 0x80, 0x95, 0xec, 0xe0, 0xfd, 0x2b, 0x33, 0x28, 0x52, 0x86, 0xfe, 0x1f, 0xcb,
0x5, 0x61, 0x3, 0xb6, 0x8, 0x17, 0x44, 0xb9, 0x75, 0xf5, 0x50, 0xd0, 0x85, 0x21, 0x56,
0x8d, 0xd3, 0xd8, 0x61, 0x8f, 0x25, 0xc1, 0x40, 0x37, 0x5a, 0xf, 0x40, 0x24, 0xc3, 0xaa,
0x23, 0xbd, 0xff, 0xfb, 0x27, 0xfb, 0xd9, 0x82, 0x20, 0x8d, 0x3e, 0xcd, 0x1f, 0xd3, 0xbc,
0xb7, 0xac, 0xc, 0x3a, 0x14, 0xb1, 0x9, 0x80, 0x4f, 0xc7, 0x48, 0xd7, 0xfa, 0x45, 0x6c,
0xff, 0xb4, 0x93, 0x4f, 0x98, 0xb, 0x6e, 0x9, 0xa2, 0x48, 0xa6, 0xf, 0x44, 0xa6, 0x15, 0xa,
0xe6, 0xc1, 0x3d, 0x7e, 0x3c, 0x6, 0x26, 0x1d, 0x7e, 0x4e, 0xed, 0x37, 0xf3, 0x9f, 0x60,
0xb0, 0x4d, 0xd9, 0xd6, 0x7, 0xfd, 0x35, 0x70, 0x12, 0x27, 0x4d, 0x3c, 0x63, 0xdb, 0xb3,
0x8e, 0x73, 0x78, 0x59, 0x9c, 0x9e, 0x97, 0xdf, 0xbb, 0x28, 0x84, 0x26, 0x94, 0x89, 0x1d,
0x5f, 0xd, 0xdc, 0x72, 0x99, 0x19, 0xb7, 0x98, 0xb4, 0x13, 0x15, 0x3, 0x40, 0x8c, 0xc5,
0x7a, 0x9c, 0x53, 0x2f, 0x44, 0x27, 0x63, 0x2c, 0x88, 0xf5, 0x4c, 0xea, 0x53, 0x86, 0x1a,
0x5b, 0xc4, 0x4c, 0x61, 0xcc, 0x60, 0x37, 0xdc, 0x31, 0xc2, 0xe8, 0xd4, 0x47, 0x4f, 0xb5,
0x19, 0x58, 0x7a, 0x44, 0x86, 0x93, 0x18, 0x2a, 0xd9, 0xd6, 0xd8, 0x6b, 0x53, 0x59, 0x57,
0x85, 0x8f, 0x54, 0x7b, 0x93, 0x40, 0x12, 0x7d, 0xa7, 0x5f, 0x80, 0x74, 0xca, 0xee, 0x94,
0x4a, 0xc3, 0x6c, 0xa, 0xc6, 0x62, 0xd3, 0x8c, 0x9b, 0x3c, 0xcc, 0xe0, 0x3a, 0x9, 0x3f,
0xcd, 0x96, 0x44, 0x4, 0x73, 0x98, 0xb8, 0x6b, 0x6e, 0x83, 0x37, 0x2f, 0xf1, 0x4f, 0xb8,
0xbb, 0xd, 0xea, 0x65, 0x53, 0x12, 0x52, 0xac, 0x70, 0xd5, 0x8a, 0x4a, 0x8, 0x10, 0xd6,
0x82, 0xa0, 0xe7, 0x9, 0xc9, 0x22, 0x7b, 0x30, 0xef, 0x6c, 0x8e, 0x17, 0xc5, 0x91, 0x5d,
0x52, 0x72, 0x21, 0xbb, 0x0, 0xda, 0x81, 0x75, 0xcd, 0x64, 0x89, 0xaa, 0x8a, 0xa4, 0x92,
0xa5, 0x0, 0xf9, 0xab, 0xee, 0x56, 0x90, 0xb9, 0xdf, 0xca, 0x88, 0x55, 0xdc, 0xb, 0xd0,
0x2a, 0x7f, 0x27, 0x7a, 0xdd, 0x24, 0xf, 0x63, 0x9a, 0xc1, 0x68, 0x1, 0xe8, 0x15, 0x74,
0xaf, 0xb4, 0x68, 0x3e, 0xdf, 0xf6, 0x3b, 0x9a, 0x1, 0xe9, 0x3d, 0xbd, 0x86, 0x7a, 0x4,
0xb6, 0x16, 0xc7, 0x6, 0xc8, 0xc, 0x75, 0x6c, 0x11, 0xa3, 0x1, 0x6b, 0xbf, 0xb6, 0x9, 0x77,
0xf4, 0x64, 0x8b, 0x5f, 0x23, 0x95, 0xa4, 0xb4, 0x28, 0xb7, 0x21, 0x19, 0x40, 0x81, 0x3e,
0x3a, 0xfd, 0xe2, 0xb8, 0x7a, 0xa9, 0xc2, 0xc3, 0x7b, 0xf7, 0x16, 0xe2, 0x57, 0x8f, 0x95,
0x65, 0x6d, 0xf1, 0x2c, 0x2f, 0xb6, 0xf5, 0xd0, 0x63, 0x1f, 0x6f, 0x71, 0xe2, 0xc3, 0x19,
0x3f, 0x6d,
]


def get_signal_system_hardcoded() -> kvac.SystemParams:
def get_point_from_hardcoded_system(system_index: int) -> RistrettoPoint:
start, end = system_index * 32, (system_index + 1) * 32
return CompressedRistretto(bytes(SIGNAL_SYSTEM_HARDCODED[start:end])).decompress()

return kvac.SystemParams(
G_w=get_point_from_hardcoded_system(0),
G_wprime=get_point_from_hardcoded_system(1),
G_x0=get_point_from_hardcoded_system(2),
G_x1=get_point_from_hardcoded_system(3),
G_ys=[get_point_from_hardcoded_system(i) for i in range(4, 10)],
G_ms=[get_point_from_hardcoded_system(i) for i in range(10, 15)],
G_V=get_point_from_hardcoded_system(15),
G_z=get_point_from_hardcoded_system(16),
)


def test_generate_signal_hardcoded_test_system():
# assumption: kvac.RistrettoSho uses HMAC-SHA-256 SHO
assert kvac.SystemParams.generate_signal_parameters() == get_signal_system_hardcoded()