@hivemind-os/collective-core 0.2.0
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.
- package/.test-data/05a845c4-1682-41b9-97e5-65a5263156c0/spending.sqlite +0 -0
- package/.test-data/10e18ba5-98f0-42e0-8899-06a09459ae85/agents.sqlite +0 -0
- package/.test-data/20464456-23cb-4ff7-8df5-3c129fb95a90/agents.sqlite +0 -0
- package/.test-data/2e2ec66c-e8b4-43eb-945f-cca84ed0a0f6/agents.sqlite +0 -0
- package/.test-data/2f5ef9b7-01da-4ba0-a6fa-af8063a2567c/agents.sqlite +0 -0
- package/.test-data/3ac13cd5-84c9-4e71-8b89-6d3ef4dd819c/agents.sqlite +0 -0
- package/.test-data/40b7dd4a-fae0-4a5d-a6a0-64c9048af35e/agents.sqlite +0 -0
- package/.test-data/59511a04-42f8-4286-bb1e-733795e08749/agents.sqlite +0 -0
- package/.test-data/6778e8c5-6eb5-416d-8aca-9d559cdf83e4/agents.sqlite +0 -0
- package/.test-data/7648dc86-df90-4460-8f9c-55cdb481324b/agents.sqlite +0 -0
- package/.test-data/77162d98-6b22-41b1-a50f-536fab739f8a/agents.sqlite +0 -0
- package/.test-data/798dbdab-cbe7-4edd-8a5b-ae99c285fe17/agents.sqlite +0 -0
- package/.test-data/8033d6ac-8b85-454d-b708-00ac695b22f8/agents.sqlite +0 -0
- package/.test-data/9155a4f4-cda3-487c-9eed-921c82d7550f/agents.sqlite +0 -0
- package/.test-data/9bfeee53-c231-46c3-8c93-2180933f5d50/agents.sqlite +0 -0
- package/.test-data/a4c64287-79f6-46e9-847d-2803c63a74fd/agents.sqlite +0 -0
- package/.test-data/b8f58952-1ed8-46ff-abd7-21fb86e9457f/agents.sqlite +0 -0
- package/.test-data/c3060504-3187-41ed-8532-82332be48b0b/spending.sqlite +0 -0
- package/.test-data/cc471629-8006-4fc1-b8a1-399d2df2cc4e/agents.sqlite +0 -0
- package/.test-data/dbca3bef-397d-4bbc-bd4c-4f7b14103e04/spending.sqlite +0 -0
- package/.test-data/f1283dd1-6602-4de7-a050-16aac7abc288/agents.sqlite +0 -0
- package/.turbo/turbo-build.log +14 -0
- package/dist/index.d.ts +1675 -0
- package/dist/index.js +8006 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
- package/src/auth/device-flow.ts +108 -0
- package/src/auth/ed25519-provider.ts +43 -0
- package/src/auth/errors.ts +82 -0
- package/src/auth/evm-key.ts +55 -0
- package/src/auth/index.ts +8 -0
- package/src/auth/session-state.ts +25 -0
- package/src/auth/session-store.ts +510 -0
- package/src/auth/types.ts +81 -0
- package/src/auth/zklogin-provider.ts +902 -0
- package/src/blobstore/WALRUS_FINDINGS.md +284 -0
- package/src/blobstore/encrypted-store.ts +56 -0
- package/src/blobstore/fs-store.ts +91 -0
- package/src/blobstore/hybrid-store.ts +144 -0
- package/src/blobstore/index.ts +5 -0
- package/src/blobstore/interface.ts +33 -0
- package/src/blobstore/walrus-spike.ts +345 -0
- package/src/blobstore/walrus-store.ts +551 -0
- package/src/cache/agent-cache.ts +403 -0
- package/src/cache/index.ts +1 -0
- package/src/crypto/encryption.ts +152 -0
- package/src/crypto/index.ts +2 -0
- package/src/crypto/x25519.ts +41 -0
- package/src/dispute/client.ts +191 -0
- package/src/dispute/index.ts +1 -0
- package/src/events/index.ts +2 -0
- package/src/events/parser.ts +291 -0
- package/src/events/subscription.ts +131 -0
- package/src/evm/constants.ts +6 -0
- package/src/evm/index.ts +2 -0
- package/src/evm/wallet.ts +136 -0
- package/src/identity/did.ts +36 -0
- package/src/identity/index.ts +4 -0
- package/src/identity/keypair.ts +199 -0
- package/src/identity/signing.ts +28 -0
- package/src/index.ts +22 -0
- package/src/internal/parsing.ts +416 -0
- package/src/marketplace/client.ts +349 -0
- package/src/marketplace/index.ts +1 -0
- package/src/metering/hash-chain.ts +94 -0
- package/src/metering/index.ts +4 -0
- package/src/metering/meter.ts +80 -0
- package/src/metering/streaming.ts +196 -0
- package/src/metering/verification.ts +104 -0
- package/src/payment/index.ts +1 -0
- package/src/payment/rail-selector.ts +41 -0
- package/src/registry/client.ts +328 -0
- package/src/registry/index.ts +1 -0
- package/src/relay/consumer-client.ts +497 -0
- package/src/relay/index.ts +1 -0
- package/src/relay-registry/client.ts +295 -0
- package/src/relay-registry/discovery.ts +109 -0
- package/src/relay-registry/index.ts +2 -0
- package/src/reputation/anchor-client.ts +126 -0
- package/src/reputation/event-publisher.ts +67 -0
- package/src/reputation/index.ts +5 -0
- package/src/reputation/merkle.ts +79 -0
- package/src/reputation/score-calculator.ts +133 -0
- package/src/reputation/serialization.ts +37 -0
- package/src/reputation/store.ts +165 -0
- package/src/reputation/validation.ts +135 -0
- package/src/routing/circuit-breaker.ts +111 -0
- package/src/routing/fan-out.ts +266 -0
- package/src/routing/index.ts +4 -0
- package/src/routing/performance.ts +244 -0
- package/src/routing/selector.ts +225 -0
- package/src/spending/index.ts +1 -0
- package/src/spending/policy.ts +271 -0
- package/src/staking/client.ts +319 -0
- package/src/staking/index.ts +1 -0
- package/src/sui/client.ts +214 -0
- package/src/sui/index.ts +2 -0
- package/src/sui/tx-helpers.ts +1070 -0
- package/src/task/client.ts +215 -0
- package/src/task/index.ts +1 -0
- package/src/x402/client.ts +295 -0
- package/src/x402/index.ts +1 -0
- package/tests/auth/device-flow.test.ts +62 -0
- package/tests/auth/ed25519-provider.test.ts +24 -0
- package/tests/auth/evm-key.test.ts +31 -0
- package/tests/auth/session-store.test.ts +201 -0
- package/tests/auth/zklogin-provider.test.ts +366 -0
- package/tests/blobstore/encrypted-store.test.ts +78 -0
- package/tests/blobstore.test.ts +91 -0
- package/tests/cache.test.ts +124 -0
- package/tests/crypto/encryption.test.ts +70 -0
- package/tests/crypto/x25519.test.ts +47 -0
- package/tests/dispute/client.test.ts +238 -0
- package/tests/events.test.ts +202 -0
- package/tests/evm/wallet.test.ts +101 -0
- package/tests/hybrid-store.test.ts +121 -0
- package/tests/identity.test.ts +161 -0
- package/tests/marketplace.test.ts +308 -0
- package/tests/metering/hash-chain.test.ts +32 -0
- package/tests/metering/meter.test.ts +23 -0
- package/tests/metering/streaming.test.ts +52 -0
- package/tests/metering/verification.test.ts +27 -0
- package/tests/payment/rail-selector.test.ts +95 -0
- package/tests/registry.test.ts +183 -0
- package/tests/relay-consumer-client.test.ts +119 -0
- package/tests/relay-registry/client.test.ts +261 -0
- package/tests/reputation/event-publisher.test.ts +70 -0
- package/tests/reputation/merkle.test.ts +44 -0
- package/tests/reputation/score-calculator.test.ts +104 -0
- package/tests/reputation/store.test.ts +94 -0
- package/tests/routing/circuit-breaker.test.ts +45 -0
- package/tests/routing/fan-out.test.ts +123 -0
- package/tests/routing/performance.test.ts +49 -0
- package/tests/routing/selector.test.ts +114 -0
- package/tests/spending.test.ts +133 -0
- package/tests/staking/client.test.ts +286 -0
- package/tests/sui-client.test.ts +85 -0
- package/tests/task.test.ts +249 -0
- package/tests/tx-helpers.test.ts +70 -0
- package/tests/walrus-spike.test.ts +100 -0
- package/tests/walrus-store.test.ts +196 -0
- package/tests/x402/client.test.ts +116 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +11 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { Chain, PublicClient, WalletClient } from 'viem';
|
|
2
|
+
import { createPublicClient, createWalletClient, defineChain, getAddress, http, toHex } from 'viem';
|
|
3
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
4
|
+
import { base, baseSepolia } from 'viem/chains';
|
|
5
|
+
|
|
6
|
+
const LOCALHOST_RPC_URL = 'http://127.0.0.1:8545';
|
|
7
|
+
const erc20BalanceOfAbi = [
|
|
8
|
+
{
|
|
9
|
+
type: 'function',
|
|
10
|
+
name: 'balanceOf',
|
|
11
|
+
stateMutability: 'view',
|
|
12
|
+
inputs: [{ name: 'account', type: 'address' }],
|
|
13
|
+
outputs: [{ name: 'balance', type: 'uint256' }],
|
|
14
|
+
},
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
export interface EvmWalletConfig {
|
|
18
|
+
network: 'base' | 'base-sepolia' | 'localhost';
|
|
19
|
+
rpcUrl?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class EvmWallet {
|
|
23
|
+
private readonly account;
|
|
24
|
+
private readonly chainConfig: Chain;
|
|
25
|
+
private readonly walletClient: WalletClient;
|
|
26
|
+
private readonly publicClient: PublicClient;
|
|
27
|
+
|
|
28
|
+
constructor(privateKey: Uint8Array, private readonly config: EvmWalletConfig) {
|
|
29
|
+
if (privateKey.byteLength !== 32) {
|
|
30
|
+
throw new Error('EVM private key must be 32 bytes.');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.account = privateKeyToAccount(toHex(privateKey));
|
|
34
|
+
this.chainConfig = resolveChain(config);
|
|
35
|
+
|
|
36
|
+
const transport = http(resolveRpcUrl(config));
|
|
37
|
+
this.walletClient = createWalletClient({
|
|
38
|
+
account: this.account,
|
|
39
|
+
chain: this.chainConfig,
|
|
40
|
+
transport,
|
|
41
|
+
});
|
|
42
|
+
this.publicClient = createPublicClient({
|
|
43
|
+
chain: this.chainConfig,
|
|
44
|
+
transport,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get address(): string {
|
|
49
|
+
return this.account.address;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get chain(): Chain {
|
|
53
|
+
return this.chainConfig;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async getBalance(): Promise<bigint> {
|
|
57
|
+
return this.publicClient.getBalance({ address: this.account.address });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async getTokenBalance(tokenAddress: string): Promise<bigint> {
|
|
61
|
+
return (await this.publicClient.readContract({
|
|
62
|
+
address: getAddress(tokenAddress),
|
|
63
|
+
abi: erc20BalanceOfAbi,
|
|
64
|
+
functionName: 'balanceOf',
|
|
65
|
+
args: [this.account.address],
|
|
66
|
+
})) as bigint;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async signMessage(message: string | Uint8Array): Promise<string> {
|
|
70
|
+
return this.walletClient.signMessage({
|
|
71
|
+
account: this.account,
|
|
72
|
+
message: typeof message === 'string' ? message : { raw: toHex(message) },
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async signTypedData(typedData: Omit<Parameters<WalletClient['signTypedData']>[0], 'account'>): Promise<string> {
|
|
77
|
+
return this.walletClient.signTypedData({
|
|
78
|
+
...typedData,
|
|
79
|
+
account: this.account,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async sendTransaction(to: string, value: bigint): Promise<string> {
|
|
84
|
+
return this.walletClient.sendTransaction({
|
|
85
|
+
account: this.account,
|
|
86
|
+
chain: this.chainConfig,
|
|
87
|
+
to: getAddress(to),
|
|
88
|
+
value,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
getWalletClient(): WalletClient {
|
|
93
|
+
return this.walletClient;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getPublicClient(): PublicClient {
|
|
97
|
+
return this.publicClient;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function resolveChain(config: EvmWalletConfig): Chain {
|
|
102
|
+
switch (config.network) {
|
|
103
|
+
case 'base':
|
|
104
|
+
return base;
|
|
105
|
+
case 'base-sepolia':
|
|
106
|
+
return baseSepolia;
|
|
107
|
+
case 'localhost':
|
|
108
|
+
return defineChain({
|
|
109
|
+
id: 31_337,
|
|
110
|
+
name: 'Localhost',
|
|
111
|
+
nativeCurrency: {
|
|
112
|
+
name: 'Ether',
|
|
113
|
+
symbol: 'ETH',
|
|
114
|
+
decimals: 18,
|
|
115
|
+
},
|
|
116
|
+
rpcUrls: {
|
|
117
|
+
default: {
|
|
118
|
+
http: [config.rpcUrl ?? LOCALHOST_RPC_URL],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
testnet: true,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function resolveRpcUrl(config: EvmWalletConfig): string | undefined {
|
|
127
|
+
if (config.rpcUrl) {
|
|
128
|
+
return config.rpcUrl;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (config.network === 'localhost') {
|
|
132
|
+
return LOCALHOST_RPC_URL;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import bs58 from 'bs58';
|
|
2
|
+
|
|
3
|
+
import type { DID } from '@hivemind-os/collective-types';
|
|
4
|
+
|
|
5
|
+
const DID_PREFIX = 'did:mesh:';
|
|
6
|
+
|
|
7
|
+
export function createDID(publicKey: Uint8Array): DID {
|
|
8
|
+
return `${DID_PREFIX}${bs58.encode(publicKey)}` as DID;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function parseDID(did: string): { publicKey: Uint8Array } {
|
|
12
|
+
if (!did.startsWith(DID_PREFIX)) {
|
|
13
|
+
throw new Error(`Invalid DID prefix: ${did}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const encodedKey = did.slice(DID_PREFIX.length);
|
|
17
|
+
if (!encodedKey) {
|
|
18
|
+
throw new Error('DID is missing a public key component.');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const publicKey = bs58.decode(encodedKey);
|
|
22
|
+
if (publicKey.length !== 32) {
|
|
23
|
+
throw new Error('DID public key must decode to 32 bytes.');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return { publicKey };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function isValidDID(did: string): boolean {
|
|
30
|
+
try {
|
|
31
|
+
parseDID(did);
|
|
32
|
+
return true;
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { etc, getPublicKey, utils } from '@noble/ed25519';
|
|
5
|
+
import { sha512 } from '@noble/hashes/sha512';
|
|
6
|
+
import pino from 'pino';
|
|
7
|
+
|
|
8
|
+
const logger = pino({ name: '@hivemind-os/collective-core:identity' });
|
|
9
|
+
const IDENTITY_KEY_FILENAME = 'identity.key';
|
|
10
|
+
const KEYCHAIN_SERVICE = 'hivemind-collective';
|
|
11
|
+
const KEYCHAIN_ACCOUNT = 'identity-key';
|
|
12
|
+
|
|
13
|
+
interface KeytarModule {
|
|
14
|
+
getPassword(service: string, account: string): Promise<string | null>;
|
|
15
|
+
setPassword(service: string, account: string, password: string): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let keytarModulePromise: Promise<KeytarModule | null> | undefined;
|
|
19
|
+
let hasLoggedKeychainFallback = false;
|
|
20
|
+
|
|
21
|
+
function configureEd25519(): void {
|
|
22
|
+
if (!etc.sha512Sync) {
|
|
23
|
+
etc.sha512Sync = (...messages) => sha512(etc.concatBytes(...messages));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function enforcePrivateFilePermissions(path: string): void {
|
|
28
|
+
chmodSync(path, 0o600);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getIdentityKeyPath(dataDir: string): string {
|
|
32
|
+
return join(dataDir, IDENTITY_KEY_FILENAME);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function logKeychainFallback(error: unknown): void {
|
|
36
|
+
if (!hasLoggedKeychainFallback) {
|
|
37
|
+
logger.warn({ err: error }, 'OS keychain unavailable; falling back to file-based identity storage.');
|
|
38
|
+
hasLoggedKeychainFallback = true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function importKeytar(): Promise<KeytarModule | null> {
|
|
43
|
+
try {
|
|
44
|
+
const imported = await import('keytar');
|
|
45
|
+
const keytar = ('default' in imported && imported.default ? imported.default : imported) as Partial<KeytarModule>;
|
|
46
|
+
if (typeof keytar.getPassword !== 'function' || typeof keytar.setPassword !== 'function') {
|
|
47
|
+
throw new Error('keytar module is missing required methods.');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
getPassword: keytar.getPassword.bind(keytar),
|
|
52
|
+
setPassword: keytar.setPassword.bind(keytar),
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
logKeychainFallback(error);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function getKeytarModule(): Promise<KeytarModule | null> {
|
|
61
|
+
keytarModulePromise ??= importKeytar();
|
|
62
|
+
return await keytarModulePromise;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function loadOrCreateStoredKeypair(store: KeyStore): Promise<SimpleKeypair> {
|
|
66
|
+
if (await store.exists()) {
|
|
67
|
+
return keypairFromSecretKey(await store.load());
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const keypair = generateKeypair();
|
|
71
|
+
await store.save(keypair.secretKey);
|
|
72
|
+
return keypair;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface SimpleKeypair {
|
|
76
|
+
publicKey: Uint8Array;
|
|
77
|
+
secretKey: Uint8Array;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface KeyStore {
|
|
81
|
+
load(): Promise<Uint8Array>;
|
|
82
|
+
save(secretKey: Uint8Array): Promise<void>;
|
|
83
|
+
exists(): Promise<boolean>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class FileKeyStore implements KeyStore {
|
|
87
|
+
constructor(private readonly keyPath: string) {}
|
|
88
|
+
|
|
89
|
+
async load(): Promise<Uint8Array> {
|
|
90
|
+
enforcePrivateFilePermissions(this.keyPath);
|
|
91
|
+
return etc.hexToBytes(readFileSync(this.keyPath, 'utf8').trim());
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async save(secretKey: Uint8Array): Promise<void> {
|
|
95
|
+
writeFileSync(this.keyPath, etc.bytesToHex(secretKey), { mode: 0o600 });
|
|
96
|
+
enforcePrivateFilePermissions(this.keyPath);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async exists(): Promise<boolean> {
|
|
100
|
+
return existsSync(this.keyPath);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
delete(): void {
|
|
104
|
+
unlinkSync(this.keyPath);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export class KeychainStore implements KeyStore {
|
|
109
|
+
constructor(
|
|
110
|
+
private readonly keytar: KeytarModule,
|
|
111
|
+
private readonly service = KEYCHAIN_SERVICE,
|
|
112
|
+
private readonly account = KEYCHAIN_ACCOUNT,
|
|
113
|
+
) {}
|
|
114
|
+
|
|
115
|
+
async load(): Promise<Uint8Array> {
|
|
116
|
+
const secretKey = await this.keytar.getPassword(this.service, this.account);
|
|
117
|
+
if (!secretKey) {
|
|
118
|
+
throw new Error('Identity key not found in OS keychain.');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return etc.hexToBytes(secretKey);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async save(secretKey: Uint8Array): Promise<void> {
|
|
125
|
+
await this.keytar.setPassword(this.service, this.account, etc.bytesToHex(secretKey));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async exists(): Promise<boolean> {
|
|
129
|
+
return (await this.keytar.getPassword(this.service, this.account)) !== null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function generateKeypair(): SimpleKeypair {
|
|
134
|
+
configureEd25519();
|
|
135
|
+
const secretKey = utils.randomPrivateKey();
|
|
136
|
+
const publicKey = getPublicKey(secretKey);
|
|
137
|
+
|
|
138
|
+
return { publicKey, secretKey };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function keypairFromSecretKey(secretKey: Uint8Array): SimpleKeypair {
|
|
142
|
+
configureEd25519();
|
|
143
|
+
const normalizedSecretKey = new Uint8Array(secretKey);
|
|
144
|
+
const publicKey = getPublicKey(normalizedSecretKey);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
publicKey,
|
|
148
|
+
secretKey: normalizedSecretKey,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function createKeyStore(dataDir: string): Promise<KeyStore> {
|
|
153
|
+
const keytar = await getKeytarModule();
|
|
154
|
+
return keytar ? new KeychainStore(keytar) : new FileKeyStore(getIdentityKeyPath(dataDir));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function identityKeyExists(dataDir: string): Promise<boolean> {
|
|
158
|
+
const fileStore = new FileKeyStore(getIdentityKeyPath(dataDir));
|
|
159
|
+
if (await fileStore.exists()) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const keyStore = await createKeyStore(dataDir);
|
|
164
|
+
if (keyStore instanceof KeychainStore) {
|
|
165
|
+
try {
|
|
166
|
+
return await keyStore.exists();
|
|
167
|
+
} catch (error) {
|
|
168
|
+
logKeychainFallback(error);
|
|
169
|
+
return await fileStore.exists();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return await keyStore.exists();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function loadOrCreateKeypair(dataDir: string): Promise<SimpleKeypair> {
|
|
177
|
+
configureEd25519();
|
|
178
|
+
mkdirSync(dataDir, { recursive: true, mode: 0o700 });
|
|
179
|
+
|
|
180
|
+
const fileStore = new FileKeyStore(getIdentityKeyPath(dataDir));
|
|
181
|
+
const keyStore = await createKeyStore(dataDir);
|
|
182
|
+
|
|
183
|
+
if (keyStore instanceof KeychainStore) {
|
|
184
|
+
try {
|
|
185
|
+
if (await fileStore.exists()) {
|
|
186
|
+
const secretKey = await fileStore.load();
|
|
187
|
+
await keyStore.save(secretKey);
|
|
188
|
+
fileStore.delete();
|
|
189
|
+
return keypairFromSecretKey(secretKey);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return await loadOrCreateStoredKeypair(keyStore);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
logKeychainFallback(error);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return await loadOrCreateStoredKeypair(fileStore);
|
|
199
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { etc, sign as nobleSign, verify as nobleVerify } from '@noble/ed25519';
|
|
2
|
+
import { sha512 } from '@noble/hashes/sha512';
|
|
3
|
+
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
|
|
6
|
+
function configureEd25519(): void {
|
|
7
|
+
if (!etc.sha512Sync) {
|
|
8
|
+
etc.sha512Sync = (...messages) => sha512(etc.concatBytes(...messages));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function sign(message: Uint8Array, secretKey: Uint8Array): Uint8Array {
|
|
13
|
+
configureEd25519();
|
|
14
|
+
return nobleSign(message, secretKey);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function verify(
|
|
18
|
+
message: Uint8Array,
|
|
19
|
+
signature: Uint8Array,
|
|
20
|
+
publicKey: Uint8Array,
|
|
21
|
+
): boolean {
|
|
22
|
+
configureEd25519();
|
|
23
|
+
return nobleVerify(signature, message, publicKey);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function signString(message: string, secretKey: Uint8Array): string {
|
|
27
|
+
return etc.bytesToHex(sign(encoder.encode(message), secretKey));
|
|
28
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export * from '@hivemind-os/collective-types';
|
|
2
|
+
export * from './identity/index.js';
|
|
3
|
+
export * from './crypto/index.js';
|
|
4
|
+
export * from './auth/index.js';
|
|
5
|
+
export * from './sui/index.js';
|
|
6
|
+
export * from './registry/index.js';
|
|
7
|
+
export * from './task/index.js';
|
|
8
|
+
export * from './marketplace/index.js';
|
|
9
|
+
export * from './dispute/index.js';
|
|
10
|
+
export * from './events/index.js';
|
|
11
|
+
export * from './cache/index.js';
|
|
12
|
+
export * from './blobstore/index.js';
|
|
13
|
+
export * from './evm/index.js';
|
|
14
|
+
export * from './payment/index.js';
|
|
15
|
+
export * from './relay/index.js';
|
|
16
|
+
export * from './relay-registry/index.js';
|
|
17
|
+
export * from './spending/index.js';
|
|
18
|
+
export * from './x402/index.js';
|
|
19
|
+
export * from './reputation/index.js';
|
|
20
|
+
export * from './staking/index.js';
|
|
21
|
+
export * from './metering/index.js';
|
|
22
|
+
export * from './routing/index.js';
|