ciris-verify 7.2.0__tar.gz → 7.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/PKG-INFO +1 -1
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/__init__.py +5 -1
- ciris_verify-7.4.0/ciris_verify/_rns_dest_hash.py +150 -0
- ciris_verify-7.4.0/ciris_verify/_scope_privacy.py +186 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify.egg-info/PKG-INFO +1 -1
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify.egg-info/SOURCES.txt +2 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/pyproject.toml +1 -1
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/README.md +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_accord_custody.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_bin_sign.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_bin_verify.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_federation_identity.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_jcs.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_manifest_contribution.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_operational_admit.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_wheel_hybrid_kex.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_wheel_key_grant.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_wheel_locale_merkle.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_wheel_reconsider_dos.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/_wheel_skill_import.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/client.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/exceptions.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/py.typed +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify/types.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify.egg-info/dependency_links.txt +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify.egg-info/entry_points.txt +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify.egg-info/requires.txt +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/ciris_verify.egg-info/top_level.txt +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/setup.cfg +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/tests/test_client.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/tests/test_memory_baseline.py +0 -0
- {ciris_verify-7.2.0 → ciris_verify-7.4.0}/tests/test_types.py +0 -0
|
@@ -30,6 +30,8 @@ import logging as _logging
|
|
|
30
30
|
|
|
31
31
|
from .client import CIRISVerify, MockCIRISVerify, verify_tree, DEFAULT_REGISTRY_URL
|
|
32
32
|
from ._jcs import jcs_canonicalize
|
|
33
|
+
from ._rns_dest_hash import rns_destination_hash
|
|
34
|
+
from . import _scope_privacy as scope_privacy
|
|
33
35
|
from ._federation_identity import create_federation_identity
|
|
34
36
|
from ._manifest_contribution import verify_build_manifest_contribution
|
|
35
37
|
from ._accord_custody import verify_accord_custody_attestation
|
|
@@ -127,12 +129,14 @@ def get_library_version() -> str:
|
|
|
127
129
|
return __version__
|
|
128
130
|
|
|
129
131
|
|
|
130
|
-
__version__ = "7.
|
|
132
|
+
__version__ = "7.4.0"
|
|
131
133
|
__all__ = [
|
|
132
134
|
"CIRISVerify",
|
|
133
135
|
"MockCIRISVerify",
|
|
134
136
|
"verify_tree",
|
|
135
137
|
"jcs_canonicalize",
|
|
138
|
+
"rns_destination_hash",
|
|
139
|
+
"scope_privacy",
|
|
136
140
|
"create_federation_identity",
|
|
137
141
|
"verify_build_manifest_contribution",
|
|
138
142
|
"verify_accord_custody_attestation",
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""RNS ``destination_hash`` recompute — Python binding (CIRISVerify#28).
|
|
2
|
+
|
|
3
|
+
Exposes :func:`rns_destination_hash`, a thin wrapper over the FFI symbol
|
|
4
|
+
``ciris_verify_rns_destination_hash`` which calls
|
|
5
|
+
``ciris_verify_core::transport_binding::compute_destination_hash`` — the one
|
|
6
|
+
blessed two-stage RNS destination-hash construction (CEG 1.0-RC6 §5.6.8.8.1.1).
|
|
7
|
+
|
|
8
|
+
This lifts the last verify-side remainder of the #28 transport-binding
|
|
9
|
+
waterfall: the recompute shipped Rust-side in v5.6.0 (``DestinationHashCheck``
|
|
10
|
+
lifted off ``Unsupported``) but was never on the wheel, so a Python consumer —
|
|
11
|
+
and CIRISConformance's ``test_150_rns_dest_hash.py`` cross-check — could not
|
|
12
|
+
verify a peer's ``destination_hash`` against the pinned algorithm. With this it
|
|
13
|
+
can, byte-for-byte, with **no** Reticulum vendoring and no second
|
|
14
|
+
implementation: the canonical bytes come from the same Rust path the verifiers
|
|
15
|
+
use.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import ctypes
|
|
21
|
+
import json as _json
|
|
22
|
+
import platform as _platform
|
|
23
|
+
import threading as _threading
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Optional, Sequence
|
|
26
|
+
|
|
27
|
+
__all__ = ["rns_destination_hash"]
|
|
28
|
+
|
|
29
|
+
_lib: Optional[ctypes.CDLL] = None
|
|
30
|
+
_lib_lock = _threading.Lock()
|
|
31
|
+
_SUCCESS = 0
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _candidate_paths() -> list[str]:
|
|
35
|
+
here = Path(__file__).resolve().parent
|
|
36
|
+
system = _platform.system()
|
|
37
|
+
names = {
|
|
38
|
+
"Linux": ["libciris_verify_ffi.so", "libciris_verify.so"],
|
|
39
|
+
"Darwin": ["libciris_verify_ffi.dylib", "libciris_verify.dylib"],
|
|
40
|
+
"Windows": ["ciris_verify_ffi.dll", "ciris_verify.dll"],
|
|
41
|
+
}.get(system, ["libciris_verify_ffi.so"])
|
|
42
|
+
|
|
43
|
+
paths: list[str] = []
|
|
44
|
+
for n in names:
|
|
45
|
+
paths.append(str(here / n))
|
|
46
|
+
try:
|
|
47
|
+
from .client import DEFAULT_BINARY_PATHS # type: ignore
|
|
48
|
+
|
|
49
|
+
paths.extend(DEFAULT_BINARY_PATHS.get(system, []))
|
|
50
|
+
except Exception: # pragma: no cover - defensive
|
|
51
|
+
pass
|
|
52
|
+
return paths
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _load_lib() -> ctypes.CDLL:
|
|
56
|
+
global _lib
|
|
57
|
+
if _lib is not None:
|
|
58
|
+
return _lib
|
|
59
|
+
with _lib_lock:
|
|
60
|
+
if _lib is not None:
|
|
61
|
+
return _lib
|
|
62
|
+
last_err: Optional[Exception] = None
|
|
63
|
+
for path in _candidate_paths():
|
|
64
|
+
if not Path(path).exists():
|
|
65
|
+
continue
|
|
66
|
+
try:
|
|
67
|
+
lib = ctypes.CDLL(path)
|
|
68
|
+
fn = lib.ciris_verify_rns_destination_hash
|
|
69
|
+
except (OSError, AttributeError) as exc:
|
|
70
|
+
last_err = exc
|
|
71
|
+
continue
|
|
72
|
+
fn.argtypes = [
|
|
73
|
+
ctypes.c_char_p, # input_json (UTF-8 bytes)
|
|
74
|
+
ctypes.c_size_t, # input_len
|
|
75
|
+
ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), # result_out
|
|
76
|
+
ctypes.POINTER(ctypes.c_size_t), # result_len_out
|
|
77
|
+
]
|
|
78
|
+
fn.restype = ctypes.c_int
|
|
79
|
+
lib.ciris_verify_free.argtypes = [ctypes.c_void_p]
|
|
80
|
+
lib.ciris_verify_free.restype = None
|
|
81
|
+
_lib = lib
|
|
82
|
+
return _lib
|
|
83
|
+
raise RuntimeError(
|
|
84
|
+
"ciris_verify_rns_destination_hash not available — could not load "
|
|
85
|
+
f"the CIRISVerify shared library (last error: {last_err}). "
|
|
86
|
+
"The library must be built with the wheel (>= v7.3.0)."
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def rns_destination_hash(
|
|
91
|
+
app_name: str,
|
|
92
|
+
aspects: Sequence[str],
|
|
93
|
+
x25519_pub: bytes,
|
|
94
|
+
ed25519_pub: bytes,
|
|
95
|
+
) -> bytes:
|
|
96
|
+
"""Recompute the RNS ``destination_hash`` per CEG §5.6.8.8.1.1.
|
|
97
|
+
|
|
98
|
+
The two-stage construction (NOT a flat single SHA-256):
|
|
99
|
+
|
|
100
|
+
name_hash = SHA256(app_name + "." + ".".join(aspects))[:10]
|
|
101
|
+
identity_hash = SHA256(x25519_pub ‖ ed25519_pub)[:16]
|
|
102
|
+
destination_hash = SHA256(name_hash ‖ identity_hash)[:16]
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
app_name: the RNS app name (e.g. ``"ciris.federation"``).
|
|
106
|
+
aspects: the dot-joined aspects (each MUST NOT contain ``"."``).
|
|
107
|
+
x25519_pub: the peer's X25519 public key bytes.
|
|
108
|
+
ed25519_pub: the peer's Ed25519 public key bytes (key order is
|
|
109
|
+
x25519 THEN ed25519, per RNS ``get_public_key``).
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
The 16-byte destination hash — byte-identical to
|
|
113
|
+
``ciris_verify_core::transport_binding::compute_destination_hash`` and
|
|
114
|
+
therefore to the pinned §5.6.8.8.1.1 algorithm.
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
ValueError: an aspect contains ``"."`` (illegal — it would alter the
|
|
118
|
+
name preimage split), or the inputs cannot be encoded.
|
|
119
|
+
RuntimeError: the shared library / FFI symbol is unavailable.
|
|
120
|
+
"""
|
|
121
|
+
req = {
|
|
122
|
+
"app_name": app_name,
|
|
123
|
+
"aspects": list(aspects),
|
|
124
|
+
"x25519_pubkey": list(x25519_pub),
|
|
125
|
+
"ed25519_pubkey": list(ed25519_pub),
|
|
126
|
+
}
|
|
127
|
+
input_bytes = _json.dumps(req).encode("utf-8")
|
|
128
|
+
|
|
129
|
+
lib = _load_lib()
|
|
130
|
+
out_ptr = ctypes.POINTER(ctypes.c_ubyte)()
|
|
131
|
+
out_len = ctypes.c_size_t(0)
|
|
132
|
+
rc = lib.ciris_verify_rns_destination_hash(
|
|
133
|
+
input_bytes,
|
|
134
|
+
len(input_bytes),
|
|
135
|
+
ctypes.byref(out_ptr),
|
|
136
|
+
ctypes.byref(out_len),
|
|
137
|
+
)
|
|
138
|
+
if rc != _SUCCESS:
|
|
139
|
+
# rc 2 == SerializationError (bad request / dotted aspect).
|
|
140
|
+
raise ValueError(
|
|
141
|
+
f"rns_destination_hash: invalid request (e.g. an aspect containing "
|
|
142
|
+
f"'.', or non-encodable input) (FFI code {rc})"
|
|
143
|
+
)
|
|
144
|
+
n = out_len.value
|
|
145
|
+
try:
|
|
146
|
+
result = ctypes.string_at(out_ptr, n)
|
|
147
|
+
finally:
|
|
148
|
+
if n != 0:
|
|
149
|
+
lib.ciris_verify_free(ctypes.cast(out_ptr, ctypes.c_void_p))
|
|
150
|
+
return result
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Scope-native privacy derivations — Python binding (CIRISVerify#82).
|
|
2
|
+
|
|
3
|
+
Exposes the ``ciris_crypto::scope_privacy`` FSD §2.2/§2.4/§3.4 derivation
|
|
4
|
+
helpers (CEWP ``SCOPE_PRIVACY.md`` — CC 1.13.3 anonymous tier) on the wheel,
|
|
5
|
+
over the FFI symbol ``ciris_verify_scope_privacy_derive``. A Python consumer can
|
|
6
|
+
reproduce a ``record_id`` / ``symbol_key`` / witness cover-leaf **byte-identically**
|
|
7
|
+
to the Rust verifiers — the canonical bytes (incl. the RFC 8949 §4.2.1
|
|
8
|
+
deterministic CBOR ``record_id`` preimage and the pinned ``RecordType`` integers)
|
|
9
|
+
come from the one Rust impl, so there is no second implementation to drift.
|
|
10
|
+
|
|
11
|
+
Imported as the ``ciris_verify.scope_privacy`` namespace::
|
|
12
|
+
|
|
13
|
+
from ciris_verify import scope_privacy
|
|
14
|
+
krid = scope_privacy.k_record_id(exporter_secret)
|
|
15
|
+
rid = scope_privacy.derive_record_id(krid, internal_id, "community", epoch)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import ctypes
|
|
21
|
+
import json as _json
|
|
22
|
+
import platform as _platform
|
|
23
|
+
import threading as _threading
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Optional
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"k_record_id",
|
|
29
|
+
"k_symbol",
|
|
30
|
+
"derive_record_id",
|
|
31
|
+
"derive_symbol_key",
|
|
32
|
+
"witness_cover_leaf",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
_lib: Optional[ctypes.CDLL] = None
|
|
36
|
+
_lib_lock = _threading.Lock()
|
|
37
|
+
_SUCCESS = 0
|
|
38
|
+
|
|
39
|
+
# The record_type strings the FFI accepts (mirrors ciris_crypto RecordType).
|
|
40
|
+
_RECORD_TYPES = ("self", "family", "community", "federation")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _candidate_paths() -> list[str]:
|
|
44
|
+
here = Path(__file__).resolve().parent
|
|
45
|
+
system = _platform.system()
|
|
46
|
+
names = {
|
|
47
|
+
"Linux": ["libciris_verify_ffi.so", "libciris_verify.so"],
|
|
48
|
+
"Darwin": ["libciris_verify_ffi.dylib", "libciris_verify.dylib"],
|
|
49
|
+
"Windows": ["ciris_verify_ffi.dll", "ciris_verify.dll"],
|
|
50
|
+
}.get(system, ["libciris_verify_ffi.so"])
|
|
51
|
+
|
|
52
|
+
paths: list[str] = []
|
|
53
|
+
for n in names:
|
|
54
|
+
paths.append(str(here / n))
|
|
55
|
+
try:
|
|
56
|
+
from .client import DEFAULT_BINARY_PATHS # type: ignore
|
|
57
|
+
|
|
58
|
+
paths.extend(DEFAULT_BINARY_PATHS.get(system, []))
|
|
59
|
+
except Exception: # pragma: no cover - defensive
|
|
60
|
+
pass
|
|
61
|
+
return paths
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _load_lib() -> ctypes.CDLL:
|
|
65
|
+
global _lib
|
|
66
|
+
if _lib is not None:
|
|
67
|
+
return _lib
|
|
68
|
+
with _lib_lock:
|
|
69
|
+
if _lib is not None:
|
|
70
|
+
return _lib
|
|
71
|
+
last_err: Optional[Exception] = None
|
|
72
|
+
for path in _candidate_paths():
|
|
73
|
+
if not Path(path).exists():
|
|
74
|
+
continue
|
|
75
|
+
try:
|
|
76
|
+
lib = ctypes.CDLL(path)
|
|
77
|
+
fn = lib.ciris_verify_scope_privacy_derive
|
|
78
|
+
except (OSError, AttributeError) as exc:
|
|
79
|
+
last_err = exc
|
|
80
|
+
continue
|
|
81
|
+
fn.argtypes = [
|
|
82
|
+
ctypes.c_char_p, # input_json (UTF-8 bytes)
|
|
83
|
+
ctypes.c_size_t, # input_len
|
|
84
|
+
ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), # result_out
|
|
85
|
+
ctypes.POINTER(ctypes.c_size_t), # result_len_out
|
|
86
|
+
]
|
|
87
|
+
fn.restype = ctypes.c_int
|
|
88
|
+
lib.ciris_verify_free.argtypes = [ctypes.c_void_p]
|
|
89
|
+
lib.ciris_verify_free.restype = None
|
|
90
|
+
_lib = lib
|
|
91
|
+
return _lib
|
|
92
|
+
raise RuntimeError(
|
|
93
|
+
"ciris_verify_scope_privacy_derive not available — could not load "
|
|
94
|
+
f"the CIRISVerify shared library (last error: {last_err}). "
|
|
95
|
+
"The library must be built with the wheel (>= v7.4.0)."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _derive(req: dict) -> bytes:
|
|
100
|
+
input_bytes = _json.dumps(req).encode("utf-8")
|
|
101
|
+
lib = _load_lib()
|
|
102
|
+
out_ptr = ctypes.POINTER(ctypes.c_ubyte)()
|
|
103
|
+
out_len = ctypes.c_size_t(0)
|
|
104
|
+
rc = lib.ciris_verify_scope_privacy_derive(
|
|
105
|
+
input_bytes,
|
|
106
|
+
len(input_bytes),
|
|
107
|
+
ctypes.byref(out_ptr),
|
|
108
|
+
ctypes.byref(out_len),
|
|
109
|
+
)
|
|
110
|
+
if rc != _SUCCESS:
|
|
111
|
+
# rc 2 == SerializationError (bad request / wrong-length key / unknown type).
|
|
112
|
+
raise ValueError(
|
|
113
|
+
f"scope_privacy: invalid request — a 32-byte key has the wrong length, "
|
|
114
|
+
f"an unknown record_type, or non-encodable input (FFI code {rc})"
|
|
115
|
+
)
|
|
116
|
+
n = out_len.value
|
|
117
|
+
try:
|
|
118
|
+
result = ctypes.string_at(out_ptr, n)
|
|
119
|
+
finally:
|
|
120
|
+
if n != 0:
|
|
121
|
+
lib.ciris_verify_free(ctypes.cast(out_ptr, ctypes.c_void_p))
|
|
122
|
+
return result
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def k_record_id(exporter_secret: bytes) -> bytes:
|
|
126
|
+
"""§2.2 — derive ``K_record_id`` from the group's 32-byte MLS exporter secret."""
|
|
127
|
+
return _derive({"op": "k_record_id", "exporter_secret": list(exporter_secret)})
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def k_symbol(exporter_secret: bytes) -> bytes:
|
|
131
|
+
"""§2.2 — derive ``K_symbol`` from the group's 32-byte MLS exporter secret."""
|
|
132
|
+
return _derive({"op": "k_symbol", "exporter_secret": list(exporter_secret)})
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def derive_record_id(
|
|
136
|
+
k_record_id: bytes,
|
|
137
|
+
internal_id: bytes,
|
|
138
|
+
record_type: str,
|
|
139
|
+
mls_group_epoch: int,
|
|
140
|
+
) -> bytes:
|
|
141
|
+
"""§2.4 — ``record_id = HMAC-SHA3-256(K_record_id, CBOR_dCE({v,iid,typ,epc}))``.
|
|
142
|
+
|
|
143
|
+
``record_type`` is one of ``"self"``, ``"family"``, ``"community"``,
|
|
144
|
+
``"federation"`` (the pinned ``RecordType`` mapping). The CBOR preimage is
|
|
145
|
+
RFC 8949 §4.2.1 core-deterministic — encoded Rust-side, so this is
|
|
146
|
+
byte-identical to the verifier's ``record_id``.
|
|
147
|
+
"""
|
|
148
|
+
if record_type not in _RECORD_TYPES:
|
|
149
|
+
raise ValueError(f"record_type must be one of {_RECORD_TYPES}, got {record_type!r}")
|
|
150
|
+
return _derive(
|
|
151
|
+
{
|
|
152
|
+
"op": "record_id",
|
|
153
|
+
"k_record_id": list(k_record_id),
|
|
154
|
+
"internal_id": list(internal_id),
|
|
155
|
+
"record_type": record_type,
|
|
156
|
+
"mls_group_epoch": int(mls_group_epoch),
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def derive_symbol_key(k_symbol: bytes, record_id: bytes, symbol_index: int) -> bytes:
|
|
162
|
+
"""§2.4 — ``symbol_key = HKDF-SHA3-256(salt=record_id, ikm=K_symbol, info=label‖u16(idx))``."""
|
|
163
|
+
return _derive(
|
|
164
|
+
{
|
|
165
|
+
"op": "symbol_key",
|
|
166
|
+
"k_symbol": list(k_symbol),
|
|
167
|
+
"record_id": list(record_id),
|
|
168
|
+
"symbol_index": int(symbol_index),
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def witness_cover_leaf(
|
|
174
|
+
witness_signing_key: bytes,
|
|
175
|
+
leaf_position: int,
|
|
176
|
+
federation_epoch_id: int,
|
|
177
|
+
) -> bytes:
|
|
178
|
+
"""§3.4 — witness cover-leaf ``HMAC-SHA3-256(key, u32_be(pos) ‖ u64_be(epoch))``."""
|
|
179
|
+
return _derive(
|
|
180
|
+
{
|
|
181
|
+
"op": "witness_cover_leaf",
|
|
182
|
+
"witness_signing_key": list(witness_signing_key),
|
|
183
|
+
"leaf_position": int(leaf_position),
|
|
184
|
+
"federation_epoch_id": int(federation_epoch_id),
|
|
185
|
+
}
|
|
186
|
+
)
|
|
@@ -8,6 +8,8 @@ ciris_verify/_federation_identity.py
|
|
|
8
8
|
ciris_verify/_jcs.py
|
|
9
9
|
ciris_verify/_manifest_contribution.py
|
|
10
10
|
ciris_verify/_operational_admit.py
|
|
11
|
+
ciris_verify/_rns_dest_hash.py
|
|
12
|
+
ciris_verify/_scope_privacy.py
|
|
11
13
|
ciris_verify/_wheel_hybrid_kex.py
|
|
12
14
|
ciris_verify/_wheel_key_grant.py
|
|
13
15
|
ciris_verify/_wheel_locale_merkle.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|