Skip to content

Commit 09ed115

Browse files
author
MesTTo
committed
feat(das-client): atom-handle hashing ported from hyperon_das/hasher.py with MD5 parity vectors
1 parent e83adfc commit 09ed115

4 files changed

Lines changed: 74 additions & 2 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { describe, it, expect } from "vitest";
2+
import { namedTypeHash, terminalHash, compositeHash, expressionHash } from "./handle";
3+
4+
// Parity vectors: MD5 of the exact strings the Python reference (`hyperon_das/hasher.py`) hashes,
5+
// computed independently via `md5sum`. Matching these guarantees handle parity with the Python/Rust
6+
// DAS clients (a wrong handle makes every query miss).
7+
describe("DAS atom-handle hashing (parity with hyperon_das/hasher.py)", () => {
8+
it("named_type_hash", () => {
9+
expect(namedTypeHash("Concept")).toBe("d99a604c79ce3c2e76a2f43488d5d4c3");
10+
});
11+
it("terminal_hash joins type and name with a space", () => {
12+
expect(terminalHash("Concept", "human")).toBe("af12f10f9ae2002a1607ba0b47ba8407");
13+
});
14+
it("composite_hash joins element handles with a space", () => {
15+
expect(compositeHash(["a", "b", "c"])).toBe("06f0760ec7f18687a7fbc0ddbf1b1722");
16+
});
17+
it("expression_hash = composite of [typeHash, ...elements]", () => {
18+
// expression_hash("a", ["b","c"]) === composite_hash(["a","b","c"])
19+
expect(expressionHash("a", ["b", "c"])).toBe(compositeHash(["a", "b", "c"]));
20+
});
21+
});

packages/das-client/src/handle.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// DAS atom-handle hashing, a faithful port of the Python reference `hyperon_das/hasher.py`.
2+
// Handles are deterministic MD5 hashes of joined strings; getting these byte-identical to the
3+
// Python/Rust clients is the prerequisite for every query (a wrong handle means every match misses).
4+
// Node-only (uses node:crypto), like the rest of the bus client.
5+
import { createHash } from "node:crypto";
6+
7+
const JOINING_CHAR = " ";
8+
const MAX_LITERAL_OR_SYMBOL_SIZE = 10000;
9+
const MAX_HASHABLE_STRING_SIZE = 100000;
10+
11+
export function computeHash(input: string): string {
12+
return createHash("md5").update(input, "utf8").digest("hex");
13+
}
14+
15+
/** Hash of a named type (`named_type_hash`). */
16+
export function namedTypeHash(name: string): string {
17+
return computeHash(name);
18+
}
19+
20+
/** Hash of a terminal node `(type, name)` (`terminal_hash`). */
21+
export function terminalHash(type: string, name: string): string {
22+
if (type.length + name.length >= MAX_HASHABLE_STRING_SIZE)
23+
throw new Error("Invalid (too large) terminal name");
24+
return computeHash(`${type}${JOINING_CHAR}${name}`);
25+
}
26+
27+
/** Hash of a composite of element handles (`composite_hash`). */
28+
export function compositeHash(elements: readonly string[]): string {
29+
let total = 0;
30+
for (const e of elements) {
31+
if (e.length > MAX_LITERAL_OR_SYMBOL_SIZE)
32+
throw new Error("Invalid (too large) composite elements");
33+
total += e.length;
34+
}
35+
if (total >= MAX_HASHABLE_STRING_SIZE) throw new Error("Invalid (too large) composite elements");
36+
return computeHash(elements.join(JOINING_CHAR));
37+
}
38+
39+
/** Hash of an expression: the type hash followed by the element handles (`expression_hash`). */
40+
export function expressionHash(typeHash: string, elements: readonly string[]): string {
41+
return compositeHash([typeHash, ...elements]);
42+
}

packages/das-client/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212
// @metta-ts/das-gateway). See README.
1313
export { type DasTransport, MockTransport } from "./transport";
1414
export { DasSpace } from "./das-space";
15+
export { computeHash, namedTypeHash, terminalHash, compositeHash, expressionHash } from "./handle";

packages/das-client/tsconfig.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
{
22
"extends": "../../tsconfig.base.json",
3-
"include": ["src"],
4-
"compilerOptions": { "outDir": "dist", "rootDir": "src" }
3+
"include": [
4+
"src"
5+
],
6+
"compilerOptions": {
7+
"outDir": "dist",
8+
"rootDir": "src",
9+
"types": [
10+
"node"
11+
]
12+
}
513
}

0 commit comments

Comments
 (0)