@oleary-labs/signet-sdk 0.1.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/dist/admin.d.ts +38 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +112 -0
- package/dist/admin.js.map +1 -0
- package/dist/authkey-session.d.ts +64 -0
- package/dist/authkey-session.d.ts.map +1 -0
- package/dist/authkey-session.js +164 -0
- package/dist/authkey-session.js.map +1 -0
- package/dist/bootstrap.d.ts +30 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +60 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/bundler.d.ts +85 -0
- package/dist/bundler.d.ts.map +1 -0
- package/dist/bundler.js +160 -0
- package/dist/bundler.js.map +1 -0
- package/dist/delegate.d.ts +57 -0
- package/dist/delegate.d.ts.map +1 -0
- package/dist/delegate.js +111 -0
- package/dist/delegate.js.map +1 -0
- package/dist/frostVerify.d.ts +23 -0
- package/dist/frostVerify.d.ts.map +1 -0
- package/dist/frostVerify.js +69 -0
- package/dist/frostVerify.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/jwks.d.ts +28 -0
- package/dist/jwks.d.ts.map +1 -0
- package/dist/jwks.js +81 -0
- package/dist/jwks.js.map +1 -0
- package/dist/jwt.d.ts +27 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +50 -0
- package/dist/jwt.js.map +1 -0
- package/dist/keygen.d.ts +26 -0
- package/dist/keygen.d.ts.map +1 -0
- package/dist/keygen.js +60 -0
- package/dist/keygen.js.map +1 -0
- package/dist/oauth.d.ts +34 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +119 -0
- package/dist/oauth.js.map +1 -0
- package/dist/request.d.ts +42 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +115 -0
- package/dist/request.js.map +1 -0
- package/dist/scopedSign.d.ts +82 -0
- package/dist/scopedSign.d.ts.map +1 -0
- package/dist/scopedSign.js +130 -0
- package/dist/scopedSign.js.map +1 -0
- package/dist/server-prover.d.ts +29 -0
- package/dist/server-prover.d.ts.map +1 -0
- package/dist/server-prover.js +54 -0
- package/dist/server-prover.js.map +1 -0
- package/dist/session.d.ts +14 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +29 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/userop.d.ts +104 -0
- package/dist/userop.d.ts.map +1 -0
- package/dist/userop.js +212 -0
- package/dist/userop.js.map +1 -0
- package/dist/x402.d.ts +127 -0
- package/dist/x402.d.ts.map +1 -0
- package/dist/x402.js +167 -0
- package/dist/x402.js.map +1 -0
- package/package.json +64 -0
- package/src/admin.ts +178 -0
- package/src/authkey-session.ts +241 -0
- package/src/bootstrap.ts +106 -0
- package/src/bundler.ts +256 -0
- package/src/delegate.ts +163 -0
- package/src/frostVerify.ts +79 -0
- package/src/generate-inputs.ts +158 -0
- package/src/index.ts +43 -0
- package/src/jwks.ts +92 -0
- package/src/jwt.ts +74 -0
- package/src/keygen.ts +89 -0
- package/src/oauth.ts +157 -0
- package/src/partial-sha.ts +99 -0
- package/src/proof.ts +99 -0
- package/src/request.ts +174 -0
- package/src/scopedSign.ts +184 -0
- package/src/server-prover.ts +76 -0
- package/src/session.ts +33 -0
- package/src/types.ts +63 -0
- package/src/userop.ts +368 -0
- package/src/witness.ts +132 -0
- package/src/x402.ts +275 -0
package/dist/bundler.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundler RPC client for ERC-4337 UserOperations.
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic — all config is passed in, no env imports.
|
|
5
|
+
* Handles serialization between the packed UserOp format (used
|
|
6
|
+
* internally and for hashing) and the unpacked v0.7 RPC format
|
|
7
|
+
* expected by signet-min-bundler.
|
|
8
|
+
*/
|
|
9
|
+
import { concat } from "viem";
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Bundler RPC
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
export async function sendUserOp(bundlerUrl, entryPointAddress, userOp) {
|
|
14
|
+
const json = await bundlerRpc(bundlerUrl, "eth_sendUserOperation", [
|
|
15
|
+
serializeUserOp(userOp),
|
|
16
|
+
entryPointAddress,
|
|
17
|
+
]);
|
|
18
|
+
return { userOpHash: json.result };
|
|
19
|
+
}
|
|
20
|
+
export async function getUserOpReceipt(bundlerUrl, userOpHash) {
|
|
21
|
+
const json = await bundlerRpc(bundlerUrl, "eth_getUserOperationReceipt", [
|
|
22
|
+
userOpHash,
|
|
23
|
+
]);
|
|
24
|
+
if (!json.result)
|
|
25
|
+
return null;
|
|
26
|
+
return {
|
|
27
|
+
userOpHash: json.result.userOpHash,
|
|
28
|
+
transactionHash: json.result.transactionHash,
|
|
29
|
+
success: json.result.success,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export async function estimateUserOpGas(bundlerUrl, entryPointAddress, userOp) {
|
|
33
|
+
const json = await bundlerRpc(bundlerUrl, "eth_estimateUserOperationGas", [
|
|
34
|
+
serializeUserOp(userOp),
|
|
35
|
+
entryPointAddress,
|
|
36
|
+
]);
|
|
37
|
+
return json.result;
|
|
38
|
+
}
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// ERC-7677 Paymaster
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
/**
|
|
43
|
+
* Call pm_getPaymasterStubData.
|
|
44
|
+
*
|
|
45
|
+
* Returns paymaster fields with a correctly-sized but zeroed signature,
|
|
46
|
+
* suitable for gas estimation. Call this BEFORE eth_estimateUserOperationGas
|
|
47
|
+
* so the estimate accounts for the paymaster's verification overhead.
|
|
48
|
+
*/
|
|
49
|
+
export async function getPaymasterStubData(bundlerUrl, entryPointAddress, chainId, userOp, context) {
|
|
50
|
+
return paymasterCall(bundlerUrl, entryPointAddress, chainId, "pm_getPaymasterStubData", userOp, context);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Call pm_getPaymasterData.
|
|
54
|
+
*
|
|
55
|
+
* Returns a real paymaster signature. The bundler first checks the
|
|
56
|
+
* paymaster contract's shouldSponsor() policy via eth_call; if sponsorship
|
|
57
|
+
* is rejected, this throws.
|
|
58
|
+
*
|
|
59
|
+
* IMPORTANT: call AFTER gas estimation, because the paymaster signs over
|
|
60
|
+
* the gas fields. Changing gas after this call invalidates the signature.
|
|
61
|
+
*/
|
|
62
|
+
export async function getPaymasterData(bundlerUrl, entryPointAddress, chainId, userOp, context) {
|
|
63
|
+
return paymasterCall(bundlerUrl, entryPointAddress, chainId, "pm_getPaymasterData", userOp, context);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Pack an ERC-7677 sponsorship response into the on-chain paymasterAndData
|
|
67
|
+
* layout expected by EntryPoint v0.7:
|
|
68
|
+
*
|
|
69
|
+
* [paymaster:20][verifGasLimit:16][postOpGasLimit:16][paymasterData:rest]
|
|
70
|
+
*
|
|
71
|
+
* The paymaster's getHash function reads paymasterAndData[20:52] as the
|
|
72
|
+
* packed (verifGasLimit || postOpGasLimit) uint128 pair — so the returned
|
|
73
|
+
* layout must match exactly or the paymaster signature will not verify
|
|
74
|
+
* on-chain (AA34 signature error).
|
|
75
|
+
*
|
|
76
|
+
* NOTE on the bundler's wire format: signet-min-bundler's FromRPC
|
|
77
|
+
* concatenates the JSON `paymaster` + `paymasterData` fields directly
|
|
78
|
+
* into paymasterAndData. It does NOT re-insert gas-limit bytes. So when
|
|
79
|
+
* serializing for eth_sendUserOperation, the `paymasterData` on the wire
|
|
80
|
+
* already includes the packed gas limits.
|
|
81
|
+
*/
|
|
82
|
+
export function applyPaymasterSponsorship(userOp, s) {
|
|
83
|
+
const verifGas = BigInt(s.paymasterVerificationGasLimit);
|
|
84
|
+
const postOpGas = BigInt(s.paymasterPostOpGasLimit);
|
|
85
|
+
const packedGas = (`0x${verifGas.toString(16).padStart(32, "0")}${postOpGas.toString(16).padStart(32, "0")}`);
|
|
86
|
+
return {
|
|
87
|
+
...userOp,
|
|
88
|
+
paymasterAndData: concat([s.paymaster, packedGas, s.paymasterData]),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Internal
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
async function paymasterCall(bundlerUrl, entryPointAddress, chainId, method, userOp, context) {
|
|
95
|
+
const json = await bundlerRpc(bundlerUrl, method, [
|
|
96
|
+
serializeUserOp(userOp),
|
|
97
|
+
entryPointAddress,
|
|
98
|
+
`0x${chainId.toString(16)}`,
|
|
99
|
+
context ?? {},
|
|
100
|
+
]);
|
|
101
|
+
return {
|
|
102
|
+
paymaster: json.result.paymaster,
|
|
103
|
+
paymasterData: json.result.paymasterData,
|
|
104
|
+
paymasterVerificationGasLimit: json.result.paymasterVerificationGasLimit,
|
|
105
|
+
paymasterPostOpGasLimit: json.result.paymasterPostOpGasLimit,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
109
|
+
async function bundlerRpc(bundlerUrl, method, params) {
|
|
110
|
+
const res = await fetch(bundlerUrl, {
|
|
111
|
+
method: "POST",
|
|
112
|
+
headers: { "Content-Type": "application/json" },
|
|
113
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
|
|
114
|
+
});
|
|
115
|
+
const json = await res.json();
|
|
116
|
+
if (json.error) {
|
|
117
|
+
throw new Error(`${method} failed: ${json.error.message}`);
|
|
118
|
+
}
|
|
119
|
+
return json;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Serialize a PackedUserOperation to the unpacked v0.7 RPC format
|
|
123
|
+
* expected by signet-min-bundler.
|
|
124
|
+
*
|
|
125
|
+
* Paymaster handling: the bundler's FromRPC builds paymasterAndData by
|
|
126
|
+
* concatenating `paymaster` + `paymasterData` with no re-insertion of gas
|
|
127
|
+
* limits, so we send `paymasterData` as bytes 20..end of our stored
|
|
128
|
+
* paymasterAndData (which already includes the packed gas limits written
|
|
129
|
+
* by applyPaymasterSponsorship).
|
|
130
|
+
*/
|
|
131
|
+
function serializeUserOp(userOp) {
|
|
132
|
+
const gasLimitsHex = userOp.accountGasLimits.slice(2).padStart(64, "0");
|
|
133
|
+
const verificationGasLimit = `0x${BigInt("0x" + gasLimitsHex.slice(0, 32)).toString(16)}`;
|
|
134
|
+
const callGasLimit = `0x${BigInt("0x" + gasLimitsHex.slice(32, 64)).toString(16)}`;
|
|
135
|
+
const gasFeesHex = userOp.gasFees.slice(2).padStart(64, "0");
|
|
136
|
+
const maxPriorityFeePerGas = `0x${BigInt("0x" + gasFeesHex.slice(0, 32)).toString(16)}`;
|
|
137
|
+
const maxFeePerGas = `0x${BigInt("0x" + gasFeesHex.slice(32, 64)).toString(16)}`;
|
|
138
|
+
const initCodeHex = userOp.initCode.slice(2);
|
|
139
|
+
const factory = initCodeHex.length >= 40 ? `0x${initCodeHex.slice(0, 40)}` : "";
|
|
140
|
+
const factoryData = initCodeHex.length > 40 ? `0x${initCodeHex.slice(40)}` : "";
|
|
141
|
+
const pmHex = userOp.paymasterAndData.slice(2);
|
|
142
|
+
const paymaster = pmHex.length >= 40 ? `0x${pmHex.slice(0, 40)}` : "";
|
|
143
|
+
const paymasterData = pmHex.length > 40 ? `0x${pmHex.slice(40)}` : "";
|
|
144
|
+
return {
|
|
145
|
+
sender: userOp.sender,
|
|
146
|
+
nonce: `0x${userOp.nonce.toString(16)}`,
|
|
147
|
+
factory,
|
|
148
|
+
factoryData,
|
|
149
|
+
callData: userOp.callData,
|
|
150
|
+
callGasLimit,
|
|
151
|
+
verificationGasLimit,
|
|
152
|
+
preVerificationGas: `0x${userOp.preVerificationGas.toString(16)}`,
|
|
153
|
+
maxFeePerGas,
|
|
154
|
+
maxPriorityFeePerGas,
|
|
155
|
+
paymaster,
|
|
156
|
+
paymasterData,
|
|
157
|
+
signature: userOp.signature,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=bundler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.js","sourceRoot":"","sources":["../src/bundler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation token minting and delegation-based auth.
|
|
3
|
+
*
|
|
4
|
+
* Delegation tokens are JWTs signed by a parent FROST/ECDSA key that grant
|
|
5
|
+
* an agent long-lived access to a specific scoped sub-key without requiring
|
|
6
|
+
* the user's OAuth session.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* 1. User creates parent key + scoped sub-key via keygen
|
|
10
|
+
* 2. User calls requestDelegation() → gets a JWT signed by parent key
|
|
11
|
+
* 3. Agent calls authenticateWithDelegation() → establishes session
|
|
12
|
+
* 4. Agent signs with the scoped sub-key via the session
|
|
13
|
+
*/
|
|
14
|
+
import type { SessionKeypair, IdTokenClaims } from "./types";
|
|
15
|
+
export interface DelegationResult {
|
|
16
|
+
token: string;
|
|
17
|
+
keyId: string;
|
|
18
|
+
parentKey: string;
|
|
19
|
+
expiresAt: number;
|
|
20
|
+
}
|
|
21
|
+
export interface DelegationAuthResult {
|
|
22
|
+
identity: string;
|
|
23
|
+
keyId: string;
|
|
24
|
+
expiresAt: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Request a delegation token for a scoped sub-key.
|
|
28
|
+
*
|
|
29
|
+
* Requires an active OAuth session. The node threshold-signs a JWT using
|
|
30
|
+
* the parent key, granting the token holder access to the sub-key.
|
|
31
|
+
*
|
|
32
|
+
* @param nodeUrl - Target group node URL
|
|
33
|
+
* @param proxyEndpoint - CORS proxy URL (e.g. "/api/node/proxy")
|
|
34
|
+
* @param groupId - Group contract address
|
|
35
|
+
* @param keyId - The sub-key to delegate access to
|
|
36
|
+
* @param parentKeyId - The parent key that signs the JWT
|
|
37
|
+
* @param curve - Key curve (e.g. "ecdsa_secp256k1")
|
|
38
|
+
* @param expiresIn - Token lifetime in seconds (e.g. 2592000 for 30 days)
|
|
39
|
+
* @param sessionKeypair - Active session keypair
|
|
40
|
+
* @param claims - OAuth claims for session auth
|
|
41
|
+
* @param identity - For auth key cert sessions
|
|
42
|
+
*/
|
|
43
|
+
export declare function requestDelegation(nodeUrl: string, proxyEndpoint: string, groupId: string, keySuffix: string, parentKeyId: string, curve: string, expiresIn: number, sessionKeypair: SessionKeypair, claims: IdTokenClaims, identity?: string): Promise<DelegationResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Authenticate with a node using a delegation token.
|
|
46
|
+
*
|
|
47
|
+
* The agent presents a JWT signed by the parent key. The node verifies
|
|
48
|
+
* the signature and creates a session scoped to the sub-key.
|
|
49
|
+
*
|
|
50
|
+
* @param nodeUrl - Target group node URL
|
|
51
|
+
* @param proxyEndpoint - CORS proxy URL
|
|
52
|
+
* @param groupId - Group contract address
|
|
53
|
+
* @param delegationToken - The JWT from requestDelegation()
|
|
54
|
+
* @param sessionKeypair - Fresh ephemeral session keypair for the agent
|
|
55
|
+
*/
|
|
56
|
+
export declare function authenticateWithDelegation(nodeUrl: string, proxyEndpoint: string, groupId: string, delegationToken: string, sessionKeypair: SessionKeypair): Promise<DelegationAuthResult>;
|
|
57
|
+
//# sourceMappingURL=delegate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegate.d.ts","sourceRoot":"","sources":["../src/delegate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAO7D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,aAAa,EACrB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CA8C3B;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CA0B/B"}
|
package/dist/delegate.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation token minting and delegation-based auth.
|
|
3
|
+
*
|
|
4
|
+
* Delegation tokens are JWTs signed by a parent FROST/ECDSA key that grant
|
|
5
|
+
* an agent long-lived access to a specific scoped sub-key without requiring
|
|
6
|
+
* the user's OAuth session.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* 1. User creates parent key + scoped sub-key via keygen
|
|
10
|
+
* 2. User calls requestDelegation() → gets a JWT signed by parent key
|
|
11
|
+
* 3. Agent calls authenticateWithDelegation() → establishes session
|
|
12
|
+
* 4. Agent signs with the scoped sub-key via the session
|
|
13
|
+
*/
|
|
14
|
+
import { signKeygenRequest } from "./request";
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Mint delegation token (user path)
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* Request a delegation token for a scoped sub-key.
|
|
20
|
+
*
|
|
21
|
+
* Requires an active OAuth session. The node threshold-signs a JWT using
|
|
22
|
+
* the parent key, granting the token holder access to the sub-key.
|
|
23
|
+
*
|
|
24
|
+
* @param nodeUrl - Target group node URL
|
|
25
|
+
* @param proxyEndpoint - CORS proxy URL (e.g. "/api/node/proxy")
|
|
26
|
+
* @param groupId - Group contract address
|
|
27
|
+
* @param keyId - The sub-key to delegate access to
|
|
28
|
+
* @param parentKeyId - The parent key that signs the JWT
|
|
29
|
+
* @param curve - Key curve (e.g. "ecdsa_secp256k1")
|
|
30
|
+
* @param expiresIn - Token lifetime in seconds (e.g. 2592000 for 30 days)
|
|
31
|
+
* @param sessionKeypair - Active session keypair
|
|
32
|
+
* @param claims - OAuth claims for session auth
|
|
33
|
+
* @param identity - For auth key cert sessions
|
|
34
|
+
*/
|
|
35
|
+
export async function requestDelegation(nodeUrl, proxyEndpoint, groupId, keySuffix, parentKeyId, curve, expiresIn, sessionKeypair, claims, identity) {
|
|
36
|
+
// Build session-authenticated request.
|
|
37
|
+
// Try with suffix in the canonical hash — if the node resolves the key
|
|
38
|
+
// from session + suffix, the signature must cover the suffixed key ID.
|
|
39
|
+
const signReq = await signKeygenRequest(sessionKeypair, claims, groupId, keySuffix, identity);
|
|
40
|
+
const res = await fetch(proxyEndpoint, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: {
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
"x-node-url": nodeUrl,
|
|
45
|
+
"x-node-path": "/v1/delegate",
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify({
|
|
48
|
+
group_id: groupId.toLowerCase(),
|
|
49
|
+
key_suffix: keySuffix,
|
|
50
|
+
parent_key_id: parentKeyId,
|
|
51
|
+
curve,
|
|
52
|
+
expires_in: expiresIn,
|
|
53
|
+
session_pub: signReq.session_pub,
|
|
54
|
+
request_sig: signReq.request_sig,
|
|
55
|
+
nonce: signReq.nonce,
|
|
56
|
+
timestamp: signReq.timestamp,
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok) {
|
|
60
|
+
const body = await res.text();
|
|
61
|
+
throw new Error(`Delegation failed: ${res.status} — ${body}`);
|
|
62
|
+
}
|
|
63
|
+
const data = await res.json();
|
|
64
|
+
return {
|
|
65
|
+
token: data.token,
|
|
66
|
+
keyId: data.key_id,
|
|
67
|
+
parentKey: data.parent_key,
|
|
68
|
+
expiresAt: data.expires_at,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Authenticate with delegation token (agent path)
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
/**
|
|
75
|
+
* Authenticate with a node using a delegation token.
|
|
76
|
+
*
|
|
77
|
+
* The agent presents a JWT signed by the parent key. The node verifies
|
|
78
|
+
* the signature and creates a session scoped to the sub-key.
|
|
79
|
+
*
|
|
80
|
+
* @param nodeUrl - Target group node URL
|
|
81
|
+
* @param proxyEndpoint - CORS proxy URL
|
|
82
|
+
* @param groupId - Group contract address
|
|
83
|
+
* @param delegationToken - The JWT from requestDelegation()
|
|
84
|
+
* @param sessionKeypair - Fresh ephemeral session keypair for the agent
|
|
85
|
+
*/
|
|
86
|
+
export async function authenticateWithDelegation(nodeUrl, proxyEndpoint, groupId, delegationToken, sessionKeypair) {
|
|
87
|
+
const res = await fetch(proxyEndpoint, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
"x-node-url": nodeUrl,
|
|
92
|
+
"x-node-path": "/v1/auth",
|
|
93
|
+
},
|
|
94
|
+
body: JSON.stringify({
|
|
95
|
+
group_id: groupId.toLowerCase(),
|
|
96
|
+
delegation_token: delegationToken,
|
|
97
|
+
session_pub: sessionKeypair.publicKeyHex,
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
if (!res.ok) {
|
|
101
|
+
const body = await res.text();
|
|
102
|
+
throw new Error(`Delegation auth failed: ${res.status} — ${body}`);
|
|
103
|
+
}
|
|
104
|
+
const data = await res.json();
|
|
105
|
+
return {
|
|
106
|
+
identity: data.identity,
|
|
107
|
+
keyId: data.key_id,
|
|
108
|
+
expiresAt: data.expires_at,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=delegate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegate.js","sourceRoot":"","sources":["../src/delegate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side FROST Schnorr signature verification (RFC 9591 secp256k1-SHA256-v1).
|
|
3
|
+
*
|
|
4
|
+
* Verifies a 65-byte FROST threshold signature against a compressed group
|
|
5
|
+
* public key and message. Uses the same algorithm as FROSTVerifier.sol:
|
|
6
|
+
*
|
|
7
|
+
* Verification equation: z·G = R + c·Y
|
|
8
|
+
* Challenge: c = H2(R || Y || msg) via expand_message_xmd (RFC 9380)
|
|
9
|
+
* DST: "FROST-secp256k1-SHA256-v1chal"
|
|
10
|
+
*
|
|
11
|
+
* Uses @noble/curves (already installed) for elliptic curve arithmetic
|
|
12
|
+
* and RFC 9380 hash-to-curve utilities.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Verify a FROST Schnorr signature.
|
|
16
|
+
*
|
|
17
|
+
* @param message - The message bytes that were signed (typically 32 bytes)
|
|
18
|
+
* @param signature - 65-byte signature: R.x(32) || z(32) || v(1)
|
|
19
|
+
* @param groupPublicKey - 33-byte compressed secp256k1 group public key
|
|
20
|
+
* @returns true if the signature is valid
|
|
21
|
+
*/
|
|
22
|
+
export declare function verifyFrostSignature(message: Uint8Array, signature: Uint8Array, groupPublicKey: Uint8Array): boolean;
|
|
23
|
+
//# sourceMappingURL=frostVerify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frostVerify.d.ts","sourceRoot":"","sources":["../src/frostVerify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,UAAU,EACrB,cAAc,EAAE,UAAU,GACzB,OAAO,CAoCT"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side FROST Schnorr signature verification (RFC 9591 secp256k1-SHA256-v1).
|
|
3
|
+
*
|
|
4
|
+
* Verifies a 65-byte FROST threshold signature against a compressed group
|
|
5
|
+
* public key and message. Uses the same algorithm as FROSTVerifier.sol:
|
|
6
|
+
*
|
|
7
|
+
* Verification equation: z·G = R + c·Y
|
|
8
|
+
* Challenge: c = H2(R || Y || msg) via expand_message_xmd (RFC 9380)
|
|
9
|
+
* DST: "FROST-secp256k1-SHA256-v1chal"
|
|
10
|
+
*
|
|
11
|
+
* Uses @noble/curves (already installed) for elliptic curve arithmetic
|
|
12
|
+
* and RFC 9380 hash-to-curve utilities.
|
|
13
|
+
*/
|
|
14
|
+
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
15
|
+
import { expand_message_xmd } from "@noble/curves/abstract/hash-to-curve";
|
|
16
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
17
|
+
import { concatBytes } from "@noble/hashes/utils";
|
|
18
|
+
const DST = new TextEncoder().encode("FROST-secp256k1-SHA256-v1chal");
|
|
19
|
+
const N = secp256k1.CURVE.n;
|
|
20
|
+
/**
|
|
21
|
+
* Verify a FROST Schnorr signature.
|
|
22
|
+
*
|
|
23
|
+
* @param message - The message bytes that were signed (typically 32 bytes)
|
|
24
|
+
* @param signature - 65-byte signature: R.x(32) || z(32) || v(1)
|
|
25
|
+
* @param groupPublicKey - 33-byte compressed secp256k1 group public key
|
|
26
|
+
* @returns true if the signature is valid
|
|
27
|
+
*/
|
|
28
|
+
export function verifyFrostSignature(message, signature, groupPublicKey) {
|
|
29
|
+
if (signature.length !== 65)
|
|
30
|
+
return false;
|
|
31
|
+
if (groupPublicKey.length !== 33)
|
|
32
|
+
return false;
|
|
33
|
+
const rx = signature.slice(0, 32);
|
|
34
|
+
const z = bytesToBigInt(signature.slice(32, 64));
|
|
35
|
+
const v = signature[64];
|
|
36
|
+
if (z === 0n || z >= N)
|
|
37
|
+
return false;
|
|
38
|
+
// Reconstruct compressed R from R.x + parity
|
|
39
|
+
const rCompressed = new Uint8Array(33);
|
|
40
|
+
rCompressed[0] = v === 0 ? 0x02 : 0x03;
|
|
41
|
+
rCompressed.set(rx, 1);
|
|
42
|
+
// Challenge: c = H2(R_compressed || groupPublicKey || message)
|
|
43
|
+
// Uses expand_message_xmd (RFC 9380) with SHA-256, output 48 bytes, reduced mod N
|
|
44
|
+
const input = concatBytes(rCompressed, groupPublicKey, message);
|
|
45
|
+
const uniform = expand_message_xmd(input, DST, 48, sha256);
|
|
46
|
+
const c = bytesToBigInt(uniform) % N;
|
|
47
|
+
if (c === 0n)
|
|
48
|
+
return false;
|
|
49
|
+
// Verify: z·G == R + c·Y
|
|
50
|
+
try {
|
|
51
|
+
const R = secp256k1.ProjectivePoint.fromHex(rCompressed);
|
|
52
|
+
const Y = secp256k1.ProjectivePoint.fromHex(groupPublicKey);
|
|
53
|
+
const G = secp256k1.ProjectivePoint.BASE;
|
|
54
|
+
const lhs = G.multiply(z);
|
|
55
|
+
const rhs = R.add(Y.multiply(c));
|
|
56
|
+
return lhs.equals(rhs);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function bytesToBigInt(bytes) {
|
|
63
|
+
let result = 0n;
|
|
64
|
+
for (const b of bytes) {
|
|
65
|
+
result = (result << 8n) | BigInt(b);
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=frostVerify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frostVerify.js","sourceRoot":"","sources":["../src/frostVerify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,+BAA+B,CAAC,CAAC;AACtE,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAE5B;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAmB,EACnB,SAAqB,EACrB,cAA0B;IAE1B,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,cAAc,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAE/C,MAAM,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClC,MAAM,CAAC,GAAG,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACjD,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IAExB,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAErC,6CAA6C;IAC7C,MAAM,WAAW,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACvC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACvC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAEvB,+DAA+D;IAC/D,kFAAkF;IAClF,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IAC3D,MAAM,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAErC,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAE3B,yBAAyB;IACzB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACzD,MAAM,CAAC,GAAG,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAC5D,MAAM,CAAC,GAAG,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC;QAEzC,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAiB;IACtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signet DKMS SDK
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic library for Signet protocol interactions.
|
|
5
|
+
*
|
|
6
|
+
* This barrel export includes only the core modules that have no heavy
|
|
7
|
+
* dependencies. For ZK proof generation (client-side), import directly:
|
|
8
|
+
*
|
|
9
|
+
* import { generateJWTProof } from "@oleary-labs/signet-sdk/proof"
|
|
10
|
+
* import { buildFullWitness } from "@oleary-labs/signet-sdk/witness"
|
|
11
|
+
*
|
|
12
|
+
* These require @noir-lang/noir_js, @aztec/bb.js, and
|
|
13
|
+
* @oleary-labs/signet-circuits as peer dependencies.
|
|
14
|
+
*/
|
|
15
|
+
export * from "./types";
|
|
16
|
+
export * from "./session";
|
|
17
|
+
export * from "./request";
|
|
18
|
+
export * from "./keygen";
|
|
19
|
+
export * from "./oauth";
|
|
20
|
+
export * from "./jwt";
|
|
21
|
+
export * from "./jwks";
|
|
22
|
+
export * from "./bootstrap";
|
|
23
|
+
export * from "./authkey-session";
|
|
24
|
+
export * from "./server-prover";
|
|
25
|
+
export * from "./admin";
|
|
26
|
+
export * from "./delegate";
|
|
27
|
+
export * from "./scopedSign";
|
|
28
|
+
export * from "./frostVerify";
|
|
29
|
+
export * from "./x402";
|
|
30
|
+
export * from "./userop";
|
|
31
|
+
export * from "./bundler";
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AAGzB,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,SAAS,CAAC;AAGxB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAG9B,cAAc,QAAQ,CAAC;AAGvB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signet DKMS SDK
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic library for Signet protocol interactions.
|
|
5
|
+
*
|
|
6
|
+
* This barrel export includes only the core modules that have no heavy
|
|
7
|
+
* dependencies. For ZK proof generation (client-side), import directly:
|
|
8
|
+
*
|
|
9
|
+
* import { generateJWTProof } from "@oleary-labs/signet-sdk/proof"
|
|
10
|
+
* import { buildFullWitness } from "@oleary-labs/signet-sdk/witness"
|
|
11
|
+
*
|
|
12
|
+
* These require @noir-lang/noir_js, @aztec/bb.js, and
|
|
13
|
+
* @oleary-labs/signet-circuits as peer dependencies.
|
|
14
|
+
*/
|
|
15
|
+
// Core
|
|
16
|
+
export * from "./types";
|
|
17
|
+
export * from "./session";
|
|
18
|
+
export * from "./request";
|
|
19
|
+
export * from "./keygen";
|
|
20
|
+
// Auth (lightweight — no WASM)
|
|
21
|
+
export * from "./oauth";
|
|
22
|
+
export * from "./jwt";
|
|
23
|
+
export * from "./jwks";
|
|
24
|
+
export * from "./bootstrap";
|
|
25
|
+
export * from "./authkey-session";
|
|
26
|
+
export * from "./server-prover";
|
|
27
|
+
// Admin
|
|
28
|
+
export * from "./admin";
|
|
29
|
+
// Signing + Delegation
|
|
30
|
+
export * from "./delegate";
|
|
31
|
+
export * from "./scopedSign";
|
|
32
|
+
export * from "./frostVerify";
|
|
33
|
+
// x402
|
|
34
|
+
export * from "./x402";
|
|
35
|
+
// ERC-4337
|
|
36
|
+
export * from "./userop";
|
|
37
|
+
export * from "./bundler";
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO;AACP,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AAEzB,+BAA+B;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAEhC,QAAQ;AACR,cAAc,SAAS,CAAC;AAExB,uBAAuB;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAE9B,OAAO;AACP,cAAc,QAAQ,CAAC;AAEvB,WAAW;AACX,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC"}
|
package/dist/jwks.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWKS (JSON Web Key Set) fetcher.
|
|
3
|
+
*
|
|
4
|
+
* Fetches RSA public keys from any OIDC-compliant issuer and extracts
|
|
5
|
+
* the modulus needed for the ZK proof witness. Supports Google, Clerk,
|
|
6
|
+
* and any issuer with a standard JWKS endpoint.
|
|
7
|
+
*/
|
|
8
|
+
import type { JWKSKey } from "./types";
|
|
9
|
+
/**
|
|
10
|
+
* Fetch JWKS keys for an issuer.
|
|
11
|
+
*/
|
|
12
|
+
export declare function fetchJWKS(issuer?: string): Promise<JWKSKey[]>;
|
|
13
|
+
/** @deprecated Use fetchJWKS() instead */
|
|
14
|
+
export declare const fetchGoogleJWKS: () => Promise<JWKSKey[]>;
|
|
15
|
+
/**
|
|
16
|
+
* Find the RSA key matching a JWT's kid.
|
|
17
|
+
* If issuer is provided, fetches from that issuer's JWKS endpoint.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getJWKSKeyForKid(kid: string, issuer?: string): Promise<JWKSKey>;
|
|
20
|
+
/**
|
|
21
|
+
* Decode a base64url-encoded JWKS modulus to a BigInt.
|
|
22
|
+
*/
|
|
23
|
+
export declare function decodeModulus(base64url: string): bigint;
|
|
24
|
+
/**
|
|
25
|
+
* Decode a base64url-encoded JWKS modulus to raw bytes.
|
|
26
|
+
*/
|
|
27
|
+
export declare function decodeModulusBytes(base64url: string): Uint8Array;
|
|
28
|
+
//# sourceMappingURL=jwks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwks.d.ts","sourceRoot":"","sources":["../src/jwks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAqBvC;;GAEG;AACH,wBAAsB,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAgBnE;AAED,0CAA0C;AAC1C,eAAO,MAAM,eAAe,0BAAiD,CAAC;AAE9E;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUrF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAOhE"}
|
package/dist/jwks.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWKS (JSON Web Key Set) fetcher.
|
|
3
|
+
*
|
|
4
|
+
* Fetches RSA public keys from any OIDC-compliant issuer and extracts
|
|
5
|
+
* the modulus needed for the ZK proof witness. Supports Google, Clerk,
|
|
6
|
+
* and any issuer with a standard JWKS endpoint.
|
|
7
|
+
*/
|
|
8
|
+
const GOOGLE_JWKS_URI = "https://www.googleapis.com/oauth2/v3/certs";
|
|
9
|
+
// Cache per issuer URI
|
|
10
|
+
const cache = new Map();
|
|
11
|
+
const CACHE_TTL = 3600_000; // 1 hour
|
|
12
|
+
/**
|
|
13
|
+
* Derive the JWKS URI from a JWT issuer.
|
|
14
|
+
* Google uses a non-standard path; all other OIDC issuers use /.well-known/jwks.json.
|
|
15
|
+
*/
|
|
16
|
+
function jwksUriForIssuer(issuer) {
|
|
17
|
+
if (issuer === "https://accounts.google.com") {
|
|
18
|
+
return GOOGLE_JWKS_URI;
|
|
19
|
+
}
|
|
20
|
+
// Standard OIDC convention
|
|
21
|
+
const base = issuer.endsWith("/") ? issuer.slice(0, -1) : issuer;
|
|
22
|
+
return `${base}/.well-known/jwks.json`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Fetch JWKS keys for an issuer.
|
|
26
|
+
*/
|
|
27
|
+
export async function fetchJWKS(issuer) {
|
|
28
|
+
const uri = jwksUriForIssuer(issuer ?? "https://accounts.google.com");
|
|
29
|
+
const cached = cache.get(uri);
|
|
30
|
+
if (cached && Date.now() < cached.expiry) {
|
|
31
|
+
return cached.keys;
|
|
32
|
+
}
|
|
33
|
+
const res = await fetch(uri);
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
throw new Error(`Failed to fetch JWKS from ${uri}: ${res.status}`);
|
|
36
|
+
}
|
|
37
|
+
const data = await res.json();
|
|
38
|
+
const keys = data.keys;
|
|
39
|
+
cache.set(uri, { keys, expiry: Date.now() + CACHE_TTL });
|
|
40
|
+
return keys;
|
|
41
|
+
}
|
|
42
|
+
/** @deprecated Use fetchJWKS() instead */
|
|
43
|
+
export const fetchGoogleJWKS = () => fetchJWKS("https://accounts.google.com");
|
|
44
|
+
/**
|
|
45
|
+
* Find the RSA key matching a JWT's kid.
|
|
46
|
+
* If issuer is provided, fetches from that issuer's JWKS endpoint.
|
|
47
|
+
*/
|
|
48
|
+
export async function getJWKSKeyForKid(kid, issuer) {
|
|
49
|
+
const keys = await fetchJWKS(issuer);
|
|
50
|
+
const key = keys.find((k) => k.kid === kid);
|
|
51
|
+
if (!key) {
|
|
52
|
+
throw new Error(`No JWKS key found for kid: ${kid}`);
|
|
53
|
+
}
|
|
54
|
+
if (key.kty !== "RSA") {
|
|
55
|
+
throw new Error(`Expected RSA key, got ${key.kty}`);
|
|
56
|
+
}
|
|
57
|
+
return key;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Decode a base64url-encoded JWKS modulus to a BigInt.
|
|
61
|
+
*/
|
|
62
|
+
export function decodeModulus(base64url) {
|
|
63
|
+
const binary = atob(base64url.replace(/-/g, "+").replace(/_/g, "/"));
|
|
64
|
+
let hex = "";
|
|
65
|
+
for (let i = 0; i < binary.length; i++) {
|
|
66
|
+
hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
|
|
67
|
+
}
|
|
68
|
+
return BigInt("0x" + hex);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Decode a base64url-encoded JWKS modulus to raw bytes.
|
|
72
|
+
*/
|
|
73
|
+
export function decodeModulusBytes(base64url) {
|
|
74
|
+
const binary = atob(base64url.replace(/-/g, "+").replace(/_/g, "/"));
|
|
75
|
+
const bytes = new Uint8Array(binary.length);
|
|
76
|
+
for (let i = 0; i < binary.length; i++) {
|
|
77
|
+
bytes[i] = binary.charCodeAt(i);
|
|
78
|
+
}
|
|
79
|
+
return bytes;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=jwks.js.map
|
package/dist/jwks.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwks.js","sourceRoot":"","sources":["../src/jwks.ts"],"names":[],"mappings":"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"}
|