@heyanon-arp/sdk 0.0.36 → 0.0.38

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.
@@ -1,9 +1,9 @@
1
- import type { KeyLinkPayload, ScryptPasswordAttestation } from '../types/identity';
1
+ import type { Ed25519KeyLinkAttestation, KeyLinkPayload } from '../types/identity';
2
2
  /**
3
- * Build an `ARP-KEY-LINK-v1` attestation record signed via
4
- * `scrypt_password_proof`. Caller assembles the payload
5
- * (DID, both pubkeys, nonce, etc.); SDK produces the MAC
6
- * and wraps the record in the standard shape.
3
+ * Build an `ARP-KEY-LINK-v1` attestation signed via `ed25519_owner_key`:
4
+ * the agent's IDENTITY key signs `canonicalBytes(payload)`. The identity
5
+ * key is already proven at registration (the ARP-CHALLENGE-v1 step), so
6
+ * the key-link is self-certified with NO owner password / shared secret.
7
7
  *
8
8
  * Identity keys are immutable in alpha (no rotation); the KEY-LINK
9
9
  * attestation is the single owner-signed link between identity and
@@ -11,7 +11,13 @@ import type { KeyLinkPayload, ScryptPasswordAttestation } from '../types/identit
11
11
  */
12
12
  export declare function signKeyLinkAttestation(input: {
13
13
  payload: KeyLinkPayload;
14
- scryptKey: Uint8Array;
15
- scryptSaltId: string;
16
- }): ScryptPasswordAttestation<KeyLinkPayload>;
17
- export declare function verifyKeyLinkAttestation(attestation: ScryptPasswordAttestation<KeyLinkPayload>, scryptKey: Uint8Array): boolean;
14
+ identitySecretKey: Uint8Array;
15
+ }): Ed25519KeyLinkAttestation<KeyLinkPayload>;
16
+ /**
17
+ * Verify a key-link attestation against the identity key EMBEDDED in its
18
+ * payload (`payload.identity_public_key`). The caller is responsible for
19
+ * cross-checking that key against the agent DID / request body — this
20
+ * function only proves the payload was signed by the identity key it
21
+ * names. Returns false on any malformed input (no throw).
22
+ */
23
+ export declare function verifyKeyLinkAttestation(attestation: Ed25519KeyLinkAttestation<KeyLinkPayload>): boolean;
@@ -1,2 +1 @@
1
- export { deriveScryptKey, scryptPasswordProofSign, scryptPasswordProofVerify } from './scrypt-proof';
2
1
  export { signKeyLinkAttestation, verifyKeyLinkAttestation } from './attestation';
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * - did — `did:arp:<...>` parse/format + DID document types
9
9
  * - envelope — sign / verify envelope (steps 4-6 of protocol verification)
10
10
  * - challenge — ARP-CHALLENGE-v1 ownership proof (registration)
11
- * - attestation — scrypt key-link owner attestation
11
+ * - attestation — ed25519 key-link owner attestation
12
12
  * - server-chain — signed_message_hash, server_event_hash, audit walker
13
13
  * - settlement — canonical Solana program-id base58 constants
14
14
  * - purpose — domain separators (`ARP-*-v1`)
package/dist/index.js CHANGED
@@ -5,8 +5,6 @@ var utils = require('@noble/hashes/utils');
5
5
  var canonicalize = require('canonicalize');
6
6
  var base = require('@scure/base');
7
7
  var ed = require('@noble/ed25519');
8
- var hmac = require('@noble/hashes/hmac');
9
- var scrypt = require('@noble/hashes/scrypt');
10
8
  var web3_js = require('@solana/web3.js');
11
9
 
12
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -189,73 +187,37 @@ function verifyChallenge(challengeBytes, signature, identityPubkey) {
189
187
  if (signature.length !== 64) return false;
190
188
  return verify2(signature, buildSigningInput(challengeBytes), identityPubkey);
191
189
  }
