hashrope 0.1.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.
@@ -0,0 +1,18 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ *.egg
8
+ .eggs/
9
+ .env
10
+ .env.local
11
+ *.key
12
+ *secrets*
13
+ venv/
14
+ .venv/
15
+ .pytest_cache/
16
+ .coverage
17
+ htmlcov/
18
+ *.so
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-04-07
4
+
5
+ ### Added
6
+ - Initial release extracted from UHC (Unified Hash-Compression Engine).
7
+ - PolynomialHash: Mersenne-prime polynomial hashing with O(log n) power caching.
8
+ - phi: Geometric accumulator via inverse-free repeated doubling in O(log q).
9
+ - Leaf, Internal, RepeatNode: Immutable hash rope nodes (Definition 6).
10
+ - BB[2/7] weight-balanced tree with single/double rotations (Definition 7).
11
+ - rope_concat: O(k * |h_L - h_R|) balanced concatenation (Theorem 10).
12
+ - rope_split: O(k * log w) split at arbitrary byte position (Theorem 7).
13
+ - rope_repeat: O(k * log q) repetition via RepeatNode (Theorem 8).
14
+ - rope_substr_hash: O(k * log w) allocation-free substring hashing (Theorem 9).
15
+ - SlidingWindow: Bounded-memory streaming hash with eviction (Theorem 11).
16
+ - validate_rope: Invariant checker for all nine rope invariants.
17
+ - rope_from_bytes, rope_to_bytes: Construction and reconstruction helpers.
hashrope-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Muntaser Syed
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,191 @@
1
+ Metadata-Version: 2.4
2
+ Name: hashrope
3
+ Version: 0.1.0
4
+ Summary: Hash rope: a BB[2/7] balanced binary tree with polynomial hash metadata for O(log n) concat, split, substring hashing, and O(log q) repetition encoding.
5
+ Project-URL: Homepage, https://github.com/jemsbhai/hashrope
6
+ Project-URL: Repository, https://github.com/jemsbhai/hashrope
7
+ Project-URL: Issues, https://github.com/jemsbhai/hashrope/issues
8
+ Author-email: Muntaser Syed <muntaser@ieee.org>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: balanced-tree,content-addressing,data-structure,hash,mersenne-prime,polynomial-hash,rope
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Classifier: Topic :: Software Development :: Libraries
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
27
+ Requires-Dist: pytest>=7.0; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # hashrope
31
+
32
+ A BB[2/7] weight-balanced binary tree augmented with polynomial hash metadata at every node.
33
+
34
+ [![PyPI version](https://img.shields.io/pypi/v/hashrope)](https://pypi.org/project/hashrope/)
35
+ [![Python 3.10+](https://img.shields.io/pypi/pyversions/hashrope)](https://pypi.org/project/hashrope/)
36
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
37
+ [![Tests](https://img.shields.io/badge/tests-88%20passing-brightgreen)](https://github.com/jemsbhai/hashrope)
38
+
39
+ **Zero dependencies. Pure Python. Python 3.10+.**
40
+
41
+ ## What it does
42
+
43
+ hashrope is a rope data structure where every node carries a polynomial hash. This enables:
44
+
45
+ - **O(k log w) concat and split** with strict BB[2/7] rebalancing via recursive join
46
+ - **O(k log q) repetition encoding** via RepeatNode -- represents "repeat this subtree q times" without materializing the data
47
+ - **O(k log w) substring hashing** without allocating new nodes
48
+ - **O(1) whole-sequence hash** at any point during streaming ingestion
49
+ - **Bounded-memory sliding window** that evicts old data while maintaining a running hash of everything seen
50
+
51
+ All arithmetic uses Mersenne prime modular reduction (bit-shift, no division).
52
+
53
+ ## Install
54
+
55
+ ```
56
+ pip install hashrope
57
+ ```
58
+
59
+ ## Quick start
60
+
61
+ ```python
62
+ from hashrope import PolynomialHash, Leaf, rope_concat, rope_split, rope_substr_hash, rope_hash
63
+
64
+ h = PolynomialHash()
65
+
66
+ # Build a rope
67
+ a = Leaf(b"hello ", h)
68
+ b = Leaf(b"world", h)
69
+ ab = rope_concat(a, b, h)
70
+
71
+ # Whole-string hash matches direct computation
72
+ assert rope_hash(ab) == h.hash(b"hello world")
73
+
74
+ # Split at any byte position
75
+ left, right = rope_split(ab, 6, h)
76
+
77
+ # Substring hash without allocation
78
+ sub_h = rope_substr_hash(ab, 0, 5, h)
79
+ assert sub_h == h.hash(b"hello")
80
+ ```
81
+
82
+ ### RepeatNode
83
+
84
+ Encode repetitions in O(log q) time and O(1) space:
85
+
86
+ ```python
87
+ from hashrope import PolynomialHash, Leaf, rope_repeat, rope_hash
88
+
89
+ h = PolynomialHash()
90
+ pattern = Leaf(b"ab", h)
91
+ repeated = rope_repeat(pattern, 1000, h) # "ab" x 1000
92
+
93
+ # Hash computed in O(log 1000), not O(2000)
94
+ assert rope_hash(repeated) == h.hash(b"ab" * 1000)
95
+ ```
96
+
97
+ ### SlidingWindow
98
+
99
+ Bounded-memory streaming hash with copy-from-window support:
100
+
101
+ ```python
102
+ from hashrope import PolynomialHash, SlidingWindow
103
+
104
+ h = PolynomialHash()
105
+ sw = SlidingWindow(d_max=1024, m_max=256)
106
+
107
+ # Stream data in
108
+ sw.append_bytes(b"hello ")
109
+ sw.append_bytes(b"world")
110
+
111
+ # Hash of everything seen so far
112
+ assert sw.current_hash() == h.hash(b"hello world")
113
+
114
+ # Copy-from-window (like LZ77 back-references)
115
+ sw.append_copy(offset=5, length=5) # copies "world" again
116
+ assert sw.final_hash() == h.hash(b"hello worldworld")
117
+ ```
118
+
119
+ ## API reference
120
+
121
+ ### Polynomial hash
122
+
123
+ | Function / Class | Description |
124
+ |---|---|
125
+ | `PolynomialHash(prime, base)` | Hash function over Z/pZ. Default: p = 2^61 - 1, base = 131 |
126
+ | `PolynomialHash.hash(data)` | H(data) with +1 byte offset to prevent zero collisions |
127
+ | `PolynomialHash.hash_concat(h_a, len_b, h_b)` | H(A \|\| B) from H(A), \|B\|, H(B) in O(1) |
128
+ | `PolynomialHash.hash_repeat(h_s, d, q)` | H(S^q) from H(S) and \|S\| in O(log q) |
129
+ | `PolynomialHash.hash_overlap(h_p, d, l, h_prefix)` | H(P^q \|\| P[0..r-1]) for overlapping references |
130
+ | `phi(q, alpha, p)` | Geometric accumulator: sum of alpha^i for i in [0, q) in O(log q) |
131
+ | `mersenne_mod(a, p)` | Bit-shift reduction mod Mersenne prime |
132
+ | `mersenne_mul(a, b, p)` | Modular multiply via mersenne_mod |
133
+ | `MERSENNE_61` | 2^61 - 1 (default prime) |
134
+ | `MERSENNE_127` | 2^127 - 1 (high-security prime) |
135
+
136
+ ### Rope nodes
137
+
138
+ | Class | Description |
139
+ |---|---|
140
+ | `Leaf(data, h)` | Immutable leaf storing a byte sequence. Weight = 1 |
141
+ | `Internal(left, right, h)` | Internal node. Hash = H(left) \* x^len(right) + H(right) |
142
+ | `RepeatNode(child, reps, h)` | Represents child^reps. Hash via geometric accumulator |
143
+
144
+ ### Rope operations
145
+
146
+ | Function | Time | Description |
147
+ |---|---|---|
148
+ | `rope_concat(left, right, h)` | O(k \|h_L - h_R\|) | Concatenate with recursive join and BB[2/7] rebalancing |
149
+ | `rope_split(node, pos, h)` | O(k log w) | Split at byte position |
150
+ | `rope_repeat(node, q, h)` | O(k log q) | Create RepeatNode |
151
+ | `rope_substr_hash(node, start, length, h)` | O(k log w) | Substring hash without allocation |
152
+ | `rope_len(node)` | O(1) | Total byte length |
153
+ | `rope_hash(node)` | O(1) | Hash of represented string |
154
+ | `rope_from_bytes(data, h)` | O(n) | Create Leaf from bytes |
155
+ | `rope_to_bytes(node)` | O(n) | Reconstruct bytes (for testing) |
156
+ | `validate_rope(node)` | O(w) | Assert all 9 invariants hold |
157
+
158
+ ### SlidingWindow
159
+
160
+ | Method | Description |
161
+ |---|---|
162
+ | `SlidingWindow(d_max, m_max, prime, base)` | Create window. W = d_max + m_max |
163
+ | `.append_bytes(data)` | Append literal bytes |
164
+ | `.append_copy(offset, length)` | Copy from window (handles overlapping) |
165
+ | `.current_hash()` | H(everything seen) in O(1) |
166
+ | `.final_hash()` | Same as current_hash (alias) |
167
+ | `.window_len` | Current window size in bytes |
168
+ | `.pos` | Total bytes ingested |
169
+
170
+ ## Mathematical foundation
171
+
172
+ The data structure and its correctness proofs come from the compressed-domain hashing framework (24 theorems, 14 lemmas, 5 corollaries). Key results used by hashrope:
173
+
174
+ | Result | Statement |
175
+ |---|---|
176
+ | Theorem 1 (Concatenation) | H(A \|\| B) = H(A) * x^{\|B\|} + H(B) |
177
+ | Theorem 2 (Repetition) | H(S^q) = H(S) * Phi(q, x^d) |
178
+ | Theorem 3 (Phi computation) | Phi(q, alpha) computable in O(log q) without modular inverse |
179
+ | Theorem 6 (Join) | Recursive join with BB[2/7] rebalancing |
180
+ | Theorem 7 (Split) | Split in O(k log w) with RepeatNode splittability |
181
+ | Theorem 8 (Repeat) | RepeatNode in O(k log q), O(1) space |
182
+ | Theorem 9 (SubstrHash) | Allocation-free substring hashing in O(k log w) |
183
+ | Theorem 11 (Sliding window) | Bounded-memory streaming with eviction |
184
+
185
+ ## Provenance
186
+
187
+ Extracted from [UHC](https://github.com/jemsbhai/uhc) (Unified Hash-Compression Engine). The rope and polynomial hash modules are verbatim copies with import paths updated. The sliding window is adapted from UHC's SlidingRopeState with the LZ77 dependency removed.
188
+
189
+ ## License
190
+
191
+ MIT
@@ -0,0 +1,162 @@
1
+ # hashrope
2
+
3
+ A BB[2/7] weight-balanced binary tree augmented with polynomial hash metadata at every node.
4
+
5
+ [![PyPI version](https://img.shields.io/pypi/v/hashrope)](https://pypi.org/project/hashrope/)
6
+ [![Python 3.10+](https://img.shields.io/pypi/pyversions/hashrope)](https://pypi.org/project/hashrope/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
8
+ [![Tests](https://img.shields.io/badge/tests-88%20passing-brightgreen)](https://github.com/jemsbhai/hashrope)
9
+
10
+ **Zero dependencies. Pure Python. Python 3.10+.**
11
+
12
+ ## What it does
13
+
14
+ hashrope is a rope data structure where every node carries a polynomial hash. This enables:
15
+
16
+ - **O(k log w) concat and split** with strict BB[2/7] rebalancing via recursive join
17
+ - **O(k log q) repetition encoding** via RepeatNode -- represents "repeat this subtree q times" without materializing the data
18
+ - **O(k log w) substring hashing** without allocating new nodes
19
+ - **O(1) whole-sequence hash** at any point during streaming ingestion
20
+ - **Bounded-memory sliding window** that evicts old data while maintaining a running hash of everything seen
21
+
22
+ All arithmetic uses Mersenne prime modular reduction (bit-shift, no division).
23
+
24
+ ## Install
25
+
26
+ ```
27
+ pip install hashrope
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ ```python
33
+ from hashrope import PolynomialHash, Leaf, rope_concat, rope_split, rope_substr_hash, rope_hash
34
+
35
+ h = PolynomialHash()
36
+
37
+ # Build a rope
38
+ a = Leaf(b"hello ", h)
39
+ b = Leaf(b"world", h)
40
+ ab = rope_concat(a, b, h)
41
+
42
+ # Whole-string hash matches direct computation
43
+ assert rope_hash(ab) == h.hash(b"hello world")
44
+
45
+ # Split at any byte position
46
+ left, right = rope_split(ab, 6, h)
47
+
48
+ # Substring hash without allocation
49
+ sub_h = rope_substr_hash(ab, 0, 5, h)
50
+ assert sub_h == h.hash(b"hello")
51
+ ```
52
+
53
+ ### RepeatNode
54
+
55
+ Encode repetitions in O(log q) time and O(1) space:
56
+
57
+ ```python
58
+ from hashrope import PolynomialHash, Leaf, rope_repeat, rope_hash
59
+
60
+ h = PolynomialHash()
61
+ pattern = Leaf(b"ab", h)
62
+ repeated = rope_repeat(pattern, 1000, h) # "ab" x 1000
63
+
64
+ # Hash computed in O(log 1000), not O(2000)
65
+ assert rope_hash(repeated) == h.hash(b"ab" * 1000)
66
+ ```
67
+
68
+ ### SlidingWindow
69
+
70
+ Bounded-memory streaming hash with copy-from-window support:
71
+
72
+ ```python
73
+ from hashrope import PolynomialHash, SlidingWindow
74
+
75
+ h = PolynomialHash()
76
+ sw = SlidingWindow(d_max=1024, m_max=256)
77
+
78
+ # Stream data in
79
+ sw.append_bytes(b"hello ")
80
+ sw.append_bytes(b"world")
81
+
82
+ # Hash of everything seen so far
83
+ assert sw.current_hash() == h.hash(b"hello world")
84
+
85
+ # Copy-from-window (like LZ77 back-references)
86
+ sw.append_copy(offset=5, length=5) # copies "world" again
87
+ assert sw.final_hash() == h.hash(b"hello worldworld")
88
+ ```
89
+
90
+ ## API reference
91
+
92
+ ### Polynomial hash
93
+
94
+ | Function / Class | Description |
95
+ |---|---|
96
+ | `PolynomialHash(prime, base)` | Hash function over Z/pZ. Default: p = 2^61 - 1, base = 131 |
97
+ | `PolynomialHash.hash(data)` | H(data) with +1 byte offset to prevent zero collisions |
98
+ | `PolynomialHash.hash_concat(h_a, len_b, h_b)` | H(A \|\| B) from H(A), \|B\|, H(B) in O(1) |
99
+ | `PolynomialHash.hash_repeat(h_s, d, q)` | H(S^q) from H(S) and \|S\| in O(log q) |
100
+ | `PolynomialHash.hash_overlap(h_p, d, l, h_prefix)` | H(P^q \|\| P[0..r-1]) for overlapping references |
101
+ | `phi(q, alpha, p)` | Geometric accumulator: sum of alpha^i for i in [0, q) in O(log q) |
102
+ | `mersenne_mod(a, p)` | Bit-shift reduction mod Mersenne prime |
103
+ | `mersenne_mul(a, b, p)` | Modular multiply via mersenne_mod |
104
+ | `MERSENNE_61` | 2^61 - 1 (default prime) |
105
+ | `MERSENNE_127` | 2^127 - 1 (high-security prime) |
106
+
107
+ ### Rope nodes
108
+
109
+ | Class | Description |
110
+ |---|---|
111
+ | `Leaf(data, h)` | Immutable leaf storing a byte sequence. Weight = 1 |
112
+ | `Internal(left, right, h)` | Internal node. Hash = H(left) \* x^len(right) + H(right) |
113
+ | `RepeatNode(child, reps, h)` | Represents child^reps. Hash via geometric accumulator |
114
+
115
+ ### Rope operations
116
+
117
+ | Function | Time | Description |
118
+ |---|---|---|
119
+ | `rope_concat(left, right, h)` | O(k \|h_L - h_R\|) | Concatenate with recursive join and BB[2/7] rebalancing |
120
+ | `rope_split(node, pos, h)` | O(k log w) | Split at byte position |
121
+ | `rope_repeat(node, q, h)` | O(k log q) | Create RepeatNode |
122
+ | `rope_substr_hash(node, start, length, h)` | O(k log w) | Substring hash without allocation |
123
+ | `rope_len(node)` | O(1) | Total byte length |
124
+ | `rope_hash(node)` | O(1) | Hash of represented string |
125
+ | `rope_from_bytes(data, h)` | O(n) | Create Leaf from bytes |
126
+ | `rope_to_bytes(node)` | O(n) | Reconstruct bytes (for testing) |
127
+ | `validate_rope(node)` | O(w) | Assert all 9 invariants hold |
128
+
129
+ ### SlidingWindow
130
+
131
+ | Method | Description |
132
+ |---|---|
133
+ | `SlidingWindow(d_max, m_max, prime, base)` | Create window. W = d_max + m_max |
134
+ | `.append_bytes(data)` | Append literal bytes |
135
+ | `.append_copy(offset, length)` | Copy from window (handles overlapping) |
136
+ | `.current_hash()` | H(everything seen) in O(1) |
137
+ | `.final_hash()` | Same as current_hash (alias) |
138
+ | `.window_len` | Current window size in bytes |
139
+ | `.pos` | Total bytes ingested |
140
+
141
+ ## Mathematical foundation
142
+
143
+ The data structure and its correctness proofs come from the compressed-domain hashing framework (24 theorems, 14 lemmas, 5 corollaries). Key results used by hashrope:
144
+
145
+ | Result | Statement |
146
+ |---|---|
147
+ | Theorem 1 (Concatenation) | H(A \|\| B) = H(A) * x^{\|B\|} + H(B) |
148
+ | Theorem 2 (Repetition) | H(S^q) = H(S) * Phi(q, x^d) |
149
+ | Theorem 3 (Phi computation) | Phi(q, alpha) computable in O(log q) without modular inverse |
150
+ | Theorem 6 (Join) | Recursive join with BB[2/7] rebalancing |
151
+ | Theorem 7 (Split) | Split in O(k log w) with RepeatNode splittability |
152
+ | Theorem 8 (Repeat) | RepeatNode in O(k log q), O(1) space |
153
+ | Theorem 9 (SubstrHash) | Allocation-free substring hashing in O(k log w) |
154
+ | Theorem 11 (Sliding window) | Bounded-memory streaming with eviction |
155
+
156
+ ## Provenance
157
+
158
+ Extracted from [UHC](https://github.com/jemsbhai/uhc) (Unified Hash-Compression Engine). The rope and polynomial hash modules are verbatim copies with import paths updated. The sliding window is adapted from UHC's SlidingRopeState with the LZ77 dependency removed.
159
+
160
+ ## License
161
+
162
+ MIT
@@ -0,0 +1,64 @@
1
+ """
2
+ hashrope -- Hash rope data structure with algebraic content addressing.
3
+
4
+ A balanced binary tree (BB[2/7]) augmented with polynomial hash metadata
5
+ at every node. Supports O(log w) concat, split, and substring hashing,
6
+ plus O(log q) repetition encoding via RepeatNode and geometric accumulator.
7
+
8
+ All arithmetic is performed modulo a Mersenne prime using bit-shift
9
+ reduction (no expensive division).
10
+ """
11
+
12
+ __version__ = "0.1.0"
13
+
14
+ from hashrope.polynomial_hash import (
15
+ PolynomialHash,
16
+ phi,
17
+ mersenne_mod,
18
+ mersenne_mul,
19
+ MERSENNE_61,
20
+ MERSENNE_127,
21
+ )
22
+ from hashrope.rope import (
23
+ Leaf,
24
+ Internal,
25
+ RepeatNode,
26
+ Node,
27
+ rope_concat,
28
+ rope_split,
29
+ rope_repeat,
30
+ rope_substr_hash,
31
+ rope_len,
32
+ rope_hash,
33
+ rope_from_bytes,
34
+ rope_to_bytes,
35
+ validate_rope,
36
+ )
37
+ from hashrope.sliding import SlidingWindow
38
+
39
+ __all__ = [
40
+ # Polynomial hash
41
+ "PolynomialHash",
42
+ "phi",
43
+ "mersenne_mod",
44
+ "mersenne_mul",
45
+ "MERSENNE_61",
46
+ "MERSENNE_127",
47
+ # Rope nodes
48
+ "Leaf",
49
+ "Internal",
50
+ "RepeatNode",
51
+ "Node",
52
+ # Rope operations
53
+ "rope_concat",
54
+ "rope_split",
55
+ "rope_repeat",
56
+ "rope_substr_hash",
57
+ "rope_len",
58
+ "rope_hash",
59
+ "rope_from_bytes",
60
+ "rope_to_bytes",
61
+ "validate_rope",
62
+ # Sliding window
63
+ "SlidingWindow",
64
+ ]