@totemsdk/identity 0.1.0 → 0.1.1

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/src/claims.ts DELETED
@@ -1,108 +0,0 @@
1
- /**
2
- * Claim creation helpers.
3
- *
4
- * Claim IDs are deterministic: SHA3-256 of claim fields + canonical payload hash.
5
- */
6
-
7
- import { sha3_256 } from '@noble/hashes/sha3.js';
8
- import { canonicalJson, toHex } from './canonical.js';
9
- import type { IdentityClaim, IdentityClaimType } from './types.js';
10
-
11
- function computeClaimId(
12
- type: IdentityClaimType,
13
- issuer: string,
14
- subject: string,
15
- object: string,
16
- issuedAt: number,
17
- payload: Record<string, unknown>,
18
- ): string {
19
- const canonical = canonicalJson({ type, issuer, subject, object, issuedAt, payload });
20
- const hash = sha3_256(new TextEncoder().encode(canonical));
21
- return toHex(hash);
22
- }
23
-
24
- export function createIdentityClaim(opts: {
25
- type: IdentityClaimType;
26
- issuer: string;
27
- subject: string;
28
- object: string;
29
- payload: Record<string, unknown>;
30
- issuedAt?: number;
31
- expiresAt?: number;
32
- }): IdentityClaim {
33
- const { type, issuer, subject, object, payload, expiresAt } = opts;
34
- const issuedAt = opts.issuedAt ?? Date.now();
35
- const id = computeClaimId(type, issuer, subject, object, issuedAt, payload);
36
- return {
37
- id,
38
- type,
39
- issuer,
40
- subject,
41
- object,
42
- issuedAt,
43
- ...(expiresAt !== undefined ? { expiresAt } : {}),
44
- payload,
45
- };
46
- }
47
-
48
- export function createDelegationClaim(opts: {
49
- issuer: string;
50
- subject: string;
51
- delegatedAddress: string;
52
- scopes: string[];
53
- issuedAt?: number;
54
- expiresAt?: number;
55
- }): IdentityClaim {
56
- const { issuer, subject, delegatedAddress, scopes, expiresAt } = opts;
57
- return createIdentityClaim({
58
- type: 'delegates_to',
59
- issuer,
60
- subject,
61
- object: delegatedAddress,
62
- payload: { scopes },
63
- issuedAt: opts.issuedAt,
64
- expiresAt,
65
- });
66
- }
67
-
68
- export function createPaymentRecipientClaim(opts: {
69
- issuer: string;
70
- subject: string;
71
- address: string;
72
- label?: string;
73
- issuedAt?: number;
74
- expiresAt?: number;
75
- }): IdentityClaim {
76
- const { issuer, subject, address, label, expiresAt } = opts;
77
- const payload: Record<string, unknown> = {};
78
- if (label !== undefined) payload.label = label;
79
- return createIdentityClaim({
80
- type: 'payment_recipient',
81
- issuer,
82
- subject,
83
- object: address,
84
- payload,
85
- issuedAt: opts.issuedAt,
86
- expiresAt,
87
- });
88
- }
89
-
90
- export function createServiceEndpointClaim(opts: {
91
- issuer: string;
92
- subject: string;
93
- endpointType: string;
94
- uri: string;
95
- issuedAt?: number;
96
- expiresAt?: number;
97
- }): IdentityClaim {
98
- const { issuer, subject, endpointType, uri, expiresAt } = opts;
99
- return createIdentityClaim({
100
- type: 'service_endpoint',
101
- issuer,
102
- subject,
103
- object: uri,
104
- payload: { endpointType },
105
- issuedAt: opts.issuedAt,
106
- expiresAt,
107
- });
108
- }
package/src/constants.ts DELETED
@@ -1 +0,0 @@
1
- export const IDENTITY_VERSION = 1 as const;
package/src/document.ts DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * Identity document creation and ID computation.
3
- *
4
- * computeIdentityId: deterministic SHA3-256 of "totem-identity" + kind + rootAddress.
5
- * Version is NOT part of the ID hash — schema version upgrades must not change the identity ID.
6
- */
7
-
8
- import { sha3_256 } from '@noble/hashes/sha3.js';
9
- import { IDENTITY_VERSION } from './constants.js';
10
- import { toHex } from './canonical.js';
11
- import type { IdentityKind, TotemIdentityDocument } from './types.js';
12
-
13
- export function computeIdentityId(kind: IdentityKind, rootAddress: string): string {
14
- const input = `totem-identity\0${kind}\0${rootAddress}`;
15
- const hash = sha3_256(new TextEncoder().encode(input));
16
- return `totem:id:${kind}:${toHex(hash)}`;
17
- }
18
-
19
- export function createIdentityDocument(opts: {
20
- kind: IdentityKind;
21
- rootAddress: string;
22
- controllerAddress: string;
23
- metadata?: Record<string, unknown>;
24
- }): TotemIdentityDocument {
25
- const { kind, rootAddress, controllerAddress, metadata } = opts;
26
- return {
27
- id: computeIdentityId(kind, rootAddress),
28
- kind,
29
- version: IDENTITY_VERSION,
30
- rootAddress,
31
- controllerAddress,
32
- createdAt: Date.now(),
33
- ...(metadata !== undefined ? { metadata } : {}),
34
- };
35
- }
package/src/guards.ts DELETED
@@ -1,75 +0,0 @@
1
- /**
2
- * Type guards for identity types.
3
- */
4
-
5
- import type {
6
- TotemIdentityDocument,
7
- IdentityClaim,
8
- SignedIdentityClaim,
9
- RotationClaim,
10
- RevocationClaim,
11
- } from './types.js';
12
-
13
- export function isTotemIdentityDocument(value: unknown): value is TotemIdentityDocument {
14
- if (!value || typeof value !== 'object') return false;
15
- const v = value as Record<string, unknown>;
16
- return (
17
- typeof v.id === 'string' &&
18
- typeof v.kind === 'string' &&
19
- typeof v.version === 'number' &&
20
- typeof v.rootAddress === 'string' &&
21
- typeof v.controllerAddress === 'string' &&
22
- typeof v.createdAt === 'number'
23
- );
24
- }
25
-
26
- export function isIdentityClaim(value: unknown): value is IdentityClaim {
27
- if (!value || typeof value !== 'object') return false;
28
- const v = value as Record<string, unknown>;
29
- return (
30
- typeof v.id === 'string' &&
31
- typeof v.type === 'string' &&
32
- typeof v.issuer === 'string' &&
33
- typeof v.subject === 'string' &&
34
- typeof v.object === 'string' &&
35
- typeof v.issuedAt === 'number' &&
36
- typeof v.payload === 'object' &&
37
- v.payload !== null
38
- );
39
- }
40
-
41
- export function isSignedIdentityClaim(value: unknown): value is SignedIdentityClaim {
42
- if (!value || typeof value !== 'object') return false;
43
- const v = value as Record<string, unknown>;
44
- if (!isIdentityClaim(v.claim)) return false;
45
- if (!v.proof || typeof v.proof !== 'object') return false;
46
- const p = v.proof as Record<string, unknown>;
47
- return (
48
- typeof p.address === 'string' &&
49
- typeof p.publicKey === 'string' &&
50
- typeof p.signature === 'string'
51
- );
52
- }
53
-
54
- export function isRotationClaim(value: unknown): value is RotationClaim {
55
- if (!value || typeof value !== 'object') return false;
56
- const v = value as Record<string, unknown>;
57
- return (
58
- typeof v.claimId === 'string' &&
59
- typeof v.issuer === 'string' &&
60
- typeof v.subject === 'string' &&
61
- typeof v.newAddress === 'string' &&
62
- typeof v.issuedAt === 'number'
63
- );
64
- }
65
-
66
- export function isRevocationClaim(value: unknown): value is RevocationClaim {
67
- if (!value || typeof value !== 'object') return false;
68
- const v = value as Record<string, unknown>;
69
- return (
70
- typeof v.claimId === 'string' &&
71
- typeof v.issuer === 'string' &&
72
- typeof v.subject === 'string' &&
73
- typeof v.issuedAt === 'number'
74
- );
75
- }
package/src/index.ts DELETED
@@ -1,55 +0,0 @@
1
- /**
2
- * @module @totemsdk/identity
3
- *
4
- * Canonical identity and claims layer for Totem Edge.
5
- * Pure package — no network, no DHT, no blockchain submission.
6
- */
7
-
8
- export { IDENTITY_VERSION } from './constants.js';
9
-
10
- export type {
11
- IdentityKind,
12
- IdentityStatus,
13
- TotemIdentityDocument,
14
- IdentityClaim,
15
- IdentityClaimType,
16
- SignedIdentityClaim,
17
- IdentityVerifyResult,
18
- IdentityProofVerifier,
19
- IdentityGraph,
20
- ResolvedIdentity,
21
- IdentityResolutionResult,
22
- DelegationClaim,
23
- PaymentRecipientClaim,
24
- ServiceEndpointClaim,
25
- RotationClaim,
26
- RevocationClaim,
27
- ManifestIdentityBinding,
28
- } from './types.js';
29
-
30
- export { computeIdentityId, createIdentityDocument } from './document.js';
31
-
32
- export {
33
- createIdentityClaim,
34
- createDelegationClaim,
35
- createPaymentRecipientClaim,
36
- createServiceEndpointClaim,
37
- } from './claims.js';
38
-
39
- export { signIdentityClaim } from './signing.js';
40
- export { verifyIdentityClaim } from './verify.js';
41
-
42
- export { rotateIdentity } from './rotation.js';
43
- export { revokeIdentity } from './revocation.js';
44
-
45
- export { resolveIdentityGraph } from './resolver.js';
46
-
47
- export { bindManifestToIdentity, verifyManifestIdentity } from './manifest-binding.js';
48
-
49
- export {
50
- isTotemIdentityDocument,
51
- isIdentityClaim,
52
- isSignedIdentityClaim,
53
- isRotationClaim,
54
- isRevocationClaim,
55
- } from './guards.js';
@@ -1,163 +0,0 @@
1
- /**
2
- * Manifest identity binding.
3
- *
4
- * bindManifestToIdentity: verify a signed manifest against an identity graph.
5
- * verifyManifestIdentity: core verification logic.
6
- *
7
- * Security model for valid signer addresses:
8
- * A manifest signer is authorized if the signing address is one of:
9
- * 1. The identity's rootAddress
10
- * 2. The identity's controllerAddress
11
- * 3. An address in authorizedAddresses (delegates with "manifest:sign" or "*" scope)
12
- * 4. An address in result.provenAddresses returned by the root-identity proof verifier
13
- *
14
- * Note: controlledAddresses (delegates with any scope) are NOT included in the
15
- * manifest-signing valid set. Only explicitly scoped manifest signers may bind.
16
- *
17
- * Verification order:
18
- * 1. verifyManifest (manifest signature must be valid)
19
- * 2. resolveIdentityGraph (traverse graph)
20
- * 3. Optional root-identity proof verifier hooks
21
- * 4. Address membership check
22
- * 5. Identity status check (revoked = invalid)
23
- */
24
-
25
- import { verifyManifest, computeManifestId } from '@totemsdk/manifest';
26
- import type { SignedManifest } from '@totemsdk/manifest';
27
- import { resolveIdentityGraph } from './resolver.js';
28
- import type {
29
- IdentityGraph,
30
- ManifestIdentityBinding,
31
- IdentityProofVerifier,
32
- } from './types.js';
33
-
34
- export async function verifyManifestIdentity(
35
- signedManifest: SignedManifest<any>,
36
- identityGraph: IdentityGraph,
37
- options?: {
38
- proofVerifiers?: Record<string, IdentityProofVerifier>;
39
- },
40
- ): Promise<ManifestIdentityBinding> {
41
- const proofVerifiers = options?.proofVerifiers ?? {};
42
- const manifestId = computeManifestId(signedManifest.manifest);
43
-
44
- // Step 1: verify manifest signature first — fail fast on invalid manifest
45
- const manifestVerifyResult = verifyManifest(signedManifest);
46
- if (!manifestVerifyResult.valid) {
47
- return {
48
- valid: false,
49
- reason: `manifest signature invalid: ${manifestVerifyResult.reason ?? 'unknown'}`,
50
- manifestId,
51
- identityId: identityGraph.document.id,
52
- signerAddress: signedManifest.authorAddress,
53
- resolvedStatus: 'active',
54
- };
55
- }
56
-
57
- // Step 2: resolve identity graph (includes claim signature verification)
58
- const resolution = resolveIdentityGraph(identityGraph);
59
- if (!resolution.resolved) {
60
- return {
61
- valid: false,
62
- reason: 'identity graph could not be resolved',
63
- manifestId,
64
- identityId: identityGraph.document.id,
65
- signerAddress: signedManifest.authorAddress,
66
- resolvedStatus: 'active',
67
- };
68
- }
69
-
70
- const resolved = resolution.resolved;
71
-
72
- // Step 3: collect additional proven addresses from proof verifiers
73
- const provenAddresses: string[] = [];
74
-
75
- // Check manifest-level rootIdentityProof
76
- if (signedManifest.rootIdentityProof && proofVerifiers['root-identity']) {
77
- try {
78
- const verifyResult = await proofVerifiers['root-identity'].verify(
79
- signedManifest.rootIdentityProof,
80
- );
81
- if (verifyResult.valid && verifyResult.provenAddresses) {
82
- provenAddresses.push(...verifyResult.provenAddresses);
83
- }
84
- } catch {
85
- // silently ignore verifier errors
86
- }
87
- }
88
-
89
- // Check claim-level rootIdentityProof fields
90
- if (proofVerifiers['root-identity']) {
91
- for (const sc of identityGraph.claims) {
92
- if (sc.rootIdentityProof) {
93
- try {
94
- const verifyResult = await proofVerifiers['root-identity'].verify(
95
- sc.rootIdentityProof,
96
- );
97
- if (verifyResult.valid && verifyResult.provenAddresses) {
98
- provenAddresses.push(...verifyResult.provenAddresses);
99
- }
100
- } catch {
101
- // silently ignore verifier errors
102
- }
103
- }
104
- }
105
- }
106
-
107
- // Step 4: check address validity
108
- // Valid signers (per spec):
109
- // 1. rootAddress
110
- // 2. controllerAddress
111
- // 3. controlledAddresses — all delegated addresses (any scope)
112
- // 4. authorizedAddresses — subset with "manifest:sign" or "*" scope (already subset of above)
113
- // 5. provenAddresses — from root-identity proof verifiers
114
- const signerAddress = signedManifest.authorAddress;
115
- const validAddresses = new Set<string>([
116
- resolved.rootAddress,
117
- resolved.controllerAddress,
118
- ...resolved.controlledAddresses,
119
- ...resolved.authorizedAddresses,
120
- ...provenAddresses,
121
- ]);
122
-
123
- if (!validAddresses.has(signerAddress)) {
124
- return {
125
- valid: false,
126
- reason: `signer address '${signerAddress}' is not authorized to sign manifests for identity '${identityGraph.document.id}'`,
127
- manifestId,
128
- identityId: identityGraph.document.id,
129
- signerAddress,
130
- resolvedStatus: resolved.status,
131
- };
132
- }
133
-
134
- // Step 5: check identity status — revoked identities cannot bind
135
- if (resolved.status === 'revoked') {
136
- return {
137
- valid: false,
138
- reason: 'identity has been revoked',
139
- manifestId,
140
- identityId: identityGraph.document.id,
141
- signerAddress,
142
- resolvedStatus: resolved.status,
143
- };
144
- }
145
-
146
- return {
147
- valid: true,
148
- manifestId,
149
- identityId: identityGraph.document.id,
150
- signerAddress,
151
- resolvedStatus: resolved.status,
152
- };
153
- }
154
-
155
- export async function bindManifestToIdentity(
156
- signedManifest: SignedManifest<any>,
157
- identityGraph: IdentityGraph,
158
- options?: {
159
- proofVerifiers?: Record<string, IdentityProofVerifier>;
160
- },
161
- ): Promise<ManifestIdentityBinding> {
162
- return verifyManifestIdentity(signedManifest, identityGraph, options);
163
- }
package/src/resolver.ts DELETED
@@ -1,171 +0,0 @@
1
- /**
2
- * Local-only identity graph resolver.
3
- *
4
- * Resolves an IdentityGraph into a ResolvedIdentity by:
5
- * - Verifying each claim's signature before accepting it
6
- * - Enforcing claim authority (only root, controller, or delegated addresses may issue)
7
- * - Detecting rotation/revocation
8
- * - Collecting payment recipients, service endpoints, delegations
9
- *
10
- * Security: every SignedIdentityClaim is passed through verifyIdentityClaim before
11
- * its issuer or content is trusted. Unsigned or tampered claims are silently dropped.
12
- *
13
- * Claim authority rules (after signature verification):
14
- * A claim is only accepted if its issuer is:
15
- * 1. The subject's rootAddress
16
- * 2. The subject's controllerAddress
17
- * 3. An address holding an active + signature-verified delegates_to claim from the subject
18
- * Claims from unauthorized issuers are silently dropped.
19
- */
20
-
21
- import { verifyIdentityClaim } from './verify.js';
22
- import type {
23
- IdentityGraph,
24
- IdentityResolutionResult,
25
- ResolvedIdentity,
26
- IdentityStatus,
27
- DelegationClaim,
28
- PaymentRecipientClaim,
29
- ServiceEndpointClaim,
30
- SignedIdentityClaim,
31
- } from './types.js';
32
-
33
- function isExpired(claim: { expiresAt?: number }): boolean {
34
- if (claim.expiresAt === undefined) return false;
35
- return Date.now() > claim.expiresAt;
36
- }
37
-
38
- export function resolveIdentityGraph(graph: IdentityGraph): IdentityResolutionResult {
39
- const { document, claims } = graph;
40
- const { rootAddress, controllerAddress } = document;
41
-
42
- // Step 1: signature-verify all claims upfront and collect the valid ones.
43
- // A claim is ONLY trusted when:
44
- // (a) the WOTS signature is valid over the canonical claim bytes, AND
45
- // (b) the cryptographic signer address (proof.address, bound to proof.publicKey via key
46
- // derivation) exactly matches claim.issuer.
47
- // This prevents issuer-field spoofing: an attacker cannot set claim.issuer to a privileged
48
- // address (root, controller, delegate) if they signed with their own key.
49
- const verifiedClaims = claims.filter((sc) => {
50
- const result = verifyIdentityClaim(sc);
51
- return result.valid && result.signerAddress === sc.claim.issuer;
52
- });
53
-
54
- // Step 2: collect delegation claims issued by root or controller only (first-level authority).
55
- const rootDelegations = verifiedClaims.filter(
56
- (sc) =>
57
- sc.claim.type === 'delegates_to' &&
58
- sc.claim.subject === document.id &&
59
- (sc.claim.issuer === rootAddress || sc.claim.issuer === controllerAddress) &&
60
- !isExpired(sc.claim),
61
- );
62
- const firstLevelDelegates = new Set<string>(rootDelegations.map((sc) => sc.claim.object));
63
-
64
- // Full authorized issuer set
65
- const allAuthorized = new Set<string>([rootAddress, controllerAddress, ...firstLevelDelegates]);
66
-
67
- // Helper: claim is authorized if its issuer is in the authorized set and targets this identity
68
- function isAuthorized(sc: SignedIdentityClaim): boolean {
69
- return allAuthorized.has(sc.claim.issuer) && sc.claim.subject === document.id;
70
- }
71
-
72
- // Detect revocation
73
- const revocationClaims = verifiedClaims.filter(
74
- (sc) => sc.claim.type === 'revokes' && isAuthorized(sc),
75
- );
76
- const isRevoked = revocationClaims.length > 0;
77
- const revokedAt = isRevoked
78
- ? Math.min(...revocationClaims.map((sc) => sc.claim.issuedAt))
79
- : undefined;
80
-
81
- // Detect rotation
82
- const rotationClaims = verifiedClaims.filter(
83
- (sc) => sc.claim.type === 'rotates_to' && isAuthorized(sc) && !isExpired(sc.claim),
84
- );
85
- const rotationTarget = rotationClaims.length > 0 ? rotationClaims[0].claim.object : undefined;
86
-
87
- let status: IdentityStatus = 'active';
88
- if (isRevoked) status = 'revoked';
89
- else if (rotationTarget !== undefined) status = 'rotated';
90
-
91
- // Collect all delegation claims from authorized issuers
92
- const allDelegationSignedClaims = verifiedClaims.filter(
93
- (sc) =>
94
- sc.claim.type === 'delegates_to' &&
95
- sc.claim.subject === document.id &&
96
- allAuthorized.has(sc.claim.issuer) &&
97
- !isExpired(sc.claim),
98
- );
99
-
100
- const delegates: DelegationClaim[] = allDelegationSignedClaims.map((sc) => ({
101
- claimId: sc.claim.id,
102
- issuer: sc.claim.issuer,
103
- subject: sc.claim.subject,
104
- delegatedAddress: sc.claim.object,
105
- scopes: Array.isArray(sc.claim.payload.scopes) ? (sc.claim.payload.scopes as string[]) : [],
106
- issuedAt: sc.claim.issuedAt,
107
- expiresAt: sc.claim.expiresAt,
108
- }));
109
-
110
- // controlledAddresses: all delegated addresses (any scope) — for informational use
111
- const controlledAddresses: string[] = [...new Set(delegates.map((d) => d.delegatedAddress))];
112
-
113
- // authorizedAddresses: only delegates with manifest:sign or * scope
114
- const authorizedAddresses: string[] = [
115
- ...new Set(
116
- delegates
117
- .filter((d) => d.scopes.includes('*') || d.scopes.includes('manifest:sign'))
118
- .map((d) => d.delegatedAddress),
119
- ),
120
- ];
121
-
122
- // Payment recipients
123
- const paymentRecipients: PaymentRecipientClaim[] = verifiedClaims
124
- .filter(
125
- (sc) =>
126
- sc.claim.type === 'payment_recipient' &&
127
- isAuthorized(sc) &&
128
- !isExpired(sc.claim),
129
- )
130
- .map((sc) => ({
131
- claimId: sc.claim.id,
132
- issuer: sc.claim.issuer,
133
- address: sc.claim.object,
134
- label: typeof sc.claim.payload.label === 'string' ? sc.claim.payload.label : undefined,
135
- issuedAt: sc.claim.issuedAt,
136
- expiresAt: sc.claim.expiresAt,
137
- }));
138
-
139
- // Service endpoints
140
- const serviceEndpoints: ServiceEndpointClaim[] = verifiedClaims
141
- .filter(
142
- (sc) =>
143
- sc.claim.type === 'service_endpoint' &&
144
- isAuthorized(sc) &&
145
- !isExpired(sc.claim),
146
- )
147
- .map((sc) => ({
148
- claimId: sc.claim.id,
149
- issuer: sc.claim.issuer,
150
- endpointType: typeof sc.claim.payload.endpointType === 'string' ? sc.claim.payload.endpointType : 'unknown',
151
- uri: sc.claim.object,
152
- issuedAt: sc.claim.issuedAt,
153
- expiresAt: sc.claim.expiresAt,
154
- }));
155
-
156
- const resolved: ResolvedIdentity = {
157
- document,
158
- status,
159
- rootAddress,
160
- controllerAddress,
161
- controlledAddresses,
162
- authorizedAddresses,
163
- delegates,
164
- paymentRecipients,
165
- serviceEndpoints,
166
- rotationTarget,
167
- revokedAt,
168
- };
169
-
170
- return { resolved, errors: [] };
171
- }
package/src/revocation.ts DELETED
@@ -1,25 +0,0 @@
1
- /**
2
- * Identity revocation — produces a RevocationClaim.
3
- */
4
-
5
- import { createIdentityClaim } from './claims.js';
6
- import type { IdentityClaim } from './types.js';
7
-
8
- export function revokeIdentity(opts: {
9
- issuer: string;
10
- subject: string;
11
- reason?: string;
12
- issuedAt?: number;
13
- }): IdentityClaim {
14
- const { issuer, subject, reason } = opts;
15
- const payload: Record<string, unknown> = {};
16
- if (reason !== undefined) payload.reason = reason;
17
- return createIdentityClaim({
18
- type: 'revokes',
19
- issuer,
20
- subject,
21
- object: subject,
22
- payload,
23
- issuedAt: opts.issuedAt,
24
- });
25
- }
package/src/rotation.ts DELETED
@@ -1,23 +0,0 @@
1
- /**
2
- * Identity rotation — produces a RotationClaim.
3
- */
4
-
5
- import { createIdentityClaim } from './claims.js';
6
- import type { IdentityClaim } from './types.js';
7
-
8
- export function rotateIdentity(opts: {
9
- issuer: string;
10
- subject: string;
11
- newAddress: string;
12
- issuedAt?: number;
13
- }): IdentityClaim {
14
- const { issuer, subject, newAddress } = opts;
15
- return createIdentityClaim({
16
- type: 'rotates_to',
17
- issuer,
18
- subject,
19
- object: newAddress,
20
- payload: {},
21
- issuedAt: opts.issuedAt,
22
- });
23
- }
package/src/signing.ts DELETED
@@ -1,38 +0,0 @@
1
- /**
2
- * Claim signing using WOTS primitives from @totemsdk/core.
3
- */
4
-
5
- import { sha3_256 } from '@noble/hashes/sha3.js';
6
- import {
7
- wotsSign,
8
- wotsKeypairFromSeed,
9
- wotsAddressFromKeypair,
10
- bytesToHex,
11
- } from '@totemsdk/core';
12
- import { canonicalJson } from './canonical.js';
13
- import type { IdentityClaim, SignedIdentityClaim } from './types.js';
14
-
15
- export function claimDigest(claim: IdentityClaim): Uint8Array {
16
- const canonical = canonicalJson(claim);
17
- return sha3_256(new TextEncoder().encode(canonical));
18
- }
19
-
20
- export async function signIdentityClaim(
21
- claim: IdentityClaim,
22
- seed: Uint8Array,
23
- keyIndex: number,
24
- ): Promise<SignedIdentityClaim> {
25
- const digest = claimDigest(claim);
26
- const sigBytes = wotsSign(seed, keyIndex, digest);
27
- const kp = wotsKeypairFromSeed(seed, keyIndex);
28
- const address = wotsAddressFromKeypair(kp);
29
-
30
- return {
31
- claim,
32
- proof: {
33
- address,
34
- publicKey: bytesToHex(kp.pk),
35
- signature: bytesToHex(sigBytes),
36
- },
37
- };
38
- }