192
-
193
- // src/types/identity.ts
194
- var OWNER_SIGNING_METHODS = ["scrypt_password_proof", "ed25519_owner_key", "totp+passphrase"];
195
- var SCRYPT_PARAMS = {
196
- N: 32768,
197
- r: 8,
198
- p: 1,
199
- dkLen: 32
200
- };
201
-
202
- // src/attestation/scrypt-proof.ts
203
- function deriveScryptKey(password, salt) {
204
- if (salt.length !== 16) {
205
- throw new Error(`deriveScryptKey: expected 16-byte salt, got ${salt.length}`);
190
+ var ED25519_SIG_PREFIX = "ed25519:";
191
+ function signKeyLinkAttestation(input) {
192
+ if (input.payload.purpose !== "ARP-KEY-LINK-v1") {
193
+ throw new Error(`signKeyLinkAttestation: expected purpose ARP-KEY-LINK-v1, got ${input.payload.purpose}`);
206
194
  }
207
- const passwordBytes = new TextEncoder().encode(password);
208
- return scrypt.scrypt(passwordBytes, salt, {
209
- N: SCRYPT_PARAMS.N,
210
- r: SCRYPT_PARAMS.r,
211
- p: SCRYPT_PARAMS.p,
212
- dkLen: SCRYPT_PARAMS.dkLen
213
- });
214
- }
215
- function scryptPasswordProofSign(payload, scryptKey) {
216
- if (scryptKey.length !== SCRYPT_PARAMS.dkLen) {
217
- throw new Error(`scryptPasswordProofSign: expected ${SCRYPT_PARAMS.dkLen}-byte scrypt key, got ${scryptKey.length}`);
195
+ if (input.payload.owner_signing_method !== "ed25519_owner_key") {
196
+ throw new Error(`signKeyLinkAttestation: this helper handles ed25519_owner_key only; got ${input.payload.owner_signing_method}`);
218
197
  }
219
- const digest = sha2.sha256(canonicalBytes(payload));
220
- const mac = hmac.hmac(sha2.sha256, scryptKey, digest);
221
- return base.base64.encode(mac);
222
- }
223
- function scryptPasswordProofVerify(payload, sigBase64, scryptKey) {
224
- if (scryptKey.length !== SCRYPT_PARAMS.dkLen) return false;
225
- let providedMac;
198
+ const sig = sign2(canonicalBytes(input.payload), input.identitySecretKey);
199
+ return { payload: input.payload, sig: `${ED25519_SIG_PREFIX}${base.base64.encode(sig)}` };
200
+ }
201
+ function verifyKeyLinkAttestation(attestation) {
202
+ const { payload, sig } = attestation;
203
+ if (payload.purpose !== "ARP-KEY-LINK-v1") return false;
204
+ if (payload.owner_signing_method !== "ed25519_owner_key") return false;
205
+ if (typeof sig !== "string" || !sig.startsWith(ED25519_SIG_PREFIX)) return false;
206
+ let sigBytes;
226
207
  try {
227
- providedMac = base.base64.decode(sigBase64);
208
+ sigBytes = base.base64.decode(sig.slice(ED25519_SIG_PREFIX.length));
228
209
  } catch {
229
210
  return false;
230
211
  }
231
- if (providedMac.length !== 32) return false;
232
- const digest = sha2.sha256(canonicalBytes(payload));
233
- const expectedMac = hmac.hmac(sha2.sha256, scryptKey, digest);
234
- return constantTimeEqualBytes(providedMac, expectedMac);
235
- }
236
- function constantTimeEqualBytes(a, b) {
237
- if (a.length !== b.length) return false;
238
- let diff = 0;
239
- for (let i = 0; i < a.length; i++) {
240
- diff |= a[i] ^ b[i];
241
- }
242
- return diff === 0;
243
- }
244
-
245
- // src/attestation/attestation.ts
246
- function signKeyLinkAttestation(input) {
247
- if (input.payload.purpose !== "ARP-KEY-LINK-v1") {
248
- throw new Error(`signKeyLinkAttestation: expected purpose ARP-KEY-LINK-v1, got ${input.payload.purpose}`);
249
- }
250
- if (input.payload.owner_signing_method !== "scrypt_password_proof") {
251
- throw new Error(`signKeyLinkAttestation: this helper handles scrypt_password_proof only; got ${input.payload.owner_signing_method}`);
212
+ if (sigBytes.length !== 64) return false;
213
+ let identityPubkey;
214
+ try {
215
+ identityPubkey = base58btcDecode(payload.identity_public_key);
216
+ } catch {
217
+ return false;
252
218
  }
253
- const sig = scryptPasswordProofSign(input.payload, input.scryptKey);
254
- return { payload: input.payload, sig, scrypt_salt_id: input.scryptSaltId };
255
- }
256
- function verifyKeyLinkAttestation(attestation, scryptKey) {
257
- if (attestation.payload.purpose !== "ARP-KEY-LINK-v1") return false;
258
- return scryptPasswordProofVerify(attestation.payload, attestation.sig, scryptKey);
219
+ if (identityPubkey.length !== 32) return false;
220
+ return verify2(sigBytes, canonicalBytes(payload), identityPubkey);
259
221
  }
260
222
  function signedMessageHash(envelope) {
261
223
  const input = envelope.attachments === void 0 ? { protected: envelope.protected, body: envelope.body } : { protected: envelope.protected, body: envelope.body, attachments: envelope.attachments };
@@ -380,7 +342,7 @@ var SHA256_HEX_RE = /^sha256:[0-9a-f]{64}$/;
380
342
  function isSha256Hex(v) {
381
343
  return typeof v === "string" && SHA256_HEX_RE.test(v);
382
344
  }
383
- var ED25519_SIG_PREFIX = "ed25519:";
345
+ var ED25519_SIG_PREFIX2 = "ed25519:";
384
346
  var PROTOCOL_VERSIONS = ["arp/0.1"];
385
347
  var CURRENT_PROTOCOL_VERSION = PROTOCOL_VERSIONS[PROTOCOL_VERSIONS.length - 1];
386
348
 
@@ -502,6 +464,16 @@ var DiscoverySorts = {
502
464
  RECENT: "recent",
503
465
  CREATED: "created"
504
466
  };
467
+ var AGENT_BADGES = ["proven", "limited", "new", "flagged"];
468
+ var AgentBadges = {
469
+ PROVEN: "proven",
470
+ LIMITED: "limited",
471
+ NEW: "new",
472
+ FLAGGED: "flagged"
473
+ };
474
+ function isAgentBadge(v) {
475
+ return typeof v === "string" && AGENT_BADGES.includes(v);
476
+ }
505
477
 
506
478
  // src/types/inbox.ts
507
479
  var INBOX_BLOCK_SCOPES = ["account", "did"];
@@ -559,6 +531,9 @@ function isReservedName(name) {
559
531
  function isValidAgentName(name) {
560
532
  return AGENT_NAME_REGEX.test(normalizeName(name));
561
533
  }
534
+
535
+ // src/types/identity.ts
536
+ var OWNER_SIGNING_METHODS = ["ed25519_owner_key", "totp+passphrase"];
562
537
  var LOCK_ACCOUNT_SIZE = 269;
563
538
  var LOCK_ACCOUNT_DISCRIMINATOR = new Uint8Array([8, 255, 36, 202, 210, 22, 57, 137]);
564
539
  var LOCK_STATE_NAMES = ["created", "canceled", "in_progress", "submitted", "paid", "revoked", "disputing", "dispute_resolved", "dispute_closed"];
@@ -1212,6 +1187,7 @@ var CliAuthTokenErrorCodes = {
1212
1187
  REQUIRED: "AUTH_TOKEN_REQUIRED"
1213
1188
  };
1214
1189
 
1190
+ exports.AGENT_BADGES = AGENT_BADGES;
1215
1191
  exports.AGENT_NAME_REGEX = AGENT_NAME_REGEX;
1216
1192
  exports.AGENT_TAG_REGEX = AGENT_TAG_REGEX;
1217
1193
  exports.ASSET_DECIMALS_MAX = ASSET_DECIMALS_MAX;
@@ -1221,6 +1197,7 @@ exports.ASSET_SYMBOL_MIN_LEN = ASSET_SYMBOL_MIN_LEN;
1221
1197
  exports.ASSET_WHITELIST = ASSET_WHITELIST;
1222
1198
  exports.ASSOCIATED_TOKEN_PROGRAM_ID = ASSOCIATED_TOKEN_PROGRAM_ID;
1223
1199
  exports.ASSOCIATED_TOKEN_PROGRAM_ID_BASE58 = ASSOCIATED_TOKEN_PROGRAM_ID_BASE58;
1200
+ exports.AgentBadges = AgentBadges;
1224
1201
  exports.BODY_TYPES = BODY_TYPES;
1225
1202
  exports.BodyTypes = BodyTypes;
1226
1203
  exports.CAIP19_REGEX = CAIP19_REGEX;
@@ -1245,7 +1222,7 @@ exports.DelegationActions = DelegationActions;
1245
1222
  exports.DelegationOfferRejectionCodes = DelegationOfferRejectionCodes;
1246
1223
  exports.DelegationStates = DelegationStates;
1247
1224
  exports.DiscoverySorts = DiscoverySorts;
1248
- exports.ED25519_SIG_PREFIX = ED25519_SIG_PREFIX;
1225
+ exports.ED25519_SIG_PREFIX = ED25519_SIG_PREFIX2;
1249
1226
  exports.ESCROW_PDA_SEEDS = ESCROW_PDA_SEEDS;
1250
1227
  exports.ESCROW_PROGRAM_ID_BASE58 = ESCROW_PROGRAM_ID_BASE58;
1251
1228
  exports.ESCROW_RELEASE_METHODS = ESCROW_RELEASE_METHODS;
@@ -1279,7 +1256,6 @@ exports.RESERVED_NAMES = RESERVED_NAMES;
1279
1256
  exports.ReadModelStatuses = ReadModelStatuses;
1280
1257
  exports.ReceiptVerdicts = ReceiptVerdicts;
1281
1258
  exports.RelationshipStates = RelationshipStates;
1282
- exports.SCRYPT_PARAMS = SCRYPT_PARAMS;
1283
1259
  exports.SHA256_HEX_RE = SHA256_HEX_RE;
1284
1260
  exports.SLIP44_SOLANA = SLIP44_SOLANA;
1285
1261
  exports.SOLANA_CLUSTER_IDS = SOLANA_CLUSTER_IDS;
@@ -1321,7 +1297,6 @@ exports.deriveEventAuthorityPda = deriveEventAuthorityPda;
1321
1297
  exports.deriveLockId = deriveLockId;
1322
1298
  exports.deriveLockPda = deriveLockPda;
1323
1299
  exports.deriveOperatorAuthPda = deriveOperatorAuthPda;
1324
- exports.deriveScryptKey = deriveScryptKey;
1325
1300
  exports.deriveStakeVaultPda = deriveStakeVaultPda;
1326
1301
  exports.expiresAt = expiresAt;
1327
1302
  exports.fetchLockAccount = fetchLockAccount;
@@ -1332,6 +1307,7 @@ exports.formatDid = formatDid;
1332
1307
  exports.generateKeyPair = generateKeyPair;
1333
1308
  exports.getPublicKey = getPublicKey2;
1334
1309
  exports.instructionDiscriminator = instructionDiscriminator;
1310
+ exports.isAgentBadge = isAgentBadge;
1335
1311
  exports.isAssetIdentifier = isAssetIdentifier;
1336
1312
  exports.isBodyType = isBodyType;
1337
1313
  exports.isCliLoginSessionWireState = isCliLoginSessionWireState;
@@ -1357,8 +1333,6 @@ exports.parseDid = parseDid;
1357
1333
  exports.pollUntil = pollUntil;
1358
1334
  exports.resolveAsset = resolveAsset;
1359
1335
  exports.rfc3339 = rfc3339;
1360
- exports.scryptPasswordProofSign = scryptPasswordProofSign;
1361
- exports.scryptPasswordProofVerify = scryptPasswordProofVerify;
1362
1336
  exports.senderNonce = senderNonce;
1363
1337
  exports.serverEventHash = serverEventHash;
1364
1338
  exports.sign = sign2;
package/dist/index.mjs CHANGED
@@ -3,8 +3,6 @@ import { bytesToHex, randomBytes } from '@noble/hashes/utils';
3
3
  import canonicalize from 'canonicalize';
4
4
  import { base58, base64, base64urlnopad } from '@scure/base';
5
5
  import * as ed from '@noble/ed25519';
6
- import { hmac } from '@noble/hashes/hmac';
7
- import { scrypt } from '@noble/hashes/scrypt';
8
6
  import { PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js';
9
7
 
10
8
  // src/canonical/canonicalize.ts
@@ -164,73 +162,37 @@ function verifyChallenge(challengeBytes, signature, identityPubkey) {
164
162
  if (signature.length !== 64) return false;
165
163
  return verify2(signature, buildSigningInput(challengeBytes), identityPubkey);
166
164
  }
167
-
168
- // src/types/identity.ts
169
- var OWNER_SIGNING_METHODS = ["scrypt_password_proof", "ed25519_owner_key", "totp+passphrase"];
170
- var SCRYPT_PARAMS = {
171
- N: 32768,
172
- r: 8,
173
- p: 1,
174
- dkLen: 32
175
- };
176
-
177
- // src/attestation/scrypt-proof.ts
178
- function deriveScryptKey(password, salt) {
179
- if (salt.length !== 16) {
180
- throw new Error(`deriveScryptKey: expected 16-byte salt, got ${salt.length}`);
165
+ var ED25519_SIG_PREFIX = "ed25519:";
166
+ function signKeyLinkAttestation(input) {
167
+ if (input.payload.purpose !== "ARP-KEY-LINK-v1") {
168
+ throw new Error(`signKeyLinkAttestation: expected purpose ARP-KEY-LINK-v1, got ${input.payload.purpose}`);
181
169
  }
182
- const passwordBytes = new TextEncoder().encode(password);
183
- return scrypt(passwordBytes, salt, {
184
- N: SCRYPT_PARAMS.N,
185
- r: SCRYPT_PARAMS.r,
186
- p: SCRYPT_PARAMS.p,
187
- dkLen: SCRYPT_PARAMS.dkLen
188
- });
189
- }
190
- function scryptPasswordProofSign(payload, scryptKey) {
191
- if (scryptKey.length !== SCRYPT_PARAMS.dkLen) {
192
- throw new Error(`scryptPasswordProofSign: expected ${SCRYPT_PARAMS.dkLen}-byte scrypt key, got ${scryptKey.length}`);
170
+ if (input.payload.owner_signing_method !== "ed25519_owner_key") {
171
+ throw new Error(`signKeyLinkAttestation: this helper handles ed25519_owner_key only; got ${input.payload.owner_signing_method}`);
193
172
  }
194
- const digest = sha256(canonicalBytes(payload));
195
- const mac = hmac(sha256, scryptKey, digest);
196
- return base64.encode(mac);
197
- }
198
- function scryptPasswordProofVerify(payload, sigBase64, scryptKey) {
199
- if (scryptKey.length !== SCRYPT_PARAMS.dkLen) return false;
200
- let providedMac;
173
+ const sig = sign2(canonicalBytes(input.payload), input.identitySecretKey);
174
+ return { payload: input.payload, sig: `${ED25519_SIG_PREFIX}${base64.encode(sig)}` };
175
+ }
176
+ function verifyKeyLinkAttestation(attestation) {
177
+ const { payload, sig } = attestation;
178
+ if (payload.purpose !== "ARP-KEY-LINK-v1") return false;
179
+ if (payload.owner_signing_method !== "ed25519_owner_key") return false;
180
+ if (typeof sig !== "string" || !sig.startsWith(ED25519_SIG_PREFIX)) return false;
181
+ let sigBytes;
201
182
  try {
202
- providedMac = base64.decode(sigBase64);
183
+ sigBytes = base64.decode(sig.slice(ED25519_SIG_PREFIX.length));
203
184
  } catch {
204
185
  return false;
205
186
  }
206
- if (providedMac.length !== 32) return false;
207
- const digest = sha256(canonicalBytes(payload));
208
- const expectedMac = hmac(sha256, scryptKey, digest);
209
- return constantTimeEqualBytes(providedMac, expectedMac);
210
- }
211
- function constantTimeEqualBytes(a, b) {
212
- if (a.length !== b.length) return false;
213
- let diff = 0;
214
- for (let i = 0; i < a.length; i++) {
215
- diff |= a[i] ^ b[i];
216
- }
217
- return diff === 0;
218
- }
219
-
220
- // src/attestation/attestation.ts
221
- function signKeyLinkAttestation(input) {
222
- if (input.payload.purpose !== "ARP-KEY-LINK-v1") {
223
- throw new Error(`signKeyLinkAttestation: expected purpose ARP-KEY-LINK-v1, got ${input.payload.purpose}`);
224
- }
225
- if (input.payload.owner_signing_method !== "scrypt_password_proof") {
226
- throw new Error(`signKeyLinkAttestation: this helper handles scrypt_password_proof only; got ${input.payload.owner_signing_method}`);
187
+ if (sigBytes.length !== 64) return false;
188
+ let identityPubkey;
189
+ try {
190
+ identityPubkey = base58btcDecode(payload.identity_public_key);
191
+ } catch {
192
+ return false;
227
193
  }
228
- const sig = scryptPasswordProofSign(input.payload, input.scryptKey);
229
- return { payload: input.payload, sig, scrypt_salt_id: input.scryptSaltId };
230
- }
231
- function verifyKeyLinkAttestation(attestation, scryptKey) {
232
- if (attestation.payload.purpose !== "ARP-KEY-LINK-v1") return false;
233
- return scryptPasswordProofVerify(attestation.payload, attestation.sig, scryptKey);
194
+ if (identityPubkey.length !== 32) return false;
195
+ return verify2(sigBytes, canonicalBytes(payload), identityPubkey);
234
196
  }
235
197
  function signedMessageHash(envelope) {
236
198
  const input = envelope.attachments === void 0 ? { protected: envelope.protected, body: envelope.body } : { protected: envelope.protected, body: envelope.body, attachments: envelope.attachments };
@@ -355,7 +317,7 @@ var SHA256_HEX_RE = /^sha256:[0-9a-f]{64}$/;
355
317
  function isSha256Hex(v) {
356
318
  return typeof v === "string" && SHA256_HEX_RE.test(v);
357
319
  }
358
- var ED25519_SIG_PREFIX = "ed25519:";
320
+ var ED25519_SIG_PREFIX2 = "ed25519:";
359
321
  var PROTOCOL_VERSIONS = ["arp/0.1"];
360
322
  var CURRENT_PROTOCOL_VERSION = PROTOCOL_VERSIONS[PROTOCOL_VERSIONS.length - 1];
361
323
 
@@ -477,6 +439,16 @@ var DiscoverySorts = {
477
439
  RECENT: "recent",
478
440
  CREATED: "created"
479
441
  };
442
+ var AGENT_BADGES = ["proven", "limited", "new", "flagged"];
443
+ var AgentBadges = {
444
+ PROVEN: "proven",
445
+ LIMITED: "limited",
446
+ NEW: "new",
447
+ FLAGGED: "flagged"
448
+ };
449
+ function isAgentBadge(v) {
450
+ return typeof v === "string" && AGENT_BADGES.includes(v);
451
+ }
480
452
 
481
453
  // src/types/inbox.ts
482
454
  var INBOX_BLOCK_SCOPES = ["account", "did"];
@@ -534,6 +506,9 @@ function isReservedName(name) {
534
506
  function isValidAgentName(name) {
535
507
  return AGENT_NAME_REGEX.test(normalizeName(name));
536
508
  }
509
+
510
+ // src/types/identity.ts
511
+ var OWNER_SIGNING_METHODS = ["ed25519_owner_key", "totp+passphrase"];
537
512
  var LOCK_ACCOUNT_SIZE = 269;
538
513
  var LOCK_ACCOUNT_DISCRIMINATOR = new Uint8Array([8, 255, 36, 202, 210, 22, 57, 137]);
539
514
  var LOCK_STATE_NAMES = ["created", "canceled", "in_progress", "submitted", "paid", "revoked", "disputing", "dispute_resolved", "dispute_closed"];
@@ -1187,4 +1162,4 @@ var CliAuthTokenErrorCodes = {
1187
1162
  REQUIRED: "AUTH_TOKEN_REQUIRED"
1188
1163
  };
1189
1164
 
1190
- export { AGENT_NAME_REGEX, AGENT_TAG_REGEX, ASSET_DECIMALS_MAX, ASSET_DECIMALS_MIN, ASSET_SYMBOL_MAX_LEN, ASSET_SYMBOL_MIN_LEN, ASSET_WHITELIST, ASSOCIATED_TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID_BASE58, BODY_TYPES, BodyTypes, CAIP19_REGEX, CLI_AUTH_TOKEN_ERROR_CODES, CLI_LOGIN_SESSION_STATES, CLI_LOGIN_SESSION_STORED_STATES, CREATE_LOCK_DISCRIMINATOR, CREATE_LOCK_NATIVE_DISCRIMINATOR, CURRENT_PROTOCOL_VERSION, CliAuthTokenErrorCodes, CliLoginSessionStates, DECIMAL_AMOUNT_REGEX, DECLINE_REASONS, DELEGATION_ACTIONS, DELEGATION_ACTIVE_STATES, DELEGATION_OFFER_REJECTION_CODES, DELEGATION_STATES, DEVNET_MINTS, DID_ARP_REGEX, DISCOVERY_SORTS, DelegationActions, DelegationOfferRejectionCodes, DelegationStates, DiscoverySorts, ED25519_SIG_PREFIX, ESCROW_PDA_SEEDS, ESCROW_PROGRAM_ID_BASE58, ESCROW_RELEASE_METHODS, EscrowReleaseMethods, HANDSHAKE_DECISIONS, HandshakeDecisions, INBOX_BLOCK_SCOPES, InboxBlockScopes, LIVE_RELATIONSHIP_STATE_NAMES, LOCK_ACCOUNT_DISCRIMINATOR, LOCK_ACCOUNT_SIZE, LOCK_STATE_NAMES, LOCK_TERMINAL_STATES, LockStates, LockTerminalStates, MAINNET_MINTS, MAX_CLOCK_SKEW_SECONDS, MAX_ENVELOPE_TTL_SECONDS, NATIVE_SOL_MINT, NATIVE_SOL_MINT_BASE58, NO_ARG_LIFECYCLE_INSTRUCTIONS, OWNER_SIGNING_METHODS, POST_COMMIT_ERROR_CODES, POST_COMMIT_ERROR_CODE_PREFIXES, PROTOCOL_VERSIONS, Purpose, READ_MODEL_STATUSES, RECEIPT_VERDICTS, RELATIONSHIP_STATE_NAMES, RESERVED_NAMES, ReadModelStatuses, ReceiptVerdicts, RelationshipStates, SCRYPT_PARAMS, SHA256_HEX_RE, SLIP44_SOLANA, SOLANA_CLUSTER_IDS, SPL_TOKEN_PROGRAM_ID, SPL_TOKEN_PROGRAM_ID_BASE58, SYSTEM_PROGRAM_ID_BASE58, TOKEN_2022_PROGRAM_ID_BASE58, WELL_KNOWN_ASSETS, WELL_KNOWN_ASSET_KEYS, WORK_LOG_STATES, WorkLogStates, base58btcDecode, base58btcEncode, buildAcceptLockIx, buildCancelLockIx, buildClaimExpiredWorkIx, buildClaimWorkPaymentIx, buildCloseDisputeIx, buildCreateLockIx, buildCreateLockIxData, buildLifecycleIxData, buildOpenDisputeIx, buildResolveDisputeIx, buildResolveDisputeIxData, buildSubmitWorkIx, bytes16ToDelegationId, canonicalBytes, canonicalJson, canonicalSha256Hex, decodeLockAccount, delegationIdToBytes16, deriveAta, deriveCollateralConfigPda, deriveConfigPda, deriveDelegationConditionHash, deriveDisputeResolutionPda, deriveEscrowPda, deriveEventAuthorityPda, deriveLockId, deriveLockPda, deriveOperatorAuthPda, deriveScryptKey, deriveStakeVaultPda, expiresAt, fetchLockAccount, findAssetByAssetId, findAssetMetaByMint, findFirstChainDivergence, formatDid, generateKeyPair, getPublicKey2 as getPublicKey, instructionDiscriminator, isAssetIdentifier, isBodyType, isCliLoginSessionWireState, isDecimalAmountString, isDeclineReason, isDelegationAction, isDelegationState, isEscrowReleaseMethod, isHandshakeDecision, isPostCommitErrorCode, isReadModelStatus, isReceiptVerdict, isRelationshipState, isReservedName, isSha256Hex, isValidAgentName, isValidDid, isWhitelistedAssetId, isWorkLogState, normalizeName, parseCaip19SolanaAssetId, parseDid, pollUntil, resolveAsset, rfc3339, scryptPasswordProofSign, scryptPasswordProofVerify, senderNonce, serverEventHash, sign2 as sign, signChallenge, signEnvelope, signKeyLinkAttestation, signedMessageHash, uuidV4, verify2 as verify, verifyChallenge, verifyEnvelope, verifyKeyLinkAttestation };
1165
+ export { AGENT_BADGES, AGENT_NAME_REGEX, AGENT_TAG_REGEX, ASSET_DECIMALS_MAX, ASSET_DECIMALS_MIN, ASSET_SYMBOL_MAX_LEN, ASSET_SYMBOL_MIN_LEN, ASSET_WHITELIST, ASSOCIATED_TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID_BASE58, AgentBadges, BODY_TYPES, BodyTypes, CAIP19_REGEX, CLI_AUTH_TOKEN_ERROR_CODES, CLI_LOGIN_SESSION_STATES, CLI_LOGIN_SESSION_STORED_STATES, CREATE_LOCK_DISCRIMINATOR, CREATE_LOCK_NATIVE_DISCRIMINATOR, CURRENT_PROTOCOL_VERSION, CliAuthTokenErrorCodes, CliLoginSessionStates, DECIMAL_AMOUNT_REGEX, DECLINE_REASONS, DELEGATION_ACTIONS, DELEGATION_ACTIVE_STATES, DELEGATION_OFFER_REJECTION_CODES, DELEGATION_STATES, DEVNET_MINTS, DID_ARP_REGEX, DISCOVERY_SORTS, DelegationActions, DelegationOfferRejectionCodes, DelegationStates, DiscoverySorts, ED25519_SIG_PREFIX2 as ED25519_SIG_PREFIX, ESCROW_PDA_SEEDS, ESCROW_PROGRAM_ID_BASE58, ESCROW_RELEASE_METHODS, EscrowReleaseMethods, HANDSHAKE_DECISIONS, HandshakeDecisions, INBOX_BLOCK_SCOPES, InboxBlockScopes, LIVE_RELATIONSHIP_STATE_NAMES, LOCK_ACCOUNT_DISCRIMINATOR, LOCK_ACCOUNT_SIZE, LOCK_STATE_NAMES, LOCK_TERMINAL_STATES, LockStates, LockTerminalStates, MAINNET_MINTS, MAX_CLOCK_SKEW_SECONDS, MAX_ENVELOPE_TTL_SECONDS, NATIVE_SOL_MINT, NATIVE_SOL_MINT_BASE58, NO_ARG_LIFECYCLE_INSTRUCTIONS, OWNER_SIGNING_METHODS, POST_COMMIT_ERROR_CODES, POST_COMMIT_ERROR_CODE_PREFIXES, PROTOCOL_VERSIONS, Purpose, READ_MODEL_STATUSES, RECEIPT_VERDICTS, RELATIONSHIP_STATE_NAMES, RESERVED_NAMES, ReadModelStatuses, ReceiptVerdicts, RelationshipStates, SHA256_HEX_RE, SLIP44_SOLANA, SOLANA_CLUSTER_IDS, SPL_TOKEN_PROGRAM_ID, SPL_TOKEN_PROGRAM_ID_BASE58, SYSTEM_PROGRAM_ID_BASE58, TOKEN_2022_PROGRAM_ID_BASE58, WELL_KNOWN_ASSETS, WELL_KNOWN_ASSET_KEYS, WORK_LOG_STATES, WorkLogStates, base58btcDecode, base58btcEncode, buildAcceptLockIx, buildCancelLockIx, buildClaimExpiredWorkIx, buildClaimWorkPaymentIx, buildCloseDisputeIx, buildCreateLockIx, buildCreateLockIxData, buildLifecycleIxData, buildOpenDisputeIx, buildResolveDisputeIx, buildResolveDisputeIxData, buildSubmitWorkIx, bytes16ToDelegationId, canonicalBytes, canonicalJson, canonicalSha256Hex, decodeLockAccount, delegationIdToBytes16, deriveAta, deriveCollateralConfigPda, deriveConfigPda, deriveDelegationConditionHash, deriveDisputeResolutionPda, deriveEscrowPda, deriveEventAuthorityPda, deriveLockId, deriveLockPda, deriveOperatorAuthPda, deriveStakeVaultPda, expiresAt, fetchLockAccount, findAssetByAssetId, findAssetMetaByMint, findFirstChainDivergence, formatDid, generateKeyPair, getPublicKey2 as getPublicKey, instructionDiscriminator, isAgentBadge, isAssetIdentifier, isBodyType, isCliLoginSessionWireState, isDecimalAmountString, isDeclineReason, isDelegationAction, isDelegationState, isEscrowReleaseMethod, isHandshakeDecision, isPostCommitErrorCode, isReadModelStatus, isReceiptVerdict, isRelationshipState, isReservedName, isSha256Hex, isValidAgentName, isValidDid, isWhitelistedAssetId, isWorkLogState, normalizeName, parseCaip19SolanaAssetId, parseDid, pollUntil, resolveAsset, rfc3339, senderNonce, serverEventHash, sign2 as sign, signChallenge, signEnvelope, signKeyLinkAttestation, signedMessageHash, uuidV4, verify2 as verify, verifyChallenge, verifyEnvelope, verifyKeyLinkAttestation };
@@ -160,7 +160,15 @@ export interface AssetVolume {
160
160
  amountDecimal: string | null;
161
161
  lockCount: number;
162
162
  }
163
- /** Per-agent settled-escrow volume, split by role and bucketed by asset. */
163
+ /**
164
+ * Per-agent settled-escrow volume, split by role and bucketed by asset.
165
+ *
166
+ * SCOPE (v1): covers the happy-path `paid` settlement only. Payouts that came
167
+ * through ARBITRATION (a `dispute_resolved` lock won by the payee) are NOT yet
168
+ * in these figures — they ARE reflected in the reputation counters
169
+ * (`settledEscrows`/`disputedEscrows`), so for a heavily-disputed agent the
170
+ * volume can under-report relative to the settled-escrow count.
171
+ */
164
172
  export interface AgentSettlementVolume {
165
173
  /** Received as payee (the worker side) — the headline trust signal. */
166
174
  earnedByAsset: AssetVolume[];
@@ -247,9 +255,9 @@ export interface ChallengeResponse {
247
255
  /**
248
256
  * Request body for `POST /v1/agents` (registration). The server DTO is
249
257
  * `RegisterAgentDto`; `ownerAttestation` mirrors the SDK
250
- * `ScryptPasswordAttestation<KeyLinkPayload>` wire shape but stays a
251
- * generic object here — its inner fields are verified by canonical-JSON
252
- * + HMAC at the server, not structurally.
258
+ * `Ed25519KeyLinkAttestation<KeyLinkPayload>` wire shape but stays a
259
+ * generic object here — its `sig` is verified against the payload's
260
+ * identity key (Ed25519) at the server, not structurally.
253
261
  */
254
262
  export interface RegisterAgentRequest {
255
263
  challengeId: string;
@@ -258,10 +266,7 @@ export interface RegisterAgentRequest {
258
266
  ownerAttestation: {
259
267
  payload: Record<string, unknown>;
260
268
  sig: string;
261
- scrypt_salt_id: string;
262
269
  };
263
- scryptKeyB64: string;
264
- scryptSaltB64: string;
265
270
  /**
266
271
  * Unique, immutable handle — lowercase `^[a-z0-9_]{3,32}$`
267
272
  * ({@link AGENT_NAME_REGEX}), REQUIRED. The server normalizes it and
@@ -16,6 +16,29 @@ export declare const DiscoverySorts: {
16
16
  readonly RECENT: "recent";
17
17
  readonly CREATED: "created";
18
18
  };
19
+ /**
20
+ * Earned-evidence discovery badge — a coarse "how much real on-chain
21
+ * history" signal carried on every search row + profile, DISTINCT from
22
+ * the manual platform `trusted` flag. Same vocab shape as the protocol
23
+ * sets (as-const array + union + guard + named-member const-object).
24
+ *
25
+ * `proven` = enough completed payee cycles across distinct owners;
26
+ * `limited` = some real on-chain cycles, below the proven bar;
27
+ * `new` = zero settled cycles (escrow/stake-backed but unproven);
28
+ * `flagged` = adverse evidence (a lost dispute or a no-show/revoke) —
29
+ * dominates the positive ladder, never masked by a high score or `trusted`.
30
+ */
31
+ export declare const AGENT_BADGES: readonly ["proven", "limited", "new", "flagged"];
32
+ export type AgentBadge = (typeof AGENT_BADGES)[number];
33
+ /** Named-member accessor for {@link AgentBadge} (vocab-tested). */
34
+ export declare const AgentBadges: {
35
+ readonly PROVEN: "proven";
36
+ readonly LIMITED: "limited";
37
+ readonly NEW: "new";
38
+ readonly FLAGGED: "flagged";
39
+ };
40
+ /** Type guard for {@link AgentBadge} (rejects non-members + non-strings). */
41
+ export declare function isAgentBadge(v: unknown): v is AgentBadge;
19
42
  /**
20
43
  * Query for `GET /v1/discovery/search` (server DTO
21
44
  * `DiscoverySearchQueryDto`). Every field optional; filters AND-compose.
@@ -32,6 +55,16 @@ export interface DiscoverySearchQuery {
32
55
  accepts?: string;
33
56
  /** Only agents seen within the liveness window. */
34
57
  online?: boolean;
58
+ /** Return ONLY platform-trusted agents (the manual `trusted` allow-list flag). */
59
+ trustedOnly?: boolean;
60
+ /** Include unproven (zero settled cycle) agents — default true; `false` hard-excludes cold-start. */
61
+ includeUnproven?: boolean;
62
+ /** Hard filter: minimum settled on-chain cycles. */
63
+ minOnchainCycles?: number;
64
+ /** Hard filter: minimum completed delegations AS THE PAYEE (paid work delivered). */
65
+ minCompletedAsPayee?: number;
66
+ /** Hard filter: minimum distinct (owner-resolved) counterparts. */
67
+ minDistinctCounterparts?: number;
35
68
  /** `reputation` (composite desc, default) | `recent` | `created` (cursor). */
36
69
  sort?: DiscoverySort;
37
70
  /** Zero-based page index (offset = page × limit) — reputation/recent sorts. */
@@ -73,6 +106,10 @@ export interface DiscoveryResult {
73
106
  reputation: DiscoveryReputation;
74
107
  liveness: DiscoveryLiveness;
75
108
  registeredAt: string;
109
+ /** Platform-curated trust flag (manual DB allow-list) — NOT earned reputation. */
110
+ trusted: boolean;
111
+ /** Earned-evidence badge derived from on-chain history (see {@link AgentBadge}). */
112
+ badge: AgentBadge;
76
113
  }
77
114
  /** Pagination envelope metadata on a discovery search page. */
78
115
  export interface DiscoveryPagination {
@@ -104,6 +141,10 @@ export interface DiscoveryProfile {
104
141
  tags: string[];
105
142
  acceptPrefs?: AcceptPrefs;
106
143
  registeredAt: string;
144
+ /** Platform-curated trust flag (manual DB allow-list) — NOT earned reputation. */
145
+ trusted: boolean;
146
+ /** Earned-evidence badge derived from on-chain history (see {@link AgentBadge}). */
147
+ badge: AgentBadge;
107
148
  reputation: AgentReputation;
108
149
  /** Liveness, plus `lastEventAt` (last protocol event either side). */
109
150
  liveness: DiscoveryLiveness & {
@@ -1,16 +1,16 @@
1
1
  import type { Did } from './envelope';
2
2
  /**
3
- * Owner attestation methods per [00-core/identity.md](../../../00-core/identity.md).
4
- *
5
- * Only `scrypt_password_proof` is active (index 0); the others are
6
- * reserved placeholders for forward-compat. Backed by an `as const`
7
- * array so the server's attestation schema can source the active method
8
- * from `OWNER_SIGNING_METHODS[0]` instead of re-hardcoding the literal.
3
+ * Owner attestation methods. `ed25519_owner_key` is active (index 0):
4
+ * the agent's IDENTITY key self-signs the key-link, so there is NO
5
+ * separate owner password. `totp+passphrase` is a reserved placeholder
6
+ * for forward-compat. Backed by an `as const` array so the server's
7
+ * attestation schema sources the active method from
8
+ * `OWNER_SIGNING_METHODS[0]` instead of re-hardcoding the literal.
9
9
  */
10
- export declare const OWNER_SIGNING_METHODS: readonly ["scrypt_password_proof", "ed25519_owner_key", "totp+passphrase"];
10
+ export declare const OWNER_SIGNING_METHODS: readonly ["ed25519_owner_key", "totp+passphrase"];
11
11
  export type OwnerSigningMethod = (typeof OWNER_SIGNING_METHODS)[number];
12
12
  /**
13
- * `ARP-KEY-LINK-v1` payload — the canonical-JSON-hashed object an owner
13
+ * `ARP-KEY-LINK-v1` payload — the canonical-JSON-hashed object the owner
14
14
  * signs at registration. Carries the link between identity and settlement
15
15
  * keys plus owner identity / method metadata.
16
16
  */
@@ -25,20 +25,14 @@ export interface KeyLinkPayload {
25
25
  nonce: string;
26
26
  }
27
27
  /**
28
- * `scrypt_password_proof` the owner attestation envelope. The
29
- * signature is HMAC-SHA256(scrypt(password, salt), sha256(canonical(payload))),
30
- * base64-encoded. NOT an Ed25519 signature; verification is
31
- * server-side via the stored scrypt-derived key.
28
+ * `ed25519_owner_key` key-link attestation. The `sig` is the agent's
29
+ * IDENTITY Ed25519 key signing `canonicalBytes(payload)`, formatted as
30
+ * `ed25519:<base64(64-byte sig)>` the same convention as envelope
31
+ * signatures. SELF-VERIFYING: the verifier checks `sig` against the
32
+ * payload's `identity_public_key`; there is no shared secret and no
33
+ * password (the identity key is already challenge-proven at register).
32
34
  */
33
- export interface ScryptPasswordAttestation<TPayload extends KeyLinkPayload = KeyLinkPayload> {
35
+ export interface Ed25519KeyLinkAttestation<TPayload extends KeyLinkPayload = KeyLinkPayload> {
34
36
  payload: TPayload;
35
37
  sig: string;
36
- scrypt_salt_id: string;
37
38
  }
38
- /** Standard scrypt parameters used for owner password proofs. */
39
- export declare const SCRYPT_PARAMS: {
40
- readonly N: 32768;
41
- readonly r: 8;
42
- readonly p: 1;
43
- readonly dkLen: 32;
44
- };
@@ -10,8 +10,8 @@ export type { WorkLogState } from './work-log';
10
10
  export { WORK_LOG_STATES, WorkLogStates, isWorkLogState } from './work-log';
11
11
  export type { ReadModelStatus } from './event';
12
12
  export { READ_MODEL_STATUSES, ReadModelStatuses, isReadModelStatus } from './event';
13
- export type { DiscoverySort, DiscoverySearchQuery, DiscoveryReputation, DiscoveryLiveness, DiscoveryResult, DiscoveryPagination, DiscoverySearchResponse, DiscoveryProfile, } from './discovery';
14
- export { DISCOVERY_SORTS, DiscoverySorts } from './discovery';
13
+ export type { DiscoverySort, AgentBadge, DiscoverySearchQuery, DiscoveryReputation, DiscoveryLiveness, DiscoveryResult, DiscoveryPagination, DiscoverySearchResponse, DiscoveryProfile, } from './discovery';
14
+ export { DISCOVERY_SORTS, DiscoverySorts, AGENT_BADGES, AgentBadges, isAgentBadge } from './discovery';
15
15
  export type { InboxBlockScope, InboxBlock, BlockInboxBody } from './inbox';
16
16
  export { INBOX_BLOCK_SCOPES, InboxBlockScopes } from './inbox';
17
17
  export type { CliSessionCreated, CliTokenIssued, CliWhoami, MyAgentSummary, CliLoginSessionStoredState, CliLoginSessionWireState, } from './cli-auth';
@@ -19,5 +19,5 @@ export { CLI_LOGIN_SESSION_STORED_STATES, CLI_LOGIN_SESSION_STATES, CliLoginSess
19
19
  export type { AssetIdentifierWire, DelegationPublic, DisputeResolutionPublic, ReceiptPublic, RelationshipPublic, WorkLogPublic, EventPublic, IngestResult, SenderSequenceResponse, InboxUnblockResult, ListRelationshipsQuery, ListInboxQuery, ListEventsQuery, ListDelegationsQuery, ListWorkLogsQuery, ListReceiptsQuery, } from './read-model';
20
20
  export type { AcceptPrefs, AcceptCurrency, AgentRegisteredResponse, AgentPublic, UpdateAgentBody, RegisterAgentRequest, ChallengeResponse, ReputationScores, ReputationCounters, AgentReputation, AssetVolume, AgentSettlementVolume, AgentStatsRates, AgentStats, } from './agent';
21
21
  export { AGENT_TAG_REGEX, AGENT_NAME_REGEX, RESERVED_NAMES, isReservedName, isValidAgentName, normalizeName } from './agent';
22
- export type { OwnerSigningMethod, KeyLinkPayload, ScryptPasswordAttestation } from './identity';
23
- export { SCRYPT_PARAMS, OWNER_SIGNING_METHODS } from './identity';
22
+ export type { OwnerSigningMethod, KeyLinkPayload, Ed25519KeyLinkAttestation } from './identity';
23
+ export { OWNER_SIGNING_METHODS } from './identity';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyanon-arp/sdk",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "description": "TypeScript SDK for the Agent Relationship Protocol — canonical JSON, Ed25519 envelope sign/verify, did:arp identity, scrypt key attestation, chain-audit helpers.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -1,28 +0,0 @@
1
- /**
2
- * Derive the scrypt key from an owner's password + salt. Uses the
3
- * standard parameters: N=32768, r=8, p=1, dkLen=32. Designed to be
4
- * computed once at owner registration time and stored encrypted-at-rest;
5
- * subsequent attestation verification recomputes the HMAC, not scrypt.
6
- *
7
- * Synchronous variant is intentional — keys derive at low frequency
8
- * (once per owner registration); the worst case is a few hundred ms
9
- * which is acceptable. Async variants can be layered on top by the
10
- * consumer if needed.
11
- */
12
- export declare function deriveScryptKey(password: string, salt: Uint8Array): Uint8Array;
13
- /**
14
- * Compute the scrypt-password-proof signature over the canonical
15
- * payload bytes, returning the base64-encoded MAC.
16
- *
17
- * Steps per [00-core/identity.md](../../../00-core/identity.md):
18
- * 1. payload_digest = sha256(canonical_json(payload))
19
- * 2. mac = HMAC-SHA256(scrypt_key, payload_digest)
20
- * 3. sig = base64(mac)
21
- */
22
- export declare function scryptPasswordProofSign(payload: unknown, scryptKey: Uint8Array): string;
23
- /**
24
- * Verify a scrypt-password-proof signature. Constant-time compare on
25
- * MAC bytes — never compares strings directly because base64 decoding
26
- * normalises some inputs which would mask differences.
27
- */
28
- export declare function scryptPasswordProofVerify(payload: unknown, sigBase64: string, scryptKey: Uint8Array): boolean;